TEIV: Proposed seed code from Ericsson for review

Large seed code proposal from Ericsson for an OSC SMO Topology & Inventory Exposure SMOS

Issue-ID: SMO-147
Change-Id: Iaa8db611f9e87ee16f85bd38aa7200a3100dabba
Signed-off-by: JohnKeeney <john.keeney@est.tech>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..713206a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+target
+**/.settings
+**/.classpath
+**/.project
+**/.buildpath
+**/.factorypath
+**/.springBeans
+**/.project
+**/.classpath
+.idea
+.checkstyle
+.DS_Store
+.*~
+*.iml
+**/logs/
+**/debug-logs/
+*.class
+*.swp
+*.log
+*.tmp
+**/bin/
+/.metadata/
+**/.sts4-cache
+**/.java-version
+index.html
+**/.openapi-generator
+.openapi-generator-ignore
+yang-parser/src/main/resources/modules/*.yang
+yang-parser/src/test/resources/_orig-modules/ietf*.yang
+yang-parser/src/test/resources/_orig-modules/_3gpp*.yang
+yang-parser/src/test/resources/_orig-modules/iana*.yang
+pgsql-schema-generator/src/test/resources/generate-defaults/import/*.yang
+teiv/src/main/resources/models/import/*.yang
diff --git a/CopyrightSample.txt b/CopyrightSample.txt
new file mode 100644
index 0000000..9bf94c8
--- /dev/null
+++ b/CopyrightSample.txt
@@ -0,0 +1,20 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) $YEAR OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..57bc88a
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..738d5e3
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+Initial ReadMe.
\ No newline at end of file
diff --git a/code_conventions.xml b/code_conventions.xml
new file mode 100644
index 0000000..1eb56a7
--- /dev/null
+++ b/code_conventions.xml
@@ -0,0 +1,587 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<profiles version="21">
+    <profile kind="CodeFormatterProfile" name="Java Conventions" version="21">
+        <setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space" />
+        <setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.indentation.size" value="8" />
+        <setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4" />
+        <setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header"
+            value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header"
+            value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header"
+            value="true" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header"
+            value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header"
+            value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration"
+            value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration"
+            value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration"
+            value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration"
+            value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation"
+            value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration"
+            value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration"
+            value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration"
+            value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement"
+            value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement"
+            value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration"
+            value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations"
+            value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration"
+            value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration"
+            value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression"
+            value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference"
+            value="do not insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference"
+            value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments"
+            value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert" />
+        <setting
+            id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters"
+            value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1" />
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line"
+            value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line"
+            value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line"
+            value="one_line_never" />
+        <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="124" />
+        <setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2" />
+        <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2" />
+        <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="49" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="18" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression"
+            value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="2" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="49" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="0" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="124" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position"
+            value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments"
+            value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags"
+            value="do not insert" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true" />
+        <setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false" />
+        <setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on" />
+        <setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off" />
+    </profile>
+</profiles>
\ No newline at end of file
diff --git a/docker-compose/cloudEventProducer/cloudEventProducer.sh b/docker-compose/cloudEventProducer/cloudEventProducer.sh
new file mode 100644
index 0000000..f0a27ef
--- /dev/null
+++ b/docker-compose/cloudEventProducer/cloudEventProducer.sh
@@ -0,0 +1,50 @@
+#! /bin/bash
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+KAFKA_NAMESPACE="${1:-teiv}"
+KAFKA_TOPIC="${2:-topology-inventory-ingestion}"
+KAFKA_POD_NAME="${3:-kafka-0}"
+FILE_DUPLICATION_FACTOR="${4:-1}" # How many times to use the same CloudEvent file
+FOLDER_OF_CLOUDEVENTS="${5:-events}" # All files in this folder are written to kafka
+# number of generated files == number of files in the $FOLDER_OF_CLOUDEVENTS * $FILE_DUPLICATION_FACTOR
+
+echo "Producing messages to Kafka topic '$KAFKA_TOPIC'..."
+
+# Loop to produce multiple messages
+for ((i=0; i<$FILE_DUPLICATION_FACTOR; i++)); do
+  for file in "$FOLDER_OF_CLOUDEVENTS"/*; do
+    if [ -f "$file" ]; then
+      # Replace the new line characters with a space and write to kafka
+      sed ':a;N;$!ba;s/\n/ /g' $file | \
+        docker exec -i kafka kafka-console-producer --bootstrap-server kafka:9092 --topic "$KAFKA_TOPIC" \
+        --property parse.headers=true --property headers.key.separator=::: --property headers.delimiter=,,, --property parse.key=false
+
+#      # Replace the new line characters with a space and write to kafka
+#      sed ':a;N;$!ba;s/\n/ /g' $file | \
+#        kubectl exec -i "$KAFKA_POD_NAME" -n "$KAFKA_NAMESPACE" -- kafka-console-producer.sh \
+#        --bootstrap-server localhost:9092 --topic "$KAFKA_TOPIC" \
+#        --property parse.headers=true --property headers.key.separator=::: --property headers.delimiter=,,, --property parse.key=false
+    fi
+  done
+  echo "$((i+1))/$FILE_DUPLICATION_FACTOR rounds completed"
+done
+
+echo "Message production completed."
\ No newline at end of file
diff --git a/docker-compose/cloudEventProducer/events/cloudEventExampleMerge.txt b/docker-compose/cloudEventProducer/events/cloudEventExampleMerge.txt
new file mode 100644
index 0000000..c6fca7f
--- /dev/null
+++ b/docker-compose/cloudEventProducer/events/cloudEventExampleMerge.txt
@@ -0,0 +1,338 @@
+ce_specversion:::1.0,ce_id:::a30e63c9-d29e-46ff-b99a-b63ed83fd237,ce_source:::dmi-plugin:nm-1,ce_type:::ran-logical-topology.merge,content-type:::application/yang-data+json,ce_time:::2023-11-30T09:05:00Z,ce_dataschema:::https://ties:8080/schemas/v1/r1-topology,,,{
+    "entities": {
+        "o-ran-smo-teiv-oam:ManagedElement": [
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01",
+                "attributes": {
+                    "fdn": "ManagedElement=NR01",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]"
+                    }
+                }
+            }
+        ],
+        "o-ran-smo-teiv-ran:GNBDUFunction": [
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1",
+                "attributes": {
+                    "gNBDUId": 1,
+                    "gNBId": 1,
+                    "gNBIdLength": 23,
+                    "dUpLMNId": {
+                        "mcc": 353,
+                        "mnc": 87
+                    },
+                    "fdn": "ManagedElement=NR01,GNBDUFunction=1",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+                    }
+                }
+            }
+        ],
+        "o-ran-smo-teiv-ran:NRSectorCarrier": [
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=1",
+                "attributes": {
+                    "arfcnDL": 4000,
+                    "arfcnUL": 40000,
+                    "frequencyDL": 4,
+                    "frequencyUL": 40,
+                    "fdn": "ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=1",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-GNBDU:NRSectorCarrier[@id=1]"
+                    }
+                }
+            },
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=2",
+                "attributes": {
+                    "arfcnDL": 5000,
+                    "arfcnUL": 50000,
+                    "frequencyDL": 5,
+                    "frequencyUL": 50,
+                    "fdn": "ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=2",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-GNBDU:NRSectorCarrier[@id=2]"
+                    }
+                }
+            },
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=3",
+                "attributes": {
+                    "arfcnDL": 6000,
+                    "arfcnUL": 60000,
+                    "frequencyDL": 6,
+                    "frequencyUL": 60,
+                    "fdn": "ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=3",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-GNBDU:NRSectorCarrier[@id=3]"
+                    }
+                }
+            }
+        ],
+        "o-ran-smo-teiv-ran:NRCellDU": [
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=1",
+                "attributes": {
+                    "cellLocalId": 1,
+                    "nRTAC": 40,
+                    "nRPCI": 400,
+                    "nCI": 24577,
+                    "fdn": "ManagedElement=NR01,GNBDUFunction=1,NRCellDU=1",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-GNBDU:NRCellDU[@id=1]"
+                    }
+                }
+            },
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=2",
+                "attributes": {
+                    "cellLocalId": 2,
+                    "nRTAC": 50,
+                    "nRPCI": 500,
+                    "nCI": 24578,
+                    "fdn": "ManagedElement=NR01,GNBDUFunction=1,NRCellDU=2",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-GNBDU:NRCellDU[@id=2]"
+                    }
+                }
+            }
+        ],
+        "o-ran-smo-teiv-ran:AntennaCapability": [
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=1",
+                "attributes": {
+                    "eUtranFqBands": "[1,2,3]",
+                    "geranFqBands": "[10,11,12]",
+                    "nRFqBands": "[100,101,102]",
+                    "fdn": "ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=1",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-ComTop:NodeSupport[@id=1]/o-ran-smo-RmeSectorEquipmentFunction:SectorEquipmentFunction[@id=1]"
+                    }
+                }
+            },
+            {
+                "id": "urn:3gpp:dn:ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=2",
+                "attributes": {
+                    "eUtranFqBands": "[4,5,6]",
+                    "geranFqBands": "[13,14,15]",
+                    "nRFqBands": "[103,104,105]",
+                    "fdn": "ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=2",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01]/o-ran-smo-ComTop:NodeSupport[@id=1]/o-ran-smo-RmeSectorEquipmentFunction:SectorEquipmentFunction[@id=2]"
+                    }
+                }
+            }
+        ],
+        "o-ran-smo-teiv-equipment:AntennaModule": [
+            {
+                "id": "urn:o-ran:smo-teiv-equipment:1",
+                "attributes": {
+                    "antennaModelNumber": "1",
+                    "mechanicalAntennaBearing": 50,
+                    "mechanicalAntennaTilt": 10,
+                    "positionWithinSector": "Unknown",
+                    "totalTilt": 14,
+                    "electricalAntennaTilt": 2,
+                    "fdn": "Unknown",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "Unknown"
+                    }
+                }
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-equipment:2",
+                "attributes": {
+                    "antennaModelNumber": "2",
+                    "mechanicalAntennaBearing": 45,
+                    "mechanicalAntennaTilt": 12,
+                    "positionWithinSector": "Unknown",
+                    "totalTilt": 15,
+                    "electricalAntennaTilt": 1,
+                    "fdn": "Unknown",
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "Unknown"
+                    }
+                }
+            }
+        ],
+        "o-ran-smo-teiv-equipment:Site": [
+            {
+                "id": "urn:o-ran:smo-teiv-equipment:1",
+                "attributes": {
+                    "name": "Site-1",
+					"geo-location": {
+					    "latitude": 41.73297,
+                        "longitude": -78.007696
+					},
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "Unknown"
+                    }
+                }
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-equipment:2",
+                "attributes": {
+                    "name": "Site-2",
+					"geo-location": {
+					    "latitude": 46.73297,
+                        "longitude": -76.007696
+					},
+                    "cmId": {
+                        "cmHandle": "9D2C7AA8AECF0B5FDE21FDBD2B93EEAG",
+                        "resourceIdentifier": "Unknown"
+                    }
+                }
+            }
+        ],
+        "o-ran-smo-teiv-equipment-to-ran:Sector": [
+            {
+                "id": "urn:o-ran:smo-teiv-equipment-to-ran:1",
+                "attributes": {
+                    "sectorId": 1,
+                    "azimuth": 75.345,
+					"geo-location": {
+					    "latitude": 40.73297,
+                        "longitude": -74.007696
+					}
+                }
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-equipment-to-ran:2",
+                "attributes": {
+                    "sectorId": 2,
+                    "azimuth": 90.8967,
+					"geo-location": {
+					    "latitude": 41.73297,
+                        "longitude": -73.007696
+					}
+                }
+            }
+        ]
+    },
+    "relationships": {
+        "o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBDUFUNCTION": [
+            {
+                "id": "urn:o-ran:smo-teiv-oam-to-logical:1",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1"
+            }
+        ],
+        "o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER": [
+            {
+                "id": "urn:o-ran:smo-teiv-ran:1",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=1"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-ran:2",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=2"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-ran:3",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=3"
+            }
+        ],
+        "o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU": [
+            {
+                "id": "urn:o-ran:smo-teiv-ran:1",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=1"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-ran:2",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=2"
+            }
+        ],
+        "o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER": [
+            {
+                "id": "urn:o-ran:smo-teiv-ran:1",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=1"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-ran:2",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=2",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=2"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-ran:3",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=2",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=3"
+            }
+        ],
+        "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+            {
+                "id": "urn:o-ran:smo-teiv-ran:1",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=1"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-ran:2",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=2",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=2"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-ran:3",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRSectorCarrier=3",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=2"
+            }
+        ],
+        "o-ran-smo-teiv-equipment-to-ran:ANTENNAMODULE_SERVES_ANTENNACAPABILITY": [
+            {
+                "id": "urn:o-ran:smo-teiv-equipment-to-ran:1",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=1",
+                "bSide": "urn:o-ran:smo-teiv-equipment:1"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-equipment-to-ran:2",
+                "aSide": "urn:3gpp:dn:ManagedElement=NR01,NodeSupport=1,SectorEquipmentFunction=2",
+                "bSide": "urn:o-ran:smo-teiv-equipment:2"
+            }
+        ],
+        "o-ran-smo-teiv-equipment-to-ran:ANTENNAMODULE_INSTALLED_AT_SITE": [
+            {
+                "id": "urn:o-ran:smo-teiv-equipment:1",
+                "aSide": "urn:o-ran:smo-teiv-equipment:1",
+                "bSide": "urn:o-ran:smo-teiv-equipment:1"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-equipment:2",
+                "aSide": "urn:o-ran:smo-teiv-equipment:2",
+                "bSide": "urn:o-ran:smo-teiv-equipment:2"
+            }
+        ],
+        "o-ran-smo-teiv-equipment-to-ran:SECTOR_GROUPS_NRCELLDU": [
+            {
+                "id": "urn:o-ran:smo-teiv-equipment-to-ran:1",
+                "aSide": "urn:o-ran:smo-teiv-equipment-to-ran:1",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=1"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-equipment-to-ran:2",
+                "aSide": "urn:o-ran:smo-teiv-equipment-to-ran:2",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=2"
+            },
+            {
+                "id": "urn:o-ran:smo-teiv-equipment-to-ran:3",
+                "aSide": "urn:o-ran:smo-teiv-equipment-to-ran:2",
+                "bSide": "urn:3gpp:dn:ManagedElement=NR01,GNBDUFunction=1,NRCellDU=3"
+            }
+        ]
+    }
+}
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
new file mode 100644
index 0000000..051e803
--- /dev/null
+++ b/docker-compose/docker-compose.yml
@@ -0,0 +1,123 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+services:
+
+  dbpostgresql:
+    container_name: dbpostgresql
+    image: postgis/postgis:13-3.4-alpine
+    ports:
+      - ${DB_PORT:-5432}:5432
+    volumes:
+      - ./sql_scripts:/docker-entrypoint-initdb.d
+    environment:
+      POSTGRES_DB: topology_exposure_db
+      POSTGRES_USER: ${DB_USERNAME:-topology_exposure_user}
+      POSTGRES_PASSWORD: ${DB_PASSWORD:-dbpassword}
+    restart: always
+    deploy:
+      resources:
+        reservations:
+          cpus: '1'
+          memory: 1G
+        limits:
+          cpus: '6'
+          memory: 3G
+
+  topology-exposure-inventory:
+    container_name: topology-exposure-inventory
+    image: topology-exposure-inventory:latest
+    ports:
+      - 31074:8080
+    depends_on:
+      - dbpostgresql
+    deploy:
+      resources:
+        reservations:
+          cpus: '2'
+          memory: 2G
+        limits:
+          cpus: '3'
+          memory: 3G
+
+  topology-ingestion-inventory:
+    container_name: topology-ingestion-inventory
+    image: topology-exposure-inventory:latest
+    environment:
+      - SPRING_PROFILES_ACTIVE=ingestion
+    depends_on:
+      - dbpostgresql
+    deploy:
+      resources:
+        reservations:
+          cpus: '2'
+          memory: 2G
+        limits:
+          cpus: '3'
+          memory: 3G
+
+  zookeeper:
+    image: confluentinc/cp-zookeeper:6.2.1
+    container_name: zookeeper
+    ports:
+      - '2181:2181'
+    environment:
+      ZOOKEEPER_CLIENT_PORT: 2181
+
+  kafka:
+    image: confluentinc/cp-kafka:7.6.1
+    container_name: kafka
+    ports:
+      - '9093:9093'
+    depends_on:
+      - zookeeper
+    environment:
+      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9092,OUTSIDE://localhost:9093
+      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
+      KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
+      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+      KAFKA_BROKER_ID: 1
+      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+
+  kafka2:
+    image: confluentinc/cp-kafka:7.6.1
+    container_name: kafka2
+    depends_on:
+      - zookeeper
+    environment:
+      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka2:9094
+      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT
+      KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
+      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+      KAFKA_BROKER_ID: 2
+      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+
+  kafka3:
+    image: confluentinc/cp-kafka:7.6.1
+    container_name: kafka3
+    depends_on:
+      - zookeeper
+    environment:
+      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka3:9096
+      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT
+      KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
+      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+      KAFKA_BROKER_ID: 3
+      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
diff --git a/docker-compose/sql_scripts/00_init-teiv-exposure-model.sql b/docker-compose/sql_scripts/00_init-teiv-exposure-model.sql
new file mode 100644
index 0000000..ad443da
--- /dev/null
+++ b/docker-compose/sql_scripts/00_init-teiv-exposure-model.sql
@@ -0,0 +1,460 @@
+--
+--  ============LICENSE_START=======================================================
+--  Copyright (C) 2024 Ericsson
+--  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+--  ================================================================================
+--  Licensed under the Apache License, Version 2.0 (the "License");
+--  you may not use this file except in compliance with the License.
+--  You may obtain a copy of the License at
+--
+--        http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+--  SPDX-License-Identifier: Apache-2.0
+--  ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+DROP SCHEMA IF EXISTS ties_model cascade;
+CREATE SCHEMA IF NOT EXISTS ties_model;
+ALTER SCHEMA ties_model OWNER TO topology_exposure_user;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE 'topology_exposure_user';
+
+CREATE TABLE IF NOT EXISTS ties_model.execution_status (
+    "schema"                 VARCHAR(127) PRIMARY KEY,
+    "status"          VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.hash_info (
+    "name"                 VARCHAR(511) PRIMARY KEY,
+    "hashedValue"          VARCHAR(511),
+    "type"                 VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.module_reference (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "namespace"              VARCHAR(511),
+    "domain"             VARCHAR(511),
+    "includedModules"        jsonb,
+    "revision"       VARCHAR(511),
+    "content"               TEXT,
+    "ownerAppId"       VARCHAR(511),
+    "status"       VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.entity_info (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.relationship_info (
+    "name"      VARCHAR(511) PRIMARY KEY,
+    "aSideAssociationName"    TEXT,
+    "aSideMOType"             TEXT,
+    "aSideMinCardinality"     BIGINT,
+    "aSideMaxCardinality"     BIGINT,
+    "bSideAssociationName"    TEXT,
+    "bSideMOType"             TEXT,
+    "bSideMinCardinality"     BIGINT,
+    "bSideMaxCardinality"     BIGINT,
+    "associationKind"    TEXT,
+    "relationshipDataLocation"          TEXT,
+    "connectSameEntity"       BOOLEAN,
+    "moduleReferenceName"     TEXT,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.decorators (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "dataType"                   VARCHAR(511),
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.classifiers (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+-- Update model schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_model', 'success');
+
+COPY ties_model.hash_info("name", "hashedValue", "type") FROM stdin;
+PK_ENodeBFunction_id	PK_ENodeBFunction_id	CONSTRAINT
+frequencyDL	frequencyDL	COLUMN
+NRCellDU	NRCellDU	TABLE
+UNIQUE_GNBCUUPFunction_REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	UNIQUE_BDB349CDF0C4055902881ECCB71F460AE1DD323E	CONSTRAINT
+REL_CD_sourceIds_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	REL_CD_sourceIds_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	COLUMN
+NRSectorCarrier	NRSectorCarrier	TABLE
+REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	COLUMN
+FK_LTESectorCarrier_REL_FK_used-by-euTranCell	FK_LTESectorCarrier_REL_FK_used-by-euTranCell	CONSTRAINT
+REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER	REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER	COLUMN
+REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU	REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU	COLUMN
+frequencyUL	frequencyUL	COLUMN
+bSChannelBwDL	bSChannelBwDL	COLUMN
+UNIQUE_GNBCUCPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION	UNIQUE_GNBCUCPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION	CONSTRAINT
+REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	COLUMN
+CD_sourceIds	CD_sourceIds	COLUMN
+REL_FK_serving-physicalNF	REL_FK_serving-physicalNF	COLUMN
+REL_CD_classifiers_PHYSICALNF_SERVES_ENODEBFUNCTION	REL_CD_classifiers_PHYSICALNF_SERVES_ENODEBFUNCTION	COLUMN
+REL_CD_decorators_PHYSICALNF_SERVES_ENODEBFUNCTION	REL_CD_decorators_PHYSICALNF_SERVES_ENODEBFUNCTION	COLUMN
+REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUUPFUNCTION	REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUUPFUNCTION	COLUMN
+REL_CD_decorators_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	REL_CD_decorators_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	COLUMN
+NRCellCU	NRCellCU	TABLE
+REL_ID_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	REL_ID_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	COLUMN
+REL_FK_used-by-euTranCell	REL_FK_used-by-euTranCell	COLUMN
+UNIQUE_NRSectorCarrier_REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991	CONSTRAINT
+REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	COLUMN
+REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	COLUMN
+NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE	NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE	TABLE
+REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION	REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION	COLUMN
+FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	CONSTRAINT
+REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+eNBId	eNBId	COLUMN
+PK_NodeCluster_id	PK_NodeCluster_id	CONSTRAINT
+FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_bSide_AntennaCapability	FK_AB3CEA707D389B107F1D10BC724542418E02ABEC	CONSTRAINT
+REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRCELLDU	REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRCELLDU	COLUMN
+REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER	REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER	COLUMN
+FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction	FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction	CONSTRAINT
+REL_CD_classifiers_ANTENNAMODULE_INSTALLED_AT_SITE	REL_CD_classifiers_ANTENNAMODULE_INSTALLED_AT_SITE	COLUMN
+CD_decorators	CD_decorators	COLUMN
+PK_Sector_id	PK_Sector_id	CONSTRAINT
+GNBCUCPFunction	GNBCUCPFunction	TABLE
+REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+PK_ManagedElement_id	PK_ManagedElement_id	CONSTRAINT
+UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	CONSTRAINT
+REL_CD_classifiers_PHYSICALNF_SERVES_GNBDUFUNCTION	REL_CD_classifiers_PHYSICALNF_SERVES_GNBDUFUNCTION	COLUMN
+REL_FK_provided-by-gnbcucpFunction	REL_FK_provided-by-gnbcucpFunction	COLUMN
+FK_ENodeBFunction_REL_FK_serving-physicalNF	FK_ENodeBFunction_REL_FK_serving-physicalNF	CONSTRAINT
+REL_CD_decorators_PHYSICALNF_SERVES_GNBCUUPFUNCTION	REL_CD_decorators_PHYSICALNF_SERVES_GNBCUUPFUNCTION	COLUMN
+ManagedElement	ManagedElement	TABLE
+PK_AntennaModule_id	PK_AntennaModule_id	CONSTRAINT
+PK_CloudNamespace_id	PK_CloudNamespace_id	CONSTRAINT
+CloudifiedNF	CloudifiedNF	TABLE
+FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule	FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule	CONSTRAINT
+FK_EUtranCell_REL_FK_provided-by-enodebFunction	FK_EUtranCell_REL_FK_provided-by-enodebFunction	CONSTRAINT
+FK_ENodeBFunction_REL_FK_managed-by-managedElement	FK_ENodeBFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+UNIQUE_GNBDUFunction_REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	UNIQUE_08DFEFAF56EDDE43CBDC336F459D28C6518D3E1D	CONSTRAINT
+PK_CloudifiedNF_id	PK_CloudifiedNF_id	CONSTRAINT
+REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	COLUMN
+FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_bSide_GNBDUFunction	FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_bSide_GNBDUFunction	CONSTRAINT
+UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	CONSTRAINT
+REL_CD_classifiers_PHYSICALNF_INSTALLED_AT_SITE	REL_CD_classifiers_PHYSICALNF_INSTALLED_AT_SITE	COLUMN
+UNIQUE_ENodeBFunction_REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION	UNIQUE_ENodeBFunction_REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION	CONSTRAINT
+FK_GNBCUUPFunction_REL_FK_managed-by-managedElement	FK_GNBCUUPFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+PK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_id	PK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_id	CONSTRAINT
+ANTENNAMODULE_SERVES_ANTENNACAPABILITY	ANTENNAMODULE_SERVES_ANTENNACAPABILITY	TABLE
+eNodeBPlmnId	eNodeBPlmnId	COLUMN
+PK_NRSectorCarrier_id	PK_NRSectorCarrier_id	CONSTRAINT
+mechanicalAntennaBearing	mechanicalAntennaBearing	COLUMN
+REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE	REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE	COLUMN
+ENodeBFunction	ENodeBFunction	TABLE
+nRPCI	nRPCI	COLUMN
+antennaModelNumber	antennaModelNumber	COLUMN
+REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION	REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION	COLUMN
+REL_CD_classifiers_SECTOR_GROUPS_ANTENNAMODULE	REL_CD_classifiers_SECTOR_GROUPS_ANTENNAMODULE	COLUMN
+PK_NRCellCU_id	PK_NRCellCU_id	CONSTRAINT
+REL_FK_used-antennaCapability	REL_FK_used-antennaCapability	COLUMN
+REL_CD_sourceIds_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	REL_CD_sourceIds_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	COLUMN
+cellId	cellId	COLUMN
+UNIQUE_NRSectorCarrier_REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	UNIQUE_872BE05F1989443F2595D99A77BC03733B2D1E2F	CONSTRAINT
+REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUUPFUNCTION	REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUUPFUNCTION	COLUMN
+REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	COLUMN
+UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL	UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL	CONSTRAINT
+REL_CD_decorators_SECTOR_GROUPS_EUTRANCELL	REL_CD_decorators_SECTOR_GROUPS_EUTRANCELL	COLUMN
+REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	COLUMN
+UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	CONSTRAINT
+name	name	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	COLUMN
+PK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_id	PK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_id	CONSTRAINT
+geranFqBands	geranFqBands	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	COLUMN
+PK_EUtranCell_id	PK_EUtranCell_id	CONSTRAINT
+REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION	REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	COLUMN
+FK_NRSectorCarrier_REL_FK_used-antennaCapability	FK_NRSectorCarrier_REL_FK_used-antennaCapability	CONSTRAINT
+bSide_GNBCUCPFunction	bSide_GNBCUCPFunction	COLUMN
+channelBandwidth	channelBandwidth	COLUMN
+PK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_id	PK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_id	CONSTRAINT
+bSide_CloudSite	bSide_CloudSite	COLUMN
+FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_aSide_NFDeployment	FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_aSide_NFDeployment	CONSTRAINT
+REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	COLUMN
+REL_CD_decorators_PHYSICALNF_INSTALLED_AT_SITE	REL_CD_decorators_PHYSICALNF_INSTALLED_AT_SITE	COLUMN
+REL_CD_classifiers_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	REL_CD_classifiers_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	COLUMN
+REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+REL_CD_sourceIds_PHYSICALNF_INSTALLED_AT_SITE	REL_CD_sourceIds_PHYSICALNF_INSTALLED_AT_SITE	COLUMN
+positionWithinSector	positionWithinSector	COLUMN
+NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION	NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION	TABLE
+REL_CD_sourceIds_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	REL_CD_sourceIds_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	COLUMN
+Sector	Sector	TABLE
+REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRCELLDU	REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRCELLDU	COLUMN
+PK_GNBCUCPFunction_id	PK_GNBCUCPFunction_id	CONSTRAINT
+REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	COLUMN
+REL_FK_deployed-on-nodeCluster	REL_FK_deployed-on-nodeCluster	COLUMN
+REL_CD_sourceIds_PHYSICALNF_SERVES_ENODEBFUNCTION	REL_CD_sourceIds_PHYSICALNF_SERVES_ENODEBFUNCTION	COLUMN
+AntennaCapability	AntennaCapability	TABLE
+NodeCluster	NodeCluster	TABLE
+REL_CD_decorators_SECTOR_GROUPS_ANTENNAMODULE	REL_CD_decorators_SECTOR_GROUPS_ANTENNAMODULE	COLUMN
+REL_ID_NRCELLDU_USES_NRSECTORCARRIER	REL_ID_NRCELLDU_USES_NRSECTORCARRIER	COLUMN
+PK_GNBCUUPFunction_id	PK_GNBCUUPFunction_id	CONSTRAINT
+bSide_GNBDUFunction	bSide_GNBDUFunction	COLUMN
+UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	CONSTRAINT
+REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL	REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL	COLUMN
+UNIQUE_NFDeployment_REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	UNIQUE_NFDeployment_REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	CONSTRAINT
+REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	COLUMN
+REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+azimuth	azimuth	COLUMN
+antennaBeamWidth	antennaBeamWidth	COLUMN
+NFDEPLOYMENT_SERVES_GNBDUFUNCTION	NFDEPLOYMENT_SERVES_GNBDUFUNCTION	TABLE
+FK_EUtranCell_REL_FK_grouped-by-sector	FK_EUtranCell_REL_FK_grouped-by-sector	CONSTRAINT
+REL_CD_decorators_PHYSICALNF_SERVES_GNBCUCPFUNCTION	REL_CD_decorators_PHYSICALNF_SERVES_GNBCUCPFUNCTION	COLUMN
+cellLocalId	cellLocalId	COLUMN
+REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+gNBCUName	gNBCUName	COLUMN
+electricalAntennaTilt	electricalAntennaTilt	COLUMN
+REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE	REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE	COLUMN
+FK_NRSectorCarrier_REL_FK_used-by-nrCellDu	FK_NRSectorCarrier_REL_FK_used-by-nrCellDu	CONSTRAINT
+FK_GNBDUFunction_REL_FK_serving-physicalNF	FK_GNBDUFunction_REL_FK_serving-physicalNF	CONSTRAINT
+REL_FK_provided-by-enodebFunction	REL_FK_provided-by-enodebFunction	COLUMN
+eUtranFqBands	eUtranFqBands	COLUMN
+REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+CD_classifiers	CD_classifiers	COLUMN
+aSide_NodeCluster	aSide_NodeCluster	COLUMN
+REL_FK_comprised-by-cloudifiedNF	REL_FK_comprised-by-cloudifiedNF	COLUMN
+UNIQUE_ManagedElement_REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	UNIQUE_E7BC94037DB5B94B7E863A10BEA20C2D4C3C307C	CONSTRAINT
+UNIQUE_CloudNamespace_REL_ID_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	UNIQUE_C72E1EF93E1AC8FA53D20808E775FF012ACB46F0	CONSTRAINT
+FK_GNBCUCPFunction_REL_FK_serving-physicalNF	FK_GNBCUCPFunction_REL_FK_serving-physicalNF	CONSTRAINT
+REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	COLUMN
+REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	COLUMN
+CloudSite	CloudSite	TABLE
+REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION	REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION	COLUMN
+FK_AntennaModule_REL_FK_grouped-by-sector	FK_AntennaModule_REL_FK_grouped-by-sector	CONSTRAINT
+REL_ID_PHYSICALNF_INSTALLED_AT_SITE	REL_ID_PHYSICALNF_INSTALLED_AT_SITE	COLUMN
+REL_FK_used-by-nrCellDu	REL_FK_used-by-nrCellDu	COLUMN
+FK_GNBDUFunction_REL_FK_managed-by-managedElement	FK_GNBDUFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+PK_LTESectorCarrier_id	PK_LTESectorCarrier_id	CONSTRAINT
+PK_AntennaCapability_id	PK_AntennaCapability_id	CONSTRAINT
+geo-location	geo-location	COLUMN
+REL_FK_grouped-by-sector	REL_FK_grouped-by-sector	COLUMN
+REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU	REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU	COLUMN
+UNIQUE_GNBDUFunction_REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION	UNIQUE_GNBDUFunction_REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION	CONSTRAINT
+FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_aSide_NFDeployment	FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_aSide_NFDeployment	CONSTRAINT
+gNBId	gNBId	COLUMN
+id	id	COLUMN
+PK_NRCellDU_id	PK_NRCellDU_id	CONSTRAINT
+EUtranCell	EUtranCell	TABLE
+REL_CD_classifiers_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	REL_CD_classifiers_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	COLUMN
+REL_CD_decorators_ANTENNAMODULE_INSTALLED_AT_SITE	REL_CD_decorators_ANTENNAMODULE_INSTALLED_AT_SITE	COLUMN
+UNIQUE_PhysicalNF_REL_ID_PHYSICALNF_INSTALLED_AT_SITE	UNIQUE_PhysicalNF_REL_ID_PHYSICALNF_INSTALLED_AT_SITE	CONSTRAINT
+PK_Site_id	PK_Site_id	CONSTRAINT
+PK_PhysicalNF_id	PK_PhysicalNF_id	CONSTRAINT
+REL_FK_installed-at-site	REL_FK_installed-at-site	COLUMN
+NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION	NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION	TABLE
+CloudNamespace	CloudNamespace	TABLE
+nRTAC	nRTAC	COLUMN
+earfcndl	earfcndl	COLUMN
+FK_NFDeployment_REL_FK_comprised-by-cloudifiedNF	FK_NFDeployment_REL_FK_comprised-by-cloudifiedNF	CONSTRAINT
+FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_aSide_NFDeployment	FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_aSide_NFDeployment	CONSTRAINT
+FK_AntennaModule_REL_FK_installed-at-site	FK_AntennaModule_REL_FK_installed-at-site	CONSTRAINT
+earfcnul	earfcnul	COLUMN
+REL_CD_decorators_ENODEBFUNCTION_PROVIDES_EUTRANCELL	REL_CD_decorators_ENODEBFUNCTION_PROVIDES_EUTRANCELL	COLUMN
+aSide_NFDeployment	aSide_NFDeployment	COLUMN
+REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUCPFUNCTION	REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUCPFUNCTION	COLUMN
+FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction	FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction	CONSTRAINT
+FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_aSide_NodeCluster	FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_aSide_NodeCluster	CONSTRAINT
+REL_CD_decorators_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	REL_CD_decorators_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	COLUMN
+bSide_GNBCUUPFunction	bSide_GNBCUUPFunction	COLUMN
+PhysicalNF	PhysicalNF	TABLE
+cmId	cmId	COLUMN
+REL_CD_classifiers_NRCELLDU_USES_NRSECTORCARRIER	REL_CD_classifiers_NRCELLDU_USES_NRSECTORCARRIER	COLUMN
+type	type	COLUMN
+PK_NFDeployment_id	PK_NFDeployment_id	CONSTRAINT
+nCI	nCI	COLUMN
+REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+REL_CD_decorators_NRCELLDU_USES_NRSECTORCARRIER	REL_CD_decorators_NRCELLDU_USES_NRSECTORCARRIER	COLUMN
+REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	COLUMN
+FK_NRCellDU_REL_FK_grouped-by-sector	FK_NRCellDU_REL_FK_grouped-by-sector	CONSTRAINT
+REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	COLUMN
+UNIQUE_LTESectorCarrier_REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9	CONSTRAINT
+duplexType	duplexType	COLUMN
+NODECLUSTER_LOCATED_AT_CLOUDSITE	NODECLUSTER_LOCATED_AT_CLOUDSITE	TABLE
+AntennaModule	AntennaModule	TABLE
+REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	COLUMN
+LTESectorCarrier	LTESectorCarrier	TABLE
+REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUCPFUNCTION	REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUCPFUNCTION	COLUMN
+REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	COLUMN
+FK_LTESectorCarrier_REL_FK_used-antennaCapability	FK_LTESectorCarrier_REL_FK_used-antennaCapability	CONSTRAINT
+REL_FK_managed-by-managedElement	REL_FK_managed-by-managedElement	COLUMN
+REL_CD_decorators_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	REL_CD_decorators_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	COLUMN
+REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	COLUMN
+aSide_AntennaModule	aSide_AntennaModule	COLUMN
+fdn	fdn	COLUMN
+REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+dUpLMNId	dUpLMNId	COLUMN
+REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	COLUMN
+REL_CD_decorators_SECTOR_GROUPS_NRCELLDU	REL_CD_decorators_SECTOR_GROUPS_NRCELLDU	COLUMN
+REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_EUTRANCELL	REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_EUTRANCELL	COLUMN
+REL_CD_classifiers_SECTOR_GROUPS_NRCELLDU	REL_CD_classifiers_SECTOR_GROUPS_NRCELLDU	COLUMN
+REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	COLUMN
+REL_CD_classifiers_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	REL_CD_classifiers_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	COLUMN
+UNIQUE_NFDeployment_REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	UNIQUE_NFDeployment_REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	CONSTRAINT
+REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+REL_CD_classifiers_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	REL_CD_classifiers_NFDEPLOYMENT_SERVES_MANAGEDELEMENT	COLUMN
+PK_NODECLUSTER_LOCATED_AT_CLOUDSITE_id	PK_NODECLUSTER_LOCATED_AT_CLOUDSITE_id	CONSTRAINT
+REL_ID_SECTOR_GROUPS_EUTRANCELL	REL_ID_SECTOR_GROUPS_EUTRANCELL	COLUMN
+REL_CD_classifiers_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	REL_CD_classifiers_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	COLUMN
+FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_aSide_NFDeployment	FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_aSide_NFDeployment	CONSTRAINT
+Site	Site	TABLE
+FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_bSide_GNBCUCPFunction	FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_bSide_GNBCUCPFunction	CONSTRAINT
+arfcnUL	arfcnUL	COLUMN
+REL_ID_SECTOR_GROUPS_NRCELLDU	REL_ID_SECTOR_GROUPS_NRCELLDU	COLUMN
+UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU	UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU	CONSTRAINT
+FK_CloudNamespace_REL_FK_deployed-on-nodeCluster	FK_CloudNamespace_REL_FK_deployed-on-nodeCluster	CONSTRAINT
+PK_GNBDUFunction_id	PK_GNBDUFunction_id	CONSTRAINT
+NFDeployment	NFDeployment	TABLE
+REL_FK_serviced-managedElement	REL_FK_serviced-managedElement	COLUMN
+dlChannelBandwidth	dlChannelBandwidth	COLUMN
+FK_GNBCUCPFunction_REL_FK_managed-by-managedElement	FK_GNBCUCPFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+REL_CD_decorators_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	REL_CD_decorators_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	COLUMN
+REL_CD_decorators_EUTRANCELL_USES_LTESECTORCARRIER	REL_CD_decorators_EUTRANCELL_USES_LTESECTORCARRIER	COLUMN
+REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	COLUMN
+REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL	REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL	COLUMN
+REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	COLUMN
+nRFqBands	nRFqBands	COLUMN
+FK_NFDeployment_REL_FK_serviced-managedElement	FK_NFDeployment_REL_FK_serviced-managedElement	CONSTRAINT
+FK_ManagedElement_REL_FK_deployed-as-cloudifiedNF	FK_ManagedElement_REL_FK_deployed-as-cloudifiedNF	CONSTRAINT
+tac	tac	COLUMN
+arfcnDL	arfcnDL	COLUMN
+REL_CD_classifiers_EUTRANCELL_USES_LTESECTORCARRIER	REL_CD_classifiers_EUTRANCELL_USES_LTESECTORCARRIER	COLUMN
+REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	COLUMN
+PK_CloudSite_id	PK_CloudSite_id	CONSTRAINT
+earfcn	earfcn	COLUMN
+sectorId	sectorId	COLUMN
+REL_CD_classifiers_SECTOR_GROUPS_EUTRANCELL	REL_CD_classifiers_SECTOR_GROUPS_EUTRANCELL	COLUMN
+PK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_id	PK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_id	CONSTRAINT
+UNIQUE_GNBCUUPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION	UNIQUE_GNBCUUPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION	CONSTRAINT
+FK_PhysicalNF_REL_FK_installed-at-site	FK_PhysicalNF_REL_FK_installed-at-site	CONSTRAINT
+GNBCUUPFunction	GNBCUUPFunction	TABLE
+FK_GNBCUUPFunction_REL_FK_serving-physicalNF	FK_GNBCUUPFunction_REL_FK_serving-physicalNF	CONSTRAINT
+FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_bSide_CloudSite	FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_bSide_CloudSite	CONSTRAINT
+UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE	UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE	CONSTRAINT
+UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER	UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER	CONSTRAINT
+REL_FK_deployed-as-cloudifiedNF	REL_FK_deployed-as-cloudifiedNF	COLUMN
+PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id	PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id	CONSTRAINT
+REL_CD_decorators_PHYSICALNF_SERVES_GNBDUFUNCTION	REL_CD_decorators_PHYSICALNF_SERVES_GNBDUFUNCTION	COLUMN
+REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	COLUMN
+totalTilt	totalTilt	COLUMN
+REL_CD_decorators_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	REL_CD_decorators_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	COLUMN
+REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+REL_CD_sourceIds_PHYSICALNF_SERVES_GNBDUFUNCTION	REL_CD_sourceIds_PHYSICALNF_SERVES_GNBDUFUNCTION	COLUMN
+gNBIdLength	gNBIdLength	COLUMN
+UNIQUE_ENodeBFunction_REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	UNIQUE_F33037EE8037D0606D15FFB45EE8A27FD6DE30EE	CONSTRAINT
+FK_NRCellDU_REL_FK_provided-by-gnbduFunction	FK_NRCellDU_REL_FK_provided-by-gnbduFunction	CONSTRAINT
+bSide_AntennaCapability	bSide_AntennaCapability	COLUMN
+FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_bSide_GNBCUUPFunction	FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_bSide_GNBCUUPFunction	CONSTRAINT
+UNIQUE_GNBCUCPFunction_REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	UNIQUE_249F73FF1F4316A56DEF4424FA43C2064FFBE4DD	CONSTRAINT
+REL_CD_classifiers_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	REL_CD_classifiers_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	COLUMN
+REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	COLUMN
+pLMNId	pLMNId	COLUMN
+REL_FK_provided-by-gnbduFunction	REL_FK_provided-by-gnbduFunction	COLUMN
+FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_bSide_CloudNamespace	FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_bSide_CloudNamespace	CONSTRAINT
+UNIQUE_LTESectorCarrier_REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88	CONSTRAINT
+sectorCarrierType	sectorCarrierType	COLUMN
+GNBDUFunction	GNBDUFunction	TABLE
+mechanicalAntennaTilt	mechanicalAntennaTilt	COLUMN
+UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	CONSTRAINT
+plmnId	plmnId	COLUMN
+bSide_CloudNamespace	bSide_CloudNamespace	COLUMN
+gNBDUId	gNBDUId	COLUMN
+REL_ID_SECTOR_GROUPS_ANTENNAMODULE	REL_ID_SECTOR_GROUPS_ANTENNAMODULE	COLUMN
+REL_CD_decorators_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	REL_CD_decorators_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	COLUMN
+\.
+
+COPY ties_model.module_reference("name", "namespace", "domain", "includedModules", "revision", "content", "ownerAppId", "status") FROM stdin;
+o-ran-smo-teiv-common-yang-extensions	urn:o-ran:smo-teiv-common-yang-extensions	\N	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMgewoKICB5YW5nLXZlcnNpb24gMS4xOwogIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMiOwogIHByZWZpeCBvci10ZWl2LXlleHQ7CgogIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOwogIGRlc2NyaXB0aW9uCiAgIlRvcG9sb2d5IGFuZCBJbnZlbnRvcnkgWUFORyBleHRlbnNpb25zIG1vZGVsLgoKICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogIFRoaXMgbW9kZWwgY29udGFpbnMgZXh0ZW5zaW9ucyB0byB0aGUgWUFORyBsYW5ndWFnZSB0aGF0IHRvcG9sb2d5IGFuZAogIGludmVudG9yeSBtb2RlbHMgd2lsbCB1c2UgdG8gZGVmaW5lIGFuZCBhbm5vdGF0ZSB0eXBlcyBhbmQgcmVsYXRpb25zaGlwcy4iOwoKICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgewogICAgZGVzY3JpcHRpb24gIkluaXRpYWwgcmV2aXNpb24uIjsKICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICB9CgogIGV4dGVuc2lvbiBiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgewoKICAgIGRlc2NyaXB0aW9uCiAgICAgICJEZWZpbmVzIGEgYmktZGlyZWN0aW9uYWwgcmVsYXRpb25zaGlwIGluIHRoZSB0b3BvbG9neS4KCiAgICAgICBBIGJpLWRpcmVjdGlvbmFsLWFzc29jaWF0aW9uIChCREEpIGlzIGEgcmVsYXRpb25zaGlwIGNvbXByaXNpbmcgb2YgYW4KICAgICAgIEEtc2lkZSBhbmQgYSBCLXNpZGUuIFRoZSBBLXNpZGUgaXMgY29uc2lkZXJlZCB0aGUgb3JpZ2luYXRpbmcgc2lkZSBvZgogICAgICAgdGhlIHJlbGF0aW9uc2hpcDsgdGhlIEItc2lkZSBpcyBjb25zaWRlcmVkIHRoZSB0ZXJtaW5hdGluZyBzaWRlIG9mIHRoZQogICAgICAgcmVsYXRpb25zaGlwLiBUaGUgb3JkZXIgb2YgQS1zaWRlIGFuZCBCLXNpZGUgaXMgb2YgaW1wb3J0YW5jZSBhbmQgTVVTVAogICAgICAgTk9UIGJlIGNoYW5nZWQgb25jZSBkZWZpbmVkLgoKICAgICAgIEJvdGggQS1zaWRlIGFuZCBCLXNpZGUgYXJlIGRlZmluZWQgb24gYSB0eXBlLCBhbmQgYXJlIGdpdmVuIGEgcm9sZS4gQQogICAgICAgdHlwZSBtYXkgaGF2ZSBtdWx0aXBsZSBvcmlnaW5hdGluZyBhbmQvb3IgdGVybWluYXRpbmcgc2lkZXMgb2YgYQogICAgICAgcmVsYXRpb25zaGlwLCBhbGwgZGlzdGluZ3Vpc2hlZCBieSByb2xlIG5hbWUuCgogICAgICAgVGhlIHN0YXRlbWVudCBNVVNUIG9ubHkgYmUgYSBzdWJzdGF0ZW1lbnQgb2YgdGhlICdtb2R1bGUnIHN0YXRlbWVudC4KICAgICAgIE11bHRpcGxlICdiaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIHN0YXRlbWVudHMgYXJlIGFsbG93ZWQKICAgICAgIHBlciBwYXJlbnQgc3RhdGVtZW50LgoKICAgICAgIFN1YnN0YXRlbWVudHMgdG8gdGhlICdiaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIGRlZmluZSB0aGUKICAgICAgIEEtc2lkZSBhbmQgdGhlIEItc2lkZSwgcmVzcGVjdGl2ZWx5LCBhbmQgb3B0aW9uYWxseSBwcm9wZXJ0aWVzIG9mIHRoZQogICAgICAgcmVsYXRpb25zaGlwLiBEYXRhIG5vZGVzIG9mIHR5cGVzICdsZWFmJyBhbmQgJ2xlYWYtbGlzdCcgYXJlIHVzZWQgZm9yCiAgICAgICB0aGlzIHB1cnBvc2UuIE9uZSBvZiB0aGUgZGF0YSBub2RlcyBNVVNUIGJlIGFubm90YXRlZCB3aXRoIHRoZSAnYS1zaWRlJwogICAgICAgZXh0ZW5zaW9uOyBhbm90aGVyIGRhdGEgbm9kZSBNVVNUIGJlIGFubm90YXRlZCB3aXRoIHRoZSAnYi1zaWRlJwogICAgICAgZXh0ZW5zaW9uLiBPdGhlciBkYXRhIG5vZGVzIGRlZmluZSBwcm9wZXJ0aWVzIG9mIHRoZSByZWxhdGlvbnNoaXAuCgogICAgICAgVGhlIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSByZWxhdGlvbnNoaXAuIFRoZSByZWxhdGlvbnNoaXAgbmFtZSBpcwogICAgICAgc2NvcGVkIHRvIHRoZSBuYW1lc3BhY2Ugb2YgdGhlIGRlY2xhcmluZyBtb2R1bGUgYW5kIE1VU1QgYmUgdW5pcXVlCiAgICAgICB3aXRoaW4gdGhlIHNjb3BlLiI7CgogICAgYXJndW1lbnQgcmVsYXRpb25zaGlwTmFtZTsKICB9CgogIGV4dGVuc2lvbiBhU2lkZSB7CiAgICBkZXNjcmlwdGlvbgogICAgICAiRGVmaW5lcyB0aGUgQS1zaWRlIG9mIGEgcmVsYXRpb25zaGlwLgoKICAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIGEgJ2xlYWYnIG9yICdsZWFmLWxpc3QnCiAgICAgICBzdGF0ZW1lbnQsIHdoaWNoIGl0c2VsZiBtdXN0IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZQogICAgICAgJ3VuaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIHN0YXRlbWVudC4KCiAgICAgICBUaGUgZGF0YSB0eXBlIG9mIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIE1VU1QgYmUKICAgICAgICdpbnN0YW5jZS1pZGVudGlmaWVyJy4gQ29uc3RyYWludHMgTUFZIGJlIHVzZWQgYXMgcGFydCBvZiB0aGUgcGFyZW50CiAgICAgICAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgdG8gZW5mb3JjZSBjYXJkaW5hbGl0eS4KCiAgICAgICBUaGUgaWRlbnRpZmllciBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBpcyB1c2VkIGFzIG5hbWUgb2YKICAgICAgIHRoZSByb2xlIG9mIHRoZSBBLXNpZGUgb2YgdGhlIHJlbGF0aW9uc2hpcC4gVGhlIG5hbWUgb2YgdGhlIHJvbGUgaXMKICAgICAgIHNjb3BlZCB0byB0aGUgdHlwZSBvbiB3aGljaCB0aGUgQS1zaWRlIGlzIGRlZmluZWQgYW5kIE1VU1QgYmUgdW5pcXVlCiAgICAgICB3aXRoaW4gdGhlIHNjb3BlLgoKICAgICAgIFdoaWxlIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIGRvZXMgbm90IHJlc3VsdCBpbiBhIHByb3BlcnR5IG9mCiAgICAgICB0aGUgcmVsYXRpb25zaGlwLCBpdCBpcyBSRUNPTU1FTkRFRCB0byBhdm9pZCB1c2luZyB0aGUgbmFtZSBvZiBhbgogICAgICAgZXhpc3RpbmcgdHlwZSBwcm9wZXJ0eSBhcyByb2xlIG5hbWUgdG8gYXZvaWQgcG90ZW50aWFsIGFtYmlndWl0aWVzCiAgICAgICBiZXR3ZWVuIHByb3BlcnRpZXMgb2YgYSB0eXBlLCBhbmQgcm9sZXMgb2YgYSByZWxhdGlvbnNoaXAgb24gdGhlIHR5cGUuCgogICAgICAgVGhlIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSB0eXBlIG9uIHdoaWNoIHRoZSBBLXNpZGUgcmVzaWRlcy4gSWYgdGhlCiAgICAgICB0eXBlIGlzIGRlY2xhcmVkIGluIGFub3RoZXIgbW9kdWxlLCB0aGUgdHlwZSBtdXN0IGJlIHByZWZpeGVkLCBhbmQgYQogICAgICAgY29ycmVzcG9uZGluZyAnaW1wb3J0JyBzdGF0ZW1lbnQgYmUgdXNlZCB0byBkZWNsYXJlIHRoZSBwcmVmaXguIjsKCiAgICBhcmd1bWVudCBhU2lkZVR5cGU7CiAgfQoKICBleHRlbnNpb24gYlNpZGUgewogICAgZGVzY3JpcHRpb24gIkRlZmluZXMgdGhlIEItc2lkZSBvZiBhIHJlbGF0aW9uc2hpcC4KCiAgICAgICBUaGUgc3RhdGVtZW50IE1VU1Qgb25seSBiZSBhIHN1YnN0YXRlbWVudCBvZiBhICdsZWFmJyBvciAnbGVhZi1saXN0JwogICAgICAgc3RhdGVtZW50LCB3aGljaCBpdHNlbGYgbXVzdCBiZSBhIHN1YnN0YXRlbWVudCBvZiB0aGUKICAgICAgICd1bmktZGlyZWN0aW9uYWwtdG9wb2xvZ3ktcmVsYXRpb25zaGlwJyBzdGF0ZW1lbnQuCgogICAgICAgVGhlIGRhdGEgdHlwZSBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBNVVNUIGJlCiAgICAgICAnaW5zdGFuY2UtaWRlbnRpZmllcicuIENvbnN0cmFpbnRzIE1BWSBiZSB1c2VkIGFzIHBhcnQgb2YgdGhlIHBhcmVudAogICAgICAgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIHRvIGVuZm9yY2UgY2FyZGluYWxpdHkuCgogICAgICAgVGhlIGlkZW50aWZpZXIgb2YgdGhlIHBhcmVudCAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgaXMgdXNlZCBhcyBuYW1lIG9mCiAgICAgICB0aGUgcm9sZSBvZiB0aGUgQi1zaWRlIG9mIHRoZSByZWxhdGlvbnNoaXAuIFRoZSBuYW1lIG9mIHRoZSByb2xlIGlzCiAgICAgICBzY29wZWQgdG8gdGhlIHR5cGUgb24gd2hpY2ggdGhlIEItc2lkZSBpcyBkZWZpbmVkIGFuZCBNVVNUIGJlIHVuaXF1ZQogICAgICAgd2l0aGluIHRoZSBzY29wZS4KCiAgICAgICBXaGlsZSB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBkb2VzIG5vdCByZXN1bHQgaW4gYSBwcm9wZXJ0eSBvZgogICAgICAgdGhlIHJlbGF0aW9uc2hpcCwgaXQgaXMgUkVDT01NRU5ERUQgdG8gYXZvaWQgdXNpbmcgdGhlIG5hbWUgb2YgYW4KICAgICAgIGV4aXN0aW5nIHR5cGUgcHJvcGVydHkgYXMgcm9sZSBuYW1lIHRvIGF2b2lkIHBvdGVudGlhbCBhbWJpZ3VpdGllcwogICAgICAgYmV0d2VlbiBwcm9wZXJ0aWVzIG9mIGEgdHlwZSwgYW5kIHJvbGVzIG9mIGEgcmVsYXRpb25zaGlwIG9uIHRoZSB0eXBlLgoKICAgICAgIFRoZSBhcmd1bWVudCBpcyB0aGUgbmFtZSBvZiB0aGUgdHlwZSBvbiB3aGljaCB0aGUgQi1zaWRlIHJlc2lkZXMuIElmIHRoZQogICAgICAgdHlwZSBpcyBkZWNsYXJlZCBpbiBhbm90aGVyIG1vZHVsZSwgdGhlIHR5cGUgbXVzdCBiZSBwcmVmaXhlZCwgYW5kIGEKICAgICAgIGNvcnJlc3BvbmRpbmcgJ2ltcG9ydCcgc3RhdGVtZW50IGJlIHVzZWQgdG8gZGVjbGFyZSB0aGUgcHJlZml4LiI7CgogICAgYXJndW1lbnQgYlNpZGVUeXBlOwogIH0KCiAgZXh0ZW5zaW9uIGRvbWFpbiB7CiAgICBkZXNjcmlwdGlvbiAiS2V5d29yZCB1c2VkIHRvIGNhcnJ5IGRvbWFpbiBpbmZvcm1hdGlvbi4iOwogICAgYXJndW1lbnQgZG9tYWluTmFtZTsKICB9CgogIGV4dGVuc2lvbiBsYWJlbCB7CiAgICBkZXNjcmlwdGlvbiAiVGhlIGxhYmVsIGNhbiBiZSB1c2VkIHRvIGdpdmUgbW9kdWxlcyBhbmQgc3VibW9kdWxlcyBhIHNlbWFudGljIHZlcnNpb24sIGluIGFkZGl0aW9uIHRvIHRoZWlyIHJldmlzaW9uLgoKICAgICAgVGhlIGZvcm1hdCBvZiB0aGUgbGFiZWwgaXMg4oCYeC55LnrigJkg4oCTIGV4cHJlc3NlZCBhcyBwYXR0ZXJuLCBpdCBpcyBbMC05XStcXC5bMC05XStcXC5bMC05XSsKCiAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZSByZXZpc2lvbiBzdGF0ZW1lbnQuICBaZXJvIG9yIG9uZSByZXZpc2lvbiBsYWJlbCBzdGF0ZW1lbnRzCiAgICAgIHBlciBwYXJlbnQgc3RhdGVtZW50IGFyZSBhbGxvd2VkLgoKICAgICAgUmV2aXNpb24gbGFiZWxzIE1VU1QgYmUgdW5pcXVlIGFtb25nc3QgYWxsIHJldmlzaW9ucyBvZiBhIG1vZHVsZSBvciBzdWJtb2R1bGUuIjsKICAgICAgYXJndW1lbnQgc2VtdmVyc2lvbjsKICB9Cn0=	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-oam-to-cloud	urn:o-ran:smo-teiv-oam-to-cloud	OAM_TO_CLOUD	["o-ran-smo-teiv-oam", "o-ran-smo-teiv-cloud"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LW9hbS10by1jbG91ZCB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtb2FtLXRvLWNsb3VkIjsKICAgIHByZWZpeCBvci10ZWl2LW9hbXRvY2xvdWQ7CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHtwcmVmaXggb3ItdGVpdi10eXBlczsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LW9hbSB7cHJlZml4IG9yLXRlaXYtb2FtOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNsb3VkIHtwcmVmaXggb3ItdGVpdi1jbG91ZDsgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBPJk0gdG8gQ2xvdWQgdG9wb2xvZ3kgbW9kZWwuCgogICAgQ29weXJpZ2h0IChjKSAyMDIzIEVyaWNzc29uIEFCLiBBbGwgcmlnaHRzIHJlc2VydmVkLgoKICAgIFRoaXMgbW9kZWwgY29udGFpbnMgdGhlIFJBTiBPJk0gdG8gQ2xvdWQgdG9wb2xvZ3kgcmVsYXRpb25zIjsKCiAgICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgewogICAgICAgIGRlc2NyaXB0aW9uICJJbml0aWFsIHJldmlzaW9uLiI7CiAgICAgICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogICAgfQoKICAgIG9yLXRlaXYteWV4dDpkb21haW4gT0FNX1RPX0NMT1VEOwoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfREVQTE9ZRURfQVNfQ0xPVURJRklFRE5GIHsgIC8vIDAuLjEgdG8gMQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZiBkZXBsb3llZC1hcy1jbG91ZGlmaWVkTkYgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWFuYWdlZCBFbGVtZW50IGRlcGxveWVkIGFzIENsb3VkaWZpZWQgTkYuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtb2FtOk1hbmFnZWRFbGVtZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIGRlcGxveWVkLW1hbmFnZWRFbGVtZW50IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkNsb3VkaWZpZWQgTkYgZGVwbG95cyBNYW5hZ2VkIEVsZW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtY2xvdWQ6Q2xvdWRpZmllZE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1hbmRhdG9yeSB0cnVlOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfTUFOQUdFREVMRU1FTlQgeyAvLyAxLi5uIHRvIDEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgc2VydmljZWQtbWFuYWdlZEVsZW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWFuYWdlZCBFbGVtZW50IHNlcnZpY2VkIGJ5IHRoaXMgTkYgRGVwbG95bWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1jbG91ZDpORkRlcGxveW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3Qgc2VydmluZy1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCB0aGF0IHNlcnZlcyB0aGlzIE1hbmFnZWQgRWxlbWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1vYW06TWFuYWdlZEVsZW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWluLWVsZW1lbnRzIDE7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-common-yang-types	urn:o-ran:smo-teiv-common-yang-types	\N	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHsKCiAgeWFuZy12ZXJzaW9uIDEuMTsKICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyI7CiAgcHJlZml4IG9yLXRlaXYtdHlwZXM7CgogIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogIGltcG9ydCBfM2dwcC1jb21tb24teWFuZy10eXBlcyB7IHByZWZpeCB0eXBlczNncHA7IH0KCiAgb3JnYW5pemF0aW9uICJFcmljc3NvbiBBQiI7CiAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgZGVzY3JpcHRpb24KICAiVG9wb2xvZ3kgYW5kIEludmVudG9yeSBjb21tb24gdHlwZXMgbW9kZWwuCgogIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgVGhpcyBtb2RlbCBjb250YWlucyByZS11c2FibGUgZGF0YSB0eXBlcyB0aGF0IHRvcG9sb2d5IGFuZCBpbnZlbnRvcnkgbW9kZWxzCiAgd2lsbCBmcmVxdWVudGx5IHVzZSBhcyBwYXJ0IG9mIHR5cGVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CgogIHJldmlzaW9uICIyMDI0LTA1LTAyIiB7CiAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogIH0KCiAgZ3JvdXBpbmcgVG9wX0dycF9UeXBlIHsKCiAgICBkZXNjcmlwdGlvbiAiR3JvdXBpbmcgY29udGFpbmluZyB0aGUga2V5IGF0dHJpYnV0ZSBjb21tb24gdG8gYWxsIHR5cGVzLiBBbGwgdHlwZXMKICAgICAgICAgICAgICAgIE1VU1QgdXNlIHRoaXMgZ3JvdXBpbmcuIjsKCiAgICBsZWFmIGlkIHsKICAgICAgdHlwZSBzdHJpbmc7CiAgICAgIGRlc2NyaXB0aW9uICJVbmlxdWUgaWRlbnRpZmllciBvZiB0b3BvbG9neSBlbnRpdGllcy4gUmVwcmVzZW50cyB0aGUgRW50aXR5IEluc3RhbmNlIElkZW50aWZpZXIuIjsKICAgIH0KICB9CgogIGdyb3VwaW5nIENNX0lEIHsKCiAgICBkZXNjcmlwdGlvbiAiR3JvdXBpbmcgY29udGFpbmluZyB0aGUga2V5IGF0dHJpYnV0ZXMgdG8gbWFrZQogICAgICAgICAgICAgICAgdXNlIG9mIENvbmZpZ3VyYXRpb24gTWFuYWdlbWVudCAoQ00pLiI7CgogICAgbGVhZiBjbUhhbmRsZSB7CiAgICAgIHR5cGUgc3RyaW5nOwogICAgICBkZXNjcmlwdGlvbiAiVW5pcXVlIGlkZW50aWZpZXIgZm9yIG5ldHdvcmsgZW50aXRpZXMgaW4gQ00uIjsKICAgIH0KCiAgICBsZWFmIHJlc291cmNlSWRlbnRpZmllciB7CiAgICAgIHR5cGUgc3RyaW5nOwogICAgICBkZXNjcmlwdGlvbiAiVGhlIHhwYXRoIGV4cHJlc3Npb24gaWRlbnRpZnlpbmcgdGhlIHJlc291cmNlIGluIHRoZSBOb2RlIG1vZGVsIHlhbmcgdHJlZS4iOwogICAgfQogIH0KCiAgdHlwZWRlZiBfM0dQUF9GRE5fVHlwZSB7CiAgICB0eXBlIHR5cGVzM2dwcDpEaXN0aW5ndWlzaGVkTmFtZTsKICB9CgogIGNvbnRhaW5lciBjb25zdW1lci1kYXRhIHsKICAgIGRlc2NyaXB0aW9uICJUaGlzIGNvbnRhaW5lciBkZWZpbmVzIHRoZSBjb25zdW1lci1kYXRhLiBDb25zdW1lci1kYXRhIG1heSBiZSBhdHRhY2hlZCB0byBUb3BvbG9neSBFbnRpdHkgb3IKICAgICAgICAgICAgICAgIFRvcG9sb2d5IFJlbGF0aW9uIGluc3RhbmNlLCBvdXRzaWRlIG9mIHRoZSBkZWNsYXJlZCBUb3BvbG9neSBFbnRpdHkgb3IgVG9wb2xvZ3kgUmVsYXRpb25zaGlwJ3MgYXR0cmlidXRlcy4KICAgICAgICAgICAgICAgIFRoaXMgY29udGFpbmVyIGNhbm5vdCBiZSBpbnN0YW50aWF0ZWQsIGFuZCBpdCBNVVNUIE5PVCBiZSBhdWdtZW50ZWQgb3IgZGV2aWF0ZWQgaW4gYW55IHdheSwgdW5sZXNzIHN0YXRlZAogICAgICAgICAgICAgICAgb3RoZXJ3aXNlLiI7CgogICAgY29udGFpbmVyIGRlY29yYXRvcnMgewogICAgICBkZXNjcmlwdGlvbiAiVGhpcyBjb250YWluZXIgc2VydmVzIGFzIGV4dGVuc2lvbiBwb2ludCBmb3IgYXBwbGljYXRpb25zIHdpc2hpbmcgdG8gZGVmaW5lIHRoZWlyIG93biBkZWNvcmF0b3JzLgogICAgICAgICAgICAgICAgICBUaGlzIGlzIGRvbmUgdmlhIGF1Z21lbnRhdGlvbnMuIFRoZXkgY2FuIG9ubHkgYmUgZGVmaW5lZCBpbiBuYW1lIHZhbHVlIHBhaXIuIjsKICAgIH0KCiAgICBsZWFmLWxpc3QgY2xhc3NpZmllcnMgewogICAgICBkZXNjcmlwdGlvbiAiQ29uc3VtZXIgZGVmaW5lZCB0YWdzIHRvIHRvcG9sb2d5IGVudGl0aWVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CiAgICAgIHR5cGUgaWRlbnRpdHlyZWYgeyBiYXNlIGNsYXNzaWZpZXI7IH0KICAgIH0KCiAgICBsZWFmLWxpc3Qgc291cmNlSWRzIHsKICAgICAgZGVzY3JpcHRpb24gIkFuIG9yZGVyZWQgbGlzdCBvZiBpZGVudGl0aWVzIHRoYXQgcmVwcmVzZW50IHRoZSBzZXQgb2YgbmF0aXZlIHNvdXJjZSBpZGVudGlmaWVycyBmb3IgcGFydGljaXBhdGluZwogICAgICAgICAgICAgICAgICBlbnRpdGllcy4iOwogICAgICB0eXBlIHN0cmluZzsKICAgICAgb3JkZXJlZC1ieSB1c2VyOwogICAgfQoKICAgIGNvbnRhaW5lciBtZXRhZGF0YSB7CiAgICAgIGRlc2NyaXB0aW9uICJUaGlzIGNvbnRhaW5lciBzZXJ2ZXMgYXMgZXh0ZW5zaW9uIHBvaW50IHRvIGRlZmluZSBtZXRhZGF0YS4gVGhleSBjYW4gb25seSBiZSBkZWZpbmVkIGluIG5hbWUgdmFsdWUKICAgICAgICAgICAgICAgICAgcGFpci4iOwogICAgfQogIH0KCiAgaWRlbnRpdHkgY2xhc3NpZmllcnsKICAgIGRlc2NyaXB0aW9uICAiVGhlIGNsYXNzaWZpZXIgaXMgdXNlZCBhcyBhIGJhc2UgdG8gcHJvdmlkZSBhbGwgY2xhc3NpZmllcnMgd2l0aCBpZGVudGl0eS4gIjsKICB9Cn0=	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-oam	urn:o-ran:smo-teiv-oam	OAM	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LW9hbSB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtb2FtIjsKICAgIHByZWZpeCBvci10ZWl2LW9hbTsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBvcmdhbml6YXRpb24gIkVyaWNzc29uIEFCIjsKICAgIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOwogICAgZGVzY3JpcHRpb24KICAgICJSQU4gTyZNIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIE8mTSBkb21haW4sIHdoaWNoIGFyZSBpbnRlbmRlZCB0byByZXByZXNlbnQgbWFuYWdlbWVudCBzeXN0ZW1zCiAgICBhbmQgbWFuYWdlbWVudCBpbnRlcmZhY2VzLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIE9BTTsKCiAgICBsaXN0IE1hbmFnZWRFbGVtZW50IHsKICAgICAgICBkZXNjcmlwdGlvbiAiQSBNYW5hZ2VkIEVsZW1lbnQgKE1FKSBpcyBhIG5vZGUgaW50byBhIHRlbGVjb21tdW5pY2F0aW9uIG5ldHdvcmsKICAgICAgICAgICAgICAgICAgICBwcm92aWRpbmcgc3VwcG9ydCBhbmQvb3Igc2VydmljZSB0byBzdWJzY3JpYmVycy4gQW4gTUUgY29tbXVuaWNhdGVzCiAgICAgICAgICAgICAgICAgICAgd2l0aCBhIG1hbmFnZXIgYXBwbGljYXRpb24gKGRpcmVjdGx5IG9yIGluZGlyZWN0bHkpIG92ZXIgb25lIG9yIG1vcmUKICAgICAgICAgICAgICAgICAgICBpbnRlcmZhY2VzIGZvciB0aGUgcHVycG9zZSBvZiBiZWluZyBtb25pdG9yZWQgYW5kL29yIGNvbnRyb2xsZWQuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBmZG4gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgRnVsbCBEaXN0aW5ndWlzaGVkIE5hbWUgKEZETikgaWRlbnRpZmllcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYW4gaW5zdGFuY2Ugb2YgdGhlIE1hbmFnZWRFbGVtZW50IE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTWFuYWdlZEVsZW1lbnQuIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-oam-to-ran	urn:o-ran:smo-teiv-oam-to-ran	OAM_TO_RAN	["o-ran-smo-teiv-oam", "o-ran-smo-teiv-ran"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LW9hbS10by1yYW4gewogICAgeWFuZy12ZXJzaW9uIDEuMTsKICAgIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LW9hbS10by1yYW4iOwogICAgcHJlZml4IG9yLXRlaXYtb2FtdG9yYW47CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHtwcmVmaXggb3ItdGVpdi10eXBlczsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LW9hbSB7cHJlZml4IG9yLXRlaXYtb2FtOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LXJhbiB7cHJlZml4IG9yLXRlaXYtcmFuOyB9CgogICAgb3JnYW5pemF0aW9uICJFcmljc3NvbiBBQiI7CiAgICBjb250YWN0ICJFcmljc3NvbiBmaXJzdCBsaW5lIHN1cHBvcnQgdmlhIGVtYWlsIjsKICAgIGRlc2NyaXB0aW9uCiAgICAiUkFOIE8mTSB0byBMb2dpY2FsIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSBSQU4gTyZNIHRvIExvZ2ljYWwgdG9wb2xvZ3kgcmVsYXRpb25zIjsKCiAgICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgewogICAgICAgIGRlc2NyaXB0aW9uICJJbml0aWFsIHJldmlzaW9uLiI7CiAgICAgICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogICAgfQoKICAgIG9yLXRlaXYteWV4dDpkb21haW4gT0FNX1RPX1JBTjsKCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE1BTkFHRURFTEVNRU5UX01BTkFHRVNfRU5PREVCRlVOQ1RJT04geyAgIC8vIDEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IG1hbmFnZWQtZW5vZGViRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWFuYWdlZCBFbGVtZW50IG1hbmFnZXMgZU5vZGVCIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBvci10ZWl2LW9hbTpNYW5hZ2VkRWxlbWVudDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBtYW5hZ2VkLWJ5LW1hbmFnZWRFbGVtZW50IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImVOb2RlQiBGdW5jdGlvbiBtYW5hZ2VkIGJ5IE1hbmFnZWQgRWxlbWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1yYW46RU5vZGVCRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfTUFOQUdFU19HTkJEVUZVTkNUSU9OIHsgICAgLy8gMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgbWFuYWdlZC1nbmJkdUZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk1hbmFnZWQgRWxlbWVudCBtYW5hZ2VzIGdOb2RlQi1EVSBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1vYW06TWFuYWdlZEVsZW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgbWFuYWdlZC1ieS1tYW5hZ2VkRWxlbWVudCB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUItRFUgRnVuY3Rpb24gbWFuYWdlZCBieSBNYW5hZ2VkIEVsZW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkRVRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfTUFOQUdFU19HTkJDVUNQRlVOQ1RJT04geyAgICAvLyAxIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBtYW5hZ2VkLWduYmN1Y3BGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJNYW5hZ2VkIEVsZW1lbnQgbWFuYWdlcyBnTm9kZUItQ1UtQ1AgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtb2FtOk1hbmFnZWRFbGVtZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIG1hbmFnZWQtYnktbWFuYWdlZEVsZW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVLUNQIEZ1bmN0aW9uIG1hbmFnZWQgYnkgTWFuYWdlZCBFbGVtZW50LiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBvci10ZWl2LXJhbjpHTkJDVUNQRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfTUFOQUdFU19HTkJDVVVQRlVOQ1RJT04geyAgICAvLyAxIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBtYW5hZ2VkLWduYmN1dXBGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJNYW5hZ2VkIEVsZW1lbnQgbWFuYWdlcyBnTm9kZUItQ1UtVVAgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtb2FtOk1hbmFnZWRFbGVtZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIG1hbmFnZWQtYnktbWFuYWdlZEVsZW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVLVVQIEZ1bmN0aW9uIG1hbmFnZWQgYnkgTWFuYWdlZCBFbGVtZW50LiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBvci10ZWl2LXJhbjpHTkJDVVVQRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-ran	urn:o-ran:smo-teiv-ran	RAN	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LXJhbiB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtcmFuIjsKICAgIHByZWZpeCBvci10ZWl2LXJhbjsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgXzNncHAtY29tbW9uLXlhbmctdHlwZXMgeyBwcmVmaXggdHlwZXMzZ3BwOyB9CgogICAgaW1wb3J0IGlldGYtZ2VvLWxvY2F0aW9uIHsKICAgICAgICBwcmVmaXggZ2VvOwogICAgICAgIHJlZmVyZW5jZSAiUkZDIDkxNzk6IEEgWUFORyBHcm91cGluZyBmb3IgR2VvZ3JhcGhpYyBMb2NhdGlvbnMiOwogICAgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBMb2dpY2FsIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIExvZ2ljYWwgZG9tYWluLCB3aGljaCByZXByZXNlbnRzIHRoZSBmdW5jdGlvbmFsIGNhcGFiaWxpdHkKICAgIG9mIHRoZSBkZXBsb3llZCBSQU4gdGhhdCBhcmUgcmVsZXZhbnQgdG8gckFwcHMgdXNlIGNhc2VzLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIFJBTjsKCiAgICBsaXN0IEdOQkRVRnVuY3Rpb24gewogICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUIgRGlzdHJpYnV0ZWQgVW5pdCAoZ05CLURVKS4KCiAgICAgICAgICAgICAgICAgICAgQSBnTkIgbWF5IGNvbnNpc3Qgb2YgYSBnTkItQ2VudHJhbGl6ZWQgVW5pdAogICAgICAgICAgICAgICAgICAgIChnTkItQ1UpIGFuZCBhIGdOQi1EVS4gVGhlIENVIHByb2Nlc3NlcyBub24tcmVhbAogICAgICAgICAgICAgICAgICAgIHRpbWUgcHJvdG9jb2xzIGFuZCBzZXJ2aWNlcywgYW5kIHRoZSBEVSBwcm9jZXNzZXMKICAgICAgICAgICAgICAgICAgICBQSFkgbGV2ZWwgcHJvdG9jb2wgYW5kIHJlYWwgdGltZSBzZXJ2aWNlcy4gVGhlCiAgICAgICAgICAgICAgICAgICAgZ05CLUNVIGFuZCB0aGUgZ05CLURVIHVuaXRzIGFyZSBjb25uZWN0ZWQgdmlhCiAgICAgICAgICAgICAgICAgICAgRjEgbG9naWNhbCBpbnRlcmZhY2UuCgogICAgICAgICAgICAgICAgICAgIFRoZSBmb2xsb3dpbmcgaXMgdHJ1ZSBmb3IgYSBnTkItRFU6CiAgICAgICAgICAgICAgICAgICAgSXMgY29ubmVjdGVkIHRvIHRoZSBnTkItQ1UtQ1AgdGhyb3VnaCB0aGUgRjEtQwogICAgICAgICAgICAgICAgICAgIGludGVyZmFjZS5JcyBjb25uZWN0ZWQgdG8gdGhlIGdOQi1DVS1VUCB0aHJvdWdoCiAgICAgICAgICAgICAgICAgICAgdGhlIEYxLVUgaW50ZXJmYWNlLiBPbmUgZ05CLURVIGlzIGNvbm5lY3RlZCB0byBvbmx5CiAgICAgICAgICAgICAgICAgICAgb25lIGdOQi1DVS1DUC4gT25lIGdOQi1EVSBjYW4gYmUgY29ubmVjdGVkIHRvCiAgICAgICAgICAgICAgICAgICAgbXVsdGlwbGUgZ05CLUNVLVVQcyB1bmRlciB0aGUgY29udHJvbCBvZiB0aGUgc2FtZQogICAgICAgICAgICAgICAgICAgIGdOQi1DVS1DUC4KICAgICAgICAgICAgICAgICAgICBOb3RlOiBBIGdOQiBtYXkgY29uc2lzdCBvZiBhIGdOQi1DVS1DUCwgbXVsdGlwbGUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtVVBzIGFuZCBtdWx0aXBsZSBnTkItRFVzLiBnTkItRFUgaXMgYSBjb25jcmV0ZQogICAgICAgICAgICAgICAgICAgIGNsYXNzIHRoYXQgZXh0ZW5kcyB0aGUgTkctUkFOIG5vZGUgb2JqZWN0LiBJbiBUb3BvbG9neSwgeW91CiAgICAgICAgICAgICAgICAgICAgY2FuIGNyZWF0ZSwgcmVhZCwgdXBkYXRlLCBhbmQgZGVsZXRlIHRoZSBnTkItRFUgb2JqZWN0LiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBHTkJEVUZ1bmN0aW9uIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgR05CRFVGdW5jdGlvbi4iOwogICAgICAgICAgICAgICAgdHlwZSBvci10ZWl2LXR5cGVzOl8zR1BQX0ZETl9UeXBlOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgZFVwTE1OSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlBMTU4gaWRlbnRpZmllciB1c2VkIGFzIHBhcnQgb2YgUE0gRXZlbnRzIGRhdGEiOwogICAgICAgICAgICAgICAgdXNlcyB0eXBlczNncHA6UExNTklkOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGdOQkRVSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgRFUgd2l0aGluIGEgZ05vZGVCIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGdOQklkIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJJZGVudGl0eSBvZiBnTm9kZUIgd2l0aGluIGEgUExNTiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJJZExlbmd0aCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTGVuZ3RoIG9mIGdOQklkIGJpdCBzdHJpbmcgcmVwcmVzZW50YXRpb24iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IEdOQkNVQ1BGdW5jdGlvbiB7CiAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQiBDZW50cmFsaXplZCBVbml0IENvbnRyb2wgUGxhbmUgKGdOQi1DVS1DUCkKCiAgICAgICAgICAgICAgICAgICAgVGhpcyBpcyBhIGxvZ2ljYWwgbm9kZSBob3N0aW5nIHRoZSBSYWRpbyBSZXNvdXJjZQogICAgICAgICAgICAgICAgICAgIENvbnRyb2wgKFJSQykgYW5kIHRoZSBjb250cm9sIHBsYW5lIHBhcnQgb2YgdGhlCiAgICAgICAgICAgICAgICAgICAgUGFja2V0IERhdGEgQ29udmVyZ2VuY2UgUHJvdG9jb2wgKFBEQ1ApIG9mIHRoZQogICAgICAgICAgICAgICAgICAgIGdOb2RlQiBDZW50cmFsaXplZCBVbml0IChnTkItQ1UpIGZvciBhbiBFLVVUUkFOIGdOb2RlQgogICAgICAgICAgICAgICAgICAgIChlbi1nTkIpIG9yIGEgZ05vZGVCIChnTkIpLiBUaGUgZ05CLUNVLUNQIHRlcm1pbmF0ZXMKICAgICAgICAgICAgICAgICAgICB0aGUgRTEgaW50ZXJmYWNlIGNvbm5lY3RlZCB3aXRoIHRoZSBnTkItQ1UtVVAgYW5kIHRoZQogICAgICAgICAgICAgICAgICAgIEYxLUMgaW50ZXJmYWNlIGNvbm5lY3RlZCB3aXRoIHRoZSBnTm9kZUIKICAgICAgICAgICAgICAgICAgICBEaXN0cmlidXRlZCBVbml0IChnTkItRFUpLgoKICAgICAgICAgICAgICAgICAgICBUaGUgZm9sbG93aW5nIGlzIHRydWUgZm9yIGEgZ05CLUNVLUNQOgogICAgICAgICAgICAgICAgICAgIElzIGNvbm5lY3RlZCB0byB0aGUgZ05CLURVIHRocm91Z2ggdGhlIEYxLUMgaW50ZXJmYWNlLgogICAgICAgICAgICAgICAgICAgIElzIGNvbm5lY3RlZCB0byB0aGUgZ05CLUNVLVVQIHRocm91Z2ggdGhlIEUxIGludGVyZmFjZS4KICAgICAgICAgICAgICAgICAgICBPbmx5IG9uZSBnTkItQ1UtQ1AgaXMgY29ubmVjdGVkIHRvIG9uZSBnTkItRFUuCiAgICAgICAgICAgICAgICAgICAgT25seSBvbmUgZ05CLUNVLUNQIGlzIGNvbm5lY3RlZCB0byBvbmUgZ05CLUNVLVVQLgogICAgICAgICAgICAgICAgICAgIE9uZSBnTkItRFUgY2FuIGJlIGNvbm5lY3RlZCB0byBtdWx0aXBsZSBnTkItQ1UtVVBzCiAgICAgICAgICAgICAgICAgICAgdW5kZXIgdGhlIGNvbnRyb2wgb2YgdGhlIHNhbWUgZ05CLUNVLUNQLk9uZSBnTkItQ1UtVVAKICAgICAgICAgICAgICAgICAgICBjYW4gYmUgY29ubmVjdGVkIHRvIG11bHRpcGxlIERVcyB1bmRlciB0aGUgY29udHJvbCBvZgogICAgICAgICAgICAgICAgICAgIHRoZSBzYW1lIGdOQi1DVS1DUC4KICAgICAgICAgICAgICAgICAgICBOb3RlOiBBIGdOQiBtYXkgY29uc2lzdCBvZiBhIGdOQi1DVS1DUCwgbXVsdGlwbGUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtVVBzIGFuZCBtdWx0aXBsZSBnTkItRFVzLiBBIGdOQi1DVS1DUCBpcyBhCiAgICAgICAgICAgICAgICAgICAgY29uY3JldGUgY2xhc3MgdGhhdCBleHRlbmRzIHRoZSBORy1SQU4gbm9kZSBvYmplY3QuCiAgICAgICAgICAgICAgICAgICAgSW4gVG9wb2xvZ3ksIHlvdSBjYW4gY3JlYXRlLCByZWFkLCB1cGRhdGUsIGFuZCBkZWxldGUKICAgICAgICAgICAgICAgICAgICB0aGUgZ05CLUNVLUNQIG9iamVjdC4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgR05CQ1VDUEZ1bmN0aW9uIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgR05CQ1VDUEZ1bmN0aW9uLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZ05CQ1VOYW1lIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOYW1lIG9mIGdOb2RlQi1DVSI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSWRlbnRpdHkgb2YgZ05vZGVCIHdpdGhpbiBhIFBMTU4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZ05CSWRMZW5ndGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxlbmd0aCBvZiBnTkJJZCBiaXQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgcExNTklkIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQTE1OIGlkZW50aWZpZXIgdG8gYmUgdXNlZCBhcyBwYXJ0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvZiBnbG9iYWwgUkFOIG5vZGUgaWRlbnRpdHkiOwogICAgICAgICAgICAgICAgdXNlcyB0eXBlczNncHA6UExNTklkOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgY21JZCB7CiAgICAgICAgICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6Q01fSUQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgbGlzdCBHTkJDVVVQRnVuY3Rpb24gewogICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUIgQ2VudHJhbGl6ZWQgVW5pdCBVc2VyIFBsYW5lIChnTkItQ1UtVVApCgogICAgICAgICAgICAgICAgICAgIEEgZ05CLUNVLVVQIGlzIGEgbG9naWNhbCBub2RlIGhvc3RpbmcgdGhlIFVzZXIKICAgICAgICAgICAgICAgICAgICBQbGFuZSBwYXJ0IG9mIHRoZSBQYWNrZXQgRGF0YSBDb252ZXJnZW5jZSwKICAgICAgICAgICAgICAgICAgICBQcm90b2NvbCAoUERDUCkgb2YgdGhlIGdOb2RlQiBDZW50cmFsaXplZCBVbml0CiAgICAgICAgICAgICAgICAgICAgKGdOQi1DVSkgZm9yIGFuIEUtVVRSQU4gZ05vZGVCIChlbi1nTkIpLCBhbmQgdGhlCiAgICAgICAgICAgICAgICAgICAgVXNlciBQbGFuZSBwYXJ0IG9mIHRoZSBQRENQIHByb3RvY29sIGFuZCB0aGUKICAgICAgICAgICAgICAgICAgICBTZXJ2aWNlIERhdGEgQWRhcHRhdGlvbiBQcm90b2NvbCAoU0RBUCkgb2YgdGhlCiAgICAgICAgICAgICAgICAgICAgZ05CLUNVIGZvciBhIGdOb2RlQiAoZ05CKS4gVGhlIGdOQi1DVS1VUCB0ZXJtaW5hdGVzCiAgICAgICAgICAgICAgICAgICAgdGhlIEUxIGludGVyZmFjZSBjb25uZWN0ZWQgd2l0aCB0aGUgZ05CLUNVLUNQIGFuZAogICAgICAgICAgICAgICAgICAgIHRoZSBGMS1VIGludGVyZmFjZSBjb25uZWN0ZWQgd2l0aCB0aGUgZ05vZGVCCiAgICAgICAgICAgICAgICAgICAgRGlzdHJpYnV0ZWQgVW5pdCAoZ05CLURVKS4KCiAgICAgICAgICAgICAgICAgICAgVGhlIGZvbGxvd2luZyBpcyB0cnVlIGZvciBhIGdOQi1DVS1VUDoKICAgICAgICAgICAgICAgICAgICBJcyBjb25uZWN0ZWQgdG8gdGhlIGdOQi1EVSB0aHJvdWdoIHRoZQogICAgICAgICAgICAgICAgICAgIEYxLVUgaW50ZXJmYWNlLiBJcyBjb25uZWN0ZWQgdG8gdGhlIGdOQi1DVS1DUCB0aHJvdWdoCiAgICAgICAgICAgICAgICAgICAgdGhlIEUxIGludGVyZmFjZS4gT25lIGdOQi1DVS1VUCBpcyBjb25uZWN0ZWQgdG8gb25seSBvbmUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtQ1AuIE9uZSBnTkItRFUgY2FuIGJlIGNvbm5lY3RlZCB0byBtdWx0aXBsZQogICAgICAgICAgICAgICAgICAgIGdOQi1DVS1VUHMgdW5kZXIgdGhlIGNvbnRyb2wgb2YgdGhlIHNhbWUgZ05CLUNVLUNQLiBPbmUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtVVAgY2FuIGJlIGNvbm5lY3RlZCB0byBtdWx0aXBsZSBEVXMgdW5kZXIgdGhlCiAgICAgICAgICAgICAgICAgICAgY29udHJvbCBvZiB0aGUgc2FtZSBnTkItQ1UtQ1AuCiAgICAgICAgICAgICAgICAgICAgTm90ZTogQSBnTkIgbWF5IGNvbnNpc3Qgb2YgYSBnTkItQ1UtQ1AsIG11bHRpcGxlIGdOQi1DVS1VUHMKICAgICAgICAgICAgICAgICAgICBhbmQgbXVsdGlwbGUgZ05CLURVcy4gQSBnTkItQ1UtVVAgaXMgYSBjb25jcmV0ZSBjbGFzcyB0aGF0CiAgICAgICAgICAgICAgICAgICAgZXh0ZW5kcyB0aGUgTkctUkFOIG5vZGUgb2JqZWN0LiBJbiBUb3BvbG9neSwgeW91IGNhbgogICAgICAgICAgICAgICAgICAgIGNyZWF0ZSwgcmVhZCwgdXBkYXRlLCBhbmQgZGVsZXRlIHRoZSBnTkItQ1UtVVAgb2JqZWN0LiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBHTkJDVVVQRnVuY3Rpb24gTU8uIEl0IGNvbnRhaW5zCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgZnVsbCBwYXRoIGZyb20gdGhlIFN1Ym5ldHdvcmsgdG8gdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHTkJDVVVQRnVuY3Rpb24uIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSWRlbnRpdHkgb2YgZ05vZGVCIHdpdGhpbiBhIFBMTU4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZ05CSWRMZW5ndGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxlbmd0aCBvZiBnTkJJZCBiaXQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgY21JZCB7CiAgICAgICAgICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6Q01fSUQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgbGlzdCBOUkNlbGxDVSB7CiAgICAgICAgZGVzY3JpcHRpb24gIlJlcHJlc2VudHMgYW4gTlIgQ2VsbCBpbiBnTm9kZUItQ1UuCgogICAgICAgICAgICAgICAgICAgIDVHIE5SIGlzIGEgbmV3IHJhZGlvIGFjY2VzcyB0ZWNobm9sb2d5IChSQVQpCiAgICAgICAgICAgICAgICAgICAgZGV2ZWxvcGVkIGJ5IDNHUFAgZm9yIHRoZSA1RyAoZmlmdGggZ2VuZXJhdGlvbikKICAgICAgICAgICAgICAgICAgICBtb2JpbGUgbmV0d29yay4gSXQgaXMgZGVzaWduZWQgdG8gYmUgdGhlIGdsb2JhbAogICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkIGZvciB0aGUgYWlyIGludGVyZmFjZSBvZiA1RyBuZXR3b3Jrcy4KCiAgICAgICAgICAgICAgICAgICAgNUcgTlIgaGFzIHN5bmNocm9uaXphdGlvbiBzaWduYWwgdGhhdCBpcyBrbm93biBhcwogICAgICAgICAgICAgICAgICAgIFByaW1hcnkgU3luY2hyb25pemF0aW9uIHNpZ25hbCAoUFNTKSBhbmQgU2Vjb25kYXJ5CiAgICAgICAgICAgICAgICAgICAgU3luY2hyb25pemF0aW9uIHNpZ25hbCAoU1NTKS4gVGhlc2Ugc2lnbmFscyBhcmUKICAgICAgICAgICAgICAgICAgICBzcGVjaWZpYyB0byBOUiBwaHlzaWNhbCBsYXllciBhbmQgcHJvdmlkZSB0aGUKICAgICAgICAgICAgICAgICAgICBmb2xsb3dpbmcgaW5mb3JtYXRpb24gcmVxdWlyZWQgYnkgVUUgZm9yIGRvd25saW5rCiAgICAgICAgICAgICAgICAgICAgc3luY2hyb25pemF0aW9uOiBQU1MgcHJvdmlkZXMgUmFkaW8gRnJhbWUgQm91bmRhcnkKICAgICAgICAgICAgICAgICAgICAoUG9zaXRpb24gb2YgMXN0IFN5bWJvbCBpbiBhIFJhZGlvIGZyYW1lKSBTU1MgcHJvdmlkZXMKICAgICAgICAgICAgICAgICAgICBTdWJmcmFtZSBCb3VuZGFyeSAoUG9zaXRpb24gb2YgMXN0IFN5bWJvbCBpbiBhIFN1YmZyYW1lKQogICAgICAgICAgICAgICAgICAgIFBoeXNpY2FsIExheWVyIENlbGwgSUQgKFBDSSkgaW5mb3JtYXRpb24gdXNpbmcgYm90aAogICAgICAgICAgICAgICAgICAgIFBTUyBhbmQgU1NTLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBOUkNlbGxDVSBNTy4gSXQgY29udGFpbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBmdWxsIHBhdGggZnJvbSB0aGUgU3VibmV0d29yayB0byB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5SQ2VsbENVLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgY2VsbExvY2FsSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlVzZWQgdG9nZXRoZXIgd2l0aCBnTm9kZUIgaWRlbnRpZmllciB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnRpZnkgTlIgY2VsbCBpbiBQTE1OLiBVc2VkIHRvZ2V0aGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoIGdOQklkIHRvIGZvcm0gTkNJLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIHBsbW5JZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiUExNTiBJRCBmb3IgTlIgQ0dJLiBJZiBlbXB0eSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdOQkNVQ1BGdW5jdGlvbjo6cExNTklkIGlzIHVzZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBQTE1OIElEIGluIE5SIENHSSI7CiAgICAgICAgICAgICAgICB1c2VzIHR5cGVzM2dwcDpQTE1OSWQ7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgbkNJIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBDZWxsIElkZW50aXR5IjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIG5SVEFDIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBUcmFja2luZyBBcmVhIENvZGUgKFRBQykiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IE5SQ2VsbERVIHsKICAgICAgICBkZXNjcmlwdGlvbiAiUmVwcmVzZW50cyBhbiBOUiBDZWxsIGluIGdOb2RlQi1EVS4KCiAgICAgICAgICAgICAgICAgICAgNUcgTlIgaXMgYSBuZXcgcmFkaW8gYWNjZXNzIHRlY2hub2xvZ3kgKFJBVCkKICAgICAgICAgICAgICAgICAgICBkZXZlbG9wZWQgYnkgM0dQUCBmb3IgdGhlIDVHIChmaWZ0aCBnZW5lcmF0aW9uKQogICAgICAgICAgICAgICAgICAgIG1vYmlsZSBuZXR3b3JrLiBJdCBpcyBkZXNpZ25lZCB0byBiZSB0aGUgZ2xvYmFsCiAgICAgICAgICAgICAgICAgICAgc3RhbmRhcmQgZm9yIHRoZSBhaXIgaW50ZXJmYWNlIG9mIDVHIG5ldHdvcmtzLgoKICAgICAgICAgICAgICAgICAgICA1RyBOUiBoYXMgc3luY2hyb25pemF0aW9uIHNpZ25hbCB0aGF0IGlzIGtub3duIGFzCiAgICAgICAgICAgICAgICAgICAgUHJpbWFyeSBTeW5jaHJvbml6YXRpb24gc2lnbmFsIChQU1MpIGFuZCBTZWNvbmRhcnkKICAgICAgICAgICAgICAgICAgICBTeW5jaHJvbml6YXRpb24gc2lnbmFsIChTU1MpLiBUaGVzZSBzaWduYWxzIGFyZQogICAgICAgICAgICAgICAgICAgIHNwZWNpZmljIHRvIE5SIHBoeXNpY2FsIGxheWVyIGFuZCBwcm92aWRlIHRoZQogICAgICAgICAgICAgICAgICAgIGZvbGxvd2luZyBpbmZvcm1hdGlvbiByZXF1aXJlZCBieSBVRSBmb3IgZG93bmxpbmsKICAgICAgICAgICAgICAgICAgICBzeW5jaHJvbml6YXRpb246IFBTUyBwcm92aWRlcyBSYWRpbyBGcmFtZSBCb3VuZGFyeQogICAgICAgICAgICAgICAgICAgIChQb3NpdGlvbiBvZiAxc3QgU3ltYm9sIGluIGEgUmFkaW8gZnJhbWUpIFNTUyBwcm92aWRlcwogICAgICAgICAgICAgICAgICAgIFN1YmZyYW1lIEJvdW5kYXJ5IChQb3NpdGlvbiBvZiAxc3QgU3ltYm9sIGluIGEgU3ViZnJhbWUpCiAgICAgICAgICAgICAgICAgICAgUGh5c2ljYWwgTGF5ZXIgQ2VsbCBJRCAoUENJKSBpbmZvcm1hdGlvbiB1c2luZyBib3RoCiAgICAgICAgICAgICAgICAgICAgUFNTIGFuZCBTU1MuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBmZG4gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgRnVsbCBEaXN0aW5ndWlzaGVkIE5hbWUgKEZETikgaWRlbnRpZmllcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYW4gaW5zdGFuY2Ugb2YgdGhlIE5SQ2VsbERVIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTlJDZWxsRFUuIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBjZWxsTG9jYWxJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVXNlZCB0b2dldGhlciB3aXRoIGdOb2RlQiBpZGVudGlmaWVyIHRvIGlkZW50aWZ5IE5SCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VsbCBpbiBQTE1OLiBVc2VkIHRvZ2V0aGVyIHdpdGggZ05CSWQgdG8gZm9ybSBOQ0kuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIG5DSSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQ2VsbCBJZGVudGl0eS4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgblJQQ0kgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBQaHlzaWNhbCBDZWxsIElkZW50aXR5IChQQ0kpIG9mIHRoZSBOUiBjZWxsLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBuUlRBQyB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgVHJhY2tpbmcgQXJlYSBDb2RlIChUQUMpLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgRU5vZGVCRnVuY3Rpb24gewogICAgICAgIGRlc2NyaXB0aW9uICJBbiBFdm9sdmVkIE5vZGUgQiAoZU5vZGVCKSBpcyB0aGUgb25seSBtYW5kYXRvcnkKICAgICAgICAgICAgICAgICAgICBub2RlIGluIHRoZSByYWRpbyBhY2Nlc3MgbmV0d29yayAoUkFOKSBvZiBMb25nLVRlcm0KICAgICAgICAgICAgICAgICAgICBFdm9sdXRpb24gKExURSkuIFRoZSBlTm9kZUIgaXMgYSBjb21wbGV4IGJhc2UKICAgICAgICAgICAgICAgICAgICBzdGF0aW9uIHRoYXQgaGFuZGxlcyByYWRpbyBjb21tdW5pY2F0aW9ucwogICAgICAgICAgICAgICAgICAgIGluIHRoZSBjZWxsIGFuZCBjYXJyaWVzIG91dCByYWRpbyByZXNvdXJjZQogICAgICAgICAgICAgICAgICAgIG1hbmFnZW1lbnQgYW5kIGhhbmRvdmVyIGRlY2lzaW9ucy4gVW5saWtlIDIvM0cKICAgICAgICAgICAgICAgICAgICB3aXJlbGVzcyBSQU4sIHRoZXJlIGlzIG5vIGNlbnRyYWxpemVkIHJhZGlvIG5ldHdvcmsKICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVyIGluIExURS4gSXQgaXMgdGhlIGhhcmR3YXJlIHRoYXQgaXMgY29ubmVjdGVkCiAgICAgICAgICAgICAgICAgICAgdG8gdGhlIG1vYmlsZSBwaG9uZSBuZXR3b3JrIHRoYXQgY29tbXVuaWNhdGVzCiAgICAgICAgICAgICAgICAgICAgZGlyZWN0bHkgd2l0aCBtb2JpbGUgaGFuZHNldHMgKFVzZXIgRXF1aXBtZW50KSwgbGlrZSBhIGJhc2UKICAgICAgICAgICAgICAgICAgICB0cmFuc2NlaXZlciBzdGF0aW9uIChCVFMpIGluIEdTTSBuZXR3b3Jrcy4gVGhpcyBzaW1wbGlmaWVzCiAgICAgICAgICAgICAgICAgICAgdGhlIGFyY2hpdGVjdHVyZSBhbmQgYWxsb3dzIGxvd2VyIHJlc3BvbnNlIHRpbWVzLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBFTm9kZUJGdW5jdGlvbiBNTy4gSXQgY29udGFpbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBmdWxsIHBhdGggZnJvbSB0aGUgU3VibmV0d29yayB0byB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVOb2RlQkZ1bmN0aW9uLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZU5CSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFTm9kZUIgSUQgdGhhdCBmb3JtcyBwYXJ0IG9mCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgQ2VsbCBHbG9iYWwgSWRlbnRpdHksIGFuZCBpcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxzbyB1c2VkIHRvIGlkZW50aWZ5IHRoZSBub2RlIG92ZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBTMSBpbnRlcmZhY2UiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBlTm9kZUJQbG1uSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFTm9kZUIgUHVibGljIExhbmQgTW9iaWxlIE5ldHdvcmsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIChQTE1OKSBJRCB0aGF0IGZvcm1zIHBhcnQgb2YgdGhlIEVOb2RlQgogICAgICAgICAgICAgICAgICAgICAgICAgICAgR2xvYmFsIElEIHVzZWQgdG8gaWRlbnRpZnkgdGhlIG5vZGUgb3ZlcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIFMxIGludGVyZmFjZS4gTm90ZTogVGhlIHZhbHVlIChNQ0M9MDAxLCBNTkM9MDEpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRpY2F0ZXMgdGhhdCB0aGUgUExNTiBpcyBub3QgaW5pdGlhdGVkLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgVGhlIHZhbHVlIGNhbiBub3QgYmUgdXNlZCBhcyBhIHZhbGlkIFBMTU4gSWRlbnRpdHkuIjsKCiAgICAgICAgICAgICAgICBsZWFmIG1jYyB7CiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBNQ0MgcGFydCBvZiBhIFBMTU4gaWRlbnRpdHkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VkIGluIHRoZSByYWRpbyBuZXR3b3JrLiI7CiAgICAgICAgICAgICAgICAgICAgdHlwZSBpbnQzMiB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlIDAuLjk5OTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBsZWFmIG1uYyB7CiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBNTkMgcGFydCBvZiBhIFBMTU4gaWRlbnRpdHkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VkIGluIHRoZSByYWRpbyBuZXR3b3JrLiI7CiAgICAgICAgICAgICAgICAgICAgdHlwZSBpbnQzMiB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlIDAuLjk5OTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBsZWFmIG1uY0xlbmd0aCB7CiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBsZW5ndGggb2YgdGhlIE1OQyBwYXJ0IG9mIGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQTE1OIGlkZW50aXR5IHVzZWQgaW4gdGhlIHJhZGlvIG5ldHdvcmsuIjsKICAgICAgICAgICAgICAgICAgICB0eXBlIGludDMyIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgMi4uMzsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IEVVdHJhbkNlbGwgewogICAgICAgIGRlc2NyaXB0aW9uICJSZXByZXNlbnRzIGFuIEZERCBvciBUREQgRVV0cmFuQ2VsbCBhbmQKICAgICAgICAgICAgICAgICAgICBjb250YWlucyBwYXJhbWV0ZXJzIG5lZWRlZCBieSB0aGUgY2VsbC4KICAgICAgICAgICAgICAgICAgICBJdCBhbHNvIGNvbnRhaW5zIHBhcmFtZXRlcnMgZm9yIHRoZQogICAgICAgICAgICAgICAgICAgIG1hbmRhdG9yeSBjb21tb24gY2hhbm5lbHMuIEFuIEVVVFJBTiBzdGFuZHMKICAgICAgICAgICAgICAgICAgICBmb3IgRXZvbHZlZCBVbml2ZXJzYWwgTW9iaWxlIFRlbGVjb21tdW5pY2F0aW9ucwogICAgICAgICAgICAgICAgICAgIFN5c3RlbSAoVU1UUykgVGVycmVzdHJpYWwgUmFkaW8gQWNjZXNzIE5ldHdvcmsKICAgICAgICAgICAgICAgICAgICB3aGljaCBjb250YWlucyBhbiBlTm9kZUIuIFRoZSBlTm9kZUIgY29uY3JldGUKICAgICAgICAgICAgICAgICAgICBjbGFzcyBpcyBleHRlbmRlZCBmcm9tIHRoZSBFVVRSQU4gTm9kZSBhYnN0cmFjdCBjbGFzcy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiBlaXRoZXIgdGhlIEVVdHJhbkNlbGxGREQgTU8gb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBFVXRyYW5DZWxsVEREIE1PLiBJdCBjb250YWlucyB0aGUgZnVsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZSBFVXRyYW5DZWxsRkREIG9yCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFVXRyYW5DZWxsVERELiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgY2VsbElkewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlJCUyBpbnRlcm5hbCBJRCBhdHRyaWJ1dGUgZm9yIEVVdHJhbkNlbGwuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNdXN0IGJlIHVuaXF1ZSBpbiB0aGUgUkJTLiBUb2dldGhlciB3aXRoIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTm9kZSBJRCBhbmQgUHVibGljIExhbmQgTW9iaWxlIE5ldHdvcmsgKFBMTU4pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzIGlzIGEgdW5pdmVyc2FsbHkgdW5pcXVlIGNlbGwgSUQiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZWFyZmNuZGwgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBjaGFubmVsIG51bWJlciBmb3IgdGhlIGNlbnRyYWwgZG93bmxpbmsgZnJlcXVlbmN5LiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBlYXJmY251bCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2hhbm5lbCBudW1iZXIgZm9yIHRoZSBjZW50cmFsIHVwbGluayBmcmVxdWVuY3kiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZGxDaGFubmVsQmFuZHdpZHRoIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGUgZG93bmxpbmsgY2hhbm5lbCBiYW5kd2lkdGggaW4gdGhlIEZERCBjZWxsLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBlYXJmY24gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFLVVUUkEgQWJzb2x1dGUgUmFkaW8gRnJlcXVlbmN5IENoYW5uZWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE51bWJlciAoRUFSRkNOKSBmb3IgdGhlIFRERCBjZWxsIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGNoYW5uZWxCYW5kd2lkdGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBjaGFubmVsIGJhbmR3aWR0aCBpbiB0aGUgVEREIGNlbGwuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIHRhYyB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVHJhY2tpbmcgQXJlYSBDb2RlIGZvciB0aGUgRVV0cmFuIENlbGwiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZHVwbGV4VHlwZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSW5kaWNhdG9yIG9mIEVVdHJhbkNlbGwgdHlwZSwgRkREIG9yIFRERCI7CiAgICAgICAgICAgICAgICB0eXBlIGVudW1lcmF0aW9uIHsKICAgICAgICAgICAgICAgICAgICBlbnVtIGZkZCB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJGREQiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIHRkZCB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDE7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUREQiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgTlJTZWN0b3JDYXJyaWVyIHsKICAgICAgICBkZXNjcmlwdGlvbiAiVGhlIE5SIFNlY3RvciBDYXJyaWVyIG9iamVjdCBwcm92aWRlcwogICAgICAgICAgICAgICAgICAgIHRoZSBhdHRyaWJ1dGVzIGZvciBkZWZpbmluZyB0aGUgbG9naWNhbAogICAgICAgICAgICAgICAgICAgIGNoYXJhY3RlcmlzdGljcyBvZiBhIGNhcnJpZXIgKGNlbGwpIGluIGEKICAgICAgICAgICAgICAgICAgICBzZWN0b3IuIEEgc2VjdG9yIGlzIGEgY292ZXJhZ2UgYXJlYSBhc3NvY2lhdGVkCiAgICAgICAgICAgICAgICAgICAgd2l0aCBhIGJhc2Ugc3RhdGlvbiBoYXZpbmcgaXRzIG93biBhbnRlbm5hcywKICAgICAgICAgICAgICAgICAgICByYWRpbyBwb3J0cywgYW5kIGNvbnRyb2wgY2hhbm5lbHMuIFRoZSBjb25jZXB0CiAgICAgICAgICAgICAgICAgICAgb2Ygc2VjdG9ycyB3YXMgZGV2ZWxvcGVkIHRvIGltcHJvdmUgY28tY2hhbm5lbAogICAgICAgICAgICAgICAgICAgIGludGVyZmVyZW5jZSBpbiBjZWxsdWxhciBzeXN0ZW1zLCBhbmQgbW9zdCB3aXJlbGVzcwogICAgICAgICAgICAgICAgICAgIHN5c3RlbXMgdXNlIHRocmVlIHNlY3RvciBjZWxscy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgTlJTZWN0b3JDYXJyaWVyIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTlJTZWN0b3JDYXJyaWVyLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgYXJmY25ETCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQWJzb2x1dGUgUmFkaW8gRnJlcXVlbmN5IENoYW5uZWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE51bWJlciAoTlItQVJGQ04pIGZvciBkb3dubGluayI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBhcmZjblVMIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBBYnNvbHV0ZSBSYWRpbyBmcmVxdWVuY3kgQ2hhbm5lbCBOdW1iZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIChOUi1BUkZDTikgZm9yIHVwbGluay4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZnJlcXVlbmN5REwgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlJGIFJlZmVyZW5jZSBGcmVxdWVuY3kgb2YgZG93bmxpbmsgY2hhbm5lbCI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBmcmVxdWVuY3lVTCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiUkYgUmVmZXJlbmNlIEZyZXF1ZW5jeSBvZiB1cGxpbmsgY2hhbm5lbCI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBiU0NoYW5uZWxCd0RMIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJCUyBDaGFubmVsIGJhbmR3aWR0aCBpbiBNSHogZm9yIGRvd25saW5rLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgTFRFU2VjdG9yQ2FycmllciB7CiAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBMVEUgU2VjdG9yIENhcnJpZXIgb2JqZWN0IHByb3ZpZGVzIHRoZQogICAgICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXMgZm9yIGRlZmluaW5nIHRoZSBsb2dpY2FsIGNoYXJhY3RlcmlzdGljcwogICAgICAgICAgICAgICAgICAgIG9mIGEgY2FycmllciAoY2VsbCkgaW4gYSBzZWN0b3IuIEEgc2VjdG9yIGlzIGEgY292ZXJhZ2UKICAgICAgICAgICAgICAgICAgICBhcmVhIGFzc29jaWF0ZWQgd2l0aCBhIGJhc2Ugc3RhdGlvbiBoYXZpbmcKICAgICAgICAgICAgICAgICAgICBpdHMgb3duIGFudGVubmFzLCByYWRpbyBwb3J0cywgYW5kIGNvbnRyb2wgY2hhbm5lbHMuCiAgICAgICAgICAgICAgICAgICAgVGhlIGNvbmNlcHQgb2Ygc2VjdG9ycyB3YXMgZGV2ZWxvcGVkIHRvIGltcHJvdmUgY28tY2hhbm5lbAogICAgICAgICAgICAgICAgICAgIGludGVyZmVyZW5jZSBpbiBjZWxsdWxhciBzeXN0ZW1zLCBhbmQgbW9zdCB3aXJlbGVzcyBzeXN0ZW1zCiAgICAgICAgICAgICAgICAgICAgdXNlIHRocmVlIHNlY3RvciBjZWxscy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgU2VjdG9yQ2FycmllciBNTy4gSXQgY29udGFpbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBmdWxsIHBhdGggZnJvbSB0aGUgU3VibmV0d29yayB0byB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNlY3RvckNhcnJpZXIuIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBzZWN0b3JDYXJyaWVyVHlwZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSW5kaWNhdGVzIHdoZXRoZXIgb3Igbm90IHRoZSBzZWN0b3IgY2FycmllcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxsZWQgYnkgTU8gU2VjdG9yQ2FycmllciBpcyBhIGRpZ2l0YWwgc2VjdG9yLiI7CiAgICAgICAgICAgICAgICB0eXBlIGVudW1lcmF0aW9uIHsKICAgICAgICAgICAgICAgICAgICBlbnVtIG5vcm1hbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAwOwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTm90IGEgZGlnaXRhbCBzZWN0b3IiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIGxlZnRfZGlnaXRhbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAxOwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTGVmdCBkaWdpdGFsIHNlY3RvciBmb3IgMkRTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSByaWdodF9kaWdpdGFsX3NlY3RvciB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDI7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSaWdodCBkaWdpdGFsIHNlY3RvciBmb3IgMkRTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSBsZWZ0X2RpZ2l0YWxfc2VjdG9yXzNkcyB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDM7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMZWZ0IGRpZ2l0YWwgc2VjdG9yIGZvciAzRFMiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIHJpZ2h0X2RpZ2l0YWxfc2VjdG9yXzNkcyB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDQ7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSaWdodCBkaWdpdGFsIHNlY3RvciBmb3IgM0RTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSBtaWRkbGVfZGlnaXRhbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA1OwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWlkZGxlIGRpZ2l0YWwgc2VjdG9yIGZvciAzRFMiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgQW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIE1PIHNlcnZlcyBhcyBhIG1hcHBpbmcgYmV0d2VlbiB0aGUgY2VsbAogICAgICAgICAgICAgICAgICAgIGFuZCB0aGUgUkJTIGVxdWlwbWVudCB1c2VkIHRvIHByb3ZpZGUgY292ZXJhZ2UKICAgICAgICAgICAgICAgICAgICBpbiBhIGNlcnRhaW4gZ2VvZ3JhcGhpY2FsIGFyZWEuIFRoZSBNTyBhbHNvCiAgICAgICAgICAgICAgICAgICAgY29udHJvbHMgdGhlIG1heGltdW0gb3V0cHV0IHBvd2VyIG9mIHRoZSBzZWN0b3IuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBmZG4gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgRnVsbCBEaXN0aW5ndWlzaGVkIE5hbWUgKEZETikgaWRlbnRpZmllcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYW4gaW5zdGFuY2Ugb2YgdGhlIFNlY3RvckVxdWlwbWVudEZ1bmN0aW9uIE1PLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgSXQgY29udGFpbnMgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byB0aGUgU2VjdG9yRXF1aXBtZW50RnVuY3Rpb24uIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZi1saXN0IGVVdHJhbkZxQmFuZHMgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxpc3Qgb2YgTFRFIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdCBhc3NvY2lhdGVkIGhhcmR3YXJlIHN1cHBvcnRzIjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmLWxpc3QgZ2VyYW5GcUJhbmRzIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIEdFUkFOIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdCBhc3NvY2lhdGVkIGhhcmR3YXJlIHN1cHBvcnRzIjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmLWxpc3QgblJGcUJhbmRzIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIE5SIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzb2NpYXRlZCBoYXJkd2FyZSBzdXBwb3J0cyI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgU2VjdG9yIHsKICAgICAgICBkZXNjcmlwdGlvbiAiQSBncm91cCBvZiBjby1sb2NhdGVkIENlbGxzIHRoYXQKICAgICAgICAgICAgICAgICAgICBoYXZlIGEgc2hhcmVkIGNvdmVyYWdlIGFyZWEuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBzZWN0b3JJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVW5pdmVyc2FsbHkgdW5pcXVlIElEIGdlbmVyYXRlZCBieSB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlY3RvcidzIGRpc2NvdmVyeSBtZWNoYW5pc20uIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDY0OwogICAgICAgICAgICB9CgogICAgICAgICAgICB1c2VzIGdlbzpnZW8tbG9jYXRpb247CgogICAgICAgICAgICBsZWFmIGF6aW11dGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkF2ZXJhZ2UgdmFsdWUgb2YgdGhlIGF6aW11dGhzIG9mIHRoZSBjZWxscwogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcHJpc2luZyB0aGUgc2VjdG9yLCBkZXRlcm1pbmVkIGR1cmluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VjdG9yIGRpc2NvdmVyeS4iOwogICAgICAgICAgICAgICAgdHlwZSBkZWNpbWFsNjR7CiAgICAgICAgICAgICAgICAgICAgZnJhY3Rpb24tZGlnaXRzIDY7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB1bml0cyAiZGVncmVlcyI7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgRU5PREVCRlVOQ1RJT05fUFJPVklERVNfRVVUUkFOQ0VMTCB7IC8vIDEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHByb3ZpZGVkLWV1VHJhbkNlbGwgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZU5vZGVCIEZ1bmN0aW9uIHByb3ZpZGVzIEVVVFJBTiBDZWxsLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBFTm9kZUJGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBwcm92aWRlZC1ieS1lbm9kZWJGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJFVVRSQU4gQ2VsbCBwcm92aWRlZCBieSBlTm9kZUIgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEVVdHJhbkNlbGw7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgRU5PREVCRlVOQ1RJT05fUFJPVklERVNfTFRFU0VDVE9SQ0FSUklFUiB7IC8vIDEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHByb3ZpZGVkLWx0ZVNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZU5vZGVCIEZ1bmN0aW9uIHByb3ZpZGVzIExURSBTZWN0b3IgQ2Fycmllci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgRU5vZGVCRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgcHJvdmlkZWQtYnktZW5vZGViRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTFRFIFNlY3RvciBDYXJyaWVyIHByb3ZpZGVkIGJ5IGVOb2RlQiBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTFRFU2VjdG9yQ2FycmllcjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtYW5kYXRvcnkgdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBHTkJEVUZVTkNUSU9OX1BST1ZJREVTX05SQ0VMTERVIHsgLy8gMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgcHJvdmlkZWQtbnJDZWxsRHUgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLURVIEZ1bmN0aW9uIHByb3ZpZGVzIE5SIENlbGwtRFUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIEdOQkRVRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgcHJvdmlkZWQtYnktZ25iZHVGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBDZWxsLURVIHByb3ZpZGVkIGJ5IGdOb2RlQi1EVSBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTlJDZWxsRFU7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgR05CRFVGVU5DVElPTl9QUk9WSURFU19OUlNFQ1RPUkNBUlJJRVIgeyAvLyAxIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBwcm92aWRlZC1uclNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLURVIEZ1bmN0aW9uIHByb3ZpZGVzIE5SIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBHTkJEVUZ1bmN0aW9uOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHByb3ZpZGVkLWJ5LWduYmR1RnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgU2VjdG9yIENhcnJpZXIgcHJvdmlkZWQgYnkgZ05vZGVCLURVIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBOUlNlY3RvckNhcnJpZXI7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgR05CQ1VDUEZVTkNUSU9OX1BST1ZJREVTX05SQ0VMTENVIHsgLy8gMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgcHJvdmlkZWQtbnJDZWxsQ3UgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVQ1AgRnVuY3Rpb24gcHJvdmlkZXMgTlIgQ2VsbC1DVS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgR05CQ1VDUEZ1bmN0aW9uOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHByb3ZpZGVkLWJ5LWduYmN1Y3BGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBDZWxsLUNVIHByb3ZpZGVkIGJ5IGdOb2RlQi1DVUNQIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBOUkNlbGxDVTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtYW5kYXRvcnkgdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBFVVRSQU5DRUxMX1VTRVNfTFRFU0VDVE9SQ0FSUklFUiB7IC8vIDAuLjEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHVzZWQtbHRlU2VjdG9yQ2FycmllciB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJFVVRSQU4gQ2VsbCB1c2VzIExURSBTZWN0b3IgQ2Fycmllci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgRVV0cmFuQ2VsbDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiB1c2VkLWJ5LWV1VHJhbkNlbGwgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTFRFIFNlY3RvciBDYXJyaWVyIHVzZWQgYnkgRVVUUkFOIENlbGwuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIExURVNlY3RvckNhcnJpZXI7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBMVEVTRUNUT1JDQVJSSUVSX1VTRVNfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyAwLi5uIHRvIDAuLjEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgdXNlZC1hbnRlbm5hQ2FwYWJpbGl0eSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMVEUgU2VjdG9yIENhcnJpZXIgdXNlcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIExURVNlY3RvckNhcnJpZXI7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYtbGlzdCB1c2VkLWJ5LWx0ZVNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHVzZWQgYnkgTFRFIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBBbnRlbm5hQ2FwYWJpbGl0eTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5SQ0VMTERVX1VTRVNfTlJTRUNUT1JDQVJSSUVSIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgdXNlZC1uclNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQ2VsbC1EVSB1c2VzIE5SIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBOUkNlbGxEVTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiB1c2VkLWJ5LW5yQ2VsbER1IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5SIFNlY3RvciBDYXJyaWVyIHVzZWQgYnkgTlIgQ2VsbC1EVS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTlJTZWN0b3JDYXJyaWVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTlJTRUNUT1JDQVJSSUVSX1VTRVNfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyAwLi5uIHRvIDAuLjEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgdXNlZC1hbnRlbm5hQ2FwYWJpbGl0eSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBTZWN0b3IgQ2FycmllciB1c2VzIEFudGVubmEgQ2FwYWJpbGl0eS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgTlJTZWN0b3JDYXJyaWVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3QgdXNlZC1ieS1uclNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHVzZWQgYnkgTlIgU2VjdG9yIENhcnJpZXIuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgU0VDVE9SX0dST1VQU19OUkNFTExEVSB7IC8vIDAuLjEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IGdyb3VwZWQtbnJDZWxsRHUgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiU2VjdG9yIGdyb3VwcyBOUiBDZWxsLURVLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBTZWN0b3I7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgZ3JvdXBlZC1ieS1zZWN0b3IgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQ2VsbC1EVSBncm91cGVkIGJ5IFNlY3Rvci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTlJDZWxsRFU7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBTRUNUT1JfR1JPVVBTX0VVVFJBTkNFTEwgeyAvLyAwLi4xIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBncm91cGVkLWV1VHJhbkNlbGwgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiU2VjdG9yIGdyb3VwcyBFVVRSQU4gQ2VsbC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgU2VjdG9yOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIGdyb3VwZWQtYnktc2VjdG9yIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkVVVFJBTiBDZWxsIGdyb3VwZWQgYnkgU2VjdG9yLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBFVXRyYW5DZWxsOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-equipment	urn:o-ran:smo-teiv-equipment	EQUIPMENT	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWVxdWlwbWVudCB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtZXF1aXBtZW50IjsKICAgIHByZWZpeCBvci10ZWl2LWVxdWlwOwoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyB7cHJlZml4IG9yLXRlaXYtdHlwZXM7IH0KCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctZXh0ZW5zaW9ucyB7cHJlZml4IG9yLXRlaXYteWV4dDsgfQoKICAgIGltcG9ydCBpZXRmLWdlby1sb2NhdGlvbiB7CiAgICAgICAgcHJlZml4IGdlbzsKICAgICAgICByZWZlcmVuY2UgIlJGQyA5MTc5OiBBIFlBTkcgR3JvdXBpbmcgZm9yIEdlb2dyYXBoaWMgTG9jYXRpb25zIjsKICAgIH0KCiAgICBvcmdhbml6YXRpb24gIkVyaWNzc29uIEFCIjsKICAgIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOwogICAgZGVzY3JpcHRpb24KICAgICJSQU4gRXF1aXBtZW50IHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIEVxdWlwbWVudCBkb21haW4sIHdoaWNoIGlzIG1vZGVsbGVkIHRvIHVuZGVyc3RhbmQgdGhlIHBoeXNpY2FsCiAgICBsb2NhdGlvbiBvZiBlcXVpcG1lbnQgc3VjaCBhcyBhbnRlbm5hcyBhc3NvY2lhdGVkIHdpdGggYSBjZWxsL2NhcnJpZXIKICAgIGFuZCB0aGVpciByZWxldmFudCBwcm9wZXJ0aWVzIGUuZy4gdGlsdCwgbWF4IHBvd2VyIGV0Yy4iOwoKICAgIHJldmlzaW9uICIyMDI0LTA1LTAyIiB7CiAgICAgICAgZGVzY3JpcHRpb24gIkluaXRpYWwgcmV2aXNpb24uIjsKICAgICAgICBvci10ZWl2LXlleHQ6bGFiZWwgMC4zLjA7CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmRvbWFpbiBFUVVJUE1FTlQ7CgogICAgbGlzdCBBbnRlbm5hTW9kdWxlIHsKICAgICAgICBkZXNjcmlwdGlvbiAiQW4gQW50ZW5uYSBNb2R1bGUgcmVwcmVzZW50cyB0aGUKICAgICAgICAgICAgICAgICAgICBwaHlzaWNhbCBhc3BlY3Qgb2YgYW4gYW50ZW5uYS4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgQW50ZW5uYVN1YlVuaXQgTU8uIEl0IGNvbnRhaW5zCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgZnVsbCBwYXRoIGZyb20gdGhlIFN1Ym5ldHdvcmsgdG8gdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbnRlbm5hU3ViVW5pdC4iOwogICAgICAgICAgICAgICAgdHlwZSBvci10ZWl2LXR5cGVzOl8zR1BQX0ZETl9UeXBlOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGFudGVubmFNb2RlbE51bWJlciB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVmVuZG9yLXNwZWNpZmljIGFudGVubmEgbW9kZWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50aWZpZXIuIFRoaXMgYXR0cmlidXRlIGlzIHBhcnQgb2YKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFJU0cgdjMgQURCIFN0YW5kYXJkIGFuZCBoYXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vIG9wZXJhdGlvbmFsIGltcGFjdC4iOwogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgbWVjaGFuaWNhbEFudGVubmFCZWFyaW5nIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIGJlYXJpbmcgb24gYW50ZW5uYSBzdWJ1bml0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGVyZSBhbnRlbm5hIHVuaXQgaXMgaW5zdGFsbGVkLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBtZWNoYW5pY2FsQW50ZW5uYVRpbHQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBmaXhlZCBhbnRlbm5hIHRpbHQgb2YgdGhlIGluc3RhbGxhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmluZWQgYXMgdGhlIGluY2xpbmF0aW9uIG9mIHRoZSBhbnRlbm5hCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50IHJlc3BlY3QgdG8gdGhlIHZlcnRpY2FsIHBsYW5lLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgSXQgaXMgYSBzaWduZWQgdmFsdWUuIFBvc2l0aXZlIGluZGljYXRlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgZG93bnRpbHQsIGFuZCBuZWdhdGl2ZSBpbmRpY2F0ZXMgdXB0aWx0LiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBwb3NpdGlvbldpdGhpblNlY3RvciB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSB1bml0IHBvc2l0aW9uIHdpdGhpbiBzZWN0b3IuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGlzIGF0dHJpYnV0ZSBpcyBwYXJ0IG9mIEFJU0cgdjMgQURCCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFuZGFyZCBhbmQgaGFzIG5vIG9wZXJhdGlvbmFsIGltcGFjdC4iOwogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgdG90YWxUaWx0IHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUb3RhbCBhbnRlbm5hIGVsZXZhdGlvbiBpbmNsdWRpbmcgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnN0YWxsZWQgdGlsdCBhbmQgdGhlIHRpbHQgYXBwbGllZCBieQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIFJlbW90ZSBFbGVjdHJpY2FsIFRpbHQgKFJFVCkuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGVsZWN0cmljYWxBbnRlbm5hVGlsdCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiRWxlY3RyaWNhbGx5LWNvbnRyb2xsZWQgdGlsdCBvZiBtYWluIGJlYW0gbWF4aW11bQogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCByZXNwZWN0IHRvIGRpcmVjdGlvbiBvcnRob2dvbmFsIHRvIGFudGVubmEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgYXhpcyAoc2VlIDNHUFAgVFMgMjUuNDY2KS4gVmFsdWUgaXMgc2lnbmVkOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlsdCBkb3duIGlzIHBvc2l0aXZlLCB0aWx0IHVwIGlzIG5lZ2F0aXZlLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZi1saXN0IGFudGVubmFCZWFtV2lkdGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBhbmd1bGFyIHNwYW4gb2YgdGhlIG1haW4gbG9iZSBvZiB0aGUgYW50ZW5uYSByYWRpYXRpb24KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiBpbiB0aGUgaG9yaXpvbnRhbCBwbGFuZS4gTWVhc3VyZWQgaW4gZGVncmVlcy4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHVzZXMgZ2VvOmdlby1sb2NhdGlvbjsKCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IFNpdGUgewogICAgICAgIGRlc2NyaXB0aW9uICJBIHNpdGUgaXMgYSBwaHlzaWNhbCBsb2NhdGlvbiB3aGVyZSBhbiBBbnRlbm5hIG9yCiAgICAgICAgICAgICAgICAgICAgUGh5c2ljYWwgTkYgY2FuIGJlIGluc3RhbGxlZC4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIG5hbWUgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5hbWUgb2YgU2l0ZSI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgdXNlcyBnZW86Z2VvLWxvY2F0aW9uOwoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgUGh5c2ljYWxORiB7CiAgICAgICAgZGVzY3JpcHRpb24gIlJlcHJlc2VudHMgYSBQaHlzaWNhbCBORiwKICAgICAgICAgICAgICAgICAgICB3aGljaCBpcyB1c2VkIHRvIHJlYWxpc2UgTmV0d29yayBGdW5jdGlvbnMuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBuYW1lIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOYW1lIG9mIFBoeXNpY2FsIE5GLiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiB0eXBlIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUeXBlIG9mIFBoeXNpY2FsIE5GLiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgdXNlcyBnZW86Z2VvLWxvY2F0aW9uOwoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgQU5URU5OQU1PRFVMRV9JTlNUQUxMRURfQVRfU0lURSB7IC8vIDAuLm4gdG8gMC4uMQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZiBpbnN0YWxsZWQtYXQtc2l0ZSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIE1vZHVsZSBpbnN0YWxsZWQgYXQgU2l0ZS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQW50ZW5uYU1vZHVsZTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IGluc3RhbGxlZC1hbnRlbm5hTW9kdWxlIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIlNpdGUgd2hlcmUgQW50ZW5uYSBNb2R1bGUgaXMgaW5zdGFsbGVkLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBTaXRlOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgUEhZU0lDQUxORl9JTlNUQUxMRURfQVRfU0lURSB7IC8vIDEuLm4gdG8gMC4uMQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZiBpbnN0YWxsZWQtYXQtc2l0ZSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQaHlzaWNhbCBORiBpbnN0YWxsZWQgYXQgU2l0ZS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgUGh5c2ljYWxORjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IGluc3RhbGxlZC1waHlzaWNhbE5GIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIlNpdGUgd2hlcmUgUGh5c2ljYWwgTkYgaXMgaW5zdGFsbGVkLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBTaXRlOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1pbi1lbGVtZW50cyAxOwogICAgICAgIH0KICAgIH0KfQ==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-cloud-to-ran	urn:o-ran:smo-teiv-cloud-to-ran	CLOUD_TO_RAN	["o-ran-smo-teiv-cloud", "o-ran-smo-teiv-ran"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNsb3VkLXRvLXJhbiB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtY2xvdWQtdG8tcmFuIjsKICAgIHByZWZpeCBvci10ZWl2LWNsb3VkdG9yYW47CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHtwcmVmaXggb3ItdGVpdi10eXBlczsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNsb3VkIHtwcmVmaXggb3ItdGVpdi1jbG91ZDsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1yYW4ge3ByZWZpeCBvci10ZWl2LXJhbjsgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBDbG91ZCB0byBSQU4gTG9naWNhbCB0b3BvbG9neSBtb2RlbC4KCiAgICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgVGhpcyBtb2RlbCBjb250YWlucyB0aGUgUkFOIENsb3VkIHRvIFJBTiBMb2dpY2FsIHRvcG9sb2d5IHJlbGF0aW9ucyI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIENMT1VEX1RPX1JBTjsKCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfR05CRFVGVU5DVElPTiB7IC8vIDAuLm4gdG8gMC4ubQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHNlcnZpY2VkLWduYmR1RnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCRFUgRnVuY3Rpb24gc2VydmljZWQgYnkgdGhpcyBORiBEZXBsb3ltZW50LiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBvci10ZWl2LWNsb3VkOk5GRGVwbG95bWVudDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IHNlcnZpbmctbkZEZXBsb3ltZW50IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5GIERlcGxveW1lbnQgdGhhdCBzZXJ2ZXMgdGhpcyBnTm9kZUJEVSBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1yYW46R05CRFVGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfR05CQ1VDUEZVTkNUSU9OIHsgLy8gMC4ubiB0byAwLi5tCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iY3VjcEZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQi1DVS1DUCBGdW5jdGlvbiBzZXJ2aWNlZCBieSB0aGlzIE5GIERlcGxveW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtY2xvdWQ6TkZEZXBsb3ltZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3Qgc2VydmluZy1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCB0aGF0IHNlcnZlcyB0aGlzIGdOb2RlQkNVQ1AgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkNVQ1BGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfR05CQ1VVUEZVTkNUSU9OIHsgLy8gMC4ubiB0byAwLi5tCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iY3V1cEZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQi1DVS1VUCBGdW5jdGlvbiBzZXJ2aWNlZCBieSB0aGlzIE5GIERlcGxveW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtY2xvdWQ6TkZEZXBsb3ltZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3Qgc2VydmluZy1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCB0aGF0IHNlcnZlcyB0aGlzIGdOb2RlQkNVVVAgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkNVVVBGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KfQ==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-cloud	urn:o-ran:smo-teiv-cloud	CLOUD	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNsb3VkIHsKICAgIHlhbmctdmVyc2lvbiAxLjE7CiAgICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1jbG91ZCI7CiAgICBwcmVmaXggb3ItdGVpdi1jbG91ZDsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgaWV0Zi1nZW8tbG9jYXRpb24gewogICAgICAgIHByZWZpeCBnZW87CiAgICAgICAgcmVmZXJlbmNlICJSRkMgOTE3OTogQSBZQU5HIEdyb3VwaW5nIGZvciBHZW9ncmFwaGljIExvY2F0aW9ucyI7CiAgICB9CgogICAgb3JnYW5pemF0aW9uICJFcmljc3NvbiBBQiI7CiAgICBjb250YWN0ICJFcmljc3NvbiBmaXJzdCBsaW5lIHN1cHBvcnQgdmlhIGVtYWlsIjsKICAgIGRlc2NyaXB0aW9uCiAgICAiUkFOIENsb3VkIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIENMT1VEIGRvbWFpbiwgd2hpY2ggY29tcHJpc2VzIGNsb3VkIGluZnJhc3RydWN0dXJlIGFuZAogICAgZGVwbG95bWVudCBhc3BlY3RzIHRoYXQgY2FuIGJlIHVzZWQgaW4gdGhlIHRvcG9sb2d5IG1vZGVsLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIENMT1VEOwoKICAgIGxpc3QgQ2xvdWRpZmllZE5GIHsKICAgICAgICBkZXNjcmlwdGlvbiAiQSBSQU4gTmV0d29yayBGdW5jdGlvbiBzb2Z0d2FyZSB0aGF0IGlzIGRlcGxveWVkIGluIHRoZSBPLUNsb3VkIHZpYSBvbmUgb3IgbW9yZSBORiBEZXBsb3ltZW50cy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIG5hbWUgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5hbWUgb2YgQ2xvdWRpZmllZCBORiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IE5GRGVwbG95bWVudCB7CiAgICAgICAgZGVzY3JpcHRpb24gIkEgc29mdHdhcmUgZGVwbG95bWVudCBvbiBPLUNsb3VkIHJlc291cmNlcyB0aGF0IHJlYWxpemVzLCBhbGwgb3IgcGFydCBvZiwgYSBDbG91ZGlmaWVkIE5GLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgbmFtZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTmFtZSBvZiBORiBEZXBsb3ltZW50IjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgQ2xvdWROYW1lc3BhY2UgewogICAgICAgIGRlc2NyaXB0aW9uICJDbG91ZE5hbWVzcGFjZSBwcm92aWRlIGEgbWVjaGFuaXNtIGZvciBpc29sYXRpbmcKICAgICAgICAgICAgICAgICAgICBncm91cHMgb2YgcmVzb3VyY2VzIHdpdGhpbiBhIHNpbmdsZSBjbHVzdGVyLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgbmFtZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTmFtZSBvZiBDbG91ZCBOYW1lc3BhY2UiOwogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgbGlzdCBOb2RlQ2x1c3RlciB7CiAgICAgICAgZGVzY3JpcHRpb24gIkEgTm9kZUNsdXN0ZXIgbWFuYWdlcyBhIGNvbGxlY3Rpb24gb2YgTm9kZXMuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBuYW1lIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOYW1lIG9mIE5vZGUgQ2x1c3RlciI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IENsb3VkU2l0ZSB7CiAgICAgICAgZGVzY3JpcHRpb24gIlJlcHJlc2VudHMgdGhlIGluZnJhc3RydWN0dXJlIHRoYXQKICAgICAgICAgICAgICAgICAgICBob3N0cyB0aGUgTkYgRGVwbG95bWVudC4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIG5hbWUgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5hbWUgb2YgQ2xvdWQgU2l0ZSI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgdXNlcyBnZW86Z2VvLWxvY2F0aW9uOwogICAgICAgIH0KICAgIH0KCgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBDTE9VRElGSUVETkZfQ09NUFJJU0VTX05GREVQTE9ZTUVOVCB7IC8vIDEgdG8gMS4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IGNvbXByaXNlZC1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2xvdWRpZmllZCBORiBjb21wcmlzZXMgb2YgdGhlc2UgTkYgRGVwbG95bWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQ2xvdWRpZmllZE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1pbi1lbGVtZW50cyAxOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBjb21wcmlzZWQtYnktY2xvdWRpZmllZE5GIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5GIERlcGxveW1lbnQgcGFydCBvZiBDbG91ZGlmaWVkIE5GLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBORkRlcGxveW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTkZERVBMT1lNRU5UX0RFUExPWUVEX09OX0NMT1VETkFNRVNQQUNFIHsgLy8gMS4ubiB0byAxLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgZGVwbG95ZWQtb24tY2xvdWROYW1lc3BhY2UgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCBkZXBsb3llZCBvbiBDbG91ZCBOYW1lc3BhY2UuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIE5GRGVwbG95bWVudDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtaW4tZWxlbWVudHMgMTsKICAgICAgICB9CgogICAgICAgIGxlYWYtbGlzdCBkZXBsb3llZC1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2xvdWQgTmFtZXNwYWNlIGRlcGxveXMgTkYgRGVwbG95bWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgQ2xvdWROYW1lc3BhY2U7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWluLWVsZW1lbnRzIDE7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgQ0xPVUROQU1FU1BBQ0VfREVQTE9ZRURfT05fTk9ERUNMVVNURVIgeyAvLyAxLi5uIHRvIDEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgZGVwbG95ZWQtb24tbm9kZUNsdXN0ZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2xvdWQgTmFtZXNwYWNlIGRlcGxveWVkIG9uIE5vZGUgQ2x1c3Rlci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQ2xvdWROYW1lc3BhY2U7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3QgZGVwbG95ZWQtY2xvdWROYW1lc3BhY2UgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTm9kZSBDbHVzdGVyIGRlcGxveXMgQ2xvdWQgTmFtZXNwYWNlLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBOb2RlQ2x1c3RlcjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtaW4tZWxlbWVudHMgMTsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBOT0RFQ0xVU1RFUl9MT0NBVEVEX0FUX0NMT1VEU0lURSB7IC8vIDEuLm4gdG8gMS4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IGxvY2F0ZWQtYXQtY2xvdWRTaXRlIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5vZGUgQ2x1c3RlciBsb2NhdGVkIGF0IENsb3VkIFNpdGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIE5vZGVDbHVzdGVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1pbi1lbGVtZW50cyAxOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IGxvY2F0aW9uLW9mLW5vZGVDbHVzdGVyIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkNsb3VkIFNpdGUgaXMgbG9jYXRpb24gb2YgTm9kZSBDbHVzdGVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBDbG91ZFNpdGU7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWluLWVsZW1lbnRzIDE7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-equipment-to-ran	urn:o-ran:smo-teiv-equipment-to-ran	EQUIPMENT_TO_RAN	["o-ran-smo-teiv-equipment", "o-ran-smo-teiv-ran"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWVxdWlwbWVudC10by1yYW4gewogICAgeWFuZy12ZXJzaW9uIDEuMTsKICAgIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LWVxdWlwbWVudC10by1yYW4iOwogICAgcHJlZml4IG9yLXRlaXYtZXF1aXB0b3JhbjsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtZXF1aXBtZW50IHtwcmVmaXggb3ItdGVpdi1lcXVpcDsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1yYW4ge3ByZWZpeCBvci10ZWl2LXJhbjsgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBFcXVpcG1lbnQgdG8gTG9naWNhbCB0b3BvbG9neSBtb2RlbC4KCiAgICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgVGhpcyBtb2RlbCBjb250YWlucyB0aGUgUkFOIEVxdWlwbWVudCB0byBMb2dpY2FsIHRvcG9sb2d5CiAgICBlbnRpdGllcyBhbmQgcmVsYXRpb25zLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIEVRVUlQTUVOVF9UT19SQU47CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBQSFlTSUNBTE5GX1NFUlZFU19HTkJEVUZVTkNUSU9OIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iZHVGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUItRFUgRnVuY3Rpb24gc2VydmljZWQgYnkgdGhpcyBQaHlzaWNhbCBORi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1lcXVpcDpQaHlzaWNhbE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHNlcnZpbmctcGh5c2ljYWxORiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQaHlzaWNhbCBORiBzZXJ2ZXMgdGhpcyBnTm9kZUItRFUgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkRVRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBQSFlTSUNBTE5GX1NFUlZFU19HTkJDVUNQRlVOQ1RJT04geyAvLyAwLi4xIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBzZXJ2aWNlZC1nbmJjdWNwRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVQ1AgRnVuY3Rpb24gc2VydmljZWQgYnkgdGhpcyBQaHlzaWNhbCBORi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1lcXVpcDpQaHlzaWNhbE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHNlcnZpbmctcGh5c2ljYWxORiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQaHlzaWNhbCBORiBzZXJ2ZXMgdGhpcyBnTm9kZUItQ1VDUCBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1yYW46R05CQ1VDUEZ1bmN0aW9uOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgUEhZU0lDQUxORl9TRVJWRVNfR05CQ1VVUEZVTkNUSU9OIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iY3V1cEZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQi1DVVVQIEZ1bmN0aW9uIHNlcnZpY2VkIGJ5IHRoaXMgUGh5c2ljYWwgTkYuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtZXF1aXA6UGh5c2ljYWxORjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBzZXJ2aW5nLXBoeXNpY2FsTkYgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiUGh5c2ljYWwgTkYgc2VydmVzIHRoaXMgZ05vZGVCLUNVVVAgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkNVVVBGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIFBIWVNJQ0FMTkZfU0VSVkVTX0VOT0RFQkZVTkNUSU9OIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZW5vZGViRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZU5vZGVCIEZ1bmN0aW9uIHNlcnZpY2VkIGJ5IHRoaXMgUGh5c2ljYWwgTkYuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtZXF1aXA6UGh5c2ljYWxORjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBzZXJ2aW5nLXBoeXNpY2FsTkYgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiUGh5c2ljYWwgTkYgc2VydmVzIHRoaXMgZU5vZGVCIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBvci10ZWl2LXJhbjpFTm9kZUJGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIEFOVEVOTkFNT0RVTEVfU0VSVkVTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gMC4ubiB0byAwLi5tCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHNlcnZpY2VkIGJ5IHRoaXMgQW50ZW5uYSBNb2R1bGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtZXF1aXA6QW50ZW5uYU1vZHVsZTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IHNlcnZpbmctYW50ZW5uYU1vZHVsZSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIE1vZHVsZSBzZXJ2ZXMgdGhpcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgU0VDVE9SX0dST1VQU19BTlRFTk5BTU9EVUxFIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgZ3JvdXBlZC1hbnRlbm5hTW9kdWxlIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIlNlY3RvciBncm91cHMgQW50ZW5uYSBNb2R1bGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtcmFuOlNlY3RvcjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBncm91cGVkLWJ5LXNlY3RvciB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIE1vZHVsZSBncm91cGVkIGJ5IFNlY3Rvci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1lcXVpcDpBbnRlbm5hTW9kdWxlOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+\.
+
+COPY ties_model.entity_info("name", "moduleReferenceName") FROM stdin;
+GNBCUUPFunction	o-ran-smo-teiv-ran
+ENodeBFunction	o-ran-smo-teiv-ran
+Sector	o-ran-smo-teiv-ran
+LTESectorCarrier	o-ran-smo-teiv-ran
+NRCellDU	o-ran-smo-teiv-ran
+GNBDUFunction	o-ran-smo-teiv-ran
+NRCellCU	o-ran-smo-teiv-ran
+EUtranCell	o-ran-smo-teiv-ran
+GNBCUCPFunction	o-ran-smo-teiv-ran
+NRSectorCarrier	o-ran-smo-teiv-ran
+AntennaCapability	o-ran-smo-teiv-ran
+CloudNamespace	o-ran-smo-teiv-cloud
+NodeCluster	o-ran-smo-teiv-cloud
+CloudSite	o-ran-smo-teiv-cloud
+NFDeployment	o-ran-smo-teiv-cloud
+CloudifiedNF	o-ran-smo-teiv-cloud
+ManagedElement	o-ran-smo-teiv-oam
+Site	o-ran-smo-teiv-equipment
+AntennaModule	o-ran-smo-teiv-equipment
+PhysicalNF	o-ran-smo-teiv-equipment
+\.
+
+COPY ties_model.relationship_info("name", "aSideAssociationName", "aSideMOType", "aSideMinCardinality", "aSideMaxCardinality", "bSideAssociationName", "bSideMOType", "bSideMinCardinality", "bSideMaxCardinality", "associationKind", "relationshipDataLocation", "connectSameEntity", "moduleReferenceName") FROM stdin;
+ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	provided-lteSectorCarrier	ENodeBFunction	1	1	provided-by-enodebFunction	LTESectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+ENODEBFUNCTION_PROVIDES_EUTRANCELL	provided-euTranCell	ENodeBFunction	1	1	provided-by-enodebFunction	EUtranCell	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+SECTOR_GROUPS_EUTRANCELL	grouped-euTranCell	Sector	0	1	grouped-by-sector	EUtranCell	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+SECTOR_GROUPS_ANTENNAMODULE	grouped-antennaModule	Sector	0	1	grouped-by-sector	AntennaModule	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+SECTOR_GROUPS_NRCELLDU	grouped-nrCellDu	Sector	0	1	grouped-by-sector	NRCellDU	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+LTESECTORCARRIER_USES_ANTENNACAPABILITY	used-antennaCapability	LTESectorCarrier	0	9223372036854775807	used-by-lteSectorCarrier	AntennaCapability	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-ran
+NRCELLDU_USES_NRSECTORCARRIER	used-nrSectorCarrier	NRCellDU	0	1	used-by-nrCellDu	NRSectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	provided-nrSectorCarrier	GNBDUFunction	1	1	provided-by-gnbduFunction	NRSectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBDUFUNCTION_PROVIDES_NRCELLDU	provided-nrCellDu	GNBDUFunction	1	1	provided-by-gnbduFunction	NRCellDU	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+EUTRANCELL_USES_LTESECTORCARRIER	used-lteSectorCarrier	EUtranCell	0	1	used-by-euTranCell	LTESectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBCUCPFUNCTION_PROVIDES_NRCELLCU	provided-nrCellCu	GNBCUCPFunction	1	1	provided-by-gnbcucpFunction	NRCellCU	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+NRSECTORCARRIER_USES_ANTENNACAPABILITY	used-antennaCapability	NRSectorCarrier	0	9223372036854775807	used-by-nrSectorCarrier	AntennaCapability	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-ran
+CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER	deployed-on-nodeCluster	CloudNamespace	1	9223372036854775807	deployed-cloudNamespace	NodeCluster	1	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-cloud
+NODECLUSTER_LOCATED_AT_CLOUDSITE	located-at-cloudSite	NodeCluster	1	9223372036854775807	location-of-nodeCluster	CloudSite	1	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud
+NFDEPLOYMENT_SERVES_GNBDUFUNCTION	serviced-gnbduFunction	NFDeployment	0	9223372036854775807	serving-nFDeployment	GNBDUFunction	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud-to-ran
+NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE	deployed-on-cloudNamespace	NFDeployment	1	9223372036854775807	deployed-nFDeployment	CloudNamespace	1	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud
+NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION	serviced-gnbcuupFunction	NFDeployment	0	9223372036854775807	serving-nFDeployment	GNBCUUPFunction	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud-to-ran
+NFDEPLOYMENT_SERVES_MANAGEDELEMENT	serviced-managedElement	NFDeployment	1	9223372036854775807	serving-nFDeployment	ManagedElement	1	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-oam-to-cloud
+NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION	serviced-gnbcucpFunction	NFDeployment	0	9223372036854775807	serving-nFDeployment	GNBCUCPFunction	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud-to-ran
+CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT	comprised-nFDeployment	CloudifiedNF	1	1	comprised-by-cloudifiedNF	NFDeployment	1	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-cloud
+MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	managed-enodebFunction	ManagedElement	1	1	managed-by-managedElement	ENodeBFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF	deployed-as-cloudifiedNF	ManagedElement	1	1	deployed-managedElement	CloudifiedNF	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-oam-to-cloud
+MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	managed-gnbcucpFunction	ManagedElement	1	1	managed-by-managedElement	GNBCUCPFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	managed-gnbcuupFunction	ManagedElement	1	1	managed-by-managedElement	GNBCUUPFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	managed-gnbduFunction	ManagedElement	1	1	managed-by-managedElement	GNBDUFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+ANTENNAMODULE_INSTALLED_AT_SITE	installed-at-site	AntennaModule	0	9223372036854775807	installed-antennaModule	Site	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-equipment
+ANTENNAMODULE_SERVES_ANTENNACAPABILITY	serviced-antennaCapability	AntennaModule	0	9223372036854775807	serving-antennaModule	AntennaCapability	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-equipment-to-ran
+PHYSICALNF_INSTALLED_AT_SITE	installed-at-site	PhysicalNF	1	9223372036854775807	installed-physicalNF	Site	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-equipment
+PHYSICALNF_SERVES_GNBDUFUNCTION	serviced-gnbduFunction	PhysicalNF	0	1	serving-physicalNF	GNBDUFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+PHYSICALNF_SERVES_ENODEBFUNCTION	serviced-enodebFunction	PhysicalNF	0	1	serving-physicalNF	ENodeBFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+PHYSICALNF_SERVES_GNBCUUPFUNCTION	serviced-gnbcuupFunction	PhysicalNF	0	1	serving-physicalNF	GNBCUUPFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+PHYSICALNF_SERVES_GNBCUCPFUNCTION	serviced-gnbcucpFunction	PhysicalNF	0	1	serving-physicalNF	GNBCUCPFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+\.
+
+;
+
+COMMIT;
diff --git a/docker-compose/sql_scripts/01_init-teiv-exposure-data.sql b/docker-compose/sql_scripts/01_init-teiv-exposure-data.sql
new file mode 100644
index 0000000..554c48e
--- /dev/null
+++ b/docker-compose/sql_scripts/01_init-teiv-exposure-data.sql
@@ -0,0 +1,1320 @@
+--
+--  ============LICENSE_START=======================================================
+--  Copyright (C) 2024 Ericsson
+--  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+--  ================================================================================
+--  Licensed under the Apache License, Version 2.0 (the "License");
+--  you may not use this file except in compliance with the License.
+--  You may obtain a copy of the License at
+--
+--        http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+--  SPDX-License-Identifier: Apache-2.0
+--  ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology TO topology_exposure_user;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO topology_exposure_user;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO topology_exposure_user;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO topology_exposure_user;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE 'topology_exposure_user';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+    t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+    IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+        EXECUTE constraint_sql;
+    END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" (
+    "id"            VARCHAR(511),
+    "aSide_AntennaModule"            VARCHAR(511),
+    "bSide_AntennaCapability"            VARCHAR(511),
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."AntennaCapability" (
+    "id"            VARCHAR(511),
+    "nRFqBands"            jsonb,
+    "cmId"            jsonb,
+    "geranFqBands"            jsonb,
+    "fdn"            TEXT,
+    "eUtranFqBands"            jsonb,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."AntennaModule" (
+    "id"            VARCHAR(511),
+    "totalTilt"            BIGINT,
+    "cmId"            jsonb,
+    "antennaBeamWidth"            jsonb,
+    "positionWithinSector"            TEXT,
+    "geo-location"            geography,
+    "mechanicalAntennaBearing"            BIGINT,
+    "fdn"            TEXT,
+    "electricalAntennaTilt"            BIGINT,
+    "mechanicalAntennaTilt"            BIGINT,
+    "antennaModelNumber"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_grouped-by-sector"            VARCHAR(511),
+    "REL_ID_SECTOR_GROUPS_ANTENNAMODULE"            VARCHAR(511),
+    "REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE"            jsonb,
+    "REL_CD_classifiers_SECTOR_GROUPS_ANTENNAMODULE"            jsonb,
+    "REL_CD_decorators_SECTOR_GROUPS_ANTENNAMODULE"            jsonb,
+    "REL_FK_installed-at-site"            VARCHAR(511),
+    "REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE"            VARCHAR(511),
+    "REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE"            jsonb,
+    "REL_CD_classifiers_ANTENNAMODULE_INSTALLED_AT_SITE"            jsonb,
+    "REL_CD_decorators_ANTENNAMODULE_INSTALLED_AT_SITE"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_classifiers_SECTOR_GROUPS_ANTENNAMODULE" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_decorators_SECTOR_GROUPS_ANTENNAMODULE" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_classifiers_ANTENNAMODULE_INSTALLED_AT_SITE" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_decorators_ANTENNAMODULE_INSTALLED_AT_SITE" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."CloudNamespace" (
+    "id"            VARCHAR(511),
+    "name"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_deployed-on-nodeCluster"            VARCHAR(511),
+    "REL_ID_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER"            VARCHAR(511),
+    "REL_CD_sourceIds_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER"            jsonb,
+    "REL_CD_classifiers_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER"            jsonb,
+    "REL_CD_decorators_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."CloudNamespace" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudNamespace" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudNamespace" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."CloudNamespace" ALTER COLUMN "REL_CD_sourceIds_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudNamespace" ALTER COLUMN "REL_CD_classifiers_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudNamespace" ALTER COLUMN "REL_CD_decorators_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."CloudSite" (
+    "id"            VARCHAR(511),
+    "name"            TEXT,
+    "geo-location"            geography,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."CloudSite" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudSite" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudSite" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."CloudifiedNF" (
+    "id"            VARCHAR(511),
+    "name"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."CloudifiedNF" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudifiedNF" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudifiedNF" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ENodeBFunction" (
+    "id"            VARCHAR(511),
+    "fdn"            TEXT,
+    "cmId"            jsonb,
+    "eNodeBPlmnId"            jsonb,
+    "eNBId"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_managed-by-managedElement"            VARCHAR(511),
+    "REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"            jsonb,
+    "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"            jsonb,
+    "REL_CD_decorators_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"            jsonb,
+    "REL_FK_serving-physicalNF"            VARCHAR(511),
+    "REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_PHYSICALNF_SERVES_ENODEBFUNCTION"            jsonb,
+    "REL_CD_classifiers_PHYSICALNF_SERVES_ENODEBFUNCTION"            jsonb,
+    "REL_CD_decorators_PHYSICALNF_SERVES_ENODEBFUNCTION"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_decorators_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_sourceIds_PHYSICALNF_SERVES_ENODEBFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_classifiers_PHYSICALNF_SERVES_ENODEBFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_decorators_PHYSICALNF_SERVES_ENODEBFUNCTION" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."EUtranCell" (
+    "id"            VARCHAR(511),
+    "earfcndl"            BIGINT,
+    "earfcnul"            BIGINT,
+    "cmId"            jsonb,
+    "tac"            BIGINT,
+    "dlChannelBandwidth"            BIGINT,
+    "fdn"            TEXT,
+    "cellId"            BIGINT,
+    "duplexType"            TEXT,
+    "channelBandwidth"            BIGINT,
+    "earfcn"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_provided-by-enodebFunction"            VARCHAR(511),
+    "REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL"            VARCHAR(511),
+    "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL"            jsonb,
+    "REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_EUTRANCELL"            jsonb,
+    "REL_CD_decorators_ENODEBFUNCTION_PROVIDES_EUTRANCELL"            jsonb,
+    "REL_FK_grouped-by-sector"            VARCHAR(511),
+    "REL_ID_SECTOR_GROUPS_EUTRANCELL"            VARCHAR(511),
+    "REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL"            jsonb,
+    "REL_CD_classifiers_SECTOR_GROUPS_EUTRANCELL"            jsonb,
+    "REL_CD_decorators_SECTOR_GROUPS_EUTRANCELL"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_EUTRANCELL" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_decorators_ENODEBFUNCTION_PROVIDES_EUTRANCELL" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_classifiers_SECTOR_GROUPS_EUTRANCELL" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_decorators_SECTOR_GROUPS_EUTRANCELL" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBCUCPFunction" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "pLMNId"            jsonb,
+    "gNBIdLength"            BIGINT,
+    "fdn"            TEXT,
+    "gNBCUName"            TEXT,
+    "gNBId"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_managed-by-managedElement"            VARCHAR(511),
+    "REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION"            jsonb,
+    "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION"            jsonb,
+    "REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION"            jsonb,
+    "REL_FK_serving-physicalNF"            VARCHAR(511),
+    "REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUCPFUNCTION"            jsonb,
+    "REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUCPFUNCTION"            jsonb,
+    "REL_CD_decorators_PHYSICALNF_SERVES_GNBCUCPFUNCTION"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUCPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUCPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "REL_CD_decorators_PHYSICALNF_SERVES_GNBCUCPFUNCTION" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBCUUPFunction" (
+    "id"            VARCHAR(511),
+    "fdn"            TEXT,
+    "cmId"            jsonb,
+    "gNBIdLength"            BIGINT,
+    "gNBId"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_managed-by-managedElement"            VARCHAR(511),
+    "REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION"            jsonb,
+    "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION"            jsonb,
+    "REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION"            jsonb,
+    "REL_FK_serving-physicalNF"            VARCHAR(511),
+    "REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUUPFUNCTION"            jsonb,
+    "REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUUPFUNCTION"            jsonb,
+    "REL_CD_decorators_PHYSICALNF_SERVES_GNBCUUPFUNCTION"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "REL_CD_sourceIds_PHYSICALNF_SERVES_GNBCUUPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "REL_CD_classifiers_PHYSICALNF_SERVES_GNBCUUPFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "REL_CD_decorators_PHYSICALNF_SERVES_GNBCUUPFUNCTION" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBDUFunction" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "gNBIdLength"            BIGINT,
+    "dUpLMNId"            jsonb,
+    "fdn"            TEXT,
+    "gNBDUId"            BIGINT,
+    "gNBId"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_managed-by-managedElement"            VARCHAR(511),
+    "REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION"            jsonb,
+    "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION"            jsonb,
+    "REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION"            jsonb,
+    "REL_FK_serving-physicalNF"            VARCHAR(511),
+    "REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION"            VARCHAR(511),
+    "REL_CD_sourceIds_PHYSICALNF_SERVES_GNBDUFUNCTION"            jsonb,
+    "REL_CD_classifiers_PHYSICALNF_SERVES_GNBDUFUNCTION"            jsonb,
+    "REL_CD_decorators_PHYSICALNF_SERVES_GNBDUFUNCTION"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "REL_CD_classifiers_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "REL_CD_decorators_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "REL_CD_sourceIds_PHYSICALNF_SERVES_GNBDUFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "REL_CD_classifiers_PHYSICALNF_SERVES_GNBDUFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "REL_CD_decorators_PHYSICALNF_SERVES_GNBDUFUNCTION" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."LTESectorCarrier" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "fdn"            TEXT,
+    "sectorCarrierType"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_provided-by-enodebFunction"            VARCHAR(511),
+    "REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"            VARCHAR(511),
+    "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"            jsonb,
+    "REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"            jsonb,
+    "REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"            jsonb,
+    "REL_FK_used-antennaCapability"            VARCHAR(511),
+    "REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY"            VARCHAR(511),
+    "REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY"            jsonb,
+    "REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY"            jsonb,
+    "REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY"            jsonb,
+    "REL_FK_used-by-euTranCell"            VARCHAR(511),
+    "REL_ID_EUTRANCELL_USES_LTESECTORCARRIER"            VARCHAR(511),
+    "REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER"            jsonb,
+    "REL_CD_classifiers_EUTRANCELL_USES_LTESECTORCARRIER"            jsonb,
+    "REL_CD_decorators_EUTRANCELL_USES_LTESECTORCARRIER"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_classifiers_EUTRANCELL_USES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_decorators_EUTRANCELL_USES_LTESECTORCARRIER" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ManagedElement" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "fdn"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_deployed-as-cloudifiedNF"            VARCHAR(511),
+    "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF"            VARCHAR(511),
+    "REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF"            jsonb,
+    "REL_CD_classifiers_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF"            jsonb,
+    "REL_CD_decorators_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "REL_CD_classifiers_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "REL_CD_decorators_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE" (
+    "id"            VARCHAR(511),
+    "aSide_NFDeployment"            VARCHAR(511),
+    "bSide_CloudNamespace"            VARCHAR(511),
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION" (
+    "id"            VARCHAR(511),
+    "aSide_NFDeployment"            VARCHAR(511),
+    "bSide_GNBCUCPFunction"            VARCHAR(511),
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION" (
+    "id"            VARCHAR(511),
+    "aSide_NFDeployment"            VARCHAR(511),
+    "bSide_GNBCUUPFunction"            VARCHAR(511),
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NFDEPLOYMENT_SERVES_GNBDUFUNCTION" (
+    "id"            VARCHAR(511),
+    "aSide_NFDeployment"            VARCHAR(511),
+    "bSide_GNBDUFunction"            VARCHAR(511),
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBDUFUNCTION" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBDUFUNCTION" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDEPLOYMENT_SERVES_GNBDUFUNCTION" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NFDeployment" (
+    "id"            VARCHAR(511),
+    "name"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_serviced-managedElement"            VARCHAR(511),
+    "REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT"            VARCHAR(511),
+    "REL_CD_sourceIds_NFDEPLOYMENT_SERVES_MANAGEDELEMENT"            jsonb,
+    "REL_CD_classifiers_NFDEPLOYMENT_SERVES_MANAGEDELEMENT"            jsonb,
+    "REL_CD_decorators_NFDEPLOYMENT_SERVES_MANAGEDELEMENT"            jsonb,
+    "REL_FK_comprised-by-cloudifiedNF"            VARCHAR(511),
+    "REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT"            VARCHAR(511),
+    "REL_CD_sourceIds_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT"            jsonb,
+    "REL_CD_classifiers_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT"            jsonb,
+    "REL_CD_decorators_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "REL_CD_sourceIds_NFDEPLOYMENT_SERVES_MANAGEDELEMENT" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "REL_CD_classifiers_NFDEPLOYMENT_SERVES_MANAGEDELEMENT" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "REL_CD_decorators_NFDEPLOYMENT_SERVES_MANAGEDELEMENT" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "REL_CD_sourceIds_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "REL_CD_classifiers_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NFDeployment" ALTER COLUMN "REL_CD_decorators_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NODECLUSTER_LOCATED_AT_CLOUDSITE" (
+    "id"            VARCHAR(511),
+    "aSide_NodeCluster"            VARCHAR(511),
+    "bSide_CloudSite"            VARCHAR(511),
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NODECLUSTER_LOCATED_AT_CLOUDSITE" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NODECLUSTER_LOCATED_AT_CLOUDSITE" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NODECLUSTER_LOCATED_AT_CLOUDSITE" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NRCellCU" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "fdn"            TEXT,
+    "nCI"            BIGINT,
+    "nRTAC"            BIGINT,
+    "plmnId"            jsonb,
+    "cellLocalId"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_provided-by-gnbcucpFunction"            VARCHAR(511),
+    "REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU"            VARCHAR(511),
+    "REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU"            jsonb,
+    "REL_CD_classifiers_GNBCUCPFUNCTION_PROVIDES_NRCELLCU"            jsonb,
+    "REL_CD_decorators_GNBCUCPFUNCTION_PROVIDES_NRCELLCU"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "REL_CD_classifiers_GNBCUCPFUNCTION_PROVIDES_NRCELLCU" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "REL_CD_decorators_GNBCUCPFUNCTION_PROVIDES_NRCELLCU" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NRCellDU" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "nCI"            BIGINT,
+    "nRPCI"            BIGINT,
+    "fdn"            TEXT,
+    "cellLocalId"            BIGINT,
+    "nRTAC"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_grouped-by-sector"            VARCHAR(511),
+    "REL_ID_SECTOR_GROUPS_NRCELLDU"            VARCHAR(511),
+    "REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU"            jsonb,
+    "REL_CD_classifiers_SECTOR_GROUPS_NRCELLDU"            jsonb,
+    "REL_CD_decorators_SECTOR_GROUPS_NRCELLDU"            jsonb,
+    "REL_FK_provided-by-gnbduFunction"            VARCHAR(511),
+    "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU"            VARCHAR(511),
+    "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU"            jsonb,
+    "REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRCELLDU"            jsonb,
+    "REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRCELLDU"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_classifiers_SECTOR_GROUPS_NRCELLDU" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_decorators_SECTOR_GROUPS_NRCELLDU" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRCELLDU" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRCELLDU" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NRSectorCarrier" (
+    "id"            VARCHAR(511),
+    "bSChannelBwDL"            BIGINT,
+    "cmId"            jsonb,
+    "arfcnDL"            BIGINT,
+    "frequencyUL"            BIGINT,
+    "fdn"            TEXT,
+    "arfcnUL"            BIGINT,
+    "frequencyDL"            BIGINT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_used-by-nrCellDu"            VARCHAR(511),
+    "REL_ID_NRCELLDU_USES_NRSECTORCARRIER"            VARCHAR(511),
+    "REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER"            jsonb,
+    "REL_CD_classifiers_NRCELLDU_USES_NRSECTORCARRIER"            jsonb,
+    "REL_CD_decorators_NRCELLDU_USES_NRSECTORCARRIER"            jsonb,
+    "REL_FK_provided-by-gnbduFunction"            VARCHAR(511),
+    "REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER"            VARCHAR(511),
+    "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER"            jsonb,
+    "REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER"            jsonb,
+    "REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER"            jsonb,
+    "REL_FK_used-antennaCapability"            VARCHAR(511),
+    "REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY"            VARCHAR(511),
+    "REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY"            jsonb,
+    "REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY"            jsonb,
+    "REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_classifiers_NRCELLDU_USES_NRSECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_decorators_NRCELLDU_USES_NRSECTORCARRIER" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_classifiers_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_decorators_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NodeCluster" (
+    "id"            VARCHAR(511),
+    "name"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."NodeCluster" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NodeCluster" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NodeCluster" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."PhysicalNF" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "geo-location"            geography,
+    "name"            TEXT,
+    "type"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb,
+    "REL_FK_installed-at-site"            VARCHAR(511),
+    "REL_ID_PHYSICALNF_INSTALLED_AT_SITE"            VARCHAR(511),
+    "REL_CD_sourceIds_PHYSICALNF_INSTALLED_AT_SITE"            jsonb,
+    "REL_CD_classifiers_PHYSICALNF_INSTALLED_AT_SITE"            jsonb,
+    "REL_CD_decorators_PHYSICALNF_INSTALLED_AT_SITE"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."PhysicalNF" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."PhysicalNF" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."PhysicalNF" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."PhysicalNF" ALTER COLUMN "REL_CD_sourceIds_PHYSICALNF_INSTALLED_AT_SITE" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."PhysicalNF" ALTER COLUMN "REL_CD_classifiers_PHYSICALNF_INSTALLED_AT_SITE" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."PhysicalNF" ALTER COLUMN "REL_CD_decorators_PHYSICALNF_INSTALLED_AT_SITE" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+    "id"            VARCHAR(511),
+    "geo-location"            geography,
+    "sectorId"            BIGINT,
+    "azimuth"            DECIMAL,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."Sector" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."Sector" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."Sector" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."Site" (
+    "id"            VARCHAR(511),
+    "cmId"            jsonb,
+    "geo-location"            geography,
+    "name"            TEXT,
+    "CD_sourceIds"            jsonb,
+    "CD_classifiers"            jsonb,
+    "CD_decorators"            jsonb
+);
+
+ALTER TABLE ONLY ties_data."Site" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."Site" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."Site" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ANTENNAMODULE_SERVES_ANTENNACAPABILITY',
+ 'PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'AntennaCapability',
+ 'PK_AntennaCapability_id',
+ 'ALTER TABLE ties_data."AntennaCapability" ADD CONSTRAINT "PK_AntennaCapability_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'AntennaModule',
+ 'PK_AntennaModule_id',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "PK_AntennaModule_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'CloudNamespace',
+ 'PK_CloudNamespace_id',
+ 'ALTER TABLE ties_data."CloudNamespace" ADD CONSTRAINT "PK_CloudNamespace_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'CloudSite',
+ 'PK_CloudSite_id',
+ 'ALTER TABLE ties_data."CloudSite" ADD CONSTRAINT "PK_CloudSite_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'CloudifiedNF',
+ 'PK_CloudifiedNF_id',
+ 'ALTER TABLE ties_data."CloudifiedNF" ADD CONSTRAINT "PK_CloudifiedNF_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ENodeBFunction',
+ 'PK_ENodeBFunction_id',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "PK_ENodeBFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'EUtranCell',
+ 'PK_EUtranCell_id',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "PK_EUtranCell_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUCPFunction',
+ 'PK_GNBCUCPFunction_id',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "PK_GNBCUCPFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUUPFunction',
+ 'PK_GNBCUUPFunction_id',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "PK_GNBCUUPFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBDUFunction',
+ 'PK_GNBDUFunction_id',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "PK_GNBDUFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'LTESectorCarrier',
+ 'PK_LTESectorCarrier_id',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "PK_LTESectorCarrier_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ManagedElement',
+ 'PK_ManagedElement_id',
+ 'ALTER TABLE ties_data."ManagedElement" ADD CONSTRAINT "PK_ManagedElement_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE',
+ 'PK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_id',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE" ADD CONSTRAINT "PK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION',
+ 'PK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_id',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION" ADD CONSTRAINT "PK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION',
+ 'PK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_id',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION" ADD CONSTRAINT "PK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBDUFUNCTION',
+ 'PK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_id',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBDUFUNCTION" ADD CONSTRAINT "PK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDeployment',
+ 'PK_NFDeployment_id',
+ 'ALTER TABLE ties_data."NFDeployment" ADD CONSTRAINT "PK_NFDeployment_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NODECLUSTER_LOCATED_AT_CLOUDSITE',
+ 'PK_NODECLUSTER_LOCATED_AT_CLOUDSITE_id',
+ 'ALTER TABLE ties_data."NODECLUSTER_LOCATED_AT_CLOUDSITE" ADD CONSTRAINT "PK_NODECLUSTER_LOCATED_AT_CLOUDSITE_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellCU',
+ 'PK_NRCellCU_id',
+ 'ALTER TABLE ties_data."NRCellCU" ADD CONSTRAINT "PK_NRCellCU_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellDU',
+ 'PK_NRCellDU_id',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "PK_NRCellDU_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRSectorCarrier',
+ 'PK_NRSectorCarrier_id',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "PK_NRSectorCarrier_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NodeCluster',
+ 'PK_NodeCluster_id',
+ 'ALTER TABLE ties_data."NodeCluster" ADD CONSTRAINT "PK_NodeCluster_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'PhysicalNF',
+ 'PK_PhysicalNF_id',
+ 'ALTER TABLE ties_data."PhysicalNF" ADD CONSTRAINT "PK_PhysicalNF_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'Site',
+ 'PK_Site_id',
+ 'ALTER TABLE ties_data."Site" ADD CONSTRAINT "PK_Site_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ANTENNAMODULE_SERVES_ANTENNACAPABILITY',
+ 'FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule" FOREIGN KEY ("aSide_AntennaModule") REFERENCES ties_data."AntennaModule" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ANTENNAMODULE_SERVES_ANTENNACAPABILITY',
+ 'FK_AB3CEA707D389B107F1D10BC724542418E02ABEC',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_AB3CEA707D389B107F1D10BC724542418E02ABEC" FOREIGN KEY ("bSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'AntennaModule',
+ 'FK_AntennaModule_REL_FK_grouped-by-sector',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "FK_AntennaModule_REL_FK_grouped-by-sector" FOREIGN KEY ("REL_FK_grouped-by-sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'AntennaModule',
+ 'UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE" UNIQUE ("REL_ID_SECTOR_GROUPS_ANTENNAMODULE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'AntennaModule',
+ 'FK_AntennaModule_REL_FK_installed-at-site',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "FK_AntennaModule_REL_FK_installed-at-site" FOREIGN KEY ("REL_FK_installed-at-site") REFERENCES ties_data."Site" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'AntennaModule',
+ 'UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE" UNIQUE ("REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'CloudNamespace',
+ 'FK_CloudNamespace_REL_FK_deployed-on-nodeCluster',
+ 'ALTER TABLE ties_data."CloudNamespace" ADD CONSTRAINT "FK_CloudNamespace_REL_FK_deployed-on-nodeCluster" FOREIGN KEY ("REL_FK_deployed-on-nodeCluster") REFERENCES ties_data."NodeCluster" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'CloudNamespace',
+ 'UNIQUE_C72E1EF93E1AC8FA53D20808E775FF012ACB46F0',
+ 'ALTER TABLE ties_data."CloudNamespace" ADD CONSTRAINT "UNIQUE_C72E1EF93E1AC8FA53D20808E775FF012ACB46F0" UNIQUE ("REL_ID_CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ENodeBFunction',
+ 'FK_ENodeBFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "FK_ENodeBFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ENodeBFunction',
+ 'UNIQUE_F33037EE8037D0606D15FFB45EE8A27FD6DE30EE',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "UNIQUE_F33037EE8037D0606D15FFB45EE8A27FD6DE30EE" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ENodeBFunction',
+ 'FK_ENodeBFunction_REL_FK_serving-physicalNF',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "FK_ENodeBFunction_REL_FK_serving-physicalNF" FOREIGN KEY ("REL_FK_serving-physicalNF") REFERENCES ties_data."PhysicalNF" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ENodeBFunction',
+ 'UNIQUE_ENodeBFunction_REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "UNIQUE_ENodeBFunction_REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION" UNIQUE ("REL_ID_PHYSICALNF_SERVES_ENODEBFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'EUtranCell',
+ 'FK_EUtranCell_REL_FK_provided-by-enodebFunction',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "FK_EUtranCell_REL_FK_provided-by-enodebFunction" FOREIGN KEY ("REL_FK_provided-by-enodebFunction") REFERENCES ties_data."ENodeBFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'EUtranCell',
+ 'UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL" UNIQUE ("REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'EUtranCell',
+ 'FK_EUtranCell_REL_FK_grouped-by-sector',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "FK_EUtranCell_REL_FK_grouped-by-sector" FOREIGN KEY ("REL_FK_grouped-by-sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'EUtranCell',
+ 'UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL" UNIQUE ("REL_ID_SECTOR_GROUPS_EUTRANCELL");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUCPFunction',
+ 'FK_GNBCUCPFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "FK_GNBCUCPFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUCPFunction',
+ 'UNIQUE_249F73FF1F4316A56DEF4424FA43C2064FFBE4DD',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "UNIQUE_249F73FF1F4316A56DEF4424FA43C2064FFBE4DD" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUCPFunction',
+ 'FK_GNBCUCPFunction_REL_FK_serving-physicalNF',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "FK_GNBCUCPFunction_REL_FK_serving-physicalNF" FOREIGN KEY ("REL_FK_serving-physicalNF") REFERENCES ties_data."PhysicalNF" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUCPFunction',
+ 'UNIQUE_GNBCUCPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "UNIQUE_GNBCUCPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION" UNIQUE ("REL_ID_PHYSICALNF_SERVES_GNBCUCPFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUUPFunction',
+ 'FK_GNBCUUPFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "FK_GNBCUUPFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUUPFunction',
+ 'UNIQUE_BDB349CDF0C4055902881ECCB71F460AE1DD323E',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "UNIQUE_BDB349CDF0C4055902881ECCB71F460AE1DD323E" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUUPFunction',
+ 'FK_GNBCUUPFunction_REL_FK_serving-physicalNF',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "FK_GNBCUUPFunction_REL_FK_serving-physicalNF" FOREIGN KEY ("REL_FK_serving-physicalNF") REFERENCES ties_data."PhysicalNF" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBCUUPFunction',
+ 'UNIQUE_GNBCUUPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "UNIQUE_GNBCUUPFunction_REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION" UNIQUE ("REL_ID_PHYSICALNF_SERVES_GNBCUUPFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBDUFunction',
+ 'FK_GNBDUFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "FK_GNBDUFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBDUFunction',
+ 'UNIQUE_08DFEFAF56EDDE43CBDC336F459D28C6518D3E1D',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "UNIQUE_08DFEFAF56EDDE43CBDC336F459D28C6518D3E1D" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBDUFunction',
+ 'FK_GNBDUFunction_REL_FK_serving-physicalNF',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "FK_GNBDUFunction_REL_FK_serving-physicalNF" FOREIGN KEY ("REL_FK_serving-physicalNF") REFERENCES ties_data."PhysicalNF" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'GNBDUFunction',
+ 'UNIQUE_GNBDUFunction_REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "UNIQUE_GNBDUFunction_REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION" UNIQUE ("REL_ID_PHYSICALNF_SERVES_GNBDUFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction" FOREIGN KEY ("REL_FK_provided-by-enodebFunction") REFERENCES ties_data."ENodeBFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'LTESectorCarrier',
+ 'UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9" UNIQUE ("REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_used-antennaCapability',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_used-antennaCapability" FOREIGN KEY ("REL_FK_used-antennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'LTESectorCarrier',
+ 'UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88" UNIQUE ("REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_used-by-euTranCell',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_used-by-euTranCell" FOREIGN KEY ("REL_FK_used-by-euTranCell") REFERENCES ties_data."EUtranCell" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'LTESectorCarrier',
+ 'UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER" UNIQUE ("REL_ID_EUTRANCELL_USES_LTESECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ManagedElement',
+ 'FK_ManagedElement_REL_FK_deployed-as-cloudifiedNF',
+ 'ALTER TABLE ties_data."ManagedElement" ADD CONSTRAINT "FK_ManagedElement_REL_FK_deployed-as-cloudifiedNF" FOREIGN KEY ("REL_FK_deployed-as-cloudifiedNF") REFERENCES ties_data."CloudifiedNF" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'ManagedElement',
+ 'UNIQUE_E7BC94037DB5B94B7E863A10BEA20C2D4C3C307C',
+ 'ALTER TABLE ties_data."ManagedElement" ADD CONSTRAINT "UNIQUE_E7BC94037DB5B94B7E863A10BEA20C2D4C3C307C" UNIQUE ("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE',
+ 'FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_aSide_NFDeployment',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE" ADD CONSTRAINT "FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_aSide_NFDeployment" FOREIGN KEY ("aSide_NFDeployment") REFERENCES ties_data."NFDeployment" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE',
+ 'FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_bSide_CloudNamespace',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE" ADD CONSTRAINT "FK_NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE_bSide_CloudNamespace" FOREIGN KEY ("bSide_CloudNamespace") REFERENCES ties_data."CloudNamespace" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION',
+ 'FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_aSide_NFDeployment',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION" ADD CONSTRAINT "FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_aSide_NFDeployment" FOREIGN KEY ("aSide_NFDeployment") REFERENCES ties_data."NFDeployment" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION',
+ 'FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_bSide_GNBCUCPFunction',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION" ADD CONSTRAINT "FK_NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION_bSide_GNBCUCPFunction" FOREIGN KEY ("bSide_GNBCUCPFunction") REFERENCES ties_data."GNBCUCPFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION',
+ 'FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_aSide_NFDeployment',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION" ADD CONSTRAINT "FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_aSide_NFDeployment" FOREIGN KEY ("aSide_NFDeployment") REFERENCES ties_data."NFDeployment" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION',
+ 'FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_bSide_GNBCUUPFunction',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION" ADD CONSTRAINT "FK_NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION_bSide_GNBCUUPFunction" FOREIGN KEY ("bSide_GNBCUUPFunction") REFERENCES ties_data."GNBCUUPFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBDUFUNCTION',
+ 'FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_aSide_NFDeployment',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBDUFUNCTION" ADD CONSTRAINT "FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_aSide_NFDeployment" FOREIGN KEY ("aSide_NFDeployment") REFERENCES ties_data."NFDeployment" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDEPLOYMENT_SERVES_GNBDUFUNCTION',
+ 'FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_bSide_GNBDUFunction',
+ 'ALTER TABLE ties_data."NFDEPLOYMENT_SERVES_GNBDUFUNCTION" ADD CONSTRAINT "FK_NFDEPLOYMENT_SERVES_GNBDUFUNCTION_bSide_GNBDUFunction" FOREIGN KEY ("bSide_GNBDUFunction") REFERENCES ties_data."GNBDUFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDeployment',
+ 'FK_NFDeployment_REL_FK_serviced-managedElement',
+ 'ALTER TABLE ties_data."NFDeployment" ADD CONSTRAINT "FK_NFDeployment_REL_FK_serviced-managedElement" FOREIGN KEY ("REL_FK_serviced-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDeployment',
+ 'UNIQUE_NFDeployment_REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT',
+ 'ALTER TABLE ties_data."NFDeployment" ADD CONSTRAINT "UNIQUE_NFDeployment_REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT" UNIQUE ("REL_ID_NFDEPLOYMENT_SERVES_MANAGEDELEMENT");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDeployment',
+ 'FK_NFDeployment_REL_FK_comprised-by-cloudifiedNF',
+ 'ALTER TABLE ties_data."NFDeployment" ADD CONSTRAINT "FK_NFDeployment_REL_FK_comprised-by-cloudifiedNF" FOREIGN KEY ("REL_FK_comprised-by-cloudifiedNF") REFERENCES ties_data."CloudifiedNF" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NFDeployment',
+ 'UNIQUE_NFDeployment_REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT',
+ 'ALTER TABLE ties_data."NFDeployment" ADD CONSTRAINT "UNIQUE_NFDeployment_REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT" UNIQUE ("REL_ID_CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NODECLUSTER_LOCATED_AT_CLOUDSITE',
+ 'FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_aSide_NodeCluster',
+ 'ALTER TABLE ties_data."NODECLUSTER_LOCATED_AT_CLOUDSITE" ADD CONSTRAINT "FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_aSide_NodeCluster" FOREIGN KEY ("aSide_NodeCluster") REFERENCES ties_data."NodeCluster" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NODECLUSTER_LOCATED_AT_CLOUDSITE',
+ 'FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_bSide_CloudSite',
+ 'ALTER TABLE ties_data."NODECLUSTER_LOCATED_AT_CLOUDSITE" ADD CONSTRAINT "FK_NODECLUSTER_LOCATED_AT_CLOUDSITE_bSide_CloudSite" FOREIGN KEY ("bSide_CloudSite") REFERENCES ties_data."CloudSite" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellCU',
+ 'FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction',
+ 'ALTER TABLE ties_data."NRCellCU" ADD CONSTRAINT "FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction" FOREIGN KEY ("REL_FK_provided-by-gnbcucpFunction") REFERENCES ties_data."GNBCUCPFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellCU',
+ 'UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU',
+ 'ALTER TABLE ties_data."NRCellCU" ADD CONSTRAINT "UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU" UNIQUE ("REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellDU',
+ 'FK_NRCellDU_REL_FK_grouped-by-sector',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "FK_NRCellDU_REL_FK_grouped-by-sector" FOREIGN KEY ("REL_FK_grouped-by-sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellDU',
+ 'UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU" UNIQUE ("REL_ID_SECTOR_GROUPS_NRCELLDU");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellDU',
+ 'FK_NRCellDU_REL_FK_provided-by-gnbduFunction',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "FK_NRCellDU_REL_FK_provided-by-gnbduFunction" FOREIGN KEY ("REL_FK_provided-by-gnbduFunction") REFERENCES ties_data."GNBDUFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRCellDU',
+ 'UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU" UNIQUE ("REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRSectorCarrier',
+ 'FK_NRSectorCarrier_REL_FK_used-by-nrCellDu',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "FK_NRSectorCarrier_REL_FK_used-by-nrCellDu" FOREIGN KEY ("REL_FK_used-by-nrCellDu") REFERENCES ties_data."NRCellDU" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRSectorCarrier',
+ 'UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER" UNIQUE ("REL_ID_NRCELLDU_USES_NRSECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRSectorCarrier',
+ 'FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction" FOREIGN KEY ("REL_FK_provided-by-gnbduFunction") REFERENCES ties_data."GNBDUFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRSectorCarrier',
+ 'UNIQUE_872BE05F1989443F2595D99A77BC03733B2D1E2F',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "UNIQUE_872BE05F1989443F2595D99A77BC03733B2D1E2F" UNIQUE ("REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRSectorCarrier',
+ 'FK_NRSectorCarrier_REL_FK_used-antennaCapability',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "FK_NRSectorCarrier_REL_FK_used-antennaCapability" FOREIGN KEY ("REL_FK_used-antennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'NRSectorCarrier',
+ 'UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991" UNIQUE ("REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'PhysicalNF',
+ 'FK_PhysicalNF_REL_FK_installed-at-site',
+ 'ALTER TABLE ties_data."PhysicalNF" ADD CONSTRAINT "FK_PhysicalNF_REL_FK_installed-at-site" FOREIGN KEY ("REL_FK_installed-at-site") REFERENCES ties_data."Site" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+    'PhysicalNF',
+ 'UNIQUE_PhysicalNF_REL_ID_PHYSICALNF_INSTALLED_AT_SITE',
+ 'ALTER TABLE ties_data."PhysicalNF" ADD CONSTRAINT "UNIQUE_PhysicalNF_REL_ID_PHYSICALNF_INSTALLED_AT_SITE" UNIQUE ("REL_ID_PHYSICALNF_INSTALLED_AT_SITE");'
+);
+
+
+
+
+
+
+COMMIT;
diff --git a/license/copyright-2024.txt b/license/copyright-2024.txt
new file mode 100644
index 0000000..ff5fad2
--- /dev/null
+++ b/license/copyright-2024.txt
@@ -0,0 +1,18 @@
+============LICENSE_START=======================================================
+Copyright (C) 2024 Ericsson
+Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+================================================================================
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+SPDX-License-Identifier: Apache-2.0
+============LICENSE_END=========================================================
diff --git a/license/javaHeaderDefinition.xml b/license/javaHeaderDefinition.xml
new file mode 100644
index 0000000..318f822
--- /dev/null
+++ b/license/javaHeaderDefinition.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2024 Ericsson
+   Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<additionalHeaders>
+    <javadoc_style>
+        <firstLine>/*</firstLine>
+        <beforeEachLine> *  </beforeEachLine>
+        <endLine> */</endLine>
+        <!--skipLine></skipLine-->
+        <firstLineDetectionPattern>(\s|\t)*/\*.*$</firstLineDetectionPattern>
+        <lastLineDetectionPattern>.*\*/(\s|\t)*$</lastLineDetectionPattern>
+        <allowBlankLines>false</allowBlankLines>
+        <multiLine>true</multiLine>
+        <padLines>false</padLines>
+    </javadoc_style>
+</additionalHeaders>
diff --git a/license/xmlHeaderDefinition.xml b/license/xmlHeaderDefinition.xml
new file mode 100644
index 0000000..f7331cb
--- /dev/null
+++ b/license/xmlHeaderDefinition.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2024 Ericsson
+   Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<additionalHeaders>
+    <xml_style>
+        <firstLine><![CDATA[<!--]]></firstLine>
+        <beforeEachLine>  </beforeEachLine>
+        <endLine><![CDATA[ -->]]></endLine>
+        <skipLine><![CDATA[^<\?xml.*>$]]></skipLine>
+        <firstLineDetectionPattern><![CDATA[(\s|\t)*<!--.*$]]></firstLineDetectionPattern>
+        <lastLineDetectionPattern><![CDATA[.*-->(\s|\t)*$]]></lastLineDetectionPattern>
+        <allowBlankLines>false</allowBlankLines>
+        <multiLine>true</multiLine>
+        <padLines>false</padLines>
+    </xml_style>
+</additionalHeaders>
diff --git a/lombok.config b/lombok.config
new file mode 100644
index 0000000..b2e2986
--- /dev/null
+++ b/lombok.config
@@ -0,0 +1,2 @@
+config.stopbubbling=true
+lombok.addLombokGeneratedAnnotation=true
\ No newline at end of file
diff --git a/pgsql-schema-generator/pom.xml b/pgsql-schema-generator/pom.xml
new file mode 100644
index 0000000..e4da0b4
--- /dev/null
+++ b/pgsql-schema-generator/pom.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- spotless:off -->
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<!-- spotless:on -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.oran.smo</groupId>
+        <artifactId>topology-exposure-inventory</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+
+
+    <groupId>org.oran.smo.teiv.pgsqlgenerator</groupId>
+    <artifactId>pgsql-schema-generator</artifactId>
+    <version>1.0.0</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <maven.compiler.release>17</maven.compiler.release>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <version.lombok>1.18.26</version.lombok>
+        <version.spotless-plugin>2.30.0</version.spotless-plugin>
+        <!-- External Yang model destination location -->
+        <test.generate-defaults.import>${project.basedir}/src/test/resources/generate-defaults/import/</test.generate-defaults.import>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- jaxb dependencies -->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <version>2.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-core</artifactId>
+            <version>2.3.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-impl</artifactId>
+            <version>2.3.1</version>
+        </dependency>
+
+        <!--yang tool dependencies -->
+        <dependency>
+            <groupId>org.oran.smo.yangtools.parser</groupId>
+            <artifactId>yang-parser-jar</artifactId>
+            <version>${version.yang-parser-jar}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.14.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>${version.lombok}</version>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Test Dependencies -->
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>com.mycila</groupId>
+                <artifactId>license-maven-plugin</artifactId>
+                <version>${version.license-maven-plugin}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.diffplug.spotless</groupId>
+                <artifactId>spotless-maven-plugin</artifactId>
+                <version>${version.spotless-plugin}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>${version.antrun-maven-plugin}</version>
+                <executions>
+                    <execution>
+                        <id>download-external-yang-models-pgsql</id>
+                        <phase>generate-test-sources</phase>
+                        <configuration>
+                            <target>
+                                <mkdir dir="${test.generate-defaults.import}" />
+                                <get
+                                    src="${source.3gpp.Rel18_SA103}_3gpp-common-yang-types.yang"
+                                    dest="${test.generate-defaults.import}_3gpp-common-yang-types.yang"
+                                    skipexisting="true" />
+                                <get
+                                    src="${source.ietfcatalog}ietf-geo-location@2022-02-11.yang"
+                                    dest="${test.generate-defaults.import}ietf-geo-location.yang"
+                                    skipexisting="true" />
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Attribute.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Attribute.java
new file mode 100644
index 0000000..20280a5
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Attribute.java
@@ -0,0 +1,37 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.util.Collection;
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class Attribute {
+    private String name;
+    private String dataType;
+    @Builder.Default
+    private Collection<Object> constraints = List.of();
+    private String defaultValue;
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Column.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Column.java
new file mode 100644
index 0000000..ff74f67
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Column.java
@@ -0,0 +1,37 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.util.Collection;
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class Column {
+    private String name;
+    private String dataType;
+    @Builder.Default
+    private Collection<PostgresConstraint> postgresConstraints = List.of();
+    private String defaultValue;
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Constants.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Constants.java
new file mode 100644
index 0000000..ab0c590
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Constants.java
@@ -0,0 +1,64 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class Constants {
+
+    public static final String NO_PREFIX = "";
+    public static final String CONSUMER_DATA = "CD_";
+    public static final String SOURCE_IDS = "sourceIds";
+    public static final String REL_ID = "REL_ID_";
+    public static final String REL_FK = "REL_FK_";
+    public static final String REL_CD = "REL_CD_";
+    public static final String FOREIGN_KEY = "FK_";
+    public static final String PRIMARY_KEY = "PK_";
+    public static final String NOT_NULL = "NOT_NULL_";
+    public static final String UNIQUE = "UNIQUE_";
+    public static final String A_SIDE_PREFIX = "aSide_";
+    public static final String B_SIDE_PREFIX = "bSide_";
+    public static final String ID = "id";
+    public static final String COLUMN = "COLUMN";
+    public static final String TABLE = "TABLE";
+    public static final String CONSTRAINT = "CONSTRAINT";
+    public static final String VARCHAR511 = "VARCHAR(511)";
+    public static final String TEXT = "TEXT";
+    public static final String DECIMAL = "DECIMAL";
+    public static final String BIGINT = "BIGINT";
+    public static final String INT = "INTEGER";
+    public static final String JSONB = "jsonb";
+    public static final String CREATE = "CREATE";
+    public static final String ALTER = "ALTER";
+    public static final String DEFAULT = "DEFAULT";
+    public static final String ALTER_TABLE_TIES_DATA_S = "ALTER TABLE ties_data.\"%s\" ";
+    public static final String ALTER_TABLE_TIES_DATA_S_ADD_CONSTRAINT_S = ALTER_TABLE_TIES_DATA_S + "ADD CONSTRAINT \"%s\" ";
+    public static final String CLASSIFIERS = "classifiers";
+    public static final String DECORATORS = "decorators";
+    public static final String DEFAULT_MODULE_STATUS = "IN_USAGE";
+    public static final String BUILT_IN_MODULE_ID = "BUILT_IN_MODULE";
+    public static final String A_SIDE = "A_SIDE";
+    public static final String B_SIDE = "B_SIDE";
+    public static final String RELATION = "RELATION";
+    public static final String GEO_LOCATION = "geo-location";
+    public static final String GEOGRAPHY = "geography";
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/ConsumerData.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/ConsumerData.java
new file mode 100644
index 0000000..fdfd5c8
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/ConsumerData.java
@@ -0,0 +1,32 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class ConsumerData {
+    private String name;
+    private String dataType;
+    private String defaultValue;
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/DatabaseSchemaGeneratorApplication.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/DatabaseSchemaGeneratorApplication.java
new file mode 100644
index 0000000..28838f0
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/DatabaseSchemaGeneratorApplication.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DatabaseSchemaGeneratorApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(DatabaseSchemaGeneratorApplication.class, args);
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Entity.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Entity.java
new file mode 100644
index 0000000..a3da50a
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Entity.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.util.List;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.Table;
+import lombok.Builder;
+import lombok.Getter;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.CLASSIFIERS;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.DECORATORS;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.JSONB;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.SOURCE_IDS;
+
+@Getter
+@Builder
+public class Entity implements Table {
+    private String entityName;
+    private String moduleReferenceName;
+    private List<Attribute> attributes;
+    @Builder.Default
+    private List<ConsumerData> consumerData = List.of(ConsumerData.builder().name(SOURCE_IDS).dataType(JSONB).defaultValue(
+            "[]").build(), ConsumerData.builder().name(CLASSIFIERS).dataType(JSONB).defaultValue("[]").build(), ConsumerData
+                    .builder().name(DECORATORS).dataType(JSONB).defaultValue("{}").build());
+
+    @Override
+    public String getTableName() {
+        return "entity_info";
+    }
+
+    @Override
+    public String getColumnsForCopyStatement() {
+        return "(\"name\", \"moduleReferenceName\")";
+    }
+
+    @Override
+    public String getRecordForCopyStatement() {
+        return this.getEntityName() + "\t" + this.getModuleReferenceName() + "\n";
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/ForeignKeyConstraint.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/ForeignKeyConstraint.java
new file mode 100644
index 0000000..130112b
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/ForeignKeyConstraint.java
@@ -0,0 +1,49 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+public class ForeignKeyConstraint implements PostgresConstraint {
+    private String constraintName;
+    private String tableName;
+    @Getter
+    private String referencedTable;
+    private String columnToAddConstraintTo;
+
+    @Override
+    public String getConstraintName() {
+        return constraintName;
+    }
+
+    @Override
+    public String getTableToAddConstraintTo() {
+        return tableName;
+    }
+
+    @Override
+    public String getColumnToAddConstraintTo() {
+        return columnToAddConstraintTo;
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/HashInfoEntity.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/HashInfoEntity.java
new file mode 100644
index 0000000..f0fece6
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/HashInfoEntity.java
@@ -0,0 +1,65 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.util.Objects;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.Table;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class HashInfoEntity implements Table {
+    private String name;
+    private String hashedValue;
+    private String type;
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        HashInfoEntity myClass = (HashInfoEntity) obj;
+        return name.equals(myClass.name);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name);
+    }
+
+    @Override
+    public String getTableName() {
+        return "hash_info";
+    }
+
+    @Override
+    public String getColumnsForCopyStatement() {
+        return "(\"name\", \"hashedValue\", \"type\")";
+    }
+
+    @Override
+    public String getRecordForCopyStatement() {
+        return this.getName() + "\t" + this.getHashedValue() + "\t" + this.getType() + "\n";
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Module.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Module.java
new file mode 100644
index 0000000..1d6dc2a
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Module.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Collection;
+import java.util.List;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.Table;
+import lombok.Getter;
+import lombok.Builder;
+import lombok.Setter;
+
+@Getter
+@Builder
+public class Module implements Table {
+    private String name;
+    private String namespace;
+    private String domain;
+    private String revision;
+    private String content;
+    private String ownerAppId;
+    private String status;
+    @Setter
+    @Builder.Default
+    private Collection<String> includedModules = List.of();
+
+    @Override
+    public String getTableName() {
+        return "module_reference";
+    }
+
+    @Override
+    public String getColumnsForCopyStatement() {
+        return "(\"name\", \"namespace\", \"domain\", \"includedModules\", \"revision\", \"content\", \"ownerAppId\", \"status\")";
+    }
+
+    @Override
+    public String getRecordForCopyStatement() {
+        return this.getName() + "\t" + this.getNamespace() + "\t" + (!this.getDomain().isEmpty() ?
+                this.getDomain() :
+                "\\N") + "\t" + this.getIncludedModules().stream().map(moduleRef -> "\"" + moduleRef + "\"")
+                        .toList() + "\t" + this.getRevision() + "\t" + Base64.getEncoder().encodeToString(this.getContent()
+                                .replaceAll("\\r\\n?", "\n").getBytes(StandardCharsets.UTF_8)) + "\t" + this
+                                        .getOwnerAppId() + "\t" + this.getStatus() + "\n";
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/NotNullConstraint.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/NotNullConstraint.java
new file mode 100644
index 0000000..6508f1e
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/NotNullConstraint.java
@@ -0,0 +1,45 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import lombok.Builder;
+
+@Builder
+public class NotNullConstraint implements PostgresConstraint {
+    private String constraintName;
+    private String tableName;
+    private String columnToAddConstraintTo;
+
+    @Override
+    public String getConstraintName() {
+        return constraintName;
+    }
+
+    @Override
+    public String getTableToAddConstraintTo() {
+        return tableName;
+    }
+
+    @Override
+    public String getColumnToAddConstraintTo() {
+        return columnToAddConstraintTo;
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PgSchemaGeneratorException.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PgSchemaGeneratorException.java
new file mode 100644
index 0000000..989dfc0
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PgSchemaGeneratorException.java
@@ -0,0 +1,71 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import lombok.Getter;
+
+@Getter
+public class PgSchemaGeneratorException extends RuntimeException {
+    private PgSchemaGeneratorException(String errorMessage, Throwable err) {
+        super(errorMessage, err);
+    }
+
+    public static PgSchemaGeneratorException extractYangDataException(Exception ex) {
+        return new PgSchemaGeneratorException("Unable to load YAM!", ex);
+    }
+
+    public static PgSchemaGeneratorException prepareBaselineException(final String schemaName, Exception ex) { //
+        return new PgSchemaGeneratorException(String.format("%s : Failed to copy skeleton schema file!", schemaName), ex);
+    }
+
+    public static PgSchemaGeneratorException readBaselineException(final String schemaName, Exception ex) {
+        return new PgSchemaGeneratorException(String.format("%s : Failed to read baseline sql file!", schemaName), ex);
+    }
+
+    public static PgSchemaGeneratorException writeGeneratedSchemaException(final String schemaName, Exception ex) {
+        return new PgSchemaGeneratorException(String.format("%s :  data writing failed!", schemaName), ex);
+    }
+
+    public static PgSchemaGeneratorException generateSHA1HashException(Exception ex) {
+        return new PgSchemaGeneratorException("Error occurred while generating hash for hash_info table entry", ex);
+    }
+
+    public static PgSchemaGeneratorException extractMoTypeFromUrnException(final String urn, Exception ex) {
+        return new PgSchemaGeneratorException(String.format("Unable to extract Managed object from urn - %s", urn), ex);
+    }
+
+    public static PgSchemaGeneratorException assignModuleRefException(final String relationshipName, Exception ex) {
+        return new PgSchemaGeneratorException(String.format("ties.model : Unable to assign module reference to - %s",
+                relationshipName), ex);
+    }
+
+    public static PgSchemaGeneratorException assignRelationshipDataLocation(final String relationshipName, Exception ex) {
+        return new PgSchemaGeneratorException(String.format(
+                "Unable to assign RelationshipDataLocation to - %s, unknown cardinalities", relationshipName), ex);
+    }
+
+    public static PgSchemaGeneratorException nbcChangeIdentifiedException(String errorMsg, Exception ex) {
+        return new PgSchemaGeneratorException(String.format(
+                "NBC change has been introduced: %s, please make sure you've enabled green-field installation!!%nFor more info please refer to README",
+                errorMsg), ex);
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PostgresConstraint.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PostgresConstraint.java
new file mode 100644
index 0000000..4b63f3e
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PostgresConstraint.java
@@ -0,0 +1,30 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+public interface PostgresConstraint {
+    String getConstraintName();
+
+    String getTableToAddConstraintTo();
+
+    String getColumnToAddConstraintTo();
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PrimaryKeyConstraint.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PrimaryKeyConstraint.java
new file mode 100644
index 0000000..fb2d1ec
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/PrimaryKeyConstraint.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import lombok.Builder;
+
+@Builder
+public class PrimaryKeyConstraint implements PostgresConstraint {
+
+    private String constraintName;
+    private String tableName;
+    private String columnToAddConstraintTo;
+
+    @Override
+    public String getConstraintName() {
+        return constraintName;
+    }
+
+    @Override
+    public String getTableToAddConstraintTo() {
+        return tableName;
+    }
+
+    @Override
+    public String getColumnToAddConstraintTo() {
+        return columnToAddConstraintTo;
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Processor.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Processor.java
new file mode 100644
index 0000000..38f9898
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Processor.java
@@ -0,0 +1,90 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.data.DataSchemaGenerator;
+import org.oran.smo.teiv.pgsqlgenerator.schema.model.ModelSchemaGenerator;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ResourceUtils;
+
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Component
+public class Processor {
+    private final YangParser yangParser;
+    private final YangModelProcessor yangModelProcessor;
+    private final DataSchemaGenerator dataSchemaGenerator;
+    private final ModelSchemaGenerator modelSchemaGenerator;
+    @Value("${yang-model.source}")
+    private String yangModelDirectory;
+
+    @PostConstruct
+    void process() throws IOException {
+        List<File> pathToImplementing = Collections.singletonList(ResourceUtils.getFile(yangModelDirectory));
+
+        // Yang model validation should be added here
+
+        // retrieve info from yang parser
+        List<Module> modules = yangParser.returnAllModuleReferences();
+
+        // retrieve info from the model
+        List<Entity> entitiesFromModelService = yangModelProcessor.getEntitiesAndAttributesFromYang(pathToImplementing);
+
+        List<Module> moduleReferences = storeRelatedModuleRefsFromIncludedModules(entitiesFromModelService, modules);
+
+        List<Relationship> relationshipsFromModelService = yangModelProcessor.getRelationshipsFromYang(pathToImplementing);
+
+        dataSchemaGenerator.generate(moduleReferences, entitiesFromModelService, relationshipsFromModelService);
+        modelSchemaGenerator.generate(moduleReferences, entitiesFromModelService, relationshipsFromModelService);
+    }
+
+    /**
+     * Included modules stores all the imported modules in a yang module
+     * This function extracts and stores only the related module names from provided entities.
+     *
+     * @param entities
+     *     The list of entities.
+     * @param moduleRefFromYangParser
+     *     The list of ModuleReferences obtained from the YANG parser.
+     * @return The list of ModuleReferences.
+     */
+    public static List<Module> storeRelatedModuleRefsFromIncludedModules(List<Entity> entities,
+            List<Module> moduleRefFromYangParser) {
+
+        List<String> moduleRefForAllEntities = entities.stream().map(Entity::getModuleReferenceName).toList();
+        for (Module module : moduleRefFromYangParser) {
+            List<String> includedModules = new ArrayList<>(module.getIncludedModules());
+            includedModules.removeIf(modelRef -> !moduleRefForAllEntities.contains(modelRef));
+            module.setIncludedModules(includedModules);
+        }
+        return moduleRefFromYangParser;
+
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Relationship.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Relationship.java
new file mode 100644
index 0000000..a4285cc
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Relationship.java
@@ -0,0 +1,78 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.util.List;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.Table;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.CLASSIFIERS;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.DECORATORS;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.JSONB;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.SOURCE_IDS;
+
+@Getter
+@Builder
+public class Relationship implements Table {
+    private String name;
+    private String aSideAssociationName;
+    private String aSideMOType;
+    private long aSideMinCardinality;
+    private long aSideMaxCardinality;
+    private String bSideAssociationName;
+    private String bSideMOType;
+    private long bSideMinCardinality;
+    private long bSideMaxCardinality;
+    private String associationKind;
+    @Setter
+    private String relationshipDataLocation;
+    private boolean connectSameEntity;
+    @Setter
+    private String moduleReferenceName;
+    @Builder.Default
+    private List<ConsumerData> consumerData = List.of(ConsumerData.builder().name(SOURCE_IDS).dataType(JSONB).defaultValue(
+            "[]").build(), ConsumerData.builder().name(CLASSIFIERS).dataType(JSONB).defaultValue("[]").build(), ConsumerData
+                    .builder().name(DECORATORS).dataType(JSONB).defaultValue("{}").build());
+
+    @Override
+    public String getTableName() {
+        return "relationship_info";
+    }
+
+    @Override
+    public String getColumnsForCopyStatement() {
+        return "(\"name\", \"aSideAssociationName\", \"aSideMOType\", \"aSideMinCardinality\", \"aSideMaxCardinality\", \"bSideAssociationName\", \"bSideMOType\", \"bSideMinCardinality\", \"bSideMaxCardinality\", \"associationKind\", \"relationshipDataLocation\", \"connectSameEntity\", \"moduleReferenceName\")";
+    }
+
+    @Override
+    public String getRecordForCopyStatement() {
+        return this.getName() + "\t" + this.getASideAssociationName() + "\t" + this.getASideMOType() + "\t" + this
+                .getASideMinCardinality() + "\t" + this.getASideMaxCardinality() + "\t" + this
+                        .getBSideAssociationName() + "\t" + this.getBSideMOType() + "\t" + this
+                                .getBSideMinCardinality() + "\t" + this.getBSideMaxCardinality() + "\t" + this
+                                        .getAssociationKind() + "\t" + this.getRelationshipDataLocation() + "\t" + this
+                                                .isConnectSameEntity() + "\t" + this.getModuleReferenceName() + "\n";
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/SchemaGenerator.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/SchemaGenerator.java
new file mode 100644
index 0000000..ca62b57
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/SchemaGenerator.java
@@ -0,0 +1,34 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+public interface SchemaGenerator {
+
+    /**
+     * Gets the schema name.
+     * Schema name should be same as the one used in skeleton SQL.
+     * TODO: Check if there is a way to ensure schema name matches the one used in skeleton
+     *
+     * @return the schema name
+     */
+    String getSchemaName();
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Table.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Table.java
new file mode 100644
index 0000000..9353eb6
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/Table.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class Table {
+    private String name;
+    private List<Column> columns;
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/UniqueConstraint.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/UniqueConstraint.java
new file mode 100644
index 0000000..53f9c49
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/UniqueConstraint.java
@@ -0,0 +1,45 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import lombok.Builder;
+
+@Builder
+public class UniqueConstraint implements PostgresConstraint {
+    private String constraintName;
+    private String tableName;
+    private String columnToAddConstraintTo;
+
+    @Override
+    public String getConstraintName() {
+        return constraintName;
+    }
+
+    @Override
+    public String getTableToAddConstraintTo() {
+        return tableName;
+    }
+
+    @Override
+    public String getColumnToAddConstraintTo() {
+        return columnToAddConstraintTo;
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/YangModelProcessor.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/YangModelProcessor.java
new file mode 100644
index 0000000..b2efcf8
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/YangModelProcessor.java
@@ -0,0 +1,338 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.A_SIDE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.BIGINT;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.B_SIDE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.DECIMAL;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.JSONB;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.RELATION;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.TEXT;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.VARCHAR511;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.findings.ModuleAndFindingTypeAndSchemaNodePathFilterPredicate;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInputResolver;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.ietf.IetfExtensionsClassSupplier;
+import org.oran.smo.yangtools.parser.model.statements.oran.OranExtensionsClassSupplier;
+import org.oran.smo.yangtools.parser.model.statements.oran.YOranSmoTeivASide;
+import org.oran.smo.yangtools.parser.model.statements.oran.YOranSmoTeivBSide;
+import org.oran.smo.yangtools.parser.model.statements.oran.YOranSmoTeivBiDirectionalTopologyRelationship;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.ThreeGppExtensionsClassSupplier;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+public class YangModelProcessor {
+    private final HashMap<String, String> dataTypeMapping;
+    private final YangDeviceModel yangDeviceModel;
+    private final ModifyableFindingSeverityCalculator severityCalculator;
+    private final FindingsManager findingsManager;
+    private final ParserExecutionContext context;
+    private final ThreeGppExtensionsClassSupplier threeGppStatementFactory;
+    private final IetfExtensionsClassSupplier ietfStatementFactory;
+    private final OranExtensionsClassSupplier oranStatementFactory;
+
+    public YangModelProcessor() {
+        dataTypeMapping = createDataTypeMapping();
+        yangDeviceModel = new YangDeviceModel("Yang Parser JAR Test Device Model");
+        severityCalculator = new ModifyableFindingSeverityCalculator();
+        findingsManager = new FindingsManager(severityCalculator);
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "ietf*,iana*;*;*"));
+
+        threeGppStatementFactory = new ThreeGppExtensionsClassSupplier();
+        ietfStatementFactory = new IetfExtensionsClassSupplier();
+        oranStatementFactory = new OranExtensionsClassSupplier();
+        context = new ParserExecutionContext(findingsManager, Arrays.asList(threeGppStatementFactory, oranStatementFactory,
+                ietfStatementFactory));
+        context.setFailFast(false);
+        context.setSuppressFindingsOnUnusedSchemaNodes(true);
+    }
+
+    private HashMap<String, String> createDataTypeMapping() {
+        HashMap<String, String> map = new HashMap<String, String>() {
+            {
+                put("string", TEXT);
+                put("uint32", BIGINT);
+                put("or-teiv-types:_3GPP_FDN_Type", TEXT);
+                put("enumeration", TEXT);
+                put("types3gpp:PLMNId", JSONB);
+                put("[]", JSONB);
+                put(JSONB, JSONB);
+                put("[uses types3gpp:PLMNId]", JSONB);
+                put("geo:geo-location", "geography");
+                put("uint64", BIGINT);
+                put("decimal64", DECIMAL);
+                put("[uses or-teiv-types:CM_ID]", JSONB);
+            }
+        };
+        return map;
+    }
+
+    public List<Entity> getEntitiesAndAttributesFromYang(List<File> pathToImplementing) {
+        List<Entity> entities = new ArrayList<>();
+
+        File rootFolder = pathToImplementing.get(0);
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(List.of(rootFolder));
+        List<YangModel> yangModels = resolver.getResolvedYangInput().stream().map(yangInput -> new YangModel(yangInput,
+                ConformanceType.IMPLEMENT)).toList();
+
+        yangDeviceModel.parseIntoYangModels(context, yangModels);
+
+        yangModels.stream().forEach(yangModel -> {
+            YModule yModule = yangModel.getYangModelRoot().getModule();
+            System.out.println("Module Name: " + yModule.getModuleName());
+
+            yModule.getLists().stream().forEach(yList -> {
+                System.out.printf("\tEntity Name: %s \n", yList.getListName());
+                List<Attribute> attributes = new ArrayList<>();
+                List constraint = List.of(PrimaryKeyConstraint.builder().constraintName("PK_" + yList.getListName() + "_id")
+                        .tableName(yList.getListName()).columnToAddConstraintTo("id").build());
+
+                attributes.add(Attribute.builder().name("id").dataType(VARCHAR511).constraints(constraint).build());
+                yList.getContainers().forEach(yContainer -> {
+                    System.out.printf("\t\tContainer Name: %s \n", yContainer.getContainerName());
+                    if (yContainer.getContainerName().equals("attributes")) {
+
+                        yContainer.getLeafs().forEach(yLeaf -> {
+
+                            System.out.printf("\t\t\tLeaf Name: %s \n", yLeaf.getLeafName());
+                            System.out.printf("\t\t\t\tLeaf Type: %s \n", yLeaf.getType().getDataType());
+                            System.out.printf("\t\t\t\tData Type: %s \n", dataTypeMapping.get(yLeaf.getType()
+                                    .getDataType()));
+
+                            if (yLeaf.getDefault() != null) {
+
+                                attributes.add(Attribute.builder().name(yLeaf.getLeafName()).dataType(dataTypeMapping.get(
+                                        yLeaf.getType().getDataType())).defaultValue(yLeaf.getDefault().getValue())
+                                        .constraints(new ArrayList()).build());
+                            } else {
+                                attributes.add(Attribute.builder().name(yLeaf.getLeafName()).dataType(dataTypeMapping.get(
+                                        yLeaf.getType().getDataType())).constraints(new ArrayList()).build());
+                            }
+                        });
+                        yContainer.getLeafLists().forEach(yLeafList -> {
+
+                            System.out.printf("\t\t\tLeaf Name: %s \n", yLeafList.getLeafListName());
+                            System.out.printf("\t\t\t\tLeaf Type: %s \n", yLeafList.getType().getDataType());
+                            System.out.printf("\t\t\t\tData Type: %s \n", dataTypeMapping.get(yLeafList.getType()
+                                    .getDataType()));
+
+                            attributes.add(Attribute.builder().name(yLeafList.getLeafListName()).dataType(JSONB)
+                                    .constraints(new ArrayList()).build());
+                        });
+                        yContainer.getContainers().forEach(container -> {
+
+                            System.out.printf("\t\t\tContainer Name: %s \n", container.getContainerName());
+                            System.out.printf("\t\t\t\tContainer Type: %s \n", container.getUses());
+                            System.out.printf("\t\t\t\tData Type: %s \n", dataTypeMapping.get(container.getUses()
+                                    .toString()));
+
+                            attributes.add(Attribute.builder().name(container.getContainerName()).dataType(dataTypeMapping
+                                    .get(container.getUses().toString())).constraints(new ArrayList()).build());
+                        });
+                        yContainer.getUses().forEach(uses -> {
+
+                            System.out.printf("\t\t\tUses Name: %s \n", uses.getDomElement().getValue());
+
+                            attributes.add(Attribute.builder().name(uses.getDomElement().getValue().substring(uses
+                                    .getDomElement().getValue().indexOf(':') + 1, uses.getDomElement().getValue().length()))
+                                    .dataType(dataTypeMapping.get(uses.getDomElement().getValue())).constraints(
+                                            new ArrayList()).build());
+                        });
+                    }
+                });
+                entities.add(Entity.builder().entityName(yList.getListName()).moduleReferenceName(yangModel
+                        .getYangModelRoot().getModule().getModuleName()).attributes(attributes).build());
+            });
+        });
+        return entities;
+    }
+
+    public List<Relationship> getRelationshipsFromYang(List<File> pathToImplementing) {
+        List<Relationship> relationships = new ArrayList<>();
+
+        File rootFolder = pathToImplementing.get(0);
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(List.of(rootFolder));
+        List<YangModel> yangModels = resolver.getResolvedYangInput().stream().map(yangInput -> new YangModel(yangInput,
+                ConformanceType.IMPLEMENT)).toList();
+
+        yangDeviceModel.parseIntoYangModels(context, yangModels);
+
+        yangModels.stream().forEach(yangModel -> {
+            YModule yModule = yangModel.getYangModelRoot().getModule();
+            System.out.println("Module Name: " + yModule.getModuleName());
+
+            StatementModuleAndName biDirectionalTopologyRelationship = new StatementModuleAndName(
+                    "o-ran-smo-teiv-common-yang-extensions", "biDirectionalTopologyRelationship");
+            StatementModuleAndName biDirectionalTopologyRelationshipAside = new StatementModuleAndName(
+                    "o-ran-smo-teiv-common-yang-extensions", "aSide");
+            StatementModuleAndName biDirectionalTopologyRelationshipBside = new StatementModuleAndName(
+                    "o-ran-smo-teiv-common-yang-extensions", "bSide");
+
+            yModule.getChildren(biDirectionalTopologyRelationship).stream().map(
+                    abstractStatement -> (YOranSmoTeivBiDirectionalTopologyRelationship) abstractStatement).forEach(
+                            yOranSmoTeivBiDirectionalTopologyRelationship -> {
+                                System.out.printf("\tRelationship Name: %s \n",
+                                        yOranSmoTeivBiDirectionalTopologyRelationship.getRelationshipName());
+                                YOranSmoTeivASide aSide = yOranSmoTeivBiDirectionalTopologyRelationship.getChildStatements()
+                                        .stream().filter(abstractStatement -> abstractStatement.getChild(
+                                                biDirectionalTopologyRelationshipAside) != null).toList().get(0).getChild(
+                                                        biDirectionalTopologyRelationshipAside);
+
+                                YOranSmoTeivBSide bSide = yOranSmoTeivBiDirectionalTopologyRelationship.getChildStatements()
+                                        .stream().filter(abstractStatement -> abstractStatement.getChild(
+                                                biDirectionalTopologyRelationshipBside) != null).toList().get(0).getChild(
+                                                        biDirectionalTopologyRelationshipBside);
+
+                                System.out.printf("\t\tA Side:\n\t\t\t Name: %s \n\t\t\t Type: %s \n", aSide
+                                        .getParentStatement().getStatementIdentifier(), aSide.getTeivTypeName());
+                                System.out.printf("\t\tB Side:\n\t\t\t Name %s \n\t\t\t Type %s \n", bSide
+                                        .getParentStatement().getStatementIdentifier(), bSide.getTeivTypeName());
+
+                                long aSideMinCardinality = 0;
+                                long aSideMaxCardinality = 0;
+                                long bSideMinCardinality = 0;
+                                long bSideMaxCardinality = 0;
+                                Optional<YangDomElement> bSideMandatory = yOranSmoTeivBiDirectionalTopologyRelationship
+                                        .getChildStatements().stream().filter(abstractStatement -> abstractStatement
+                                                .getChild(biDirectionalTopologyRelationshipBside) != null).toList().get(0)
+                                        .getDomElement().getChildren().stream().filter(name -> name.getNameValue().contains(
+                                                "mandatory true")).findAny();
+                                Optional<YangDomElement> aSideMandatory = yOranSmoTeivBiDirectionalTopologyRelationship
+                                        .getChildStatements().stream().filter(abstractStatement -> abstractStatement
+                                                .getChild(biDirectionalTopologyRelationshipAside) != null).toList().get(0)
+                                        .getDomElement().getChildren().stream().filter(name -> name.getNameValue().contains(
+                                                "mandatory true")).findAny();
+                                Optional<YangDomElement> bSideMinElement = yOranSmoTeivBiDirectionalTopologyRelationship
+                                        .getChildStatements().stream().filter(abstractStatement -> abstractStatement
+                                                .getChild(biDirectionalTopologyRelationshipBside) != null).toList().get(0)
+                                        .getDomElement().getChildren().stream().filter(name -> name.getNameValue().contains(
+                                                "min-elements 1")).findAny();
+                                Optional<YangDomElement> aSideMinElement = yOranSmoTeivBiDirectionalTopologyRelationship
+                                        .getChildStatements().stream().filter(abstractStatement -> abstractStatement
+                                                .getChild(biDirectionalTopologyRelationshipAside) != null).toList().get(0)
+                                        .getDomElement().getChildren().stream().filter(name -> name.getNameValue().contains(
+                                                "min-elements 1")).findAny();
+
+                                if (aSide.getParentStatement().getDomElement().getName() == "leaf") {
+                                    if (aSideMandatory.isPresent() || aSideMinElement.isPresent()) {
+                                        bSideMinCardinality = 1;
+                                    } else {
+                                        bSideMinCardinality = 0;
+                                    }
+                                    bSideMaxCardinality = 1;
+
+                                }
+                                if (aSide.getParentStatement().getDomElement().getName() == "leaf-list") {
+                                    if (aSideMandatory.isPresent() || aSideMinElement.isPresent()) {
+                                        bSideMinCardinality = 1;
+                                    } else {
+                                        bSideMinCardinality = 0;
+                                    }
+                                    bSideMaxCardinality = Long.MAX_VALUE;
+
+                                }
+                                if (bSide.getParentStatement().getDomElement().getName() == "leaf") {
+                                    if (bSideMandatory.isPresent() || bSideMinElement.isPresent()) {
+                                        aSideMinCardinality = 1;
+                                    } else {
+                                        aSideMinCardinality = 0;
+                                    }
+                                    aSideMaxCardinality = 1;
+                                }
+                                if (bSide.getParentStatement().getDomElement().getName() == "leaf-list") {
+                                    if (bSideMandatory.isPresent() || bSideMinElement.isPresent()) {
+                                        aSideMinCardinality = 1;
+                                    } else {
+                                        aSideMinCardinality = 0;
+                                    }
+                                    aSideMaxCardinality = Long.MAX_VALUE;
+                                }
+
+                                String relDataLocation = getRelationshipDataLocation(aSideMaxCardinality,
+                                        bSideMaxCardinality, aSide.getValue(), bSide.getValue(),
+                                        yOranSmoTeivBiDirectionalTopologyRelationship.getRelationshipName());
+
+                                String aSideMoType = aSide.getValue().substring(aSide.getValue().indexOf(':') + 1, aSide
+                                        .getValue().length());
+                                String bSideMoType = bSide.getValue().substring(bSide.getValue().indexOf(':') + 1, bSide
+                                        .getValue().length());
+
+                                boolean connectSameEntity;
+                                if (aSideMoType.equals(bSideMoType)) {
+                                    connectSameEntity = true;
+                                } else {
+                                    connectSameEntity = false;
+                                }
+
+                                Relationship relationship = Relationship.builder().name(
+                                        yOranSmoTeivBiDirectionalTopologyRelationship.getRelationshipName())
+                                        .aSideAssociationName(aSide.getParentStatement().getStatementIdentifier())
+                                        .aSideMOType(aSideMoType).aSideMinCardinality(aSideMinCardinality)
+                                        .aSideMaxCardinality(aSideMaxCardinality).bSideAssociationName(bSide
+                                                .getParentStatement().getStatementIdentifier()).bSideMOType(bSideMoType)
+                                        .bSideMinCardinality(bSideMinCardinality).bSideMaxCardinality(bSideMaxCardinality)
+                                        .relationshipDataLocation(relDataLocation).moduleReferenceName(yModule
+                                                .getModuleName()).associationKind(("BI_DIRECTIONAL"))   // Hard coded for now
+                                        .connectSameEntity(connectSameEntity).build();     // Hard coded for now
+                                relationships.add(relationship);
+                            });
+        });
+        return relationships;
+    }
+
+    /**
+     * Identify where relationship data should be stored
+     */
+    private String getRelationshipDataLocation(long aSideMaxCardinality, long bSideMaxCardinality, String aSideMO,
+            String bSideMO, String relName) {
+        if (aSideMO.equals(bSideMO) || (aSideMaxCardinality > 1 && bSideMaxCardinality > 1)) {
+            return RELATION;
+        } else if ((aSideMaxCardinality == 1 && bSideMaxCardinality == 1) || (aSideMaxCardinality > 1 && bSideMaxCardinality == 1)) {
+            return A_SIDE;
+        } else if (aSideMaxCardinality == 1 && bSideMaxCardinality > 1) {
+            return B_SIDE;
+        } else {
+            throw PgSchemaGeneratorException.assignRelationshipDataLocation(relName, new UnsupportedOperationException());
+        }
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/YangParser.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/YangParser.java
new file mode 100644
index 0000000..1b773fc
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/YangParser.java
@@ -0,0 +1,132 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.BUILT_IN_MODULE_ID;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.DEFAULT_MODULE_STATUS;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.input.ByteArrayYangInput;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+
+@Slf4j
+@Component
+public class YangParser {
+
+    @Value("${yang-model.source}")
+    private String yangModelDirectory;
+
+    /**
+     * Store name, domains and namespace from yang modules
+     *
+     * @return list of module references
+     */
+    public List<Module> returnAllModuleReferences() throws IOException {
+        YangDeviceModel yangDeviceModel = extractYangData();
+        List<Module> modules = new ArrayList<>();
+        for (final YangModel yangInput : yangDeviceModel.getModuleRegistry().getAllYangModels()) {
+            final AbstractStatement moduleOrSubmodule = yangInput.getYangModelRoot().getModuleOrSubmodule();
+            String moduleReferenceName = moduleOrSubmodule.getDomElement().getValue();
+            String domain = getDomain(moduleOrSubmodule);
+            String namespace = getNamespace(moduleOrSubmodule);
+            List<String> includedModules = getIncludedModules(moduleOrSubmodule);
+            modules.add(Module.builder().name(moduleReferenceName).namespace(namespace).domain(domain).includedModules(
+                    includedModules).revision(yangInput.getModuleIdentity().getRevision()).content(new String(yangInput
+                            .getYangInput().getInputStream().readAllBytes(), StandardCharsets.UTF_8)).ownerAppId(
+                                    BUILT_IN_MODULE_ID).status(DEFAULT_MODULE_STATUS).build());
+        }
+        return modules;
+    }
+
+    private String getDomain(AbstractStatement moduleOrSubmodule) {
+        AbstractStatement domainStatement = moduleOrSubmodule.getChild(new StatementModuleAndName(
+                "o-ran-smo-teiv-common-yang-extensions", "domain"));
+        return domainStatement != null && domainStatement.getDomElement() != null ?
+                domainStatement.getDomElement().getValue() :
+                "";
+    }
+
+    private String getNamespace(AbstractStatement moduleOrSubmodule) {
+        for (AbstractStatement child : moduleOrSubmodule.getChildStatements()) {
+            if (child.getDomElement().getName().equalsIgnoreCase("namespace")) {
+                return child.getDomElement().getValue();
+            }
+        }
+        return "";
+    }
+
+    /**
+     * Extract all imported modules in a yang module
+     */
+    private List<String> getIncludedModules(AbstractStatement statement) {
+        List<String> includedModules = new ArrayList<>();
+        statement.getChildStatements().forEach(childStatement -> {
+            String domStatement = childStatement.getDomElement().toString();
+            if (domStatement.contains("import")) {
+                includedModules.add(childStatement.getDomElement().getValue());
+            }
+        });
+        return includedModules;
+    }
+
+    private YangDeviceModel extractYangData() {
+        YangDeviceModel yangDeviceModel = new YangDeviceModel("r1");
+        final List<YangModel> yangModelInputs = new ArrayList<>();
+        try {
+            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(this.getClass().getClassLoader());
+            Resource[] yangResources = resolver.getResources(yangModelDirectory + "/*.yang");
+            for (Resource yangResource : yangResources) {
+                yangModelInputs.add(new YangModel(new ByteArrayYangInput(yangResource.getContentAsByteArray(), Objects
+                        .requireNonNull(yangResource.getFilename())), ConformanceType.IMPORT));
+            }
+        } catch (final IOException ex) {
+            throw PgSchemaGeneratorException.extractYangDataException(ex);
+        }
+
+        final ModifyableFindingSeverityCalculator severityCalculator = new ModifyableFindingSeverityCalculator();
+        final FindingsManager findingsManager = new FindingsManager(severityCalculator);
+        final ParserExecutionContext context = new ParserExecutionContext(findingsManager);
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+        context.setFailFast(false);
+        yangDeviceModel.parseIntoYangModels(context, yangModelInputs);
+        return yangDeviceModel;
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/BackwardCompatibilityChecker.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/BackwardCompatibilityChecker.java
new file mode 100644
index 0000000..0b310bf
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/BackwardCompatibilityChecker.java
@@ -0,0 +1,138 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema;
+
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.ForeignKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.PgSchemaGeneratorException;
+import org.oran.smo.teiv.pgsqlgenerator.PostgresConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Optional;
+
+@Slf4j
+@Component
+public class BackwardCompatibilityChecker {
+
+    @Value("${green-field-installation}")
+    private boolean isGreenFieldInstallation;
+
+    public void checkForNBCChangesInModel(List<Relationship> relationshipsInBaselineSql,
+            List<Relationship> relationshipsFromModelSvc) {
+        if (!isGreenFieldInstallation) {
+            relationshipsInBaselineSql.forEach(baselineRel -> {
+                Optional<Relationship> matchingRelationship = relationshipsFromModelSvc.stream().filter(rel -> rel.getName()
+                        .equals(baselineRel.getName())).findFirst();
+                matchingRelationship.ifPresentOrElse(modelSvcRel -> {
+                    if (!(baselineRel.getBSideMinCardinality() == modelSvcRel.getBSideMinCardinality() && baselineRel
+                            .getBSideMaxCardinality() == modelSvcRel.getBSideMaxCardinality() && baselineRel
+                                    .getASideMinCardinality() == modelSvcRel.getASideMinCardinality() && baselineRel
+                                            .getASideMaxCardinality() == modelSvcRel.getASideMaxCardinality())) {
+                        throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                                "modified cardinalities for relationship(%s)", baselineRel.getName()),
+                                new UnsupportedOperationException());
+                    }
+                }, () -> {
+                    throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                            "modified/removed relationship(%s) present in baseline", baselineRel.getName()),
+                            new UnsupportedOperationException());
+                });
+            });
+        } else {
+            log.info("No NBC checks done as green field installation is enabled");
+        }
+    }
+
+    public void checkForNBCChangesInData(List<Table> tablesInBaselineSql, List<Table> tablesFromModelSvc) {
+        if (!isGreenFieldInstallation) {
+            tablesInBaselineSql.forEach(baselineTable -> {
+                Optional<Table> matchingTable = tablesFromModelSvc.stream().filter(modelTable -> modelTable.getName()
+                        .equals(baselineTable.getName())).findFirst();
+                matchingTable.ifPresentOrElse(table -> {
+                    verifyTableColumns(baselineTable.getColumns(), table.getColumns(), table.getName());
+                }, () -> {
+                    throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                            "modified/removed table(%s) present in baseline", baselineTable.getName()),
+                            new UnsupportedOperationException());
+                });
+            });
+        } else {
+            log.info("No NBC checks done as green field installation is enabled");
+        }
+    }
+
+    private void verifyTableColumns(List<Column> columnsInBaseline, List<Column> columnsInModelSvc, String tableName) {
+        columnsInBaseline.forEach(baselineColumn -> {
+            Optional<Column> matchingColumn = columnsInModelSvc.stream().filter(modelColumn -> modelColumn.getName().equals(
+                    baselineColumn.getName())).findFirst();
+            matchingColumn.ifPresentOrElse(modelColumn -> {
+                validateColumnConstraints(baselineColumn, modelColumn, tableName);
+                validateColumnDataType(baselineColumn, modelColumn, tableName);
+            }, () -> {
+                throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                        "modified/removed column(%s.%s) present in baseline", tableName, baselineColumn.getName()),
+                        new UnsupportedOperationException());
+            });
+        });
+    }
+
+    private void validateColumnConstraints(Column baselineColumn, Column modelColumn, String tableName) {
+        for (PostgresConstraint constraint : baselineColumn.getPostgresConstraints()) {
+            Optional<PostgresConstraint> matchingConstraint = modelColumn.getPostgresConstraints().stream().filter(
+                    constraint1 -> constraint1.getConstraintName().equals(constraint.getConstraintName())).findFirst();
+
+            matchingConstraint.ifPresentOrElse(constraint1 -> {
+                if (!constraint.getTableToAddConstraintTo().equals(constraint1.getTableToAddConstraintTo()) && !constraint
+                        .getColumnToAddConstraintTo().equals(constraint1.getColumnToAddConstraintTo()) && !constraint
+                                .getConstraintName().equals(constraint1.getConstraintName())) {
+                    throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                            "modified/removed constraint for column(%s.%s) present in baseline", tableName, baselineColumn
+                                    .getName()), new UnsupportedOperationException());
+                }
+                if (constraint instanceof ForeignKeyConstraint && !constraint.getTableToAddConstraintTo().equals(constraint1
+                        .getTableToAddConstraintTo())) {
+                    throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                            "modified/removed constraint for column(%s.%s) present in baseline", tableName, baselineColumn
+                                    .getName()), new UnsupportedOperationException());
+                }
+            }, () -> {
+                throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                        "modified/removed constraint for column(%s.%s) present in baseline", tableName, baselineColumn
+                                .getName()), new UnsupportedOperationException());
+            });
+        }
+    }
+
+    private void validateColumnDataType(Column baselineColumn, Column modelColumn, String tableName) {
+        if (!baselineColumn.getDataType().equals(modelColumn.getDataType())) {
+            throw PgSchemaGeneratorException.nbcChangeIdentifiedException(String.format(
+                    "modified/removed datatype for column(%s.%s) present in baseline", tableName, baselineColumn.getName()),
+                    new UnsupportedOperationException());
+        }
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaGenerator.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaGenerator.java
new file mode 100644
index 0000000..7487d2c
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaGenerator.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema;
+
+import static org.apache.commons.lang3.StringUtils.isEmpty;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.springframework.util.Assert;
+
+import org.oran.smo.teiv.pgsqlgenerator.Entity;
+import org.oran.smo.teiv.pgsqlgenerator.Module;
+import org.oran.smo.teiv.pgsqlgenerator.PgSchemaGeneratorException;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public abstract class SchemaGenerator {
+    protected File schema;
+    protected String sqlStatements;
+
+    /**
+     * Template for generating the schema
+     */
+    public final void generate(List<Module> modules, List<Entity> entities, List<Relationship> relationships) {
+        prepareSchema();
+        setSqlStatements(modules, entities, relationships);
+        writeSqlStatementsToSchema();
+    }
+
+    protected abstract void prepareSchema();
+
+    protected abstract void setSqlStatements(List<Module> modules, List<Entity> entities, List<Relationship> relationships);
+
+    private void writeSqlStatementsToSchema() {
+        if (!isEmpty(sqlStatements)) {
+            Assert.notNull(schema, "Schema file is null");
+            try (FileOutputStream outputStream = new FileOutputStream(schema, true)) {
+                byte[] strToBytes = sqlStatements.getBytes(StandardCharsets.UTF_8);
+                outputStream.write(strToBytes);
+            } catch (IOException exception) {
+                if (schema.getName().endsWith("data.sql")) {
+                    throw PgSchemaGeneratorException.writeGeneratedSchemaException("ties.data", exception);
+                } else {
+                    throw PgSchemaGeneratorException.writeGeneratedSchemaException("ties.model", exception);
+                }
+            }
+        } else {
+            log.warn("No SQL statements to write to schema");
+        }
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaParser.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaParser.java
new file mode 100644
index 0000000..a51fe1e
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaParser.java
@@ -0,0 +1,221 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.ALTER;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.PostgresConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.ForeignKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.NotNullConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.PgSchemaGeneratorException;
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.UniqueConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+
+import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Extracts entities and Columns from a baseline schema chart file. The extracted data is stored as a list of entities
+ * containing their respective
+ * Columns.
+ */
+@Slf4j
+@UtilityClass
+public class SchemaParser {
+
+    /**
+     * Extracts data from model.sql baseline schema chart file.
+     *
+     * @return List of identified entities with their respective Columns
+     */
+    public static List<Relationship> extractFromModelBaseline(String filePath) {
+        List<Relationship> identifiedRelationships = new ArrayList<>();
+        File baseline = new File(filePath);
+
+        if (baseline.exists()) {
+            try (BufferedReader br = new BufferedReader(new FileReader(baseline, StandardCharsets.UTF_8))) {
+                String line;
+                while ((line = br.readLine()) != null) {
+                    line = line.trim();
+                    if (line.startsWith("COPY ties_model.relationship_info") && !line.startsWith("\\.")) {
+                        line = br.readLine();
+                        List<String> relData = Arrays.asList(line.replace("\"", "").split("\\s+"));
+                        identifiedRelationships.add(Relationship.builder().name(relData.get(0)).aSideAssociationName(relData
+                                .get(1)).aSideMOType(relData.get(2)).aSideMinCardinality(Long.parseLong(relData.get(3)))
+                                .aSideMaxCardinality(Long.parseLong(relData.get(4))).bSideAssociationName(relData.get(5))
+                                .bSideMOType(relData.get(6)).bSideMinCardinality(Long.parseLong(relData.get(7)))
+                                .bSideMaxCardinality(Long.parseLong(relData.get(8))).associationKind(relData.get(9))
+                                .relationshipDataLocation(relData.get(10)).connectSameEntity(Boolean.parseBoolean(relData
+                                        .get(11))).moduleReferenceName(relData.get(12)).build());
+                    }
+                }
+            } catch (IOException exception) {
+                throw PgSchemaGeneratorException.readBaselineException("ties.data", exception);
+            }
+        }
+        return identifiedRelationships;
+    }
+
+    /**
+     * Extracts data from data.sql baseline schema chart file.
+     *
+     * @return List of identified entities with their respective Columns
+     */
+    public static List<Table> extractDataFromBaseline(String filePath) {
+        List<Table> identifiedTables = new ArrayList<>();
+        File baseline = new File(filePath);
+
+        if (baseline.exists()) {
+            try (BufferedReader br = new BufferedReader(new FileReader(baseline, StandardCharsets.UTF_8))) {
+                String line;
+                while ((line = br.readLine()) != null) {
+                    line = line.trim();
+                    if (line.contains("ALTER TABLE ONLY") && line.contains("SET DEFAULT")) {
+                        extractDefaultValueFromBaseline(line, identifiedTables);
+                    } else if ((line.contains("CREATE TABLE") || line.contains("ALTER TABLE")) && !line.startsWith("'")) {
+                        extractTableColumns(line, identifiedTables, br);
+                    } else if (line.contains("SELECT") && line.contains("ties_data.create_constraint_if_not_exists")) {
+                        extractConstraints(identifiedTables, br);
+                    }
+                }
+            } catch (IOException exception) {
+                throw PgSchemaGeneratorException.readBaselineException("ties.data", exception);
+            }
+        }
+        return identifiedTables;
+    }
+
+    private static void extractConstraints(List<org.oran.smo.teiv.pgsqlgenerator.Table> identifiedTables, BufferedReader br)
+            throws IOException {
+
+        String tableToAddConstraintTo = br.readLine().trim().replace(",", "").replace("'", "");
+        String constraintName = br.readLine().trim().replace(",", "").replace("'", "");
+
+        String alterStatement = br.readLine();
+        String columnToAddForeignKeyTo = StringUtils.substringBetween(alterStatement, "(", ")").replace("\"", "");
+        String[] stringInQuotes = StringUtils.substringsBetween(alterStatement, "\"", "\"");
+        String referenceTable = stringInQuotes[stringInQuotes.length - 1];
+
+        identifiedTables.stream().filter(table -> table.getName().equals(tableToAddConstraintTo)).findFirst().flatMap(
+                table -> table.getColumns().stream().filter(column -> column.getName().equals(columnToAddForeignKeyTo))
+                        .findFirst()).ifPresent(column -> {
+                            Collection<PostgresConstraint> postgresConstraintCollection = new ArrayList<>();
+                            if (column.getPostgresConstraints() != null) {
+                                postgresConstraintCollection.addAll(column.getPostgresConstraints());
+                            }
+                            if (alterStatement.contains("UNIQUE")) {
+                                postgresConstraintCollection.add(UniqueConstraint.builder().constraintName(constraintName)
+                                        .tableName(tableToAddConstraintTo).columnToAddConstraintTo(columnToAddForeignKeyTo)
+                                        .build());
+                            } else if (alterStatement.contains("PRIMARY KEY")) {
+                                postgresConstraintCollection.add(PrimaryKeyConstraint.builder().constraintName(
+                                        constraintName).tableName(tableToAddConstraintTo).columnToAddConstraintTo(
+                                                columnToAddForeignKeyTo).build());
+                            } else if (alterStatement.contains("NOT NULL")) {
+                                postgresConstraintCollection.add(NotNullConstraint.builder().constraintName(constraintName)
+                                        .tableName(tableToAddConstraintTo).columnToAddConstraintTo(columnToAddForeignKeyTo)
+                                        .build());
+                            } else if (alterStatement.contains("FOREIGN KEY")) {
+                                postgresConstraintCollection.add(ForeignKeyConstraint.builder().constraintName(
+                                        constraintName).tableName(tableToAddConstraintTo).columnToAddConstraintTo(
+                                                columnToAddForeignKeyTo).referencedTable(referenceTable).build());
+                            }
+                            column.setPostgresConstraints(postgresConstraintCollection);
+                        });
+
+    }
+
+    private static void extractDefaultValueFromBaseline(String line,
+            List<org.oran.smo.teiv.pgsqlgenerator.Table> identifiedTables) {
+        String[] valuesInQuotes = StringUtils.substringsBetween(line, "\"", "\"");
+
+        identifiedTables.forEach(table -> {
+            if (table.getName().equals(valuesInQuotes[0])) {
+                table.getColumns().forEach(column -> {
+                    if (column.getName().equals(valuesInQuotes[1])) {
+                        String[] defaultValueFromBaseline = StringUtils.substringsBetween(line, "'", "'");
+                        column.setDefaultValue(defaultValueFromBaseline[0]);
+                    }
+                });
+            }
+        });
+    }
+
+    private static void extractTableColumns(String line, List<org.oran.smo.teiv.pgsqlgenerator.Table> identifiedTables,
+            BufferedReader br) throws IOException {
+        String[] tableName = line.split("\"");
+        List<Column> identifiedColumns = new ArrayList<>();
+
+        if (line.contains("ADD COLUMN")) {
+            extractColumnsFromAlterStatements(line, identifiedTables);
+        } else {
+            extractColumnsFromCreateTable(tableName[1], identifiedTables, br, identifiedColumns);
+        }
+    }
+
+    private static void extractColumnsFromAlterStatements(String line,
+            List<org.oran.smo.teiv.pgsqlgenerator.Table> identifiedTables) {
+        line = line.replace(";", "");
+        for (String str : line.split("ADD COLUMN")) {
+            str = str.trim();
+            String[] arr = StringUtils.substringsBetween(line, "\"", "\"");
+            final String finalStr = str;
+            identifiedTables.forEach(table -> {
+                if (table.getName().equals(arr[0]) && !finalStr.contains(ALTER)) {
+                    table.getColumns().add(Column.builder().name(arr[1]).dataType(finalStr.substring(finalStr.lastIndexOf(
+                            " ") + 1)).build());
+                }
+            });
+        }
+    }
+
+    private static void extractColumnsFromCreateTable(String entityName,
+            List<org.oran.smo.teiv.pgsqlgenerator.Table> identifiedTables, BufferedReader br,
+            List<Column> identifiedColumns) throws IOException {
+        String line = br.readLine();
+        while (!line.contains(");")) {
+            line = line.replace(",", "");
+            List<String> column = Arrays.asList(line.split("\\s+"));
+            String columnName = column.get(1).replace("\"", "");
+            String dataType = column.get(2).replace("\"", "");
+            // constraints are added later
+            identifiedColumns.add(Column.builder().name(columnName).dataType(dataType).build());
+            line = br.readLine();
+        }
+        identifiedTables.add(Table.builder().name(entityName).columns(identifiedColumns).build());
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/Table.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/Table.java
new file mode 100644
index 0000000..af47e3d
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/Table.java
@@ -0,0 +1,49 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema;
+
+public interface Table {
+
+    /**
+     * Gets table name.
+     * Table name should match the CREATE statement in skeleton schema.
+     *
+     * @return the table name
+     */
+    String getTableName();
+
+    /**
+     * Gets columns for copy statement.
+     * Column names should match the CREATE statement in skeleton schema.
+     * It should adhere to syntax: "(\"column1\", \"column2\", ...)".
+     *
+     * @return the columns for copy statement
+     */
+    String getColumnsForCopyStatement();
+
+    /**
+     * Gets record for copy statement.
+     * Each tuple in the record should be separated by tab space and ends with a "\n".
+     *
+     * @return the record for copy statement
+     */
+    String getRecordForCopyStatement();
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaGenerator.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaGenerator.java
new file mode 100644
index 0000000..81845ca
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaGenerator.java
@@ -0,0 +1,109 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.BackwardCompatibilityChecker;
+import org.oran.smo.teiv.pgsqlgenerator.schema.SchemaParser;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.pgsqlgenerator.Entity;
+import org.oran.smo.teiv.pgsqlgenerator.Module;
+import org.oran.smo.teiv.pgsqlgenerator.PgSchemaGeneratorException;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.schema.SchemaGenerator;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class DataSchemaGenerator extends SchemaGenerator {
+    @Value("${schema.data.baseline}")
+    private String baselineDataSchema;
+    @Value("${schema.data.output}")
+    private String dataSchemaFileName;
+    @Value("${schema.data.skeleton}")
+    private String skeletonDataSchema;
+    @Value("${green-field-installation}")
+    private boolean isGreenFieldInstallation;
+
+    private final ModelComparator modelComparator;
+    private final DataSchemaHelper dataSchemaHelper;
+    private final TableBuilder tableBuilder;
+    private final BackwardCompatibilityChecker backwardCompatibilityChecker;
+
+    @Override
+    protected void prepareSchema() {
+        try {
+            File baselineDataSchemaFile = new File(baselineDataSchema);
+            File newDataSchema = new File(dataSchemaFileName);
+            if (isGreenFieldInstallation || !baselineDataSchemaFile.exists()) {
+                log.info("Baseline DOES NOT EXISTS!!");
+                File skeletonSql = new ClassPathResource(skeletonDataSchema).getFile();
+                Files.copy(skeletonSql.toPath(), newDataSchema.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            } else {
+                log.info("Baseline EXISTS!!");
+                Path sourcePath = baselineDataSchemaFile.toPath();
+                List<String> stmts = Files.readAllLines(sourcePath);
+                List<String> commitExcludedStmts = stmts.stream().filter(line -> !line.equals("COMMIT;")).toList();
+
+                Files.write(Paths.get(dataSchemaFileName), commitExcludedStmts, StandardOpenOption.CREATE,
+                        StandardOpenOption.TRUNCATE_EXISTING);
+            }
+            this.schema = newDataSchema;
+        } catch (IOException exception) {
+            throw PgSchemaGeneratorException.prepareBaselineException("ties.data", exception);
+        }
+    }
+
+    @Override
+    protected void setSqlStatements(List<Module> modules, List<Entity> entities, List<Relationship> relationships) {
+        // Create table from entities and relationships
+        List<Table> tablesFromModelSvc = tableBuilder.getTables(entities, relationships);
+        // Get tables from baseline sql
+        List<Table> tablesFromBaselineSql = isGreenFieldInstallation ?
+                List.of() :
+                SchemaParser.extractDataFromBaseline(baselineDataSchema);
+        // Check for NBCs
+        backwardCompatibilityChecker.checkForNBCChangesInData(tablesFromBaselineSql, tablesFromModelSvc);
+        // Compare and store differences in tables from baseline sql with tables from model service
+        Map<String, List<Table>> differences = modelComparator.identifyDifferencesInBaselineAndGenerated(tablesFromModelSvc,
+                tablesFromBaselineSql);
+        // Generate schema from differences
+        StringBuilder generatedSchema = dataSchemaHelper.generateSchemaFromDifferences(differences);
+        generatedSchema.append("\nCOMMIT;\n");
+        this.sqlStatements = generatedSchema.toString();
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaHelper.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaHelper.java
new file mode 100644
index 0000000..ca29e4c
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaHelper.java
@@ -0,0 +1,242 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.PostgresConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.ForeignKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.NotNullConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.UniqueConstraint;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.CREATE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.ALTER;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.ALTER_TABLE_TIES_DATA_S_ADD_CONSTRAINT_S;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.ID;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.ALTER_TABLE_TIES_DATA_S;
+
+@Slf4j
+@Component
+public class DataSchemaHelper {
+
+    /**
+     * Generates SQL statements for schema alterations based on identified changes.
+     *
+     * @param differences
+     *     Map of identified changes to models
+     * @return StringBuilder containing SQL statements
+     */
+    public StringBuilder generateSchemaFromDifferences(Map<String, List<Table>> differences) {
+        StringBuilder generatedSchema = new StringBuilder();
+        if (differences.isEmpty()) {
+            log.info("No differences identified!!");
+        } else {
+            for (Map.Entry<String, List<Table>> entry : differences.entrySet()) {
+                switch (entry.getKey()) {
+                    case CREATE -> generatedSchema.append(generateCreateStatementsFromDifferences(entry.getValue()));
+                    case ALTER -> generatedSchema.append(generateAlterStatementsFromDifferences(entry.getValue()));
+                    default -> generatedSchema.append(generateDefaultStatementsFromDifferences(entry.getValue()));
+                }
+            }
+        }
+        return generatedSchema;
+    }
+
+    /**
+     * Generates SQL statements for CREATE TABLE from differences.
+     */
+    private StringBuilder generateCreateStatementsFromDifferences(List<Table> tables) {
+        StringBuilder storeSchemaForCreateStatements = new StringBuilder();
+        StringBuilder storeAlterStatementsForPrimaryKeyConstraints = new StringBuilder();
+        StringBuilder storeAlterStatementsForAllOtherConstraints = new StringBuilder();
+        for (Table table : tables) {
+            storeAlterStatementsForPrimaryKeyConstraints.append(generateAlterStatementsForPrimaryKeyConstraints(table
+                    .getColumns()));
+            storeAlterStatementsForAllOtherConstraints.append(generateAlterStatementsForAllOtherConstraints(table
+                    .getColumns()));
+            storeSchemaForCreateStatements.append(generateCreateTableStatements(table.getColumns(), table.getName()));
+        }
+        storeSchemaForCreateStatements.append(storeAlterStatementsForPrimaryKeyConstraints).append(
+                storeAlterStatementsForAllOtherConstraints);
+        return storeSchemaForCreateStatements;
+    }
+
+    /**
+     * Generates SQL statements for creating new tables.
+     */
+    private StringBuilder generateCreateTableStatements(List<Column> newColumns, String tableName) {
+
+        StringBuilder storeTableSchema = new StringBuilder(String.format("CREATE TABLE IF NOT EXISTS ties_data.\"%s\" (%n",
+                tableName));
+        StringBuilder storeColumns = new StringBuilder();
+        StringBuilder storeDefaultValues = new StringBuilder();
+
+        for (Column newColumn : newColumns) {
+            if (newColumn.getDefaultValue() != null) {
+                storeDefaultValues.append(generateDefaultValueStatements(newColumn, tableName));
+            }
+            // id column must come in the top of the table
+            if (newColumn.getName().equals(ID)) {
+                storeTableSchema.append(String.format("\t\"%s\"\t\t\t%s,%n", newColumn.getName(), newColumn.getDataType()));
+            } else {
+                storeColumns.append(generateCreateColumnStatements(newColumn));
+            }
+        }
+        storeColumns.deleteCharAt(storeColumns.lastIndexOf(","));
+        storeTableSchema.append(storeColumns).append(");\n\n");
+        return storeTableSchema.append(storeDefaultValues);
+    }
+
+    /**
+     * Generate CREATE sql statements for columns who have no constraints, default value or enums defined.
+     */
+    private StringBuilder generateCreateColumnStatements(Column newColumn) {
+        return new StringBuilder(String.format("\t\"%s\"\t\t\t%s,%n", newColumn.getName(), newColumn.getDataType()));
+    }
+
+    /**
+     * Generate ALTER sql statements for attributes with default values.
+     */
+    private StringBuilder generateDefaultValueStatements(Column newColumn, String tableName) {
+        return new StringBuilder(String.format(
+                "ALTER TABLE ONLY ties_data.\"%s\" ALTER COLUMN \"%s\" SET DEFAULT '%s';%n%n", tableName, newColumn
+                        .getName(), newColumn.getDefaultValue()));
+    }
+
+    /**
+     * Write sql statements for UNIQUE, NOT NULL and FOREIGN KEY constraints.
+     */
+    private StringBuilder generateAlterStatementsForAllOtherConstraints(List<Column> columns) {
+        StringBuilder storeOtherAlterStatements = new StringBuilder();
+
+        columns.stream().flatMap(newColumn -> newColumn.getPostgresConstraints().stream()).filter(
+                constraint -> !(constraint instanceof PrimaryKeyConstraint)).forEach(constraint -> storeOtherAlterStatements
+                        .append(generateConstraintStatement(constraint)));
+
+        return storeOtherAlterStatements;
+    }
+
+    private StringBuilder generateAlterStatementsForPrimaryKeyConstraints(List<Column> columns) {
+        StringBuilder storePKAlterStatements = new StringBuilder();
+
+        columns.stream().flatMap(newColumn -> newColumn.getPostgresConstraints().stream()).filter(
+                PrimaryKeyConstraint.class::isInstance).forEach(constraint -> storePKAlterStatements.append(
+                        generateConstraintStatement(constraint)));
+
+        return storePKAlterStatements;
+    }
+
+    private String generateConstraintStatement(PostgresConstraint postgresConstraint) {
+        String constraintSql = generateConstraintSql(postgresConstraint);
+        return String.format("SELECT ties_data.create_constraint_if_not_exists(%n\t'%s',%n '%s',%n '%s;'%n);%n%n",
+                postgresConstraint.getTableToAddConstraintTo(), postgresConstraint.getConstraintName(), constraintSql);
+    }
+
+    private String generateConstraintSql(PostgresConstraint postgresConstraint) {
+        if (postgresConstraint instanceof PrimaryKeyConstraint) {
+            return String.format(ALTER_TABLE_TIES_DATA_S_ADD_CONSTRAINT_S + "PRIMARY KEY (\"%s\")", postgresConstraint
+                    .getTableToAddConstraintTo(), postgresConstraint.getConstraintName(), postgresConstraint
+                            .getColumnToAddConstraintTo());
+        } else if (postgresConstraint instanceof ForeignKeyConstraint) {
+            return String.format(
+                    ALTER_TABLE_TIES_DATA_S_ADD_CONSTRAINT_S + "FOREIGN KEY (\"%s\") REFERENCES ties_data.\"%s\" (id) ON DELETE CASCADE",
+                    postgresConstraint.getTableToAddConstraintTo(), postgresConstraint.getConstraintName(),
+                    postgresConstraint.getColumnToAddConstraintTo(), ((ForeignKeyConstraint) postgresConstraint)
+                            .getReferencedTable());
+        } else if (postgresConstraint instanceof UniqueConstraint) {
+            return String.format(ALTER_TABLE_TIES_DATA_S_ADD_CONSTRAINT_S + "UNIQUE (\"%s\")", postgresConstraint
+                    .getTableToAddConstraintTo(), postgresConstraint.getConstraintName(), postgresConstraint
+                            .getColumnToAddConstraintTo());
+        } else if (postgresConstraint instanceof NotNullConstraint) {
+            return String.format(ALTER_TABLE_TIES_DATA_S_ADD_CONSTRAINT_S + "NOT NULL (\"%s\")", postgresConstraint
+                    .getTableToAddConstraintTo(), postgresConstraint.getConstraintName(), postgresConstraint
+                            .getColumnToAddConstraintTo());
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Generates SQL statements for ALTER TABLE from mapped entity attributes.
+     */
+    private StringBuilder generateAlterStatementsFromDifferences(List<Table> tables) {
+        StringBuilder storeSchemaForAlterStatements = new StringBuilder();
+        StringBuilder storeAlterStatementsForPrimaryKeyConstraints = new StringBuilder();
+        StringBuilder storeAlterStatementsForAllOtherConstraints = new StringBuilder();
+        for (Table table : tables) {
+            storeSchemaForAlterStatements.append(generateAlterStatements(table.getColumns(), table.getName()));
+            storeAlterStatementsForPrimaryKeyConstraints.append(generateAlterStatementsForPrimaryKeyConstraints(table
+                    .getColumns()));
+            storeAlterStatementsForAllOtherConstraints.append(generateAlterStatementsForAllOtherConstraints(table
+                    .getColumns()));
+        }
+        return storeSchemaForAlterStatements.append(storeAlterStatementsForPrimaryKeyConstraints).append(
+                storeAlterStatementsForAllOtherConstraints);
+    }
+
+    /**
+     * Generates SQL statements for altering tables based on mapped entity attributes.
+     */
+    private StringBuilder generateAlterStatements(List<Column> columns, String tableName) {
+
+        StringBuilder storeSchema = new StringBuilder();
+        for (Column newColumn : columns) {
+            if (newColumn.getName().equals("geo-location")) {
+                newColumn.setDataType("\"geography\"");
+            }
+            storeSchema.append(generateAlterTableStatements(newColumn, tableName));
+        }
+        return storeSchema;
+    }
+
+    /**
+     * Generates ALTER SQL statements to add new default values in newly identified columns.
+     */
+    private StringBuilder generateDefaultStatementsFromDifferences(List<Table> tables) {
+        StringBuilder storeSchemaForDefaultStatements = new StringBuilder();
+        for (Table table : tables) {
+            StringBuilder storeSchema = new StringBuilder();
+            for (Column newColumn : table.getColumns()) {
+                if (newColumn.getDefaultValue() != null) {
+                    storeSchema.append(generateDefaultValueStatements(newColumn, table.getName()));
+                }
+            }
+            storeSchemaForDefaultStatements.append(storeSchema);
+        }
+        return storeSchemaForDefaultStatements;
+    }
+
+    /**
+     * Generate ALTER sql statements for attributes who have no constraints, default value or enums defined.
+     */
+    private StringBuilder generateAlterTableStatements(Column newColumn, String tableName) {
+        return new StringBuilder(String.format(ALTER_TABLE_TIES_DATA_S + "ADD COLUMN IF NOT EXISTS \"%s\" %s;%n%n",
+                tableName, newColumn.getName(), newColumn.getDataType()));
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/ModelComparator.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/ModelComparator.java
new file mode 100644
index 0000000..fa0423d
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/ModelComparator.java
@@ -0,0 +1,164 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.ALTER;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.CREATE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.DEFAULT;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+
+@Component
+public class ModelComparator {
+
+    private Map<String, List<Table>> identifiedChangesToModels;
+
+    /**
+     * Identifies differences between baseline and generated models.
+     *
+     * @param tablesFromModelService
+     *     Model information from Model Service
+     * @param tablesFromBaselineSql
+     *     Model information from the baseline
+     * @return A map with identified changes to models
+     */
+    public Map<String, List<Table>> identifyDifferencesInBaselineAndGenerated(List<Table> tablesFromModelService,
+            List<Table> tablesFromBaselineSql) {
+        //TODO: Throw error if there is table from model service doesn't contain any info in baseline
+        identifiedChangesToModels = identifiedModelChangeMapping();
+
+        List<String> tableNamesOfBaseline = extractTableNames(tablesFromBaselineSql);
+        List<String> tableNameOfModelSvc = extractTableNames(tablesFromModelService);
+
+        if (!tableNameOfModelSvc.equals(tableNamesOfBaseline)) {
+            storeNewTables(tablesFromModelService, tableNamesOfBaseline, tableNameOfModelSvc);
+        }
+        compareAndStoreChangesToColumns(tablesFromModelService, tablesFromBaselineSql);
+
+        return Collections.unmodifiableMap(identifiedChangesToModels);
+    }
+
+    private Map<String, List<Table>> identifiedModelChangeMapping() {
+        Map<String, List<Table>> storeIdentifiedChangesToModels = new HashMap<>();
+        storeIdentifiedChangesToModels.put(CREATE, new ArrayList<>());
+        storeIdentifiedChangesToModels.put(ALTER, new ArrayList<>());
+        storeIdentifiedChangesToModels.put(DEFAULT, new ArrayList<>());
+        return storeIdentifiedChangesToModels;
+    }
+
+    /**
+     * Check if all tables in extracted data from module service are same as what's in baseline schema Store identified with
+     * a "CREATE" key
+     */
+    private void storeNewTables(List<Table> tablesFromModelService, List<String> tableNamesOfBaseline,
+            List<String> tableNameOfGenerated) {
+        List<String> differences = tableNameOfGenerated.stream().filter(element -> !tableNamesOfBaseline.contains(element))
+                .toList();
+        differences.forEach(tableName -> tablesFromModelService.stream().filter(table -> table.getName().equals(tableName))
+                .findFirst().ifPresent(table -> identifiedChangesToModels.get(CREATE).add(Table.builder().name(table
+                        .getName()).columns(table.getColumns()).build())));
+    }
+
+    /**
+     * Compare columns of each table from module service with columns of each table from baseline schema
+     */
+    private void compareAndStoreChangesToColumns(List<Table> tablesFromModelService, List<Table> tablesFromBaselineSql) {
+        tablesFromModelService.forEach(tableFromModelService -> {
+            tablesFromBaselineSql.stream().filter(baselineTable -> tableFromModelService.getName().equals(baselineTable
+                    .getName())).findFirst().ifPresent(baselineTable -> {
+
+                        List<Column> columnsInBaseline = new ArrayList<>(baselineTable.getColumns());
+                        List<Column> columnsFromModuleSvc = new ArrayList<>(tableFromModelService.getColumns());
+
+                        columnsInBaseline.sort(Comparator.comparing(Column::getName));
+                        columnsFromModuleSvc.sort(Comparator.comparing(Column::getName));
+
+                        // Check for new columns in table
+                        if (columnsFromModuleSvc.size() > columnsInBaseline.size()) {
+                            storeNewColumns(tableFromModelService.getName(), columnsInBaseline, columnsFromModuleSvc);
+                        }
+                        detectAndStoreDefaultValueChanges(tableFromModelService.getName(), columnsInBaseline,
+                                columnsFromModuleSvc);
+                    });
+        });
+    }
+
+    private List<String> extractTableNames(List<Table> tables) {
+        return tables.stream().map(Table::getName).sorted().toList();
+    }
+
+    /**
+     * Check if new columns are introduced by comparing data from module service and baseline schema
+     */
+    private void storeNewColumns(String tableName, List<Column> columnsInBaseline, List<Column> columnsFromModuleSvc) {
+        List<Column> newColumns = columnsFromModuleSvc.stream().filter(columnInGenerated -> !getListOfAllColumns(
+                columnsInBaseline).contains(columnInGenerated.getName())).toList();
+        identifiedChangesToModels.get(ALTER).add(Table.builder().name(tableName).columns(newColumns.stream().map(
+                column -> Column.builder().name(column.getName()).dataType(column.getDataType()).postgresConstraints(column
+                        .getPostgresConstraints()).build()).toList()).build());
+        List<Column> columnsWithDefaultValues = newColumns.stream().filter(columnIdentified -> columnIdentified
+                .getDefaultValue() != null).toList();
+        if (!columnsWithDefaultValues.isEmpty()) {
+            identifiedChangesToModels.get(DEFAULT).add(Table.builder().name(tableName).columns(columnsWithDefaultValues)
+                    .build());
+        }
+    }
+
+    /**
+     * Check if default values for all columns in tables from module service are same as what's in baseline schema Store
+     * identified with a "DEFAULT" key
+     */
+    private void detectAndStoreDefaultValueChanges(String tableName, List<Column> columnsInBaseline,
+            List<Column> columnsFromModuleSvc) {
+        List<Column> list = new ArrayList<>();
+        columnsInBaseline.forEach(columnInBaseline -> {
+            columnsFromModuleSvc.forEach(columnInGenerated -> {
+                if (columnInGenerated.getName().equals(columnInBaseline.getName()) && !Objects.equals(columnInGenerated
+                        .getDefaultValue(), columnInBaseline.getDefaultValue())) {
+                    list.add(columnInGenerated);
+                }
+            });
+        });
+        if (!list.isEmpty()) {
+            identifiedChangesToModels.get(DEFAULT).add(Table.builder().name(tableName).columns(list).build());
+        }
+    }
+
+    private List<String> getListOfAllColumns(List<Column> columns) {
+        List<String> allColumns = new ArrayList<>();
+        for (Column col : columns) {
+            allColumns.add(col.getName().replace("\"", ""));
+        }
+        return allColumns;
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/TableBuilder.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/TableBuilder.java
new file mode 100644
index 0000000..ce3f579
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/TableBuilder.java
@@ -0,0 +1,243 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.A_SIDE_PREFIX;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.B_SIDE_PREFIX;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.COLUMN;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.CONSTRAINT;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.CONSUMER_DATA;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.FOREIGN_KEY;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.ID;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.NO_PREFIX;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.PRIMARY_KEY;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.REL_CD;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.REL_FK;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.REL_ID;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.TABLE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.UNIQUE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.VARCHAR511;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.A_SIDE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.B_SIDE;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.RELATION;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.oran.smo.teiv.pgsqlgenerator.ForeignKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.springframework.stereotype.Component;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.Entity;
+import org.oran.smo.teiv.pgsqlgenerator.PostgresConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.UniqueConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.schema.model.HashInfoDataGenerator;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class TableBuilder {
+
+    private final HashInfoDataGenerator hashInfoDataGenerator;
+
+    /**
+     * Generate tables from entities and relationships.
+     *
+     * @param entities
+     *     List of entities from model service
+     * @param relationships
+     *     List of relationships from model service
+     * @return List relationships in the form of tables
+     */
+    public List<Table> getTables(List<Entity> entities, List<Relationship> relationships) {
+        // Create table from entities and relationships
+        Map<String, List<Column>> tableFromMSvc = new HashMap<>();
+
+        entities.forEach(entity -> {
+            String tableName = entity.getEntityName();
+            String hashedTableName = hashInfoDataGenerator.generateHashAndRegisterTableRow(NO_PREFIX, tableName, TABLE);
+            tableFromMSvc.put(hashedTableName, getColumnsByEntity(entity, hashedTableName));
+        });
+
+        relationships.forEach(relationship -> {
+            String tableName = "";
+            switch (relationship.getRelationshipDataLocation()) {
+                case A_SIDE -> tableName = relationship.getASideMOType();
+                case B_SIDE -> tableName = relationship.getBSideMOType();
+                case RELATION -> tableName = relationship.getName();
+                default -> log.error(String.format("Relationship with name %s cannot be mapped", relationship.getName()));
+            }
+            String hashedTableName = hashInfoDataGenerator.generateHashAndRegisterTableRow(NO_PREFIX, tableName, TABLE);
+
+            tableFromMSvc.computeIfAbsent(hashedTableName, k -> new ArrayList<>()).addAll(getColumnsByRelationship(
+                    relationship, tableName, hashedTableName));
+        });
+
+        return tableFromMSvc.entrySet().stream().map(entry -> Table.builder().name(entry.getKey()).columns(entry.getValue())
+                .build()).collect(Collectors.toList());
+    }
+
+    private List<Column> getColumnsByEntity(Entity entity, String hashedTableName) {
+        List<Column> entityCols = new ArrayList<>();
+        entityCols.addAll(entity.getAttributes().stream().map(attribute -> {
+            String attributeName = attribute.getName();
+            String hashedAttributeName = hashInfoDataGenerator.generateHashAndRegisterTableRow(NO_PREFIX, attributeName,
+                    COLUMN);
+            return Column.builder().name(hashedAttributeName).dataType(attribute.getDataType()).postgresConstraints(
+                    getConstraintsForColumn(entity.getEntityName(), hashedTableName, attribute.getConstraints(),
+                            attributeName, hashedAttributeName)).defaultValue(attribute.getDefaultValue()).build();
+        }).toList());
+        entityCols.addAll(entity.getConsumerData().stream().map(cd -> {
+            String hashedAttributeName = hashInfoDataGenerator.generateHashAndRegisterTableRow(CONSUMER_DATA, cd.getName(),
+                    COLUMN);
+            return Column.builder().name(hashedAttributeName).dataType(cd.getDataType()).defaultValue(cd.getDefaultValue())
+                    .build();
+        }).toList());
+        return entityCols;
+    }
+
+    private List<Column> getColumnsByRelationship(Relationship relationship, String tableName, String hashedTableName) {
+        if (relationship.getRelationshipDataLocation().equals(RELATION)) {
+            return createRelationshipColumnsForRelationTables(relationship, tableName, hashedTableName);
+        } else {
+            return createRelationshipColumnsForEntityTables(relationship, tableName, hashedTableName);
+        }
+    }
+
+    private List<Column> createRelationshipColumnsForEntityTables(Relationship rel, String tableName,
+            String hashedTableName) {
+        List<Column> relColumns = new ArrayList<>();
+
+        final String associationEndpointName = tableName.equals(rel.getASideMOType()) ?
+                rel.getASideAssociationName() :
+                rel.getBSideAssociationName();
+        final String relFk = REL_FK + associationEndpointName;
+        final String relId = REL_ID + rel.getName();
+
+        String hashedTableNameASide = hashInfoDataGenerator.generateHashAndRegisterTableRow(NO_PREFIX, rel.getASideMOType(),
+                TABLE);
+        String hashedTableNameBSide = hashInfoDataGenerator.generateHashAndRegisterTableRow(NO_PREFIX, rel.getBSideMOType(),
+                TABLE);
+        final String hashedReferenceTable = tableName.equals(hashedTableNameASide) ?
+                hashedTableNameBSide :
+                hashedTableNameASide;
+        final String hashedRelId = hashInfoDataGenerator.generateHashAndRegisterTableRow(REL_ID, rel.getName(), COLUMN);
+        final String hashedRelFk = hashInfoDataGenerator.generateHashAndRegisterTableRow(REL_FK, associationEndpointName,
+                COLUMN);
+
+        relColumns.add(Column.builder().name(hashedRelFk).dataType(VARCHAR511).postgresConstraints(new ArrayList<>(List.of(
+                createForeignKeyConstraints(tableName, hashedTableName, hashedReferenceTable, relFk, hashedRelFk))))
+                .build());
+
+        relColumns.add(Column.builder().name(hashedRelId).dataType(VARCHAR511).postgresConstraints(new ArrayList<>(List.of(
+                createUniqueConstraints(tableName, hashedTableName, relId, hashedRelId)))).build());
+        rel.getConsumerData().forEach(cd -> {
+            final String cdColumnName = hashInfoDataGenerator.generateHashAndRegisterTableRow(REL_CD, cd
+                    .getName() + "_" + rel.getName(), COLUMN);
+            relColumns.add(Column.builder().name(cdColumnName).dataType(cd.getDataType()).defaultValue(cd.getDefaultValue())
+                    .build());
+        });
+        return relColumns;
+    }
+
+    private List<Column> createRelationshipColumnsForRelationTables(Relationship rel, String tableName,
+            String hashedTableName) {
+
+        String hashedASideMOType = hashInfoDataGenerator.generateHashAndRegisterTableRow(NO_PREFIX, rel.getASideMOType(),
+                TABLE);
+        String hashedBSideMOType = hashInfoDataGenerator.generateHashAndRegisterTableRow(NO_PREFIX, rel.getBSideMOType(),
+                TABLE);
+
+        final String relASide = A_SIDE_PREFIX + rel.getASideMOType();
+        final String hashedRelASide = hashInfoDataGenerator.generateHashAndRegisterTableRow(A_SIDE_PREFIX, rel
+                .getASideMOType(), COLUMN);
+        final String relBSide = B_SIDE_PREFIX + rel.getBSideMOType();
+        final String hashedRelBSide = hashInfoDataGenerator.generateHashAndRegisterTableRow(B_SIDE_PREFIX, rel
+                .getBSideMOType(), COLUMN);
+        List<Column> relColumns = new ArrayList<>(Arrays.asList(Column.builder().name(ID).dataType(VARCHAR511)
+                .postgresConstraints(new ArrayList<>(List.of(createPrimaryKeyConstraints(tableName, hashedTableName, ID))))
+                .build(), Column.builder().name(hashedRelASide).dataType(VARCHAR511).postgresConstraints(new ArrayList<>(
+                        List.of(createForeignKeyConstraints(tableName, hashedTableName, hashedASideMOType, relASide,
+                                hashedRelASide)))).build(), Column.builder().name(hashedRelBSide).dataType(VARCHAR511)
+                                        .postgresConstraints(new ArrayList<>(List.of(createForeignKeyConstraints(tableName,
+                                                hashedTableName, hashedBSideMOType, relBSide, hashedRelBSide)))).build()));
+        rel.getConsumerData().forEach(cd -> {
+            final String columnName = hashInfoDataGenerator.generateHashAndRegisterTableRow(CONSUMER_DATA, cd.getName(),
+                    COLUMN);
+            relColumns.add(Column.builder().name(columnName).dataType(cd.getDataType()).defaultValue(cd.getDefaultValue())
+                    .build());
+        });
+        return relColumns;
+    }
+
+    private Collection<PostgresConstraint> getConstraintsForColumn(String tableName, String hashedTableName,
+            Collection<Object> constraintsFromEModel, String attributeName, String hashedAttributeName) {
+        Collection<PostgresConstraint> postgresConstraintCollection = new ArrayList<>();
+        if (constraintsFromEModel != null) {
+            if (constraintsFromEModel.stream().anyMatch(PrimaryKeyConstraint.class::isInstance)) {
+                if (attributeName.equals(ID)) {
+                    postgresConstraintCollection.add(createPrimaryKeyConstraints(tableName, hashedTableName,
+                            attributeName));
+                }
+            }
+            //            if (constraintsFromEModel.stream().anyMatch(<any-other-constraint>.class::isInstance)) {
+            //                postgresConstraintCollection.add(createUniqueConstraints(tableName, hashedTableName, attributeName,
+            //                        hashedAttributeName));
+            //            }
+        }
+        return postgresConstraintCollection;
+    }
+
+    private PostgresConstraint createForeignKeyConstraints(String tableToAddForeignKeyTo,
+            String hashedTableToAddForeignKeyTo, String hashedReferenceTable, String columnName, String hashedColumnName) {
+        String constraintName = hashInfoDataGenerator.generateHashAndRegisterTableRow(FOREIGN_KEY,
+                tableToAddForeignKeyTo + "_" + columnName, CONSTRAINT);
+        return ForeignKeyConstraint.builder().constraintName(constraintName).tableName(hashedTableToAddForeignKeyTo)
+                .referencedTable(hashedReferenceTable).columnToAddConstraintTo(hashedColumnName).build();
+    }
+
+    private PostgresConstraint createPrimaryKeyConstraints(String tableName, String hashedTableName, String columnName) {
+        String constraintName = hashInfoDataGenerator.generateHashAndRegisterTableRow(PRIMARY_KEY,
+                tableName + "_" + columnName, CONSTRAINT);
+        return PrimaryKeyConstraint.builder().constraintName(constraintName).tableName(hashedTableName)
+                .columnToAddConstraintTo(columnName).build();
+    }
+
+    private PostgresConstraint createUniqueConstraints(String tableName, String hashedTableName, String columnName,
+            String hashedColumnName) {
+        String constraintName = hashInfoDataGenerator.generateHashAndRegisterTableRow(UNIQUE, tableName + "_" + columnName,
+                CONSTRAINT);
+        return UniqueConstraint.builder().constraintName(constraintName).tableName(hashedTableName).columnToAddConstraintTo(
+                hashedColumnName).build();
+    }
+
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/HashInfoDataGenerator.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/HashInfoDataGenerator.java
new file mode 100644
index 0000000..771baee
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/HashInfoDataGenerator.java
@@ -0,0 +1,83 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.model;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.oran.smo.teiv.pgsqlgenerator.HashInfoEntity;
+import org.oran.smo.teiv.pgsqlgenerator.PgSchemaGeneratorException;
+import org.springframework.stereotype.Component;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Getter
+@Slf4j
+public class HashInfoDataGenerator {
+
+    private final Set<HashInfoEntity> hashInfoRowsList = new HashSet<>();
+
+    /**
+     * Generates a hash_info table entry for any table, column or constraint name passed and adds it to the hash_info data.
+     *
+     * @param prefix
+     *     Any prefix if applicable for the entry
+     * @param name
+     *     Actual name of table, column or constraint generated from model service
+     * @param type
+     *     Type of entry table, column or constraint
+     * @return Returns the generated name of table or column
+     */
+    public String generateHashAndRegisterTableRow(String prefix, String name, String type) {
+        String hashedValue;
+        if (prefix.length() + name.length() < 64) {
+            hashInfoRowsList.add(HashInfoEntity.builder().name(prefix + name).hashedValue(prefix + name).type(type)
+                    .build());
+            return prefix + name;
+        } else {
+            hashedValue = generateSHA1Hash(prefix + name);
+            hashInfoRowsList.add(HashInfoEntity.builder().name(prefix + name).hashedValue(prefix + hashedValue).type(type)
+                    .build());
+            return prefix + hashedValue;
+        }
+    }
+
+    private String generateSHA1Hash(String input) {
+        String hashedResult = "";
+        try {
+            MessageDigest md = MessageDigest.getInstance("SHA-1");
+            md.update(input.getBytes(StandardCharsets.UTF_8));
+            byte[] digest = md.digest();
+            hashedResult = DatatypeConverter.printHexBinary(digest).toUpperCase(Locale.US);
+        } catch (NoSuchAlgorithmException exception) {
+            throw PgSchemaGeneratorException.generateSHA1HashException(exception);
+        }
+        return hashedResult;
+    }
+}
diff --git a/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/ModelSchemaGenerator.java b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/ModelSchemaGenerator.java
new file mode 100644
index 0000000..10eb426
--- /dev/null
+++ b/pgsql-schema-generator/src/main/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/ModelSchemaGenerator.java
@@ -0,0 +1,107 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.model;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.BackwardCompatibilityChecker;
+import org.oran.smo.teiv.pgsqlgenerator.schema.SchemaParser;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ResourceUtils;
+
+import org.oran.smo.teiv.pgsqlgenerator.Entity;
+import org.oran.smo.teiv.pgsqlgenerator.Module;
+import org.oran.smo.teiv.pgsqlgenerator.PgSchemaGeneratorException;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+import org.oran.smo.teiv.pgsqlgenerator.schema.SchemaGenerator;
+import org.oran.smo.teiv.pgsqlgenerator.schema.Table;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class ModelSchemaGenerator extends SchemaGenerator {
+    @Value("${schema.model.output}")
+    private String modelOutputFileName;
+    @Value("${schema.model.skeleton}")
+    private String skeletonModelSchemaFileClassPath;
+    @Value("${schema.model.baseline}")
+    private String baselineModelSchemaFileClassPath;
+    @Value("${schema.model.temp-baseline}")
+    private String tempBaselineModelSchemaFileClassPath;
+    @Value("${green-field-installation}")
+    private boolean isGreenFieldInstallation;
+
+    private final HashInfoDataGenerator hashInfoDataGenerator;
+    private final BackwardCompatibilityChecker backwardCompatibilityChecker;
+
+    @Override
+    protected void prepareSchema() {
+        try {
+            File skeletonFile = ResourceUtils.getFile("classpath:" + skeletonModelSchemaFileClassPath);
+            File newGeneratedModelFile = new File(modelOutputFileName);
+            Files.copy(skeletonFile.toPath(), newGeneratedModelFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            if (!isGreenFieldInstallation) {
+                File helmBaseline = ResourceUtils.getFile(baselineModelSchemaFileClassPath);
+                File modelBaseline = new File(tempBaselineModelSchemaFileClassPath);
+                Files.copy(helmBaseline.toPath(), modelBaseline.toPath(), StandardCopyOption.REPLACE_EXISTING);
+            }
+            this.schema = newGeneratedModelFile;
+        } catch (IOException exception) {
+            throw PgSchemaGeneratorException.prepareBaselineException("ties.model", exception);
+        }
+    }
+
+    @Override
+    protected void setSqlStatements(List<Module> modules, List<Entity> entities, List<Relationship> relationships) {
+        if (!isGreenFieldInstallation) {
+            // Get relationships from baseline sql
+            List<Relationship> relFromBaselineSql = SchemaParser.extractFromModelBaseline(
+                    tempBaselineModelSchemaFileClassPath);
+            // Check for NBCs
+            backwardCompatibilityChecker.checkForNBCChangesInModel(relFromBaselineSql, relationships);
+        }
+        StringBuilder tiesModelSql = new StringBuilder();
+        tiesModelSql.append(prepareCopyStatement(hashInfoDataGenerator.getHashInfoRowsList().stream().toList()));
+        tiesModelSql.append(prepareCopyStatement(modules));
+        tiesModelSql.append(prepareCopyStatement(entities));
+        tiesModelSql.append(prepareCopyStatement(relationships));
+        tiesModelSql.append(";\n").append("\nCOMMIT;");
+        this.sqlStatements = tiesModelSql.toString();
+    }
+
+    private StringBuilder prepareCopyStatement(List<? extends Table> table) {
+        StringBuilder copyStatement = new StringBuilder();
+        if (!table.isEmpty()) {
+            copyStatement.append("COPY ties_model.").append(table.get(0).getTableName()).append(table.get(0)
+                    .getColumnsForCopyStatement()).append(" FROM stdin;\n");
+            table.forEach(table1 -> copyStatement.append(table1.getRecordForCopyStatement()));
+            copyStatement.append("\\.\n\n");
+        }
+        return copyStatement;
+    }
+}
diff --git a/pgsql-schema-generator/src/main/resources/application.yaml b/pgsql-schema-generator/src/main/resources/application.yaml
new file mode 100644
index 0000000..e2fb82b
--- /dev/null
+++ b/pgsql-schema-generator/src/main/resources/application.yaml
@@ -0,0 +1,36 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+green-field-installation: true
+yang-model:
+  source: classpath:generate-defaults
+schema:
+  data:
+    skeleton: scripts/00_init-oran-smo-teiv-data.sql
+    baseline:
+    output: target/00_init-oran-smo-teiv-data.sql
+  model:
+    skeleton: scripts/01_init-oran-smo-teiv-model.sql
+    baseline:
+    temp-baseline: target/01_init-oran-smo-teiv-model_baseline.sql
+    output: target/01_init-oran-smo-teiv-model.sql
+exclusions:
+  model-names: metadata, decorators
diff --git a/pgsql-schema-generator/src/main/resources/scripts/00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/main/resources/scripts/00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..9be0569
--- /dev/null
+++ b/pgsql-schema-generator/src/main/resources/scripts/00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,53 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_data', 'success');
+
diff --git a/pgsql-schema-generator/src/main/resources/scripts/01_init-oran-smo-teiv-model.sql b/pgsql-schema-generator/src/main/resources/scripts/01_init-oran-smo-teiv-model.sql
new file mode 100644
index 0000000..9ea8054
--- /dev/null
+++ b/pgsql-schema-generator/src/main/resources/scripts/01_init-oran-smo-teiv-model.sql
@@ -0,0 +1,92 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+DROP SCHEMA IF EXISTS ties_model cascade;
+CREATE SCHEMA IF NOT EXISTS ties_model;
+ALTER SCHEMA ties_model OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+CREATE TABLE IF NOT EXISTS ties_model.execution_status (
+    "schema" VARCHAR(127) PRIMARY KEY,
+    "status" VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.hash_info (
+    "name"        VARCHAR(511) PRIMARY KEY,
+    "hashedValue" VARCHAR(511) NOT NULL,
+    "type"        VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.module_reference (
+    "name"            VARCHAR(511) PRIMARY KEY,
+    "namespace"       VARCHAR(511),
+    "domain"          VARCHAR(511),
+    "includedModules" jsonb DEFAULT '[]'::jsonb,
+    "revision"        VARCHAR(511) NOT NULL,
+    "content"         TEXT NOT NULL,
+    "ownerAppId"      VARCHAR(511) NOT NULL,
+    "status"          VARCHAR(127) NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.entity_info (
+    "name"                VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName" VARCHAR(511) NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.relationship_info (
+    "name"                     VARCHAR(511) PRIMARY KEY,
+    "aSideAssociationName"     TEXT NOT NULL,
+    "aSideMOType"              TEXT NOT NULL,
+    "aSideMinCardinality"      BIGINT NOT NULL,
+    "aSideMaxCardinality"      BIGINT NOT NULL,
+    "bSideAssociationName"     TEXT NOT NULL,
+    "bSideMOType"              TEXT NOT NULL,
+    "bSideMinCardinality"      BIGINT NOT NULL,
+    "bSideMaxCardinality"      BIGINT NOT NULL,
+    "associationKind"          TEXT NOT NULL,
+    "relationshipDataLocation" TEXT NOT NULL,
+    "connectSameEntity"        BOOLEAN NOT NULL,
+    "moduleReferenceName"      TEXT NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.decorators (
+    "name"                VARCHAR(511) PRIMARY KEY,
+    "dataType"            VARCHAR(511) NOT NULL,
+    "moduleReferenceName" VARCHAR(511) NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.classifiers (
+    "name"                VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName" VARCHAR(511) NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+-- Update model schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_model', 'success');
+
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/EndToEndTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/EndToEndTest.java
new file mode 100644
index 0000000..1ba8f74
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/EndToEndTest.java
@@ -0,0 +1,261 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.SchemaParser;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@SpringBootTest
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class EndToEndTest {
+
+    @Autowired
+    private Processor processor;
+    @Value("${test-result.data}")
+    private String expectedDataSql;
+    @Value("${schema.data.output}")
+    private String actualDataSql;
+    @Value("${test-result.model}")
+    private String expectedModelSql;
+    @Value("${schema.model.output}")
+    private String actualModelSql;
+
+    @Test
+    @Order(1)
+    void generateDataAndModelSchemaTest() throws IOException {
+        //when
+        //Generate new sql file from mocked models
+        processor.process();
+        File generatedDataSql = new File(actualDataSql);
+        File generatedModelSql = new File(actualModelSql);
+
+        //then
+        Assertions.assertTrue(generatedDataSql.exists());
+        Assertions.assertTrue(generatedModelSql.exists());
+    }
+
+    @Test
+    @Order(2)
+    void verifyGeneratedDataSqlFileTest() {
+        //then
+        List<Table> expectedTables = SchemaParser.extractDataFromBaseline(expectedDataSql);
+        List<Table> generatedTables = SchemaParser.extractDataFromBaseline(actualDataSql);
+
+        // Check if the generated sql is as expected
+        // Check if all table/entities were added correctly
+        Assertions.assertEquals(expectedTables.size(), generatedTables.size());
+
+        List<String> allTableNamesFromGeneratedResult = TestHelper.extractTableNames(generatedTables);
+        List<String> allTableNamesFromExpectedResult = TestHelper.extractTableNames(expectedTables);
+
+        // Check if generatedResult contains all tables
+        Assertions.assertEquals(allTableNamesFromExpectedResult, allTableNamesFromGeneratedResult);
+
+        //spotless:off
+        expectedTables.forEach(expectedTable -> {
+            generatedTables.stream().filter(generatedTable -> generatedTable.getName().equals(expectedTable.getName()))
+                .findFirst().ifPresent(generatedTable -> {
+                List<Column> columnsInExpected = expectedTable.getColumns();
+                List<Column> columnsInGenerated = generatedTable.getColumns();
+
+                // Check if all columns for each table were added correctly
+                Assertions.assertEquals(columnsInExpected.size(), columnsInGenerated.size());
+                List<String> allColumnNamesForATableInGeneratedResult = TestHelper.extractColumnNamesForATable(columnsInGenerated);
+                List<String> allColumnNamesForATableInExpectedResult = TestHelper.extractColumnNamesForATable(columnsInExpected);
+
+                // Check if generatedResult contains all columns for a table
+                Assertions.assertEquals(allColumnNamesForATableInExpectedResult, allColumnNamesForATableInGeneratedResult);
+
+                columnsInExpected.forEach(columnInExpected -> {
+                    columnsInGenerated.stream().filter(columnInGenerated -> columnInGenerated.getName().equals(columnInExpected.getName()))
+                        .findFirst().ifPresent(columnInGenerated -> {
+
+                        if (columnInExpected.getName().equals("id")) {
+                            Assertions.assertEquals("VARCHAR(511)", columnInGenerated.getDataType());
+                            Assertions.assertTrue(TestHelper.checkIfColumnIsPrimaryKey(columnInGenerated.getPostgresConstraints()));
+                        }
+
+                        // Check if each attributes' datatype is picked correctly
+                        Assertions.assertEquals(columnInExpected.getDataType().replace("\"", ""), columnInGenerated.getDataType());
+
+                        // Check if each attributes' default value is picked correctly
+                        Assertions.assertEquals(columnInExpected.getDefaultValue(), columnInGenerated.getDefaultValue());
+
+                        if (!columnInExpected.getPostgresConstraints().isEmpty()) {
+
+                            Assertions.assertEquals(columnInExpected.getPostgresConstraints().size(), columnInGenerated.getPostgresConstraints().size());
+
+
+                            List<String> expectedConstraintNames = TestHelper.extractConstraintName(columnInExpected.getPostgresConstraints());
+                            List<String> actualConstraintNames = TestHelper.extractConstraintName(columnInGenerated.getPostgresConstraints());
+
+                            // Check if constraint names in expected result match with those in actual result
+                            Assertions.assertEquals(expectedConstraintNames, actualConstraintNames);
+
+                            columnInExpected.getPostgresConstraints().forEach(constraint -> {
+                                columnInGenerated.getPostgresConstraints().stream().filter(constraint1 ->
+                                    constraint1.getConstraintName().equals(constraint.getConstraintName())).findFirst().ifPresent(constraint1 -> {
+
+                                    // Check table name where constraint is to be added
+                                    Assertions.assertEquals(constraint.getTableToAddConstraintTo(), constraint1.getTableToAddConstraintTo());
+
+                                    // Check column where constraint is to be added
+                                    Assertions.assertEquals(constraint.getColumnToAddConstraintTo(), constraint1.getColumnToAddConstraintTo());
+
+                                    if (constraint instanceof ForeignKeyConstraint expectedFk) {
+                                        ForeignKeyConstraint actualFK = (ForeignKeyConstraint) constraint1;
+
+                                        Assertions.assertEquals(expectedFk.getReferencedTable(), actualFK.getReferencedTable());
+                                    }
+                                });
+                            });
+                        }
+                    });
+                });
+            });
+        });
+        //spotless:on
+    }
+
+    @Test
+    @Order(3)
+    void verifyGeneratedModelSqlFileTest() {
+        //when
+        Set<String> expectedSqlStatements = TestHelper.readFile(expectedModelSql);
+        Set<String> actualSqlStatements = TestHelper.readFile(actualModelSql);
+        //then
+        Assertions.assertEquals(expectedSqlStatements.size(), actualSqlStatements.size());
+        Assertions.assertEquals(expectedSqlStatements, actualSqlStatements);
+    }
+
+    @Test
+    @Order(5)
+    void verifyGeneratedAlterStatementsSchemaTest() {
+        //when
+        Set<String> expectedSqlStatements = TestHelper.readFile(expectedDataSql);
+        Set<String> actualSqlStatements = TestHelper.readFile(actualDataSql);
+
+        HashMap<String, Long> expectedAlterStatements = new HashMap<>();
+        expectedAlterStatements.put("ALTER ADD DEFAULT", expectedSqlStatements.stream().filter(s -> s.contains(
+                "ALTER TABLE") && s.contains("SET DEFAULT")).count());
+        expectedAlterStatements.put("ALTER ADD CONSTRAINT", expectedSqlStatements.stream().filter(s -> s.contains(
+                "ALTER TABLE") && s.contains("ADD CONSTRAINT")).count());
+
+        HashMap<String, Long> actualAlterStatements = new HashMap<>();
+        actualAlterStatements.put("ALTER ADD COLUMN", actualSqlStatements.stream().filter(s -> s.contains(
+                "ALTER TABLE") && s.contains("ADD COLUMN")).count());
+        actualAlterStatements.put("ALTER ADD DEFAULT", actualSqlStatements.stream().filter(s -> s.contains(
+                "ALTER TABLE") && s.contains("SET DEFAULT")).count());
+        actualAlterStatements.put("ALTER ADD CONSTRAINT", actualSqlStatements.stream().filter(s -> s.contains(
+                "ALTER TABLE") && s.contains("ADD CONSTRAINT")).count());
+
+        //then
+        Assertions.assertEquals(0, actualAlterStatements.get("ALTER ADD COLUMN"));
+        Assertions.assertEquals(expectedAlterStatements.get("ALTER ADD DEFAULT"), actualAlterStatements.get(
+                "ALTER ADD DEFAULT"));
+        Assertions.assertEquals(expectedAlterStatements.get("ALTER ADD CONSTRAINT"), actualAlterStatements.get(
+                "ALTER ADD CONSTRAINT"));
+
+    }
+
+    @Test
+    void storeRelatedModuleRefsFromIncludedModulesTest() {
+        //spotless:off
+        List<Module> mockModuleRefFromYangParser = List.of(
+            Module.builder().name("o-ran-smo-teiv-ran-equipment")
+                    .namespace("urn:rdns:o-ran:smo:teiv:o-ran-smo-teiv-ran-equipment")
+                    .domain("RAN_EQUIPMENT")
+                    .includedModules(new ArrayList<>(List.of( "o-ran-smo-teiv-common-yang-types",
+                            "o-ran-smo-teiv-common-yang-extensions", "ietf-geo-location"))).build(),
+            Module.builder().name("o-ran-smo-teiv-ran-equipment-to-logical")
+                    .namespace("urn:rdns:o-ran:smo:teiv:ericsson-topologyandinventory-ran-logical-to-equipment")
+                    .domain("EQUIPMENT_TO_RAN_LOGICAL")
+                    .includedModules(new ArrayList<>(List.of( "o-ran-smo-teiv-common-yang-types",
+                    "o-ran-smo-teiv-common-yang-extensions", "o-ran-smo-teiv-ran-logical",
+                    "o-ran-smo-teiv-ran-equipment"))).build(),
+            Module.builder().name("o-ran-smo-teiv-ran-oam-to-cloud")
+                    .namespace("urn:rdns:o-ran:smo:teiv:o-ran-smo-teiv-ran-oam-to-cloud")
+                    .domain("RAN_OAM_TO_CLOUD")
+                    .includedModules(new ArrayList<>(List.of( "o-ran-smo-teiv-common-yang-types",
+                    "o-ran-smo-teiv-common-yang-extensions", "o-ran-smo-teiv-ran-oam",
+                    "o-ran-smo-teiv-ran-cloud"))).build()
+        );
+
+        List<Entity> mockEntitiesFromModelSvc = List.of(
+                Entity.builder().entityName("AntennaModule").moduleReferenceName("o-ran-smo-teiv-ran-equipment")
+                        .attributes(List.of()).build(),
+                Entity.builder().entityName("AntennaCapability").moduleReferenceName("o-ran-smo-teiv-ran-logical")
+                        .attributes(List.of()).build(),
+                Entity.builder().entityName("CloudNativeSystem").moduleReferenceName("o-ran-smo-teiv-ran-cloud")
+                        .attributes(List.of()).build(),
+                Entity.builder().entityName("ManagedElement").moduleReferenceName("o-ran-smo-teiv-ran-oam")
+                        .attributes(List.of()).build(),
+                Entity.builder().entityName("Sector").moduleReferenceName("o-ran-smo-teiv-ran-equipment-to-logical")
+                        .attributes(List.of()).build(),
+                Entity.builder().entityName("NRCellDU").moduleReferenceName("o-ran-smo-teiv-ran-logical")
+                        .attributes(List.of()).build()
+        );
+
+        List<Module> expectedResult = List.of(
+            Module.builder().name("o-ran-smo-teiv-ran-equipment")
+                    .namespace("urn:rdns:o-ran:smo:teiv:o-ran-smo-teiv-ran-equipment")
+                    .domain("RAN_EQUIPMENT").build(),
+            Module.builder().name("o-ran-smo-teiv-ran-equipment-to-logical")
+                    .namespace("urn:rdns:o-ran:smo:teiv:ericsson-topologyandinventory-ran-logical-to-equipment")
+                    .domain("EQUIPMENT_TO_RAN_LOGICAL")
+                    .includedModules(new ArrayList<>(List.of("o-ran-smo-teiv-ran-logical",
+                            "o-ran-smo-teiv-ran-equipment"))).build(),
+            Module.builder().name("o-ran-smo-teiv-ran-oam-to-cloud")
+                    .namespace("urn:rdns:o-ran:smo:teiv:o-ran-smo-teiv-ran-oam-to-cloud")
+                    .domain("RAN_OAM_TO_CLOUD")
+                    .includedModules(new ArrayList<>(List.of("o-ran-smo-teiv-ran-oam",
+                            "o-ran-smo-teiv-ran-cloud"))).build()
+        );
+        //spotless:on
+
+        List<Module> actualResult = Processor.storeRelatedModuleRefsFromIncludedModules(mockEntitiesFromModelSvc,
+                mockModuleRefFromYangParser);
+
+        actualResult.forEach(actual -> {
+            expectedResult.stream().filter(expected -> expected.getName().equals(actual.getName())).findFirst().ifPresent(
+                    expected -> {
+                        Assertions.assertEquals(actual.getIncludedModules(), expected.getIncludedModules());
+                    });
+        });
+    }
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/TestHelper.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/TestHelper.java
new file mode 100644
index 0000000..f85353e
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/TestHelper.java
@@ -0,0 +1,106 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+
+@Slf4j
+public class TestHelper {
+
+    public static List<String> extractTableNames(List<Table> tables) {
+        return tables.stream().map(Table::getName).sorted().toList();
+    }
+
+    public static List<String> extractColumnNamesForATable(List<Column> columns) {
+        return columns.stream().map(Column::getName).sorted().toList();
+    }
+
+    public static List<String> extractConstraintName(Collection<PostgresConstraint> postgresConstraints) {
+        return postgresConstraints.stream().map(PostgresConstraint::getConstraintName).map(String::toUpperCase).sorted()
+                .toList();
+    }
+
+    public static boolean checkIfColumnIsPrimaryKey(Collection<PostgresConstraint> postgresConstraints) {
+        return postgresConstraints.stream().anyMatch(PrimaryKeyConstraint.class::isInstance);
+    }
+
+    public static Map<String, List<Table>> identifiedModelChangeMapping() {
+        Map<String, List<Table>> storeIdentifiedChangesToModels = new HashMap<>();
+        storeIdentifiedChangesToModels.put("CREATE", new ArrayList<>());
+        storeIdentifiedChangesToModels.put("ALTER", new ArrayList<>());
+        storeIdentifiedChangesToModels.put("DEFAULT", new ArrayList<>());
+        return storeIdentifiedChangesToModels;
+    }
+
+    public static boolean filesCompareByLine(Path path1, Path path2, String... exclusions) throws IOException {
+        try (BufferedReader br1 = Files.newBufferedReader(path1); BufferedReader br2 = Files.newBufferedReader(path2)) {
+            String line1, line2;
+            while ((line1 = br1.readLine()) != null) {
+                line2 = br2.readLine();
+                if (!line1.equals(line2) && !Arrays.stream(exclusions).toList().contains(line1)) {
+                    return false;
+                }
+            }
+            return br2.readLine() == null;
+        }
+    }
+
+    public static void appendToFile(String fileName, String contentToAppend) throws IOException {
+        Files.write(Paths.get(fileName), contentToAppend.getBytes(), StandardOpenOption.APPEND);
+    }
+
+    public static Set<String> readFile(String filePath) {
+        Set<String> lines = new HashSet<>();
+        try (BufferedReader br = new BufferedReader(new FileReader(filePath, StandardCharsets.UTF_8))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                line = line.trim();
+                if (!line.isEmpty() && Character.isLetterOrDigit(line.charAt(0)) && !line.startsWith("SELECT") && !line
+                        .startsWith("FOREIGN KEY")) {
+                    Assertions.assertTrue(lines.add(line), String.format("Duplicate identified in file - %s on line --> %s",
+                            filePath, line));
+                }
+            }
+        } catch (IOException exception) {
+            throw PgSchemaGeneratorException.readBaselineException("ties.data", exception);
+        }
+        return lines;
+    }
+
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/YangParserTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/YangParserTest.java
new file mode 100644
index 0000000..138bf52
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/YangParserTest.java
@@ -0,0 +1,52 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest(classes = YangParser.class)
+class YangParserTest {
+
+    @Autowired
+    private YangParser yangParser;
+
+    @Test
+    void returnAllModuleReferencesTest() throws IOException {
+
+        List<Module> moduleList = yangParser.returnAllModuleReferences();
+
+        Assertions.assertEquals(5, moduleList.size());
+
+        List<String> allModuleReferenceNames = moduleList.stream().map(Module::getName).sorted().toList();
+
+        Assertions.assertEquals(allModuleReferenceNames, Stream.of("o-ran-smo-teiv-common-yang-extensions",
+                "o-ran-smo-teiv-common-yang-types", "o-ran-smo-teiv-equipment", "o-ran-smo-teiv-rel-equipment-ran",
+                "o-ran-smo-teiv-ran").sorted().toList());
+
+    }
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/BackwardCompatibilityCheckerTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/BackwardCompatibilityCheckerTest.java
new file mode 100644
index 0000000..ce97ec6
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/BackwardCompatibilityCheckerTest.java
@@ -0,0 +1,591 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema;
+
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.PgSchemaGeneratorException;
+import org.oran.smo.teiv.pgsqlgenerator.UniqueConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.List;
+
+@SpringBootTest(classes = { BackwardCompatibilityChecker.class }, properties = { "green-field-installation=false" })
+class BackwardCompatibilityCheckerTest {
+
+    @Autowired
+    private BackwardCompatibilityChecker nbcChecker;
+
+    //spotless:off
+
+    private List<Table> mockModelServiceEntities = List.of(
+            Table.builder().name("Sector").columns(
+                List.of(
+                        Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                        Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                        .columnToAddConstraintTo("id").build())).build(),
+                        Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                        Column.builder().name("geo-location").dataType("geography").build())).build(),
+            Table.builder().name("Namespace").columns(
+                List.of(
+                        Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                        .columnToAddConstraintTo("id").build())).build(),
+                        Column.builder().name("name").dataType("TEXT").build())).build());
+
+    //Data:Entities
+    @Test
+    void verifyExceptionThrownOnDeletedTableWhenGreenfieldDisabledTest()  {
+
+        // When - baseline
+        List<Table> mockBaselineEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        //Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed table(NRCellDU) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+
+    }
+
+    @Test
+    void verifyExceptionThrownOnDeletedColumnWhenGreenfieldDisabledTest()  {
+
+        // Given baseline
+        List<Table> mockBaselineEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // When - entities from Model svc with Sector.sectorId deleted
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        //Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed column(Sector.sectorId) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+
+    }
+
+    @Test
+    void verifyExceptionThrownOnColumnNameModifiedWhenGreenfieldDisabledTest()  {
+        // rename column name
+        // Given baseline
+        List<Table> mockBaselineEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // When - entities from Model svc with renamed column name
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId123").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        //Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed column(Sector.sectorId) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+    }
+
+    @Test
+    void verifyExceptionThrownOnColumnDataModifiedWhenGreenfieldDisabledTest()  {
+        // Given baseline
+        List<Table> mockBaselineEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // When - entities from Model svc with modified column datatype
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("SMALLINT").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed datatype for column(Namespace.id) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+    }
+
+    @Test
+    void verifyExceptionThrownOnColumnConstraintModifiedWhenGreenfieldDisabledTest()  {
+
+        // Given baseline
+        List<Table> mockBaselineEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // When - entities from Model svc with modified column constraints
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed constraint for column(Sector.id) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+
+        // When - entities from Model svc with Sector.id's pk constraint name changed
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                        List.of(
+                                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                        PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id_123")
+                                                .columnToAddConstraintTo("id").build())).build(),
+                                Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                                Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                        List.of(
+                                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                        PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                                .columnToAddConstraintTo("id").build())).build(),
+                                Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("NRCellDU").columns(
+                        List.of(
+                                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                        PrimaryKeyConstraint.builder().tableName("NRCellDU").constraintName("PK_NRCellDU_id")
+                                                .columnToAddConstraintTo("id").build())).build(),
+                                Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed constraint for column(Sector.id) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+
+    }
+
+    //Data:Relationships
+    @Test
+    void verifyExceptionThrownOnModifiedRelationshipCardinalityWhenGreenfieldDisabledTest() {
+        // Given
+        // ONE_TO_ONE
+        List<Table> mockBaselineEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build(),
+                            Column.builder().name("REL_FK_managed-Namespace").dataType("VARCHAR(511)").postgresConstraints(List.of()).build(),
+                            Column.builder().name("REL_ID_SECTOR_MANAGES_NAMESPACE").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    UniqueConstraint.builder().constraintName("UNIQUE_Sector_REL_ID_SECTOR_MANAGES_NAMESPACE").tableName("Sector")
+                                            .columnToAddConstraintTo("REL_ID_SECTOR_MANAGES_NAMESPACE").build())).build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // When
+        // Changing SECTOR_MANAGES_NAMESPACE from ONE_TO_ONE to ONE_TO_MANY
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build(),
+                            Column.builder().name("REL_FK_managed-by-Sector").dataType("VARCHAR(511)").postgresConstraints(List.of()).build(),
+                            Column.builder().name("REL_ID_SECTOR_MANAGES_NAMESPACE").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    UniqueConstraint.builder().constraintName("UNIQUE_Namespace_REL_ID_SECTOR_MANAGES_NAMESPACE").tableName("Namespace")
+                                            .columnToAddConstraintTo("REL_ID_SECTOR_MANAGES_NAMESPACE").build())).build())).build());
+
+        // Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed column(Sector.REL_FK_managed-Namespace) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+
+        // When
+        // Changing SECTOR_MANAGES_NAMESPACE rel from ONE_TO_ONE to MANY_TO_MANY
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                    List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                    List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build(),
+                Table.builder().name("SECTOR_MANAGES_NAMESPACE").columns(
+                        List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("SECTOR_MANAGES_NAMESPACE").constraintName("PK_SECTOR_MANAGES_NAMESPACE_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("aSide_Sector").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    UniqueConstraint.builder().constraintName("FK_SECTOR_MANAGES_NAMESPACE_aSide_Sector")
+                                            .tableName("SECTOR_MANAGES_NAMESPACE").columnToAddConstraintTo("aSide_Sector").build())).build(),
+                            Column.builder().name("bSide_Namespace").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    UniqueConstraint.builder().constraintName("FK_SECTOR_MANAGES_NAMESPACE_bSide_Namespace")
+                                            .tableName("SECTOR_MANAGES_NAMESPACE").columnToAddConstraintTo("bSide_Namespace").build())).build())).build());
+
+        // Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed column(Sector.REL_FK_managed-Namespace) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaselineEntities, mockModelServiceEntities)).getMessage());
+
+
+        // Given
+        // Changing SECTOR_MANAGES_NAMESPACE rel from ONE_TO_MANY to ONE_TO_ONE - Changing cardinality
+        List<Table> mockBaseline = List.of(
+                Table.builder().name("Sector").columns(
+                        List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build())).build(),
+                Table.builder().name("Namespace").columns(
+                        List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build(),
+                            Column.builder().name("REL_FK_managed-by-Sector").dataType("VARCHAR(511)").postgresConstraints(List.of()).build(),
+                            Column.builder().name("REL_ID_SECTOR_MANAGES_NAMESPACE").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    UniqueConstraint.builder().constraintName("UNIQUE_Namespace_REL_ID_SECTOR_MANAGES_NAMESPACE").tableName("Namespace")
+                                            .columnToAddConstraintTo("REL_ID_SECTOR_MANAGES_NAMESPACE").build())).build())).build());
+
+        // When
+        mockModelServiceEntities = List.of(
+                Table.builder().name("Sector").columns(
+                        List.of(
+                            Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                            Column.builder().name("geo-location").dataType("geography").build(),
+                            Column.builder().name("REL_FK_managed-Namespace").dataType("VARCHAR(511)").postgresConstraints(List.of()).build(),
+                            Column.builder().name("REL_ID_SECTOR_MANAGES_NAMESPACE").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    UniqueConstraint.builder().constraintName("UNIQUE_Sector_REL_ID_SECTOR_MANAGES_NAMESPACE").tableName("Sector")
+                                            .columnToAddConstraintTo("REL_ID_SECTOR_MANAGES_NAMESPACE").build())).build())).build(),
+                Table.builder().name("Namespace").columns(
+                        List.of(
+                            Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                                    PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id")
+                                            .columnToAddConstraintTo("id").build())).build(),
+                            Column.builder().name("name").dataType("TEXT").build())).build());
+
+        // Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed column(Namespace.REL_FK_managed-by-Sector) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInData(
+                        mockBaseline, mockModelServiceEntities)).getMessage());
+    }
+
+    //Model
+    @Test
+    void verifyExceptionThrownOnChangingRelAttributesWhenGreenfieldDisabledTest() {
+
+        //from ONE_TO_ONE to MANY_TO_ONE
+        //Given
+        List<Relationship> baselineRel = List.of(
+                Relationship.builder().name("ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER")
+                        .aSideAssociationName("provided-lteSectorCarrier")
+                        .aSideMOType("ENodeBFunction")
+                        .aSideMinCardinality(0)
+                        .aSideMaxCardinality(1)
+                        .bSideAssociationName("provided-by-enodebFunction")
+                        .bSideMOType("LTESectorCarrier")
+                        .bSideMinCardinality(0)
+                        .bSideMaxCardinality(1)
+                        .associationKind("BI_DIRECTIONAL")
+                        .relationshipDataLocation("B_SIDE")
+                        .connectSameEntity(false)
+                        .moduleReferenceName("o-ran-smo-teiv-ran").build());
+        //When
+        List<Relationship> mockModelSvcRel1 = List.of(
+                Relationship.builder().name("ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER")
+                        .aSideAssociationName("provided-lteSectorCarrier")
+                        .aSideMOType("ENodeBFunction")
+                        .aSideMinCardinality(0)
+                        .aSideMaxCardinality(100)
+                        .bSideAssociationName("provided-by-enodebFunction")
+                        .bSideMOType("LTESectorCarrier")
+                        .bSideMinCardinality(0)
+                        .bSideMaxCardinality(1)
+                        .associationKind("BI_DIRECTIONAL")
+                        .relationshipDataLocation("A_SIDE")
+                        .connectSameEntity(false)
+                        .moduleReferenceName("o-ran-smo-teiv-ran").build());
+        //Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified cardinalities for relationship(ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER), please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInModel(
+                        baselineRel, mockModelSvcRel1)).getMessage());
+
+        //from ONE_TO_ONE to MANY_TO_MANY
+        //When
+        List<Relationship> mockModelSvcRel2 = List.of(
+                Relationship.builder().name("ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER")
+                        .aSideAssociationName("provided-lteSectorCarrier")
+                        .aSideMOType("ENodeBFunction")
+                        .aSideMinCardinality(1)
+                        .aSideMaxCardinality(100)
+                        .bSideAssociationName("provided-by-enodebFunction")
+                        .bSideMOType("LTESectorCarrier")
+                        .bSideMinCardinality(0)
+                        .bSideMaxCardinality(100)
+                        .associationKind("BI_DIRECTIONAL")
+                        .relationshipDataLocation("A_SIDE")
+                        .connectSameEntity(false)
+                        .moduleReferenceName("o-ran-smo-teiv-ran").build());
+        //Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified cardinalities for relationship(ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER), please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInModel(
+                        baselineRel, mockModelSvcRel2)).getMessage());
+
+        //Change aSide and bSide
+        //When
+        List<Relationship> mockModelSvcRel3 = List.of(
+                Relationship.builder().name("LTESECTORCARRIER_PROVIDES_ENODEBFUNCTION")
+                        .aSideAssociationName("provided-eNodeBFunction")
+                        .aSideMOType("LTESectorCarrier")
+                        .aSideMinCardinality(0)
+                        .aSideMaxCardinality(100)
+                        .bSideAssociationName("provided-by-lteSectorCarrier")
+                        .bSideMOType("ENodeBFunction")
+                        .bSideMinCardinality(0)
+                        .bSideMaxCardinality(100)
+                        .associationKind("BI_DIRECTIONAL")
+                        .relationshipDataLocation("RELATION")
+                        .connectSameEntity(false)
+                        .moduleReferenceName("o-ran-smo-teiv-ran").build());
+        //Then
+        Assertions.assertEquals(
+                String.format("NBC change has been introduced: modified/removed relationship(ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER) present in baseline, please make sure you've enabled green-field installation!!%nFor more info please refer to README"),
+                Assertions.assertThrowsExactly(PgSchemaGeneratorException.class, () -> nbcChecker.checkForNBCChangesInModel(
+                        baselineRel, mockModelSvcRel3)).getMessage());
+
+        //When
+        List<Relationship> mockModelSvcRel4 = List.of(
+                Relationship.builder().name("ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER")
+                        .aSideAssociationName("provided-lteSectorCarrier")
+                        .aSideMOType("ENodeBFunction")
+                        .aSideMinCardinality(0)
+                        .aSideMaxCardinality(1)
+                        .bSideAssociationName("provided-by-enodebFunction")
+                        .bSideMOType("LTESectorCarrier")
+                        .bSideMinCardinality(0)
+                        .bSideMaxCardinality(1)
+                        .associationKind("BI_DIRECTIONAL")
+                        .relationshipDataLocation("A_SIDE")
+                        .connectSameEntity(false)
+                        .moduleReferenceName("o-ran-smo-teiv-ran").build());
+        //Then
+        Assertions.assertDoesNotThrow(() -> nbcChecker.checkForNBCChangesInModel(
+                        baselineRel, mockModelSvcRel4));
+    }
+    //spotless:on
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaParserTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaParserTest.java
new file mode 100644
index 0000000..9fa8da9
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/SchemaParserTest.java
@@ -0,0 +1,513 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.UniqueConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.TestHelper;
+import org.oran.smo.teiv.pgsqlgenerator.ForeignKeyConstraint;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class SchemaParserTest {
+
+    private String mockForEntities;
+    private String mockForModelRels;
+    private String mockForRelOneToOne;
+    private String mockForRelOneToMany;
+    private String mockForRelManyToOne;
+    private String mockForRelManyToMany;
+    private String mockForRelSameEntities;
+    private String testSqlFileForProcessorTest;
+
+    @BeforeEach
+    void setUp() {
+        String mockDir = "src/test/resources/SchemaParserTest/";
+        mockForModelRels = mockDir + "model/mock_01_init-oran-smo-teiv-model.sql";
+        mockForEntities = mockDir + "data/entities/mock_00_init-oran-smo-teiv-data.sql";
+        mockForRelOneToOne = mockDir + "data/relationships/oneToOne/mock_00_init-oran-smo-teiv-data.sql";
+        mockForRelOneToMany = mockDir + "data/relationships/oneToMany/mock_00_init-oran-smo-teiv-data.sql";
+        mockForRelManyToOne = mockDir + "data/relationships/manyToOne/mock_00_init-oran-smo-teiv-data.sql";
+        mockForRelManyToMany = mockDir + "data/relationships/manyToMany/mock_00_init-oran-smo-teiv-data.sql";
+        mockForRelSameEntities = mockDir + "data/relationships/sameEntities/mock_00_init-oran-smo-teiv-data.sql";
+        testSqlFileForProcessorTest = "target/TEST_00_init-oran-smo-teiv-data.sql";
+    }
+
+    @Test
+    void checkIfRelationshipsAreExtractedCorrectlyFromBaselineModelTest() {
+        //Given
+        List<Relationship> expectedRelationships = List.of(Relationship.builder().name(
+                "ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER").aSideAssociationName("provided-lteSectorCarrier").aSideMOType(
+                        "ENodeBFunction").aSideMinCardinality(1).aSideMaxCardinality(1).bSideAssociationName(
+                                "provided-by-enodebFunction").bSideMOType("LTESectorCarrier").bSideMinCardinality(0)
+                .bSideMaxCardinality(100).associationKind("BI_DIRECTIONAL").relationshipDataLocation("B_SIDE")
+                .connectSameEntity(false).moduleReferenceName("o-ran-smo-teiv-ran").build(), Relationship.builder().name(
+                        "LTESECTORCARRIER_USES_ANTENNACAPABILITY").aSideAssociationName("used-antennaCapability")
+                        .aSideMOType("LTESectorCarrier").aSideMinCardinality(0).aSideMaxCardinality(1).bSideAssociationName(
+                                "used-by-lteSectorCarrier").bSideMOType("AntennaCapability").bSideMinCardinality(0)
+                        .bSideMaxCardinality(1).associationKind("BI_DIRECTIONAL").relationshipDataLocation("A_SIDE")
+                        .connectSameEntity(false).moduleReferenceName("o-ran-smo-teiv-ran").build());
+
+        //When
+        List<Relationship> actualResult = SchemaParser.extractFromModelBaseline(mockForModelRels);
+
+        //Then
+        expectedRelationships.forEach(expectedRel -> {
+            actualResult.stream().filter(rel -> rel.getName().equals(expectedRel.getName())).findFirst().ifPresent(
+                    extractedRel -> {
+                        Assertions.assertEquals(expectedRel.getName(), extractedRel.getName());
+                        Assertions.assertEquals(expectedRel.getASideAssociationName(), extractedRel
+                                .getASideAssociationName());
+                        Assertions.assertEquals(expectedRel.getASideMOType(), extractedRel.getASideMOType());
+                        Assertions.assertEquals(expectedRel.getASideMinCardinality(), extractedRel
+                                .getASideMinCardinality());
+                        Assertions.assertEquals(expectedRel.getASideMaxCardinality(), extractedRel
+                                .getASideMaxCardinality());
+                        Assertions.assertEquals(expectedRel.getBSideAssociationName(), extractedRel
+                                .getBSideAssociationName());
+                        Assertions.assertEquals(expectedRel.getBSideMOType(), extractedRel.getBSideMOType());
+                        Assertions.assertEquals(expectedRel.getBSideMinCardinality(), extractedRel
+                                .getBSideMinCardinality());
+                        Assertions.assertEquals(expectedRel.getBSideMaxCardinality(), extractedRel
+                                .getBSideMaxCardinality());
+                        Assertions.assertEquals(expectedRel.getAssociationKind(), extractedRel.getAssociationKind());
+                        Assertions.assertEquals(expectedRel.getRelationshipDataLocation(), extractedRel
+                                .getRelationshipDataLocation());
+                        Assertions.assertEquals(expectedRel.isConnectSameEntity(), extractedRel.isConnectSameEntity());
+                        Assertions.assertEquals(expectedRel.getModuleReferenceName(), extractedRel
+                                .getModuleReferenceName());
+                    });
+        });
+    }
+
+    /*
+     * These tests check if the data extracted from mocked sql file by the algorithm is correct
+     * This includes checking if each Table, their Columns and each Columns' name, datatype or default value are picked up as expected
+     */
+
+    @Test
+    void checkIfAllTablesAndItsColumnsAreParsedCorrectlyTest() {
+
+        // spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build(),
+
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build())).build());
+        // spotless:on
+
+        // When
+        // Test extractDataFromBaseline with a sample file path
+        List<Table> actualResult = SchemaParser.extractDataFromBaseline(mockForEntities);
+
+        // Then
+        assertNotNull(actualResult);
+        runTest(actualResult, expectedResult);
+
+    }
+
+    /*
+     * This test checks if algorithm can correctly pick new default value 'hello-to-the-world' for column 'name' in table 'Namespace'
+     */
+    @Test
+    void checkIfColumnsWithDefaultValuesAreParsedCorrectlyTest() throws IOException {
+
+        // spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build(),
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").defaultValue("hello-to-the-world").build())).build());
+        // spotless:on
+
+        // Create a copy to perform tests on
+        File mockSqlFile = new File(mockForEntities);
+        File testSqlFile = new File(testSqlFileForProcessorTest);
+        Files.copy(mockSqlFile.toPath(), testSqlFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+
+        // Add to copy
+        String sampleLine = "ALTER TABLE ONLY ties_data.\"Namespace\" ALTER COLUMN \"name\" SET DEFAULT 'hello-to-the-world';\n\n";
+
+        // When
+        TestHelper.appendToFile(testSqlFileForProcessorTest, sampleLine);
+        List<Table> entities = SchemaParser.extractDataFromBaseline(testSqlFileForProcessorTest);
+
+        // Then
+        for (int i = 0; i < expectedResult.size(); i++) {
+            for (int j = 0; j < expectedResult.get(i).getColumns().size(); j++) {
+                // Check if each Columns' default value is picked correctly
+                Assertions.assertEquals(expectedResult.get(i).getColumns().get(j).getDefaultValue(), entities.get(i)
+                        .getColumns().get(j).getDefaultValue());
+            }
+        }
+
+        Assertions.assertTrue(testSqlFile.delete());
+
+    }
+
+    /*
+     * This test checks if algorithm can correctly pick new Column 'azimuth' with datatype 'DECIMAL' for table 'Sector'
+     */
+    @Test
+    void checkIfAlterTableAddColumnAreParsedCorrectlyTest() throws IOException {
+
+        // spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build(),
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build(),
+                Column.builder().name("namespaceId").dataType("DECIMAL").build())).build());
+        // spotless:on
+
+        // Create a copy to perform tests on
+        File mockSqlFile = new File(mockForEntities);
+        File testSqlFile = new File(testSqlFileForProcessorTest);
+        Files.copy(mockSqlFile.toPath(), testSqlFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+
+        // Add to copy
+        String sampleLine = "ALTER TABLE ties_data.\"Namespace\" ADD COLUMN IF NOT EXISTS \"namespaceId\" DECIMAL;";
+
+        // When
+        TestHelper.appendToFile(testSqlFileForProcessorTest, sampleLine);
+        List<Table> entities = SchemaParser.extractDataFromBaseline(testSqlFileForProcessorTest);
+
+        // Then
+        for (int i = 0; i < expectedResult.size(); i++) {
+            Assertions.assertEquals(expectedResult.get(i).getColumns().size(), entities.get(i).getColumns().size());
+        }
+
+        Assertions.assertTrue(testSqlFile.delete());
+
+    }
+
+    /*
+     * This test checks if algorithm can correctly pick foreign key constraint for 1:1 relationships
+     * The parser must also be able to pick up constraint name, which table pointsTo and pointsFrom as well as column that have constraints
+     */
+    @Test
+    void checkIfTableConstraintsAreParsedCorrectlyForOneToOneRelationshipTest() {
+
+        // spotless:off
+        // Given
+
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                                .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build(),
+                Column.builder().name("REL_FK_serviced-sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_Sector_REL_FK_serviced-sector").tableName("Sector")
+                                .referencedTable("Namespace").columnToAddConstraintTo("REL_FK_serviced-sector").build())).build(),
+                Column.builder().name("REL_ID_serviced-sector_serving-namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(UniqueConstraint.builder().constraintName("UNIQUE_Sector_REL_ID_serviced-sector_serving-namespace")
+                                .tableName("Sector").columnToAddConstraintTo("REL_ID_serviced-sector_serving-namespace").build())).build())).build(),
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build(),
+                Column.builder().name("REL_FK_serving-namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_Namespace_REL_FK_serving-namespace").tableName("Namespace")
+                                .referencedTable("Sector").columnToAddConstraintTo("REL_FK_serving-namespace").build())).build())).build());
+
+        // spotless:on
+
+        // When
+        List<Table> actualResult = SchemaParser.extractDataFromBaseline(mockForRelOneToOne);
+
+        // Then
+        Assertions.assertNotNull(actualResult);
+        runTest(actualResult, expectedResult);
+
+    }
+
+    /*
+     * This test checks if algorithm can correctly pick foreign key constraint for 1:N relationships
+     * The parser must also be able to pick up constraint name, which table pointsTo and pointsFrom as well as column that have constraints
+     */
+    @Test
+    void checkIfTableConstraintsAreParsedCorrectlyForOneToManyRelationshipTest() {
+
+        // spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build(),
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build(),
+                Column.builder().name("REL_FK_serving-namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_Namespace_REL_FK_serving-namespace")
+                                .tableName("Namespace").referencedTable("Sector").columnToAddConstraintTo("REL_FK_serving-namespace").build())).build(),
+                Column.builder().name("REL_ID_serviced-sector_serving-namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(UniqueConstraint.builder().constraintName("UNIQUE_Namespace_REL_ID_serviced-sector_serving-namespace")
+                                .tableName("Namespace").columnToAddConstraintTo("REL_ID_serviced-sector_serving-namespace").build())).build())).build());
+
+        // spotless:on
+
+        // When
+        List<Table> actualResult = SchemaParser.extractDataFromBaseline(mockForRelOneToMany);
+
+        // Then
+        Assertions.assertNotNull(actualResult);
+        runTest(actualResult, expectedResult);
+
+    }
+
+    /*
+     * This test checks if algorithm can correctly pick foreign key constraint for N:1 relationships
+     * The parser must also be able to pick up constraint name, which table pointsTo and pointsFrom as well as column that have constraints
+     */
+    @Test
+    void checkIfTableConstraintsForManyToOneAreParsedCorrectlyForManyToOneRelationshipTest() {
+
+        // spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                    .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build(),
+                Column.builder().name("REL_FK_serviced-sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_Sector_REL_FK_serviced-sector").tableName("Sector").referencedTable("Namespace")
+                                .columnToAddConstraintTo("REL_FK_serviced-sector").build())).build(),
+                Column.builder().name("REL_ID_serviced-sector_serving-namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(UniqueConstraint.builder().constraintName("UNIQUE_Sector_REL_ID_serviced-sector_serving-namespace").tableName("Sector")
+                                .columnToAddConstraintTo("REL_ID_serviced-sector_serving-namespace").build())).build())).build(),
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build())).build());
+        // spotless:on
+
+        // When
+        List<Table> actualResult = SchemaParser.extractDataFromBaseline(mockForRelManyToOne);
+
+        // Then
+        Assertions.assertNotNull(actualResult);
+        runTest(actualResult, expectedResult);
+
+    }
+
+    /*
+     * This test checks if algorithm can correctly pick foreign key constraint for M:N relationships
+     * The parser must also be able to pick up constraint name, which table pointsTo and pointsFrom as well as column that have constraints
+     */
+    @Test
+    void checkIfTableConstraintsAreParsedCorrectlyForManyToManyRelationshipTest() {
+
+        // spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build(),
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build())).build(),
+        Table.builder().name("REL_serviced-sector_serving-namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_REL_serviced-sector_serving-namespace_id")
+                        .tableName("REL_serviced-sector_serving-namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("aSide_Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_REL_serviced-sector_serving-namespace_aSide_Sector")
+                                .tableName("REL_serviced-sector_serving-namespace").referencedTable("Sector").columnToAddConstraintTo("aSide_Sector").build())).build(),
+                Column.builder().name("bSide_Namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_REL_serviced-sector_serving-namespace_bSide_Namespace")
+                                .tableName("REL_serviced-sector_serving-namespace").referencedTable("Namespace").columnToAddConstraintTo("bSide_Namespace").build())).build())).build());
+        // spotless:on
+
+        // When
+        List<Table> actualResult = SchemaParser.extractDataFromBaseline(mockForRelManyToMany);
+
+        // Then
+        Assertions.assertNotNull(actualResult);
+        runTest(actualResult, expectedResult);
+
+    }
+
+    /*
+     * This test checks if algorithm can correctly pick foreign key constraint for relationships connecting same entity
+     * The parser must also be able to pick up constraint name, which table pointsTo and pointsFrom as well as column that have constraints
+     */
+    @Test
+    void checkIfTableConstraintsAreParsedCorrectlyForRelationshipWithSameEntityTest() {
+
+        // spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build(),
+        Table.builder().name("REL_serviced-sector_serving-sector").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_REL_serviced-sector_serving-sector_id")
+                        .tableName("REL_serviced-sector_serving-sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("aSide_Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_REL_serviced-sector_serving-sector_aSide_Sector")
+                                .tableName("REL_serviced-sector_serving-sector").referencedTable("Sector").columnToAddConstraintTo("aSide_Sector").build())).build(),
+                Column.builder().name("bSide_Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_REL_serviced-sector_serving-sector_bSide_Sector")
+                                .tableName("REL_serviced-sector_serving-sector").referencedTable("Sector").columnToAddConstraintTo("bSide_Sector").build())).build())).build());
+        // spotless:on
+
+        // When
+        List<Table> actualResult = SchemaParser.extractDataFromBaseline(mockForRelSameEntities);
+
+        // Then
+        Assertions.assertNotNull(actualResult);
+        runTest(actualResult, expectedResult);
+
+    }
+
+    void runTest(List<Table> actualResult, List<Table> expectedResult) {
+
+        List<String> allEntitiesFromActualResult = TestHelper.extractTableNames(actualResult);
+        List<String> allEntitiesFromExpectedResult = TestHelper.extractTableNames(expectedResult);
+
+        // Check if all tables are picked correctly by the algorithm
+        Assertions.assertEquals(allEntitiesFromExpectedResult, allEntitiesFromActualResult);
+
+        //spotless:off
+        expectedResult.forEach(expectedTable -> {
+            actualResult.stream().filter(generatedTable -> generatedTable.getName().equals(expectedTable.getName())).findFirst()
+            .ifPresent(generatedTable -> {
+                List<Column> columnsInExpected = expectedTable.getColumns();
+                List<Column> columnsInGenerated = generatedTable.getColumns();
+
+                // Check if all columns for each table were added correctly
+                Assertions.assertEquals(columnsInExpected.size(), columnsInGenerated.size());
+
+                List<String> allColumnNamesForATableInGeneratedResult = TestHelper.extractColumnNamesForATable(columnsInGenerated);
+                List<String> allColumnNamesForATableInExpectedResult = TestHelper.extractColumnNamesForATable(columnsInExpected);
+
+                // Check if generatedResult contains all columns for a table
+                Assertions.assertEquals(allColumnNamesForATableInExpectedResult, allColumnNamesForATableInGeneratedResult);
+
+                columnsInExpected.forEach(columnInExpected -> {
+                    columnsInGenerated.stream().filter(columnInGenerated -> columnInGenerated.getName().equals(columnInExpected.getName()))
+                    .findFirst().ifPresent(columnInGenerated -> {
+
+                        if (columnInExpected.getName().equals("id")) {
+                            Assertions.assertEquals("VARCHAR(511)", columnInGenerated.getDataType());
+                            Assertions.assertTrue(TestHelper.checkIfColumnIsPrimaryKey(columnInGenerated.getPostgresConstraints()));
+                        }
+
+                        // Check if each attributes' datatype is picked correctly
+                        Assertions.assertEquals(columnInExpected.getDataType().replace("\"", ""), columnInGenerated.getDataType());
+
+                        // Check if each attributes' default value is picked correctly
+                        Assertions.assertEquals(columnInExpected.getDefaultValue(), columnInGenerated.getDefaultValue());
+
+                        if (!columnInExpected.getPostgresConstraints().isEmpty()) {
+
+                            Assertions.assertEquals(columnInExpected.getPostgresConstraints().size(), columnInGenerated.getPostgresConstraints().size());
+
+                            List<String> expectedConstraintNames = TestHelper.extractConstraintName(columnInExpected.getPostgresConstraints());
+                            List<String> actualConstraintNames = TestHelper.extractConstraintName(columnInGenerated.getPostgresConstraints());
+
+                            // Check if constraint names in expected result match with those in actual result
+                            Assertions.assertEquals(expectedConstraintNames, actualConstraintNames);
+
+                            columnInExpected.getPostgresConstraints().forEach(constraint -> {
+                                columnInGenerated.getPostgresConstraints().stream()
+                                .filter(constraint1 -> constraint1.getConstraintName().equals(constraint.getConstraintName())).findFirst()
+                                .ifPresent(constraint1 -> {
+
+                                    // Check table name where constraint is to be added
+                                    Assertions.assertEquals(constraint.getTableToAddConstraintTo(), constraint1.getTableToAddConstraintTo());
+
+                                    // Check column where constraint is to be added
+                                    Assertions.assertEquals(constraint.getColumnToAddConstraintTo(), constraint1.getColumnToAddConstraintTo());
+
+                                    if (constraint instanceof ForeignKeyConstraint expectedFk) {
+                                        ForeignKeyConstraint actualFK = (ForeignKeyConstraint) constraint1;
+
+                                        Assertions.assertEquals(expectedFk.getReferencedTable(), actualFK.getReferencedTable());
+                                    }
+                                });
+                            });
+                        }
+                    });
+                });
+            });
+        });
+        //spotless:on
+    }
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaGeneratorTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaGeneratorTest.java
new file mode 100644
index 0000000..4822b02
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/DataSchemaGeneratorTest.java
@@ -0,0 +1,67 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.BackwardCompatibilityChecker;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import org.oran.smo.teiv.pgsqlgenerator.TestHelper;
+import org.oran.smo.teiv.pgsqlgenerator.schema.model.HashInfoDataGenerator;
+
+@SpringBootTest(classes = { DataSchemaGenerator.class, ModelComparator.class, DataSchemaHelper.class, TableBuilder.class,
+        HashInfoDataGenerator.class, BackwardCompatibilityChecker.class }, properties = {
+                "green-field-installation=false" })
+public class DataSchemaGeneratorTest {
+    @Autowired
+    private DataSchemaGenerator dataSchemaGenerator;
+    @Value("${green-field-installation}")
+    private boolean isGreenFieldInstallation;
+    @Value("${schema.data.baseline}")
+    private String baselineDataSqlFile;
+    @Value("${schema.data.output}")
+    private String actualResultSqlFile;
+
+    @Test
+    void prepareSchemaTest() throws IOException {
+        //when
+        dataSchemaGenerator.prepareSchema();
+        //then
+        Assertions.assertFalse(isGreenFieldInstallation);
+        //exclude commit statement in the prepare statement as it will be added in the later stage at the end of the schema.
+        Assertions.assertTrue(TestHelper.filesCompareByLine(Paths.get(baselineDataSqlFile), Paths.get(actualResultSqlFile),
+                "COMMIT;", ""));
+    }
+
+    @AfterEach
+    public void tearDown() {
+        assertTrue(Paths.get(actualResultSqlFile).toFile().delete());
+    }
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/GreenFieldInstallationTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/GreenFieldInstallationTest.java
new file mode 100644
index 0000000..20c81bb
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/GreenFieldInstallationTest.java
@@ -0,0 +1,151 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.oran.smo.teiv.pgsqlgenerator.TestHelper;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+import org.oran.smo.teiv.pgsqlgenerator.schema.BackwardCompatibilityChecker;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.ClassPathResource;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.model.HashInfoDataGenerator;
+
+@SpringBootTest(classes = { DataSchemaGenerator.class, ModelComparator.class, DataSchemaHelper.class, TableBuilder.class,
+        HashInfoDataGenerator.class, BackwardCompatibilityChecker.class }, properties = { "green-field-installation=true" })
+public class GreenFieldInstallationTest {
+
+    static File outputSqlFile;
+    @Autowired
+    private DataSchemaGenerator dataSchemaGenerator;
+    @Autowired
+    private BackwardCompatibilityChecker nbcChecker;
+    @Value("${green-field-installation}")
+    private boolean isGreenFieldInstallation;
+    @Value("${schema.data.skeleton}")
+    private String skeletonDataSqlFile;
+    @Value("${schema.data.output}")
+    private String actualResultSqlFile;
+    @Value("${schema.model.temp-baseline}")
+    private String tempBaselineModelSqlFile;
+
+    @BeforeEach
+    void cleanup() throws IOException {
+        Files.deleteIfExists(Paths.get(tempBaselineModelSqlFile));
+    }
+
+    @Test
+    void prepareSchemaTest() throws IOException {
+        //when
+        dataSchemaGenerator.prepareSchema();
+        File skeletonFile = new ClassPathResource(skeletonDataSqlFile).getFile();
+        outputSqlFile = new File(actualResultSqlFile);
+
+        //then
+        Assertions.assertFalse(new File(tempBaselineModelSqlFile).exists());
+        Assertions.assertTrue(outputSqlFile.exists());
+        Assertions.assertTrue(isGreenFieldInstallation);
+        Assertions.assertTrue(TestHelper.filesCompareByLine(skeletonFile.toPath(), outputSqlFile.toPath()));
+        Assertions.assertTrue(outputSqlFile.delete());
+    }
+
+    @Test
+    void verifyNoExceptionsThrownForNBCWhenGreenfieldEnabled() {
+        //Given
+        List<Table> mockModelServiceEntities = List.of(Table.builder().name("Sector").columns(List.of(Column.builder().name(
+                "azimuth").dataType("DECIMAL").build(), Column.builder().name("id").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(PrimaryKeyConstraint.builder().tableName("Sector").constraintName(
+                                "PK_Source_id").columnToAddConstraintTo("id").build())).build(), Column.builder().name(
+                                        "sectorId").dataType("jsonb").defaultValue("101").build(), Column.builder().name(
+                                                "geo-location").dataType("geography").build())).build());
+
+        // When
+        List<Table> mockBaselineEntitiesTableDeleted = List.of();
+        //Then
+        // Renaming Sector table won't throw exception when green field is enabled
+        Assertions.assertDoesNotThrow(() -> nbcChecker.checkForNBCChangesInData(mockBaselineEntitiesTableDeleted,
+                mockModelServiceEntities));
+
+        // When
+        List<Table> mockBaselineEntitiesColumnRenamed = List.of(Table.builder().name("Sector").columns(List.of(Column
+                .builder().name("azimuth").dataType("DECIMAL").build(), Column.builder().name("id").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(PrimaryKeyConstraint.builder().tableName("Sector").constraintName(
+                                "PK_Source_id").columnToAddConstraintTo("id").build())).build(), Column.builder().name(
+                                        "sectorId123").dataType("jsonb").defaultValue("101").build(), Column.builder().name(
+                                                "geo-location").dataType("geography").build())).build());
+        //Then
+        // Renaming Sector.sectorId won't throw exception when green field is enabled
+        Assertions.assertDoesNotThrow(() -> nbcChecker.checkForNBCChangesInData(mockBaselineEntitiesColumnRenamed,
+                mockModelServiceEntities));
+
+        // When
+        List<Table> mockBaselineEntitiesColumnDeleted = List.of(Table.builder().name("Sector").columns(List.of(Column
+                .builder().name("azimuth").dataType("DECIMAL").build(), Column.builder().name("id").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(PrimaryKeyConstraint.builder().tableName("Sector").constraintName(
+                                "PK_Source_id").columnToAddConstraintTo("id").build())).build(), Column.builder().name(
+                                        "geo-location").dataType("geography").build())).build());
+        //Then
+        Assertions.assertDoesNotThrow(() -> nbcChecker.checkForNBCChangesInData(mockBaselineEntitiesColumnDeleted,
+                mockModelServiceEntities));
+
+        //When
+        //ONE_TO_ONE
+        List<Relationship> baselineRel = List.of(Relationship.builder().name("ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER")
+                .aSideAssociationName("provided-lteSectorCarrier").aSideMOType("ENodeBFunction").aSideMinCardinality(0)
+                .aSideMaxCardinality(1).bSideAssociationName("provided-by-enodebFunction").bSideMOType("LTESectorCarrier")
+                .bSideMinCardinality(0).bSideMaxCardinality(1).associationKind("BI_DIRECTIONAL").relationshipDataLocation(
+                        "B_SIDE").connectSameEntity(false).moduleReferenceName("o-ran-smo-teiv-ran").build());
+
+        //Deleted relationship ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER
+        //Then
+        List<Relationship> mockModelSvcRel1 = List.of(Relationship.builder().name(
+                "LTESECTORCARRIER_PROVIDES_ENODEBFUNCTION").aSideAssociationName("provided-eNodeBFunction").aSideMOType(
+                        "LTESectorCarrier").aSideMinCardinality(0).aSideMaxCardinality(100).bSideAssociationName(
+                                "provided-by-lteSectorCarrier").bSideMOType("ENodeBFunction").bSideMinCardinality(0)
+                .bSideMaxCardinality(100).associationKind("BI_DIRECTIONAL").relationshipDataLocation("RELATION")
+                .connectSameEntity(false).moduleReferenceName("o-ran-smo-teiv-ran").build());
+        Assertions.assertDoesNotThrow(() -> nbcChecker.checkForNBCChangesInModel(baselineRel, mockModelSvcRel1));
+
+        //from ONE_TO_ONE to MANY_TO_MANY
+        List<Relationship> mockModelSvcRel2 = List.of(Relationship.builder().name(
+                "ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER").aSideAssociationName("provided-lteSectorCarrier").aSideMOType(
+                        "ENodeBFunction").aSideMinCardinality(1).aSideMaxCardinality(100).bSideAssociationName(
+                                "provided-by-enodebFunction").bSideMOType("LTESectorCarrier").bSideMinCardinality(0)
+                .bSideMaxCardinality(100).associationKind("BI_DIRECTIONAL").relationshipDataLocation("A_SIDE")
+                .connectSameEntity(false).moduleReferenceName("o-ran-smo-teiv-ran").build());
+        Assertions.assertDoesNotThrow(() -> nbcChecker.checkForNBCChangesInModel(baselineRel, mockModelSvcRel2));
+
+    }
+
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/ModelComparatorTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/ModelComparatorTest.java
new file mode 100644
index 0000000..b428154
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/ModelComparatorTest.java
@@ -0,0 +1,166 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.TestHelper;
+
+@SpringBootTest(classes = { ModelComparator.class, DataSchemaHelper.class })
+class ModelComparatorTest {
+
+    @Autowired
+    private DataSchemaHelper dataSchemaHelper;
+    @Autowired
+    private ModelComparator modelComparator;
+    //spotless:off
+    private final List<Table> mockModelServiceEntities = List.of(
+        Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                        PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build(),
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                        PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build())).build());
+    //spotless:on
+
+    /*
+     * Find differences between extracted data from module service and baseline
+     * Then check if the schema generated for both are the same
+     */
+
+    // Test will all present except table "Namespace". The algorithm should correctly identify difference as well as generate correct schema for the same.
+    @Test
+    void identifyDifferencesInBaselineAndGeneratedWithTableMissingTest() {
+
+        //spotless:off
+
+        // Given baseline mock data
+        List<Table> baselineEntitiesTableMissing = List.of(Table.builder().name("Sector").columns(
+            List.of(Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                        PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build());
+
+        // Correct result of difference below
+        Map<String, List<Table>> correctMappedDifferences = TestHelper.identifiedModelChangeMapping();
+        correctMappedDifferences.get("CREATE").add(Table.builder().name("Namespace").columns(
+            List.of(Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                            PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build())).build());
+
+        //spotless:on
+
+        // When
+        Map<String, List<Table>> mappedDifferences = modelComparator.identifyDifferencesInBaselineAndGenerated(
+                mockModelServiceEntities, baselineEntitiesTableMissing);
+
+        // Then - check if the schema for diff identified above match with the correct result
+        Assertions.assertEquals(dataSchemaHelper.generateSchemaFromDifferences(correctMappedDifferences).toString(),
+                dataSchemaHelper.generateSchemaFromDifferences(mappedDifferences).toString());
+
+    }
+
+    // Test will all present except table "Namespace" & column "Sector.azimuth"
+    @Test
+    void identifyDifferencesInBaselineAndGeneratedWithTableAndAttributesMissingTest() {
+
+        //spotless:off
+
+        // Given baseline mock data
+        List<Table> baselineEntitiesWIthColumnAndTableMissing = List.of(Table.builder().name("Sector").columns(
+            List.of(Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                            PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build());
+
+        // Correct result of difference below
+        Map<String, List<Table>> correctMappedDifferences = TestHelper.identifiedModelChangeMapping();
+        correctMappedDifferences.get("CREATE").add(Table.builder().name("Namespace").columns(
+            List.of(Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                            PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build())).build());
+        correctMappedDifferences.get("ALTER")
+            .add(Table.builder().name("Sector").columns(List.of(Column.builder().name("azimuth").dataType("DECIMAL")
+                    .build())).build());
+
+        //spotless:on
+
+        // When
+        Map<String, List<Table>> mappedDifferences = modelComparator.identifyDifferencesInBaselineAndGenerated(
+                mockModelServiceEntities, baselineEntitiesWIthColumnAndTableMissing);
+
+        // Then - check if the schema for diff identified above match with the correct result
+        Assertions.assertEquals(dataSchemaHelper.generateSchemaFromDifferences(correctMappedDifferences).toString(),
+                dataSchemaHelper.generateSchemaFromDifferences(mappedDifferences).toString());
+    }
+
+    // Test will all present except table "Namespace", column "Sector.azimuth" & No default value set to "Sector.sectorId"
+    @Test
+    void identifyDifferencesInBaselineAndGeneratedWithTableAttributeAndDefaultMissingTest() {
+
+        //spotless:off
+
+        // Given baseline mock data
+        List<Table> baselineEntitiesWIthColumnAndTableAndDefaultValueMissing = List.of(Table.builder().name("Sector").columns(
+            List.of(Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                            PrimaryKeyConstraint.builder().tableName("Sector").constraintName("PK_Source_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build())).build());
+
+        // Correct result of difference below
+        Map<String, List<Table>> correctMappedDifferences = TestHelper.identifiedModelChangeMapping();
+        correctMappedDifferences.get("CREATE").add(Table.builder().name("Namespace").columns(
+            List.of(Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(
+                            PrimaryKeyConstraint.builder().tableName("Namespace").constraintName("PK_Namespace_id").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build())).build());
+        correctMappedDifferences.get("ALTER")
+            .add(Table.builder().name("Sector").columns(List.of(Column.builder().name("azimuth").dataType("DECIMAL")
+                    .build())).build());
+        correctMappedDifferences.get("DEFAULT").add(Table.builder().name("Sector").columns(
+            List.of(Column.builder().name("sectorId").dataType("jsonb").defaultValue("101").build())).build());
+        //spotless:on
+
+        // When
+        Map<String, List<Table>> mappedDifferences = modelComparator.identifyDifferencesInBaselineAndGenerated(
+                mockModelServiceEntities, baselineEntitiesWIthColumnAndTableAndDefaultValueMissing);
+
+        // Then - check if the schema for diff identified above match with the correct result
+        Assertions.assertEquals(dataSchemaHelper.generateSchemaFromDifferences(correctMappedDifferences).toString(),
+                dataSchemaHelper.generateSchemaFromDifferences(mappedDifferences).toString());
+    }
+
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/TableBuilderTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/TableBuilderTest.java
new file mode 100644
index 0000000..7e9041d
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/data/TableBuilderTest.java
@@ -0,0 +1,521 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.data;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockitoAnnotations;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import org.oran.smo.teiv.pgsqlgenerator.Attribute;
+import org.oran.smo.teiv.pgsqlgenerator.Column;
+import org.oran.smo.teiv.pgsqlgenerator.Entity;
+import org.oran.smo.teiv.pgsqlgenerator.UniqueConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.PrimaryKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.ForeignKeyConstraint;
+import org.oran.smo.teiv.pgsqlgenerator.Relationship;
+import org.oran.smo.teiv.pgsqlgenerator.Table;
+import org.oran.smo.teiv.pgsqlgenerator.TestHelper;
+import org.oran.smo.teiv.pgsqlgenerator.schema.model.HashInfoDataGenerator;
+import lombok.extern.slf4j.Slf4j;
+
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.CLASSIFIERS;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.DECORATORS;
+import static org.oran.smo.teiv.pgsqlgenerator.Constants.JSONB;
+
+@Slf4j
+@SpringBootTest(classes = { TableBuilder.class, HashInfoDataGenerator.class })
+class TableBuilderTest {
+    @Autowired
+    private TableBuilder tableBuilder;
+
+    @BeforeEach
+    void setUp() {
+
+        //mocks
+        MockitoAnnotations.openMocks(this);
+
+    }
+
+    //spotless:off
+    List<Entity> entities = List.of(
+            Entity.builder().entityName("Sector").attributes(
+                List.of(
+                    Attribute.builder().name("azimuth").dataType("DECIMAL").build(),
+                    Attribute.builder().name("id").dataType("VARCHAR(511)").constraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                            .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                    Attribute.builder().name("geo-location").dataType("geography").build(),
+                    Attribute.builder().name("sectorId").dataType("jsonb").build()))
+                .moduleReferenceName("").build(),
+
+            Entity.builder().entityName("Namespace").attributes(
+                List.of(
+                    Attribute.builder().name("id").dataType("VARCHAR(511)").constraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                            .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                    Attribute.builder().name("name").dataType("TEXT").build()))
+                .moduleReferenceName("").build());
+
+    List<List<Relationship>> relationships = List.of(
+            List.of(Relationship.builder().name("oneToOne")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(1)
+                    .bSideAssociationName("used-by-Namespace")
+                    .bSideMOType("Namespace")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(1)
+                    .relationshipDataLocation("A_SIDE")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(false)
+                    .moduleReferenceName("").build()),
+            List.of(Relationship.builder().name("oneToMany")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(1)
+                    .bSideAssociationName("used-by-Namespace")
+                    .bSideMOType("Namespace")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(100)
+                    .relationshipDataLocation("B_SIDE")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(false)
+                    .moduleReferenceName("").build()),
+            List.of(Relationship.builder().name("manyToOne")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(100)
+                    .bSideAssociationName("used-by-Namespace")
+                    .bSideMOType("Namespace")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(1)
+                    .relationshipDataLocation("A_SIDE")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(false)
+                    .moduleReferenceName("").build()),
+            List.of(Relationship.builder().name("manyToMany")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(100)
+                    .bSideAssociationName("used-by-Namespace")
+                    .bSideMOType("Namespace")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(100)
+                    .relationshipDataLocation("RELATION")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(false)
+                    .moduleReferenceName("").build()),
+            // Relationship connecting same entity 1:1
+            List.of(Relationship.builder().name("relationshipConnectingSameEntity")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(1)
+                    .bSideAssociationName("used-by-Sector")
+                    .bSideMOType("Sector")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(1)
+                    .relationshipDataLocation("RELATION")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(true)
+                    .moduleReferenceName("").build()),
+            // Relationship connecting same entity 1:N
+            List.of(Relationship.builder().name("relationshipConnectingSameEntity")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(1)
+                    .bSideAssociationName("used-by-Sector")
+                    .bSideMOType("Sector")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(100)
+                    .relationshipDataLocation("RELATION")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(true)
+                    .moduleReferenceName("").build()),
+            // Relationship connecting same entity N:1
+            List.of(Relationship.builder().name("relationshipConnectingSameEntity")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(100)
+                    .bSideAssociationName("used-by-Sector")
+                    .bSideMOType("Sector")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(1)
+                    .relationshipDataLocation("RELATION")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(true)
+                    .moduleReferenceName("").build()),
+            // Relationship connecting same entity N:M
+            List.of(Relationship.builder().name("relationshipConnectingSameEntity")
+                    .aSideAssociationName("used-Sector")
+                    .aSideMOType("Sector")
+                    .aSideMinCardinality(0)
+                    .aSideMaxCardinality(100)
+                    .bSideAssociationName("used-by-Sector")
+                    .bSideMOType("Sector")
+                    .bSideMinCardinality(0)
+                    .bSideMaxCardinality(100)
+                    .relationshipDataLocation("RELATION")
+                    .associationKind("BI_DIRECTIONAL")
+                    .connectSameEntity(true)
+                    .moduleReferenceName("").build()));
+    //spotless:on
+
+    @Test
+    void checkOneToOneRelationshipMappingTest() {
+
+        //spotless:off
+
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name("REL_FK_used-Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_Sector_REL_FK_used-Sector").tableName("Sector")
+                                .referencedTable("Namespace").columnToAddConstraintTo("REL_FK_used-sector").build())).build(),
+                Column.builder().name("REL_ID_oneToOne").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(UniqueConstraint.builder().constraintName("UNIQUE_Sector_REL_ID_oneToOne").tableName("Sector")
+                                .columnToAddConstraintTo("REL_ID_oneToOne").build())).build(),
+                Column.builder().name("REL_CD_sourceIds_oneToOne").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType(JSONB).defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", DECORATORS)).dataType(JSONB).defaultValue("{}").build(),
+                    Column.builder().name(String.format("REL_CD_%s_oneToOne", CLASSIFIERS)).dataType(JSONB).defaultValue("[]").build(),
+                    Column.builder().name(String.format("REL_CD_%s_oneToOne", DECORATORS)).dataType(JSONB).defaultValue("{}").build())).build(),
+
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build());
+
+        //spotless:on
+
+        // When
+        List<Table> actualResult = tableBuilder.getTables(entities, relationships.get(0));
+
+        // Then
+        runTest(actualResult, expectedResult);
+    }
+
+    @Test
+    void checkOneToManyRelationshipMappingTest() {
+
+        //spotless:off
+
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build(),
+
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name("REL_FK_used-by-Namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_Namespace_REL_FK_used-by-Namespace")
+                                .tableName("Namespace").referencedTable("Sector").columnToAddConstraintTo("REL_FK_used-by-Namespace").build())).build(),
+                Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build(),
+                Column.builder().name("REL_ID_oneToMany").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(UniqueConstraint.builder().constraintName("UNIQUE_Namespace_REL_ID_oneToMany").tableName("Namespace")
+                                .columnToAddConstraintTo("REL_ID_oneToMany").build())).build(),
+                Column.builder().name("REL_CD_sourceIds_oneToMany").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("REL_CD_%s_oneToMany", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("REL_CD_%s_oneToMany", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build());
+        //spotless:on
+
+        // When
+        List<Table> actualResult = tableBuilder.getTables(entities, relationships.get(1));
+
+        // Then
+        runTest(actualResult, expectedResult);
+
+    }
+
+    @Test
+    void checkManyToOneRelationshipMappingTest() {
+
+        //spotless:off
+
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build(),
+                Column.builder().name("REL_FK_used-Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_Sector_REL_FK_used-Sector").tableName("Sector")
+                                .referencedTable("Namespace").columnToAddConstraintTo("REL_FK_used-sector").build())).build(),
+                Column.builder().name("REL_ID_manyToOne").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(UniqueConstraint.builder().constraintName("UNIQUE_Sector_REL_ID_manyToOne").tableName("Sector")
+                                .columnToAddConstraintTo("REL_ID_oneToOne").build())).build(),
+                Column.builder().name("REL_CD_sourceIds_manyToOne").dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("REL_CD_%s_manyToOne", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("REL_CD_%s_manyToOne", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build(),
+
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build());
+        //spotless:on
+
+        // When
+        List<Table> actualResult = tableBuilder.getTables(entities, relationships.get(2));
+
+        // Then
+        runTest(actualResult, expectedResult);
+
+    }
+
+    @Test
+    void checkManyToManyRelationshipMappingTest() {
+        //spotless:off
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build(),
+
+        Table.builder().name("Namespace").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Namespace_id")
+                        .tableName("Namespace").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("name").dataType("TEXT").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build(),
+
+        Table.builder().name("manyToMany").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_manyToMany_id")
+                        .tableName("manyToMany").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("aSide_Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_manyToMany_aSide_Sector")
+                                .tableName("manyToMany").referencedTable("Sector").columnToAddConstraintTo("aSide_Sector").build())).build(),
+                Column.builder().name("bSide_Namespace").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_manyToMany_bSide_Namespace")
+                                .tableName("manyToMany").referencedTable("Namespace").columnToAddConstraintTo("bSide_Namespace").build())).build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                    Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build());
+        //spotless:on
+
+        // When
+        List<Table> actualResult = tableBuilder.getTables(entities, relationships.get(3));
+
+        // Then
+        runTest(actualResult, expectedResult);
+    }
+
+    @Test
+    void checkRelationshipConnectingSameEntityMappingTest() {
+        //spotless:off
+        List<Entity> sameEntities = List.of(
+
+            Entity.builder().entityName("Sector").attributes(
+                List.of(Attribute.builder().name("azimuth").dataType("DECIMAL").build(),
+                    Attribute.builder().name("id").dataType("VARCHAR(511)").constraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                            .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                    Attribute.builder().name("sectorId").dataType("jsonb").build(),
+                    Attribute.builder().name("geo-location").dataType("geography").build()))
+                .moduleReferenceName("").build());
+
+        // Given
+        List<Table> expectedResult = List.of(Table.builder().name("Sector").columns(
+            List.of(
+                Column.builder().name("azimuth").dataType("DECIMAL").build(),
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder().constraintName("PK_Sector_id")
+                        .tableName("Sector").columnToAddConstraintTo("id").build())).build(),
+                Column.builder().name("sectorId").dataType("jsonb").build(),
+                Column.builder().name("geo-location").dataType("geography").build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build(),
+
+        Table.builder().name("relationshipConnectingSameEntity").columns(
+            List.of(
+                Column.builder().name("id").dataType("VARCHAR(511)").postgresConstraints(List.of(PrimaryKeyConstraint.builder()
+                        .constraintName("PK_relationshipConnectingSameEntity_id").tableName("relationshipConnectingSameEntity").columnToAddConstraintTo("id")
+                        .build())).build(),
+                Column.builder().name("aSide_Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_relationshipConnectingSameEntity_aSide_Sector")
+                                .tableName("relationshipConnectingSameEntity").referencedTable("Sector").columnToAddConstraintTo("aSide_Sector").build())).build(),
+                Column.builder().name("bSide_Sector").dataType("VARCHAR(511)")
+                        .postgresConstraints(List.of(ForeignKeyConstraint.builder().constraintName("FK_relationshipConnectingSameEntity_bSide_Sector")
+                                .tableName("relationshipConnectingSameEntity").referencedTable("Sector").columnToAddConstraintTo("bSide_Sector").build())).build(),
+                Column.builder().name("CD_sourceIds").dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", CLASSIFIERS)).dataType("jsonb").defaultValue("[]").build(),
+                Column.builder().name(String.format("CD_%s", DECORATORS)).dataType("jsonb").defaultValue("{}").build())).build());
+        //spotless:on
+
+        // When
+        List<Table> actualResultOneToOne = tableBuilder.getTables(sameEntities, relationships.get(4));
+        List<Table> actualResultOneToMany = tableBuilder.getTables(sameEntities, relationships.get(5));
+        List<Table> actualResultManyToOne = tableBuilder.getTables(sameEntities, relationships.get(6));
+        List<Table> actualResultManyToMany = tableBuilder.getTables(sameEntities, relationships.get(7));
+
+        // Then
+        // Test relationship connecting same entity (one to one)
+        runTest(actualResultOneToOne, expectedResult);
+
+        // Test relationship connecting same entity (one to many)
+        runTest(actualResultOneToMany, expectedResult);
+
+        // Test relationship connecting same entity (many to one)
+        runTest(actualResultManyToOne, expectedResult);
+
+        // Test relationship connecting same entity (many to many)
+        runTest(actualResultManyToMany, expectedResult);
+
+    }
+
+    void runTest(List<Table> generatedTables, List<Table> expectedTables) {
+
+        List<String> allTableNamesFromGeneratedResult = TestHelper.extractTableNames(generatedTables);
+        List<String> allTableNamesFromExpectedResult = TestHelper.extractTableNames(expectedTables);
+
+        // Check if generatedResult contains all tables
+        Assertions.assertEquals(allTableNamesFromExpectedResult, allTableNamesFromGeneratedResult);
+
+        //spotless:off
+        expectedTables.forEach(expectedTable -> {
+            generatedTables.stream().filter(generatedTable -> generatedTable.getName().equals(expectedTable.getName())).findFirst()
+                .ifPresent(generatedTable -> {
+                    List<Column> columnsInExpected = expectedTable.getColumns();
+                    List<Column> columnsInGenerated = generatedTable.getColumns();
+
+                    // Check if all columns for each table were added correctly
+                    Assertions.assertEquals(columnsInExpected.size(), columnsInGenerated.size());
+
+                    List<String> allColumnNamesForATableInGeneratedResult = TestHelper.extractColumnNamesForATable(columnsInGenerated);
+                    List<String> allColumnNamesForATableInExpectedResult = TestHelper.extractColumnNamesForATable(columnsInExpected);
+
+                    // Check if generatedResult contains all columns for a table
+                    Assertions.assertEquals(allColumnNamesForATableInExpectedResult, allColumnNamesForATableInGeneratedResult);
+
+                    columnsInExpected.forEach(columnInExpected -> {
+                        columnsInGenerated.stream().filter(columnInGenerated -> columnInGenerated.getName().equals(columnInExpected.getName()))
+                            .findFirst().ifPresent(columnInGenerated -> {
+
+                                if (columnInExpected.getName().equals("id")) {
+                                    Assertions.assertEquals("VARCHAR(511)", columnInGenerated.getDataType());
+                                    Assertions.assertTrue(TestHelper.checkIfColumnIsPrimaryKey(columnInGenerated.getPostgresConstraints()));
+                                }
+
+                                // Check if each attributes' datatype is picked correctly
+                                Assertions.assertEquals(columnInExpected.getDataType().replace("\"", ""), columnInGenerated.getDataType());
+
+                                // Check if each attributes' default value is picked correctly
+                                Assertions.assertEquals(columnInExpected.getDefaultValue(), columnInGenerated.getDefaultValue());
+
+                                if (!columnInExpected.getPostgresConstraints().isEmpty()) {
+
+                                    Assertions.assertEquals(columnInExpected.getPostgresConstraints().size(), columnInGenerated.getPostgresConstraints().size());
+
+                                    List<String> expectedConstraintNames = TestHelper.extractConstraintName(columnInExpected.getPostgresConstraints());
+                                    List<String> actualConstraintNames = TestHelper.extractConstraintName(columnInGenerated.getPostgresConstraints());
+
+                                    // Check if constraint names in expected result match with those in actual result
+                                    Assertions.assertEquals(expectedConstraintNames, actualConstraintNames);
+
+                                    columnInExpected.getPostgresConstraints().forEach(constraint -> {
+                                        columnInGenerated.getPostgresConstraints().stream()
+                                            .filter(constraint1 -> constraint1.getConstraintName().equals(constraint.getConstraintName())).findFirst()
+                                            .ifPresent(constraint1 -> {
+
+                                                // Check table name where constraint is to be added
+                                                Assertions.assertEquals(constraint.getTableToAddConstraintTo(), constraint.getTableToAddConstraintTo());
+
+                                                // Check column where constraint is to be added
+                                                Assertions.assertEquals(constraint.getColumnToAddConstraintTo(), constraint.getColumnToAddConstraintTo());
+
+                                                if (constraint instanceof ForeignKeyConstraint expectedFk) {
+                                                    ForeignKeyConstraint actualFK = (ForeignKeyConstraint) constraint1;
+
+                                                    Assertions.assertEquals(expectedFk.getReferencedTable(), actualFK.getReferencedTable());
+                                                }
+                                            });
+                                    });
+                                }
+                            });
+                    });
+                });
+        });
+        //spotless:on
+    }
+
+    Collection<Object> addEModelPrimaryKeyConstraint() {
+        Collection<Object> eModelPrimaryKeyConstraint = new ArrayList<>();
+        try {
+            Constructor<PrimaryKeyConstraint> constructor = PrimaryKeyConstraint.class.getDeclaredConstructor();
+            eModelPrimaryKeyConstraint.add(constructor.newInstance());
+        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
+            log.error("Failure in tests --> Error while adding primary key constraint: " + e.getMessage());
+        }
+        return eModelPrimaryKeyConstraint;
+    }
+
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/HashInfoDataGeneratorTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/HashInfoDataGeneratorTest.java
new file mode 100644
index 0000000..84af934
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/HashInfoDataGeneratorTest.java
@@ -0,0 +1,70 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.model;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+
+import org.oran.smo.teiv.pgsqlgenerator.Constants;
+import org.oran.smo.teiv.pgsqlgenerator.HashInfoEntity;
+
+@SpringBootTest(classes = HashInfoDataGenerator.class)
+@ActiveProfiles("test")
+class HashInfoDataGeneratorTest {
+
+    @Autowired
+    private HashInfoDataGenerator hashInfoDataGenerator;
+
+    // 64 character string
+    final String longString = "looooooooooooooooooooooooooooooooooooooooooooooooooooooongString";
+    final String hashValue = "4F29EB756894D5F3ADB9F615D1A00F1AE04A8C54";
+
+    @Test
+    void generateHashInfoRowTest() {
+        // Given
+
+        List<HashInfoEntity> expectedResult = List.of(HashInfoEntity.builder().name("Sector").hashedValue("Sector").type(
+                Constants.TABLE).build(), HashInfoEntity.builder().name("azimuth").hashedValue("azimuth").type(
+                        Constants.TABLE).build(), HashInfoEntity.builder().name(longString).hashedValue(hashValue).type(
+                                Constants.COLUMN).build());
+
+        //when
+        populateHashInfoTable();
+
+        //then
+        List<HashInfoEntity> codeBookList = new ArrayList<>(hashInfoDataGenerator.getHashInfoRowsList());
+        assertTrue(expectedResult.containsAll(codeBookList) && codeBookList.containsAll(expectedResult),
+                "Expected and Actual code book entries differs");
+    }
+
+    private void populateHashInfoTable() {
+        hashInfoDataGenerator.generateHashAndRegisterTableRow(Constants.NO_PREFIX, "Sector", Constants.TABLE);
+        hashInfoDataGenerator.generateHashAndRegisterTableRow(Constants.NO_PREFIX, "azimuth", Constants.COLUMN);
+        hashInfoDataGenerator.generateHashAndRegisterTableRow(Constants.NO_PREFIX, longString, Constants.COLUMN);
+    }
+}
diff --git a/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/ModelSchemaGeneratorTest.java b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/ModelSchemaGeneratorTest.java
new file mode 100644
index 0000000..23e436c
--- /dev/null
+++ b/pgsql-schema-generator/src/test/java/org/oran/smo/teiv/pgsqlgenerator/schema/model/ModelSchemaGeneratorTest.java
@@ -0,0 +1,80 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.pgsqlgenerator.schema.model;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.oran.smo.teiv.pgsqlgenerator.schema.BackwardCompatibilityChecker;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.ClassPathResource;
+
+import org.oran.smo.teiv.pgsqlgenerator.TestHelper;
+import org.oran.smo.teiv.pgsqlgenerator.YangParser;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest(classes = { HashInfoDataGenerator.class, ModelSchemaGenerator.class, YangParser.class,
+        BackwardCompatibilityChecker.class }, properties = { "green-field-installation=false" })
+public class ModelSchemaGeneratorTest {
+
+    @Autowired
+    private ModelSchemaGenerator modelSchemaGenerator;
+
+    static File generatedResultFile;
+    static File tempBaselineFile;
+    @Value("${test-result.model}")
+    private String expectedResultSqlFile;
+    @Value("${schema.model.output}")
+    private String actualResultSqlFile;
+    @Value("${schema.model.skeleton}")
+    private String skeletonModelSqlFile;
+    @Value("${schema.model.baseline}")
+    private String baselineModelSqlFile;
+    @Value("${schema.model.temp-baseline}")
+    private String tempBaselineModelSqlFile;
+
+    @Test
+    void prepareSchemaTest() throws IOException {
+        //when
+        modelSchemaGenerator.prepareSchema();
+        File skeletionFile = new ClassPathResource(skeletonModelSqlFile).getFile();
+        generatedResultFile = new File(actualResultSqlFile);
+        tempBaselineFile = new File(tempBaselineModelSqlFile);
+
+        //then
+        assertTrue(generatedResultFile.exists());
+        assertTrue(tempBaselineFile.exists());
+        assertTrue(TestHelper.filesCompareByLine(skeletionFile.toPath(), generatedResultFile.toPath()));
+        assertTrue(TestHelper.filesCompareByLine(new File(baselineModelSqlFile).toPath(), tempBaselineFile.toPath()));
+    }
+
+    @AfterAll
+    public static void teardown() {
+        assertTrue(generatedResultFile.delete());
+        assertTrue(tempBaselineFile.delete());
+    }
+
+}
diff --git a/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/entities/mock_00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/entities/mock_00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..89da1ee
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/entities/mock_00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,81 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.entity_info("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+	"id"			 VARCHAR(511),
+	"azimuth"			DECIMAL,
+	"sectorId"			 jsonb,
+	"geo-location"			"geography"
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."Namespace" (
+	"id"			 VARCHAR(511),
+	"name"			TEXT
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'PK_Namespace_id',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+COMMIT;
+
+
diff --git a/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/manyToMany/mock_00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/manyToMany/mock_00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..91e2606
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/manyToMany/mock_00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,101 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.entity_info("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+	"id"			 VARCHAR(511),
+	"azimuth"			DECIMAL,
+	"sectorId"			 jsonb,
+	"geo-location"			"geography"
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."Namespace" (
+	"id"			 VARCHAR(511),
+	"name"			TEXT
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."REL_serviced-sector_serving-namespace" (
+	"id"			VARCHAR(511),
+	"aSide_Sector"			VARCHAR(511),
+	"bSide_Namespace"			VARCHAR(511)
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'PK_Namespace_id',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'REL_serviced-sector_serving-namespace',
+ 'PK_REL_serviced-sector_serving-namespace_id',
+ 'ALTER TABLE ties_data."REL_serviced-sector_serving-namespace" ADD CONSTRAINT "PK_REL_serviced-sector_serving-namespace_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'REL_serviced-sector_serving-namespace',
+ 'FK_REL_serviced-sector_serving-namespace_aSide_Sector',
+ 'ALTER TABLE ties_data."REL_serviced-sector_serving-namespace" ADD CONSTRAINT FK_REL_serviced-sector_serving-namespace_aSide_Sector FOREIGN KEY ("aSide_Sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;')
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'REL_serviced-sector_serving-namespace',
+ 'FK_REL_serviced-sector_serving-namespace_bSide_Namespace',
+ 'ALTER TABLE ties_data."REL_serviced-sector_serving-namespace" ADD CONSTRAINT FK_REL_serviced-sector_serving-namespace_bSide_Namespace FOREIGN KEY ("bSide_Namespace") REFERENCES ties_data."Namespace" (id) ON DELETE CASCADE;')
+
+COMMIT;
diff --git a/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/manyToOne/mock_00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/manyToOne/mock_00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..6cae7ca
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/manyToOne/mock_00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,93 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.entity_info("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+	"id"			 VARCHAR(511),
+	"azimuth"			DECIMAL,
+	"sectorId"			 jsonb,
+	"geo-location"			"geography",
+	"REL_FK_serviced-sector"			VARCHAR(511),
+    "REL_ID_serviced-sector_serving-namespace"			VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."Namespace" (
+	"id"			 VARCHAR(511),
+	"name"			TEXT
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'PK_Namespace_id',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'FK_Sector_REL_FK_serviced-sector',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "FK_Sector_REL_FK_serviced-sector" FOREIGN KEY ("REL_FK_serviced-sector") REFERENCES ties_data."Namespace" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'UNIQUE_Sector_REL_ID_serviced-sector_serving-namespace',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "UNIQUE_Sector_REL_ID_serviced-sector_serving-namespace" UNIQUE ("REL_ID_serviced-sector_serving-namespace");'
+);
+
+COMMIT;
diff --git a/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/oneToMany/mock_00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/oneToMany/mock_00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..34c5019
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/oneToMany/mock_00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,93 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.entity_info("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+	"id"			 VARCHAR(511),
+	"azimuth"			DECIMAL,
+	"sectorId"			 jsonb,
+	"geo-location"			"geography"
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."Namespace" (
+	"id"			 VARCHAR(511),
+	"name"			TEXT,
+	"REL_FK_serving-namespace"			VARCHAR(511),
+	"REL_ID_serviced-sector_serving-namespace"			VARCHAR(511)
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'PK_Namespace_id',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'FK_Namespace_REL_FK_serving-namespace',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "FK_Namespace_REL_FK_serving-namespace" FOREIGN KEY ("REL_FK_serving-namespace") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'UNIQUE_Namespace_REL_ID_serviced-sector_serving-namespace',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "UNIQUE_Namespace_REL_ID_serviced-sector_serving-namespace" UNIQUE ("REL_ID_serviced-sector_serving-namespace");'
+);
+
+COMMIT;
diff --git a/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/oneToOne/mock_00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/oneToOne/mock_00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..c7057bc
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/oneToOne/mock_00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,100 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.entity_info("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+	"id"			 VARCHAR(511),
+	"azimuth"			DECIMAL,
+	"sectorId"			 jsonb,
+	"geo-location"			"geography",
+	"REL_FK_serviced-sector"			VARCHAR(511),
+    "REL_ID_serviced-sector_serving-namespace"			VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."Namespace" (
+	"id"			 VARCHAR(511),
+	"name"			TEXT,
+	"REL_FK_serving-namespace"			VARCHAR(511)
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'PK_Namespace_id',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'FK_Sector_REL_FK_serviced-sector',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "FK_Sector_REL_FK_serviced-sector" FOREIGN KEY ("REL_FK_serviced-sector") REFERENCES ties_data."Namespace" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'FK_Namespace_REL_FK_serving-namespace',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "FK_Namespace_REL_FK_serving-namespace" FOREIGN KEY ("REL_FK_serving-namespace") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'UNIQUE_Sector_REL_ID_serviced-sector_serving-namespace',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "UNIQUE_Sector_REL_ID_serviced-sector_serving-namespace" UNIQUE ("REL_ID_serviced-sector_serving-namespace");'
+);
+
+COMMIT;
diff --git a/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/sameEntities/mock_00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/sameEntities/mock_00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..1bd776d
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/SchemaParserTest/data/relationships/sameEntities/mock_00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,90 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.entity_info("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+	"id"			 VARCHAR(511),
+	"azimuth"			DECIMAL,
+	"sectorId"			 jsonb,
+	"geo-location"			"geography"
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."REL_serviced-sector_serving-sector" (
+	"id"			VARCHAR(511),
+	"aSide_Sector"			VARCHAR(511),
+	"bSide_Sector"			VARCHAR(511)
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'REL_serviced-sector_serving-sector',
+ 'PK_REL_serviced-sector_serving-sector_id',
+ 'ALTER TABLE ties_data."REL_serviced-sector_serving-sector" ADD CONSTRAINT "PK_REL_serviced-sector_serving-sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'REL_serviced-sector_serving-sector',
+ 'FK_REL_serviced-sector_serving-sector_aSide_Sector',
+ 'ALTER TABLE ties_data."REL_serviced-sector_serving-sector" ADD CONSTRAINT "FK_REL_serviced-sector_serving-sector_aSide_Sector" FOREIGN KEY ("aSide_Sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;')
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'REL_serviced-sector_serving-sector',
+ 'FK_REL_serviced-sector_serving-sector_bSide_Sector',
+ 'ALTER TABLE ties_data."REL_serviced-sector_serving-sector" ADD CONSTRAINT "FK_REL_serviced-sector_serving-sector_bSide_Sector FOREIGN KEY" ("bSide_Sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;')
+
+COMMIT;
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/SchemaParserTest/model/mock_01_init-oran-smo-teiv-model.sql b/pgsql-schema-generator/src/test/resources/SchemaParserTest/model/mock_01_init-oran-smo-teiv-model.sql
new file mode 100644
index 0000000..6c71cc4
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/SchemaParserTest/model/mock_01_init-oran-smo-teiv-model.sql
@@ -0,0 +1,109 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+DROP SCHEMA IF EXISTS ties_model cascade;
+CREATE SCHEMA IF NOT EXISTS ties_model;
+ALTER SCHEMA ties_model OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+CREATE TABLE IF NOT EXISTS ties_model.execution_status (
+    "schema"                 VARCHAR(127) PRIMARY KEY,
+    "status"          VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.hash_info (
+    "name"                 VARCHAR(511) PRIMARY KEY,
+    "hashedValue"          VARCHAR(511),
+    "type"                 VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.module_reference (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "namespace"              VARCHAR(511),
+    "domain"             VARCHAR(511),
+    "includedModules"        jsonb,
+    "revision"       VARCHAR(511),
+    "content"               TEXT,
+    "ownerAppId"       VARCHAR(511),
+    "status"       VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.entity_info (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.relationship_info (
+    "name"      VARCHAR(511) PRIMARY KEY,
+    "aSideAssociationName"    TEXT,
+    "aSideMOType"             TEXT,
+    "aSideMinCardinality"     BIGINT,
+    "aSideMaxCardinality"     BIGINT,
+    "bSideAssociationName"    TEXT,
+    "bSideMOType"             TEXT,
+    "bSideMinCardinality"     BIGINT,
+    "bSideMaxCardinality"     BIGINT,
+    "associationKind"    TEXT,
+    "relationshipDataLocation"          TEXT,
+    "connectSameEntity"       BOOLEAN,
+    "moduleReferenceName"     TEXT,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.decorators (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "dataType"                   VARCHAR(511),
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.classifiers (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+-- Update model schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_model', 'success');
+
+COPY ties_model.hash_info("name", "hashedValue", "type") FROM stdin;
+\.
+
+COPY ties_model.module_reference("name", "namespace", "domain", "includedModules", "revision", "content", "ownerAppId", "status") FROM stdin;
+\.
+
+COPY ties_model.entity_info("name", "moduleReferenceName") FROM stdin;
+\.
+
+COPY ties_model.relationship_info("name", "aSideAssociationName", "aSideMOType", "aSideMinCardinality", "aSideMaxCardinality", "bSideAssociationName", "bSideMOType", "bSideMinCardinality", "bSideMaxCardinality", "associationKind", "relationshipDataLocation", "connectSameEntity", "moduleReferenceName") FROM stdin;
+ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	provided-lteSectorCarrier	ENodeBFunction	1	1	provided-by-enodebFunction	LTESectorCarrier	0	100	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+LTESECTORCARRIER_USES_ANTENNACAPABILITY	used-antennaCapability	LTESectorCarrier	0	1	used-by-lteSectorCarrier	AntennaCapability	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-ran
+\.
+
+;
+
+COMMIT;
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/application.yaml b/pgsql-schema-generator/src/test/resources/application.yaml
new file mode 100644
index 0000000..fe3176f
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/application.yaml
@@ -0,0 +1,39 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+green-field-installation: true
+yang-model:
+  source: classpath:generate-defaults
+schema:
+  data:
+    skeleton: scripts/00_init-oran-smo-teiv-data.sql
+    baseline: src/test/resources/baseline-schema/00_init-oran-smo-teiv-data.sql
+    output: target/test-classes/TEST_00_init-oran-smo-teiv-data.sql
+  model:
+    skeleton: scripts/01_init-oran-smo-teiv-model.sql
+    baseline: src/test/resources/baseline-schema/01_init-oran-smo-teiv-model.sql
+    temp-baseline: target/test-classes/01_init-oran-smo-teiv-model_baseline.sql
+    output: target/test-classes/TEST_01_init-oran-smo-teiv-model.sql
+test-result:
+    data: src/test/resources/expected-db-schema/result_00_init-oran-smo-teiv-data.sql
+    model: src/test/resources/expected-db-schema/result_01_init-oran-smo-teiv-model.sql
+exclusions:
+  model-names: metadata, decorators
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/baseline-schema/00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/baseline-schema/00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..b356a1f
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/baseline-schema/00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,140 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_data', 'success');
+
+--missing CD_sourceIds column and its default value
+CREATE TABLE IF NOT EXISTS ties_data."AntennaModule" (
+	"id"			VARCHAR(511),
+	"positionWithinSector"			TEXT,
+	"electricalAntennaTilt"			BIGINT,
+	"mechanicalAntennaBearing"			BIGINT,
+	"antennaBeamWidth"			jsonb,
+	"mechanicalAntennaTilt"			BIGINT,
+	"antennaModelNumber"			TEXT,
+	"totalTilt"			BIGINT,
+	"geo-location"	geography
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaModule',
+ 'PK_AntennaModule_id',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "PK_AntennaModule_id" PRIMARY KEY ("id");'
+);
+
+--missing eNodeBPlmnId column
+CREATE TABLE IF NOT EXISTS ties_data."ENodeBFunction" (
+	"id"			VARCHAR(511),
+	"eNBId"			BIGINT,
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "eNBId" SET DEFAULT '11';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ENodeBFunction',
+ 'PK_ENodeBFunction_id',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "PK_ENodeBFunction_id" PRIMARY KEY ("id");'
+);
+
+--missing "ANTENNACAPABILITY_USED_BY_LTESECTORCARRIER" relationship
+CREATE TABLE IF NOT EXISTS ties_data."AntennaCapability" (
+	"id"			VARCHAR(511),
+	"geranFqBands"			jsonb,
+	"nRFqBands"			jsonb,
+	"eUtranFqBands"			jsonb,
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaCapability',
+ 'PK_AntennaCapability_id',
+ 'ALTER TABLE ties_data."AntennaCapability" ADD CONSTRAINT "PK_AntennaCapability_id" PRIMARY KEY ("id");'
+);
+
+CREATE TABLE IF NOT EXISTS ties_data."LTESectorCarrier" (
+	"id"			VARCHAR(511),
+	"sectorCarrierType"			TEXT,
+	"CD_sourceIds"			jsonb,
+	"REL_FK_provided-by-enodebFunction"			VARCHAR(511),
+	"REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"			VARCHAR(511),
+	"REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'PK_LTESectorCarrier_id',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "PK_LTESectorCarrier_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9" UNIQUE ("REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction" FOREIGN KEY ("REL_FK_provided-by-enodebFunction") REFERENCES ties_data."ENodeBFunction" (id) ON DELETE CASCADE;'
+);
+
+COMMIT;
+
+
diff --git a/pgsql-schema-generator/src/test/resources/baseline-schema/01_init-oran-smo-teiv-model.sql b/pgsql-schema-generator/src/test/resources/baseline-schema/01_init-oran-smo-teiv-model.sql
new file mode 100644
index 0000000..089b788
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/baseline-schema/01_init-oran-smo-teiv-model.sql
@@ -0,0 +1,150 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+
+BEGIN;
+
+DROP SCHEMA IF EXISTS ties_model cascade;
+CREATE SCHEMA IF NOT EXISTS ties_model;
+ALTER SCHEMA ties_model OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+CREATE TABLE IF NOT EXISTS ties_model.execution_status (
+    "schema"                 VARCHAR(127) PRIMARY KEY,
+    "status"          VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.hash_info (
+    "name"                 VARCHAR(511) PRIMARY KEY,
+    "hashedValue"          VARCHAR(511),
+    "type"                 VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.module_reference (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "namespace"              VARCHAR(511),
+    "domain"             VARCHAR(511),
+    "includedModules"        jsonb,
+    "revision"       VARCHAR(511),
+    "content"               TEXT,
+    "ownerAppId"       VARCHAR(511),
+    "status"       VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.entity_info (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.relationship_info (
+    "name"      VARCHAR(511) PRIMARY KEY,
+    "aSideAssociationName"    TEXT,
+    "aSideMOType"             TEXT,
+    "aSideMinCardinality"     BIGINT,
+    "aSideMaxCardinality"     BIGINT,
+    "bSideAssociationName"    TEXT,
+    "bSideMOType"             TEXT,
+    "bSideMinCardinality"     BIGINT,
+    "bSideMaxCardinality"     BIGINT,
+    "associationKind"    TEXT,
+    "relationshipDataLocation"          TEXT,
+    "connectSameEntity"       BOOLEAN,
+    "moduleReferenceName"     TEXT,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.decorators (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "dataType"                   VARCHAR(511),
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.classifiers (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+-- Update model schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_model', 'success');
+
+COPY ties_model.hash_info("name", "hashedValue", "type") FROM stdin;
+AntennaModule	AntennaModule	TABLE
+positionWithinSector	positionWithinSector	COLUMN
+electricalAntennaTilt	electricalAntennaTilt	COLUMN
+mechanicalAntennaBearing	mechanicalAntennaBearing	COLUMN
+AntennaBeamWidth	AntennaBeamWidth	COLUMN
+mechanicalAntennaTilt	mechanicalAntennaTilt	COLUMN
+antennaModelNumber	antennaModelNumber	COLUMN
+totalTilt	totalTilt	COLUMN
+PK_AntennaModule_id	PK_AntennaModule_id	CONSTRAINT
+CloudSite	CloudSite	TABLE
+geo-location	geo-location	COLUMN
+CD_sourceIds	CD_sourceIds	COLUMN
+PK_CloudSite_id	PK_CloudSite_id	CONSTRAINT
+ENodeBFunction	ENodeBFunction	TABLE
+eNBId	eNBId	COLUMN
+eNodeBPlmnId	eNodeBPlmnId	COLUMN
+PK_ENodeBFunction_id	PK_ENodeBFunction_id	CONSTRAINT
+AntennaCapability	AntennaCapability	TABLE
+geranFqBands	geranFqBands	COLUMN
+nRFqBands	nRFqBands	COLUMN
+eUtranFqBands	eUtranFqBands	COLUMN
+PK_AntennaCapability_id	PK_AntennaCapability_id	CONSTRAINT
+LTESectorCarrier	LTESectorCarrier	TABLE
+sectorCarrierType	sectorCarrierType	COLUMN
+REL_FK_provided-by-enodebFunction	REL_FK_provided-by-enodebFunction	COLUMN
+REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+PK_LTESectorCarrier_id	PK_LTESectorCarrier_id	CONSTRAINT
+UNIQUE_LTESectorCarrier_REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9	CONSTRAINT
+FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	CONSTRAINT
+\.
+
+COPY ties_model.module_reference("name", "namespace", "domain", "includedModules", "revision", "content", "ownerAppId", "status") FROM stdin;
+o-ran-smo-teiv-common-yang-extensions	urn:o-ran:smo-teiv-common-yang-extensions	\N	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMgewoKICB5YW5nLXZlcnNpb24gMS4xOwogIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMiOwogIHByZWZpeCBvci10ZWl2LXlleHQ7CgogIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOwogIGRlc2NyaXB0aW9uCiAgIlRvcG9sb2d5IGFuZCBJbnZlbnRvcnkgWUFORyBleHRlbnNpb25zIG1vZGVsLgoKICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogIFRoaXMgbW9kZWwgY29udGFpbnMgZXh0ZW5zaW9ucyB0byB0aGUgWUFORyBsYW5ndWFnZSB0aGF0IHRvcG9sb2d5IGFuZAogIGludmVudG9yeSBtb2RlbHMgd2lsbCB1c2UgdG8gZGVmaW5lIGFuZCBhbm5vdGF0ZSB0eXBlcyBhbmQgcmVsYXRpb25zaGlwcy4iOwoKICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgewogICAgZGVzY3JpcHRpb24gIkluaXRpYWwgcmV2aXNpb24uIjsKICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICB9CgogIGV4dGVuc2lvbiBiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgewoKICAgIGRlc2NyaXB0aW9uCiAgICAgICJEZWZpbmVzIGEgYmktZGlyZWN0aW9uYWwgcmVsYXRpb25zaGlwIGluIHRoZSB0b3BvbG9neS4KCiAgICAgICBBIGJpLWRpcmVjdGlvbmFsLWFzc29jaWF0aW9uIChCREEpIGlzIGEgcmVsYXRpb25zaGlwIGNvbXByaXNpbmcgb2YgYW4KICAgICAgIEEtc2lkZSBhbmQgYSBCLXNpZGUuIFRoZSBBLXNpZGUgaXMgY29uc2lkZXJlZCB0aGUgb3JpZ2luYXRpbmcgc2lkZSBvZgogICAgICAgdGhlIHJlbGF0aW9uc2hpcDsgdGhlIEItc2lkZSBpcyBjb25zaWRlcmVkIHRoZSB0ZXJtaW5hdGluZyBzaWRlIG9mIHRoZQogICAgICAgcmVsYXRpb25zaGlwLiBUaGUgb3JkZXIgb2YgQS1zaWRlIGFuZCBCLXNpZGUgaXMgb2YgaW1wb3J0YW5jZSBhbmQgTVVTVAogICAgICAgTk9UIGJlIGNoYW5nZWQgb25jZSBkZWZpbmVkLgoKICAgICAgIEJvdGggQS1zaWRlIGFuZCBCLXNpZGUgYXJlIGRlZmluZWQgb24gYSB0eXBlLCBhbmQgYXJlIGdpdmVuIGEgcm9sZS4gQQogICAgICAgdHlwZSBtYXkgaGF2ZSBtdWx0aXBsZSBvcmlnaW5hdGluZyBhbmQvb3IgdGVybWluYXRpbmcgc2lkZXMgb2YgYQogICAgICAgcmVsYXRpb25zaGlwLCBhbGwgZGlzdGluZ3Vpc2hlZCBieSByb2xlIG5hbWUuCgogICAgICAgVGhlIHN0YXRlbWVudCBNVVNUIG9ubHkgYmUgYSBzdWJzdGF0ZW1lbnQgb2YgdGhlICdtb2R1bGUnIHN0YXRlbWVudC4KICAgICAgIE11bHRpcGxlICdiaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIHN0YXRlbWVudHMgYXJlIGFsbG93ZWQKICAgICAgIHBlciBwYXJlbnQgc3RhdGVtZW50LgoKICAgICAgIFN1YnN0YXRlbWVudHMgdG8gdGhlICdiaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIGRlZmluZSB0aGUKICAgICAgIEEtc2lkZSBhbmQgdGhlIEItc2lkZSwgcmVzcGVjdGl2ZWx5LCBhbmQgb3B0aW9uYWxseSBwcm9wZXJ0aWVzIG9mIHRoZQogICAgICAgcmVsYXRpb25zaGlwLiBEYXRhIG5vZGVzIG9mIHR5cGVzICdsZWFmJyBhbmQgJ2xlYWYtbGlzdCcgYXJlIHVzZWQgZm9yCiAgICAgICB0aGlzIHB1cnBvc2UuIE9uZSBvZiB0aGUgZGF0YSBub2RlcyBNVVNUIGJlIGFubm90YXRlZCB3aXRoIHRoZSAnYS1zaWRlJwogICAgICAgZXh0ZW5zaW9uOyBhbm90aGVyIGRhdGEgbm9kZSBNVVNUIGJlIGFubm90YXRlZCB3aXRoIHRoZSAnYi1zaWRlJwogICAgICAgZXh0ZW5zaW9uLiBPdGhlciBkYXRhIG5vZGVzIGRlZmluZSBwcm9wZXJ0aWVzIG9mIHRoZSByZWxhdGlvbnNoaXAuCgogICAgICAgVGhlIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSByZWxhdGlvbnNoaXAuIFRoZSByZWxhdGlvbnNoaXAgbmFtZSBpcwogICAgICAgc2NvcGVkIHRvIHRoZSBuYW1lc3BhY2Ugb2YgdGhlIGRlY2xhcmluZyBtb2R1bGUgYW5kIE1VU1QgYmUgdW5pcXVlCiAgICAgICB3aXRoaW4gdGhlIHNjb3BlLiI7CgogICAgYXJndW1lbnQgcmVsYXRpb25zaGlwTmFtZTsKICB9CgogIGV4dGVuc2lvbiBhU2lkZSB7CiAgICBkZXNjcmlwdGlvbgogICAgICAiRGVmaW5lcyB0aGUgQS1zaWRlIG9mIGEgcmVsYXRpb25zaGlwLgoKICAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIGEgJ2xlYWYnIG9yICdsZWFmLWxpc3QnCiAgICAgICBzdGF0ZW1lbnQsIHdoaWNoIGl0c2VsZiBtdXN0IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZQogICAgICAgJ3VuaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIHN0YXRlbWVudC4KCiAgICAgICBUaGUgZGF0YSB0eXBlIG9mIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIE1VU1QgYmUKICAgICAgICdpbnN0YW5jZS1pZGVudGlmaWVyJy4gQ29uc3RyYWludHMgTUFZIGJlIHVzZWQgYXMgcGFydCBvZiB0aGUgcGFyZW50CiAgICAgICAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgdG8gZW5mb3JjZSBjYXJkaW5hbGl0eS4KCiAgICAgICBUaGUgaWRlbnRpZmllciBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBpcyB1c2VkIGFzIG5hbWUgb2YKICAgICAgIHRoZSByb2xlIG9mIHRoZSBBLXNpZGUgb2YgdGhlIHJlbGF0aW9uc2hpcC4gVGhlIG5hbWUgb2YgdGhlIHJvbGUgaXMKICAgICAgIHNjb3BlZCB0byB0aGUgdHlwZSBvbiB3aGljaCB0aGUgQS1zaWRlIGlzIGRlZmluZWQgYW5kIE1VU1QgYmUgdW5pcXVlCiAgICAgICB3aXRoaW4gdGhlIHNjb3BlLgoKICAgICAgIFdoaWxlIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIGRvZXMgbm90IHJlc3VsdCBpbiBhIHByb3BlcnR5IG9mCiAgICAgICB0aGUgcmVsYXRpb25zaGlwLCBpdCBpcyBSRUNPTU1FTkRFRCB0byBhdm9pZCB1c2luZyB0aGUgbmFtZSBvZiBhbgogICAgICAgZXhpc3RpbmcgdHlwZSBwcm9wZXJ0eSBhcyByb2xlIG5hbWUgdG8gYXZvaWQgcG90ZW50aWFsIGFtYmlndWl0aWVzCiAgICAgICBiZXR3ZWVuIHByb3BlcnRpZXMgb2YgYSB0eXBlLCBhbmQgcm9sZXMgb2YgYSByZWxhdGlvbnNoaXAgb24gdGhlIHR5cGUuCgogICAgICAgVGhlIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSB0eXBlIG9uIHdoaWNoIHRoZSBBLXNpZGUgcmVzaWRlcy4gSWYgdGhlCiAgICAgICB0eXBlIGlzIGRlY2xhcmVkIGluIGFub3RoZXIgbW9kdWxlLCB0aGUgdHlwZSBtdXN0IGJlIHByZWZpeGVkLCBhbmQgYQogICAgICAgY29ycmVzcG9uZGluZyAnaW1wb3J0JyBzdGF0ZW1lbnQgYmUgdXNlZCB0byBkZWNsYXJlIHRoZSBwcmVmaXguIjsKCiAgICBhcmd1bWVudCBhU2lkZVR5cGU7CiAgfQoKICBleHRlbnNpb24gYlNpZGUgewogICAgZGVzY3JpcHRpb24gIkRlZmluZXMgdGhlIEItc2lkZSBvZiBhIHJlbGF0aW9uc2hpcC4KCiAgICAgICBUaGUgc3RhdGVtZW50IE1VU1Qgb25seSBiZSBhIHN1YnN0YXRlbWVudCBvZiBhICdsZWFmJyBvciAnbGVhZi1saXN0JwogICAgICAgc3RhdGVtZW50LCB3aGljaCBpdHNlbGYgbXVzdCBiZSBhIHN1YnN0YXRlbWVudCBvZiB0aGUKICAgICAgICd1bmktZGlyZWN0aW9uYWwtdG9wb2xvZ3ktcmVsYXRpb25zaGlwJyBzdGF0ZW1lbnQuCgogICAgICAgVGhlIGRhdGEgdHlwZSBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBNVVNUIGJlCiAgICAgICAnaW5zdGFuY2UtaWRlbnRpZmllcicuIENvbnN0cmFpbnRzIE1BWSBiZSB1c2VkIGFzIHBhcnQgb2YgdGhlIHBhcmVudAogICAgICAgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIHRvIGVuZm9yY2UgY2FyZGluYWxpdHkuCgogICAgICAgVGhlIGlkZW50aWZpZXIgb2YgdGhlIHBhcmVudCAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgaXMgdXNlZCBhcyBuYW1lIG9mCiAgICAgICB0aGUgcm9sZSBvZiB0aGUgQi1zaWRlIG9mIHRoZSByZWxhdGlvbnNoaXAuIFRoZSBuYW1lIG9mIHRoZSByb2xlIGlzCiAgICAgICBzY29wZWQgdG8gdGhlIHR5cGUgb24gd2hpY2ggdGhlIEItc2lkZSBpcyBkZWZpbmVkIGFuZCBNVVNUIGJlIHVuaXF1ZQogICAgICAgd2l0aGluIHRoZSBzY29wZS4KCiAgICAgICBXaGlsZSB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBkb2VzIG5vdCByZXN1bHQgaW4gYSBwcm9wZXJ0eSBvZgogICAgICAgdGhlIHJlbGF0aW9uc2hpcCwgaXQgaXMgUkVDT01NRU5ERUQgdG8gYXZvaWQgdXNpbmcgdGhlIG5hbWUgb2YgYW4KICAgICAgIGV4aXN0aW5nIHR5cGUgcHJvcGVydHkgYXMgcm9sZSBuYW1lIHRvIGF2b2lkIHBvdGVudGlhbCBhbWJpZ3VpdGllcwogICAgICAgYmV0d2VlbiBwcm9wZXJ0aWVzIG9mIGEgdHlwZSwgYW5kIHJvbGVzIG9mIGEgcmVsYXRpb25zaGlwIG9uIHRoZSB0eXBlLgoKICAgICAgIFRoZSBhcmd1bWVudCBpcyB0aGUgbmFtZSBvZiB0aGUgdHlwZSBvbiB3aGljaCB0aGUgQi1zaWRlIHJlc2lkZXMuIElmIHRoZQogICAgICAgdHlwZSBpcyBkZWNsYXJlZCBpbiBhbm90aGVyIG1vZHVsZSwgdGhlIHR5cGUgbXVzdCBiZSBwcmVmaXhlZCwgYW5kIGEKICAgICAgIGNvcnJlc3BvbmRpbmcgJ2ltcG9ydCcgc3RhdGVtZW50IGJlIHVzZWQgdG8gZGVjbGFyZSB0aGUgcHJlZml4LiI7CgogICAgYXJndW1lbnQgYlNpZGVUeXBlOwogIH0KCiAgZXh0ZW5zaW9uIGRvbWFpbiB7CiAgICBkZXNjcmlwdGlvbiAiS2V5d29yZCB1c2VkIHRvIGNhcnJ5IGRvbWFpbiBpbmZvcm1hdGlvbi4iOwogICAgYXJndW1lbnQgZG9tYWluTmFtZTsKICB9CgogIGV4dGVuc2lvbiBsYWJlbCB7CiAgICBkZXNjcmlwdGlvbiAiVGhlIGxhYmVsIGNhbiBiZSB1c2VkIHRvIGdpdmUgbW9kdWxlcyBhbmQgc3VibW9kdWxlcyBhIHNlbWFudGljIHZlcnNpb24sIGluIGFkZGl0aW9uIHRvIHRoZWlyIHJldmlzaW9uLgoKICAgICAgVGhlIGZvcm1hdCBvZiB0aGUgbGFiZWwgaXMg4oCYeC55LnrigJkg4oCTIGV4cHJlc3NlZCBhcyBwYXR0ZXJuLCBpdCBpcyBbMC05XStcXC5bMC05XStcXC5bMC05XSsKCiAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZSByZXZpc2lvbiBzdGF0ZW1lbnQuICBaZXJvIG9yIG9uZSByZXZpc2lvbiBsYWJlbCBzdGF0ZW1lbnRzCiAgICAgIHBlciBwYXJlbnQgc3RhdGVtZW50IGFyZSBhbGxvd2VkLgoKICAgICAgUmV2aXNpb24gbGFiZWxzIE1VU1QgYmUgdW5pcXVlIGFtb25nc3QgYWxsIHJldmlzaW9ucyBvZiBhIG1vZHVsZSBvciBzdWJtb2R1bGUuIjsKICAgICAgYXJndW1lbnQgc2VtdmVyc2lvbjsKICB9Cn0=	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-common-yang-types	urn:o-ran:smo-teiv-common-yang-types	\N	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHsKCiAgeWFuZy12ZXJzaW9uIDEuMTsKICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyI7CiAgcHJlZml4IG9yLXRlaXYtdHlwZXM7CgogIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogIGltcG9ydCBfM2dwcC1jb21tb24teWFuZy10eXBlcyB7IHByZWZpeCB0eXBlczNncHA7IH0KCiAgb3JnYW5pemF0aW9uICJFcmljc3NvbiBBQiI7CiAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgZGVzY3JpcHRpb24KICAiVG9wb2xvZ3kgYW5kIEludmVudG9yeSBjb21tb24gdHlwZXMgbW9kZWwuCgogIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgVGhpcyBtb2RlbCBjb250YWlucyByZS11c2FibGUgZGF0YSB0eXBlcyB0aGF0IHRvcG9sb2d5IGFuZCBpbnZlbnRvcnkgbW9kZWxzCiAgd2lsbCBmcmVxdWVudGx5IHVzZSBhcyBwYXJ0IG9mIHR5cGVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CgogIHJldmlzaW9uICIyMDI0LTA1LTAyIiB7CiAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogIH0KCiAgZ3JvdXBpbmcgVG9wX0dycF9UeXBlIHsKCiAgICBkZXNjcmlwdGlvbiAiR3JvdXBpbmcgY29udGFpbmluZyB0aGUga2V5IGF0dHJpYnV0ZSBjb21tb24gdG8gYWxsIHR5cGVzLiBBbGwgdHlwZXMKICAgICAgICAgICAgICAgIE1VU1QgdXNlIHRoaXMgZ3JvdXBpbmcuIjsKCiAgICBsZWFmIGlkIHsKICAgICAgdHlwZSBzdHJpbmc7CiAgICAgIGRlc2NyaXB0aW9uICJVbmlxdWUgaWRlbnRpZmllciBvZiB0b3BvbG9neSBlbnRpdGllcy4gUmVwcmVzZW50cyB0aGUgRW50aXR5IEluc3RhbmNlIElkZW50aWZpZXIuIjsKICAgIH0KICB9CgogIGdyb3VwaW5nIENNX0lEIHsKCiAgICBkZXNjcmlwdGlvbiAiR3JvdXBpbmcgY29udGFpbmluZyB0aGUga2V5IGF0dHJpYnV0ZXMgdG8gbWFrZQogICAgICAgICAgICAgICAgdXNlIG9mIENvbmZpZ3VyYXRpb24gTWFuYWdlbWVudCAoQ00pLiI7CgogICAgbGVhZiBjbUhhbmRsZSB7CiAgICAgIHR5cGUgc3RyaW5nOwogICAgICBkZXNjcmlwdGlvbiAiVW5pcXVlIGlkZW50aWZpZXIgZm9yIG5ldHdvcmsgZW50aXRpZXMgaW4gQ00uIjsKICAgIH0KCiAgICBsZWFmIHJlc291cmNlSWRlbnRpZmllciB7CiAgICAgIHR5cGUgc3RyaW5nOwogICAgICBkZXNjcmlwdGlvbiAiVGhlIHhwYXRoIGV4cHJlc3Npb24gaWRlbnRpZnlpbmcgdGhlIHJlc291cmNlIGluIHRoZSBOb2RlIG1vZGVsIHlhbmcgdHJlZS4iOwogICAgfQogIH0KCiAgdHlwZWRlZiBfM0dQUF9GRE5fVHlwZSB7CiAgICB0eXBlIHR5cGVzM2dwcDpEaXN0aW5ndWlzaGVkTmFtZTsKICB9CgogIGNvbnRhaW5lciBjb25zdW1lci1kYXRhIHsKICAgIGRlc2NyaXB0aW9uICJUaGlzIGNvbnRhaW5lciBkZWZpbmVzIHRoZSBjb25zdW1lci1kYXRhLiBDb25zdW1lci1kYXRhIG1heSBiZSBhdHRhY2hlZCB0byBUb3BvbG9neSBFbnRpdHkgb3IKICAgICAgICAgICAgICAgIFRvcG9sb2d5IFJlbGF0aW9uIGluc3RhbmNlLCBvdXRzaWRlIG9mIHRoZSBkZWNsYXJlZCBUb3BvbG9neSBFbnRpdHkgb3IgVG9wb2xvZ3kgUmVsYXRpb25zaGlwJ3MgYXR0cmlidXRlcy4KICAgICAgICAgICAgICAgIFRoaXMgY29udGFpbmVyIGNhbm5vdCBiZSBpbnN0YW50aWF0ZWQsIGFuZCBpdCBNVVNUIE5PVCBiZSBhdWdtZW50ZWQgb3IgZGV2aWF0ZWQgaW4gYW55IHdheSwgdW5sZXNzIHN0YXRlZAogICAgICAgICAgICAgICAgb3RoZXJ3aXNlLiI7CgogICAgY29udGFpbmVyIGRlY29yYXRvcnMgewogICAgICBkZXNjcmlwdGlvbiAiVGhpcyBjb250YWluZXIgc2VydmVzIGFzIGV4dGVuc2lvbiBwb2ludCBmb3IgYXBwbGljYXRpb25zIHdpc2hpbmcgdG8gZGVmaW5lIHRoZWlyIG93biBkZWNvcmF0b3JzLgogICAgICAgICAgICAgICAgICBUaGlzIGlzIGRvbmUgdmlhIGF1Z21lbnRhdGlvbnMuIFRoZXkgY2FuIG9ubHkgYmUgZGVmaW5lZCBpbiBuYW1lIHZhbHVlIHBhaXIuIjsKICAgIH0KCiAgICBsZWFmLWxpc3QgY2xhc3NpZmllcnMgewogICAgICBkZXNjcmlwdGlvbiAiQ29uc3VtZXIgZGVmaW5lZCB0YWdzIHRvIHRvcG9sb2d5IGVudGl0aWVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CiAgICAgIHR5cGUgaWRlbnRpdHlyZWYgeyBiYXNlIGNsYXNzaWZpZXI7IH0KICAgIH0KCiAgICBsZWFmLWxpc3Qgc291cmNlSWRzIHsKICAgICAgZGVzY3JpcHRpb24gIkFuIG9yZGVyZWQgbGlzdCBvZiBpZGVudGl0aWVzIHRoYXQgcmVwcmVzZW50IHRoZSBzZXQgb2YgbmF0aXZlIHNvdXJjZSBpZGVudGlmaWVycyBmb3IgcGFydGljaXBhdGluZwogICAgICAgICAgICAgICAgICBlbnRpdGllcy4iOwogICAgICB0eXBlIHN0cmluZzsKICAgICAgb3JkZXJlZC1ieSB1c2VyOwogICAgfQoKICAgIGNvbnRhaW5lciBtZXRhZGF0YSB7CiAgICAgIGRlc2NyaXB0aW9uICJUaGlzIGNvbnRhaW5lciBzZXJ2ZXMgYXMgZXh0ZW5zaW9uIHBvaW50IHRvIGRlZmluZSBtZXRhZGF0YS4gVGhleSBjYW4gb25seSBiZSBkZWZpbmVkIGluIG5hbWUgdmFsdWUKICAgICAgICAgICAgICAgICAgcGFpci4iOwogICAgfQogIH0KCiAgaWRlbnRpdHkgY2xhc3NpZmllcnsKICAgIGRlc2NyaXB0aW9uICAiVGhlIGNsYXNzaWZpZXIgaXMgdXNlZCBhcyBhIGJhc2UgdG8gcHJvdmlkZSBhbGwgY2xhc3NpZmllcnMgd2l0aCBpZGVudGl0eS4gIjsKICB9Cn0=	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-ran	urn:o-ran:smo-teiv-ran	RAN	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LXJhbiB7DQogICAgeWFuZy12ZXJzaW9uIDEuMTsNCiAgICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1yYW4iOw0KICAgIHByZWZpeCBvci10ZWl2LXJhbjsNCg0KICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyB7cHJlZml4IG9yLXRlaXYtdHlwZXM7IH0NCg0KICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9DQoNCiAgICBpbXBvcnQgXzNncHAtY29tbW9uLXlhbmctdHlwZXMgeyBwcmVmaXggdHlwZXMzZ3BwOyB9DQoNCiAgICBvcmdhbml6YXRpb24gIkVyaWNzc29uIEFCIjsNCiAgICBjb250YWN0ICJFcmljc3NvbiBmaXJzdCBsaW5lIHN1cHBvcnQgdmlhIGVtYWlsIjsNCiAgICBkZXNjcmlwdGlvbg0KICAgICJSQU4gTG9naWNhbCB0b3BvbG9neSBtb2RlbC4NCg0KICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCg0KICAgIFRoaXMgbW9kZWwgY29udGFpbnMgdGhlIHRvcG9sb2d5IGVudGl0aWVzIGFuZCByZWxhdGlvbnMgaW4gdGhlDQogICAgUkFOIExvZ2ljYWwgZG9tYWluLCB3aGljaCByZXByZXNlbnRzIHRoZSBmdW5jdGlvbmFsIGNhcGFiaWxpdHkNCiAgICBvZiB0aGUgZGVwbG95ZWQgUkFOIHRoYXQgYXJlIHJlbGV2YW50IHRvIHJBcHBzIHVzZSBjYXNlcy4iOw0KDQogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsNCiAgICAgICAgZGVzY3JpcHRpb24gIkluaXRpYWwgcmV2aXNpb24uIjsNCiAgICAgICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOw0KICAgIH0NCg0KICAgIG9yLXRlaXYteWV4dDpkb21haW4gUkFOOw0KDQogICAgbGlzdCBHTkJEVUZ1bmN0aW9uIHsNCiAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQiBEaXN0cmlidXRlZCBVbml0IChnTkItRFUpLg0KDQogICAgICAgICAgICAgICAgICAgIEEgZ05CIG1heSBjb25zaXN0IG9mIGEgZ05CLUNlbnRyYWxpemVkIFVuaXQNCiAgICAgICAgICAgICAgICAgICAgKGdOQi1DVSkgYW5kIGEgZ05CLURVLiBUaGUgQ1UgcHJvY2Vzc2VzIG5vbi1yZWFsDQogICAgICAgICAgICAgICAgICAgIHRpbWUgcHJvdG9jb2xzIGFuZCBzZXJ2aWNlcywgYW5kIHRoZSBEVSBwcm9jZXNzZXMNCiAgICAgICAgICAgICAgICAgICAgUEhZIGxldmVsIHByb3RvY29sIGFuZCByZWFsIHRpbWUgc2VydmljZXMuIFRoZQ0KICAgICAgICAgICAgICAgICAgICBnTkItQ1UgYW5kIHRoZSBnTkItRFUgdW5pdHMgYXJlIGNvbm5lY3RlZCB2aWENCiAgICAgICAgICAgICAgICAgICAgRjEgbG9naWNhbCBpbnRlcmZhY2UuDQoNCiAgICAgICAgICAgICAgICAgICAgVGhlIGZvbGxvd2luZyBpcyB0cnVlIGZvciBhIGdOQi1EVToNCiAgICAgICAgICAgICAgICAgICAgSXMgY29ubmVjdGVkIHRvIHRoZSBnTkItQ1UtQ1AgdGhyb3VnaCB0aGUgRjEtQw0KICAgICAgICAgICAgICAgICAgICBpbnRlcmZhY2UuSXMgY29ubmVjdGVkIHRvIHRoZSBnTkItQ1UtVVAgdGhyb3VnaA0KICAgICAgICAgICAgICAgICAgICB0aGUgRjEtVSBpbnRlcmZhY2UuIE9uZSBnTkItRFUgaXMgY29ubmVjdGVkIHRvIG9ubHkNCiAgICAgICAgICAgICAgICAgICAgb25lIGdOQi1DVS1DUC4gT25lIGdOQi1EVSBjYW4gYmUgY29ubmVjdGVkIHRvDQogICAgICAgICAgICAgICAgICAgIG11bHRpcGxlIGdOQi1DVS1VUHMgdW5kZXIgdGhlIGNvbnRyb2wgb2YgdGhlIHNhbWUNCiAgICAgICAgICAgICAgICAgICAgZ05CLUNVLUNQLg0KICAgICAgICAgICAgICAgICAgICBOb3RlOiBBIGdOQiBtYXkgY29uc2lzdCBvZiBhIGdOQi1DVS1DUCwgbXVsdGlwbGUNCiAgICAgICAgICAgICAgICAgICAgZ05CLUNVLVVQcyBhbmQgbXVsdGlwbGUgZ05CLURVcy4gZ05CLURVIGlzIGEgY29uY3JldGUNCiAgICAgICAgICAgICAgICAgICAgY2xhc3MgdGhhdCBleHRlbmRzIHRoZSBORy1SQU4gbm9kZSBvYmplY3QuIEluIFRvcG9sb2d5LCB5b3UNCiAgICAgICAgICAgICAgICAgICAgY2FuIGNyZWF0ZSwgcmVhZCwgdXBkYXRlLCBhbmQgZGVsZXRlIHRoZSBnTkItRFUgb2JqZWN0LiI7DQoNCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsNCiAgICAgICAga2V5IGlkOw0KDQogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsNCg0KICAgICAgICAgICAgY29udGFpbmVyIGRVcExNTklkIHsNCiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiUExNTiBpZGVudGlmaWVyIHVzZWQgYXMgcGFydCBvZiBQTSBFdmVudHMgZGF0YSI7DQogICAgICAgICAgICAgICAgdXNlcyB0eXBlczNncHA6UExNTklkOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBsZWFmIGdOQkRVSWQgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIERVIHdpdGhpbiBhIGdOb2RlQiI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYgZ05CSWQgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJJZGVudGl0eSBvZiBnTm9kZUIgd2l0aGluIGEgUExNTiI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYgZ05CSWRMZW5ndGggew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMZW5ndGggb2YgZ05CSWQgYml0IHN0cmluZyByZXByZXNlbnRhdGlvbiI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICB9DQogICAgICAgIH0NCiAgICB9DQoNCiAgICBsaXN0IEVOb2RlQkZ1bmN0aW9uIHsNCiAgICAgICAgZGVzY3JpcHRpb24gIkFuIEV2b2x2ZWQgTm9kZSBCIChlTm9kZUIpIGlzIHRoZSBvbmx5IG1hbmRhdG9yeQ0KICAgICAgICAgICAgICAgICAgICBub2RlIGluIHRoZSByYWRpbyBhY2Nlc3MgbmV0d29yayAoUkFOKSBvZiBMb25nLVRlcm0NCiAgICAgICAgICAgICAgICAgICAgRXZvbHV0aW9uIChMVEUpLiBUaGUgZU5vZGVCIGlzIGEgY29tcGxleCBiYXNlDQogICAgICAgICAgICAgICAgICAgIHN0YXRpb24gdGhhdCBoYW5kbGVzIHJhZGlvIGNvbW11bmljYXRpb25zDQogICAgICAgICAgICAgICAgICAgIGluIHRoZSBjZWxsIGFuZCBjYXJyaWVzIG91dCByYWRpbyByZXNvdXJjZQ0KICAgICAgICAgICAgICAgICAgICBtYW5hZ2VtZW50IGFuZCBoYW5kb3ZlciBkZWNpc2lvbnMuIFVubGlrZSAyLzNHDQogICAgICAgICAgICAgICAgICAgIHdpcmVsZXNzIFJBTiwgdGhlcmUgaXMgbm8gY2VudHJhbGl6ZWQgcmFkaW8gbmV0d29yaw0KICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVyIGluIExURS4gSXQgaXMgdGhlIGhhcmR3YXJlIHRoYXQgaXMgY29ubmVjdGVkDQogICAgICAgICAgICAgICAgICAgIHRvIHRoZSBtb2JpbGUgcGhvbmUgbmV0d29yayB0aGF0IGNvbW11bmljYXRlcw0KICAgICAgICAgICAgICAgICAgICBkaXJlY3RseSB3aXRoIG1vYmlsZSBoYW5kc2V0cyAoVXNlciBFcXVpcG1lbnQpLCBsaWtlIGEgYmFzZQ0KICAgICAgICAgICAgICAgICAgICB0cmFuc2NlaXZlciBzdGF0aW9uIChCVFMpIGluIEdTTSBuZXR3b3Jrcy4gVGhpcyBzaW1wbGlmaWVzDQogICAgICAgICAgICAgICAgICAgIHRoZSBhcmNoaXRlY3R1cmUgYW5kIGFsbG93cyBsb3dlciByZXNwb25zZSB0aW1lcy4iOw0KDQogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7DQogICAgICAgIGtleSBpZDsNCg0KICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7DQogICAgICAgICAgICBsZWFmIGVOQklkIHsNCiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhlIEVOb2RlQiBJRCB0aGF0IGZvcm1zIHBhcnQgb2YNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgQ2VsbCBHbG9iYWwgSWRlbnRpdHksIGFuZCBpcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsc28gdXNlZCB0byBpZGVudGlmeSB0aGUgbm9kZSBvdmVyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIFMxIGludGVyZmFjZSI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICAgICAgZGVmYXVsdCAxMTsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgbGVhZiBkdXBsZXhUeXBlIHsNCiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSW5kaWNhdG9yIG9mIEVVdHJhbkNlbGwgdHlwZSwgRkREIG9yIFRERCI7DQogICAgICAgICAgICAgICAgdHlwZSBlbnVtZXJhdGlvbiB7DQogICAgICAgICAgICAgICAgICAgIGVudW0gdGRkIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDE7DQogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVEREIjsNCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgY29udGFpbmVyIGVOb2RlQlBsbW5JZCB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFTm9kZUIgUHVibGljIExhbmQgTW9iaWxlIE5ldHdvcmsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoUExNTikgSUQgdGhhdCBmb3JtcyBwYXJ0IG9mIHRoZSBFTm9kZUINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHbG9iYWwgSUQgdXNlZCB0byBpZGVudGlmeSB0aGUgbm9kZSBvdmVyDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIFMxIGludGVyZmFjZS4gTm90ZTogVGhlIHZhbHVlIChNQ0M9MDAxLCBNTkM9MDEpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kaWNhdGVzIHRoYXQgdGhlIFBMTU4gaXMgbm90IGluaXRpYXRlZC4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGUgdmFsdWUgY2FuIG5vdCBiZSB1c2VkIGFzIGEgdmFsaWQgUExNTiBJZGVudGl0eS4iOw0KDQogICAgICAgICAgICAgICAgbGVhZiBtY2Mgew0KICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhlIE1DQyBwYXJ0IG9mIGEgUExNTiBpZGVudGl0eQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VkIGluIHRoZSByYWRpbyBuZXR3b3JrLiI7DQogICAgICAgICAgICAgICAgICAgIHR5cGUgaW50MzIgew0KICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgMC4uOTk5Ow0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIGxlYWYgbW5jIHsNCiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBNTkMgcGFydCBvZiBhIFBMTU4gaWRlbnRpdHkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlZCBpbiB0aGUgcmFkaW8gbmV0d29yay4iOw0KICAgICAgICAgICAgICAgICAgICB0eXBlIGludDMyIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlIDAuLjk5OTsNCiAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICBsZWFmIG1uY0xlbmd0aCB7DQogICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGUgbGVuZ3RoIG9mIHRoZSBNTkMgcGFydCBvZiBhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBMTU4gaWRlbnRpdHkgdXNlZCBpbiB0aGUgcmFkaW8gbmV0d29yay4iOw0KICAgICAgICAgICAgICAgICAgICB0eXBlIGludDMyIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlIDIuLjM7DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQogICAgICAgIH0NCiAgICB9DQoNCiAgICBsaXN0IEFudGVubmFDYXBhYmlsaXR5IHsNCiAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgTU8gc2VydmVzIGFzIGEgbWFwcGluZyBiZXR3ZWVuIHRoZSBjZWxsDQogICAgICAgICAgICAgICAgICAgIGFuZCB0aGUgUkJTIGVxdWlwbWVudCB1c2VkIHRvIHByb3ZpZGUgY292ZXJhZ2UNCiAgICAgICAgICAgICAgICAgICAgaW4gYSBjZXJ0YWluIGdlb2dyYXBoaWNhbCBhcmVhLiBUaGUgTU8gYWxzbw0KICAgICAgICAgICAgICAgICAgICBjb250cm9scyB0aGUgbWF4aW11bSBvdXRwdXQgcG93ZXIgb2YgdGhlIHNlY3Rvci4iOw0KDQogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7DQogICAgICAgIGtleSBpZDsNCg0KICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7DQogICAgICAgICAgICBsZWFmLWxpc3QgZVV0cmFuRnFCYW5kcyB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxpc3Qgb2YgTFRFIGZyZXF1ZW5jeSBiYW5kcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQgYXNzb2NpYXRlZCBoYXJkd2FyZSBzdXBwb3J0cyI7DQogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYtbGlzdCBnZXJhbkZxQmFuZHMgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIEdFUkFOIGZyZXF1ZW5jeSBiYW5kcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQgYXNzb2NpYXRlZCBoYXJkd2FyZSBzdXBwb3J0cyI7DQogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYtbGlzdCBuUkZxQmFuZHMgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIE5SIGZyZXF1ZW5jeSBiYW5kcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc29jaWF0ZWQgaGFyZHdhcmUgc3VwcG9ydHMiOw0KICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOw0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQogICAgfQ0KDQogICAgbGlzdCBMVEVTZWN0b3JDYXJyaWVyIHsNCiAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBMVEUgU2VjdG9yIENhcnJpZXIgb2JqZWN0IHByb3ZpZGVzIHRoZQ0KICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzIGZvciBkZWZpbmluZyB0aGUgbG9naWNhbCBjaGFyYWN0ZXJpc3RpY3MNCiAgICAgICAgICAgICAgICAgICAgb2YgYSBjYXJyaWVyIChjZWxsKSBpbiBhIHNlY3Rvci4gQSBzZWN0b3IgaXMgYSBjb3ZlcmFnZQ0KICAgICAgICAgICAgICAgICAgICBhcmVhIGFzc29jaWF0ZWQgd2l0aCBhIGJhc2Ugc3RhdGlvbiBoYXZpbmcNCiAgICAgICAgICAgICAgICAgICAgaXRzIG93biBhbnRlbm5hcywgcmFkaW8gcG9ydHMsIGFuZCBjb250cm9sIGNoYW5uZWxzLg0KICAgICAgICAgICAgICAgICAgICBUaGUgY29uY2VwdCBvZiBzZWN0b3JzIHdhcyBkZXZlbG9wZWQgdG8gaW1wcm92ZSBjby1jaGFubmVsDQogICAgICAgICAgICAgICAgICAgIGludGVyZmVyZW5jZSBpbiBjZWxsdWxhciBzeXN0ZW1zLCBhbmQgbW9zdCB3aXJlbGVzcyBzeXN0ZW1zDQogICAgICAgICAgICAgICAgICAgIHVzZSB0aHJlZSBzZWN0b3IgY2VsbHMuIjsNCg0KICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOw0KICAgICAgICBrZXkgaWQ7DQoNCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgew0KICAgICAgICAgICAgbGVhZiBzZWN0b3JDYXJyaWVyVHlwZSB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkluZGljYXRlcyB3aGV0aGVyIG9yIG5vdCB0aGUgc2VjdG9yIGNhcnJpZXINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbGxlZCBieSBNTyBTZWN0b3JDYXJyaWVyIGlzIGEgZGlnaXRhbCBzZWN0b3IuIjsNCiAgICAgICAgICAgICAgICB0eXBlIGVudW1lcmF0aW9uIHsNCiAgICAgICAgICAgICAgICAgICAgZW51bSBub3JtYWxfc2VjdG9yIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDA7DQogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTm90IGEgZGlnaXRhbCBzZWN0b3IiOw0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgIGVudW0gbGVmdF9kaWdpdGFsX3NlY3RvciB7DQogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAxOw0KICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxlZnQgZGlnaXRhbCBzZWN0b3IgZm9yIDJEUyI7DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgZW51bSByaWdodF9kaWdpdGFsX3NlY3RvciB7DQogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAyOw0KICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlJpZ2h0IGRpZ2l0YWwgc2VjdG9yIGZvciAyRFMiOw0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgIGVudW0gbGVmdF9kaWdpdGFsX3NlY3Rvcl8zZHMgew0KICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgMzsNCiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMZWZ0IGRpZ2l0YWwgc2VjdG9yIGZvciAzRFMiOw0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgIGVudW0gcmlnaHRfZGlnaXRhbF9zZWN0b3JfM2RzIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDQ7DQogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiUmlnaHQgZGlnaXRhbCBzZWN0b3IgZm9yIDNEUyI7DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgZW51bSBtaWRkbGVfZGlnaXRhbF9zZWN0b3Igew0KICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgNTsNCiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJNaWRkbGUgZGlnaXRhbCBzZWN0b3IgZm9yIDNEUyI7DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQogICAgICAgIH0NCiAgICB9DQoNCiAgICBsaXN0IE5SU2VjdG9yQ2FycmllciB7DQogICAgICAgIGRlc2NyaXB0aW9uICJUaGUgTlIgU2VjdG9yIENhcnJpZXIgb2JqZWN0IHByb3ZpZGVzDQogICAgICAgICAgICAgICAgICAgIHRoZSBhdHRyaWJ1dGVzIGZvciBkZWZpbmluZyB0aGUgbG9naWNhbA0KICAgICAgICAgICAgICAgICAgICBjaGFyYWN0ZXJpc3RpY3Mgb2YgYSBjYXJyaWVyIChjZWxsKSBpbiBhDQogICAgICAgICAgICAgICAgICAgIHNlY3Rvci4gQSBzZWN0b3IgaXMgYSBjb3ZlcmFnZSBhcmVhIGFzc29jaWF0ZWQNCiAgICAgICAgICAgICAgICAgICAgd2l0aCBhIGJhc2Ugc3RhdGlvbiBoYXZpbmcgaXRzIG93biBhbnRlbm5hcywNCiAgICAgICAgICAgICAgICAgICAgcmFkaW8gcG9ydHMsIGFuZCBjb250cm9sIGNoYW5uZWxzLiBUaGUgY29uY2VwdA0KICAgICAgICAgICAgICAgICAgICBvZiBzZWN0b3JzIHdhcyBkZXZlbG9wZWQgdG8gaW1wcm92ZSBjby1jaGFubmVsDQogICAgICAgICAgICAgICAgICAgIGludGVyZmVyZW5jZSBpbiBjZWxsdWxhciBzeXN0ZW1zLCBhbmQgbW9zdCB3aXJlbGVzcw0KICAgICAgICAgICAgICAgICAgICBzeXN0ZW1zIHVzZSB0aHJlZSBzZWN0b3IgY2VsbHMuIjsNCg0KICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOw0KICAgICAgICBrZXkgaWQ7DQoNCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgew0KICAgICAgICAgICAgbGVhZiBhcmZjbkRMIHsNCiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQWJzb2x1dGUgUmFkaW8gRnJlcXVlbmN5IENoYW5uZWwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXIgKE5SLUFSRkNOKSBmb3IgZG93bmxpbmsiOw0KICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBsZWFmIGFyZmNuVUwgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBBYnNvbHV0ZSBSYWRpbyBmcmVxdWVuY3kgQ2hhbm5lbCBOdW1iZXINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoTlItQVJGQ04pIGZvciB1cGxpbmsuIjsNCiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgbGVhZiBmcmVxdWVuY3lETCB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlJGIFJlZmVyZW5jZSBGcmVxdWVuY3kgb2YgZG93bmxpbmsgY2hhbm5lbCI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYgZnJlcXVlbmN5VUwgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSRiBSZWZlcmVuY2UgRnJlcXVlbmN5IG9mIHVwbGluayBjaGFubmVsIjsNCiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsNCiAgICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgIH0NCg0KICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTFRFU0VDVE9SQ0FSUklFUl9VU0VTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gMC4uMSB0byAwLi4xDQoNCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsNCiAgICAgICAga2V5IGlkOw0KDQogICAgICAgIGxlYWYgdXNlZC1hbnRlbm5hQ2FwYWJpbGl0eSB7DQogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTFRFIFNlY3RvciBDYXJyaWVyIHVzZXMgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgTFRFU2VjdG9yQ2FycmllcjsNCiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsNCiAgICAgICAgfQ0KDQogICAgICAgIGxlYWYgdXNlZC1ieS1sdGVTZWN0b3JDYXJyaWVyIHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENwYWJpbGl0eSB1c2VkIGJ5IExURSBTZWN0b3IgQ2Fycmllci4iOw0KICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEFudGVubmFDYXBhYmlsaXR5Ow0KICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOw0KICAgICAgICB9DQogICAgfQ0KDQogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBFTk9ERUJGVU5DVElPTl9QUk9WSURFU19MVEVTRUNUT1JDQVJSSUVSIHsgLy8gMSB0byAwLi5uDQoNCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsNCiAgICAgICAga2V5IGlkOw0KDQogICAgICAgIGxlYWYtbGlzdCBwcm92aWRlZC1sdGVTZWN0b3JDYXJyaWVyIHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJlTm9kZUIgRnVuY3Rpb24gcHJvdmlkZXMgTFRFIFNlY3RvciBDYXJyaWVyLiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgRU5vZGVCRnVuY3Rpb247DQogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7DQogICAgICAgIH0NCg0KICAgICAgICBsZWFmIHByb3ZpZGVkLWJ5LWVub2RlYkZ1bmN0aW9uIHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMVEUgU2VjdG9yIENhcnJpZXIgcHJvdmlkZWQgYnkgZU5vZGVCIEZ1bmN0aW9uLiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTFRFU2VjdG9yQ2FycmllcjsNCiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsNCiAgICAgICAgICAgIG1hbmRhdG9yeSB0cnVlOw0KICAgICAgICB9DQogICAgfQ0KDQogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBOUlNFQ1RPUkNBUlJJRVJfVVNFU19BTlRFTk5BQ0FQQUJJTElUWSB7IC8vIDAuLm4gdG8gMC4uMQ0KDQogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7DQogICAgICAgIGtleSBpZDsNCg0KICAgICAgICBsZWFmIHVzZWQtYW50ZW5uYUNhcGFiaWxpdHkgew0KICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5SIFNlY3RvciBDYXJyaWVyIHVzZXMgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgTlJTZWN0b3JDYXJyaWVyOw0KICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOw0KICAgICAgICB9DQoNCiAgICAgICAgbGVhZi1saXN0IHVzZWQtYnktbnJTZWN0b3JDYXJyaWVyIHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENhcGFiaWxpdHkgdXNlZCBieSBOUiBTZWN0b3IgQ2Fycmllci4iOw0KICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEFudGVubmFDYXBhYmlsaXR5Ow0KICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOw0KICAgICAgICB9DQogICAgfQ0KDQogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBBTlRFTk5BQ0FQQUJJTElUWV9VU0VTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gU2FtZSBlbnRpdHkgKDAuLjEgdG8gMC4uMSkNCg0KICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOw0KICAgICAgICBrZXkgaWQ7DQoNCiAgICAgICAgbGVhZiB1c2VkLWFudGVubmFDYXBhYmlsaXR5IHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENhcGFiaWxpdHkgcmVhbGlzZWQgYnkgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7DQogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7DQogICAgICAgIH0NCg0KICAgICAgICBsZWFmIHVzZWQtYnktYW50ZW5uYUNhcGFiaWxpdHkgew0KICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsNCiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBBbnRlbm5hQ2FwYWJpbGl0eTsNCiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsNCiAgICAgICAgfQ0KICAgIH0NCg0KICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgQU5URU5OQUNBUEFCSUxJVFlfUFJPVklERVNfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyBTYW1lIGVudGl0eSAoMC4uMSB0byAwLi5uKQ0KDQogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7DQogICAgICAgIGtleSBpZDsNCg0KICAgICAgICBsZWFmIHByb3ZpZGVkLWFudGVubmFDYXBhYmlsaXR5IHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENhcGFiaWxpdHkgcmVhbGlzZWQgYnkgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7DQogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7DQogICAgICAgIH0NCg0KICAgICAgICBsZWFmLWxpc3QgcHJvdmlkZWQtYnktYW50ZW5uYUNhcGFiaWxpdHkgew0KICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsNCiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBBbnRlbm5hQ2FwYWJpbGl0eTsNCiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsNCiAgICAgICAgfQ0KICAgIH0NCg0KICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgQU5URU5OQUNBUEFCSUxJVFlfU0VSVkVTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gU2FtZSBlbnRpdHkgKDAuLm4gdG8gMC4uMSkNCg0KICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOw0KICAgICAgICBrZXkgaWQ7DQoNCiAgICAgICAgbGVhZi1saXN0IHNlcnZpY2VkLWFudGVubmFDYXBhYmlsaXR5IHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENhcGFiaWxpdHkgcmVhbGlzZWQgYnkgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7DQogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7DQogICAgICAgIH0NCg0KICAgICAgICBsZWFmIHNlcnZpY2VkLWJ5LWFudGVubmFDYXBhYmlsaXR5IHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENhcGFiaWxpdHkgcmVhbGlzZXMgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7DQogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7DQogICAgICAgIH0NCiAgICB9DQoNCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIEFOVEVOTkFDQVBBQklMSVRZX1JFQUxJU0VEX0JZX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gU2FtZSBlbnRpdHkgKDAuLm4gdG8gMC4ubSkNCg0KICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOw0KICAgICAgICBrZXkgaWQ7DQoNCiAgICAgICAgbGVhZi1saXN0IHJlYWxpc2VkLWJ5LWFudGVubmFDYXBhYmlsaXR5IHsNCiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENhcGFiaWxpdHkgcmVhbGlzZWQgYnkgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7DQogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7DQogICAgICAgIH0NCg0KICAgICAgICBsZWFmLWxpc3QgcmVhbGlzZWQtYW50ZW5uYUNhcGFiaWxpdHkgew0KICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsNCiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBBbnRlbm5hQ2FwYWJpbGl0eTsNCiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsNCiAgICAgICB9DQogICAgfQ0KfQ==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-equipment	urn:o-ran:smo-teiv-equipment	EQUIPMENT	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWVxdWlwbWVudCB7DQogICAgeWFuZy12ZXJzaW9uIDEuMTsNCiAgICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1lcXVpcG1lbnQiOw0KICAgIHByZWZpeCBvci10ZWl2LWVxdWlwOw0KDQogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHtwcmVmaXggb3ItdGVpdi10eXBlczsgfQ0KDQogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0NCg0KICAgIGltcG9ydCBpZXRmLWdlby1sb2NhdGlvbiB7DQogICAgICAgIHByZWZpeCBnZW87DQogICAgICAgIHJlZmVyZW5jZSAiUkZDIDkxNzk6IEEgWUFORyBHcm91cGluZyBmb3IgR2VvZ3JhcGhpYyBMb2NhdGlvbnMiOw0KICAgIH0NCg0KICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOw0KICAgIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOw0KICAgIGRlc2NyaXB0aW9uDQogICAgIlJBTiBFcXVpcG1lbnQgdG9wb2xvZ3kgbW9kZWwuDQoNCiAgICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQoNCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQ0KICAgIFJBTiBMb2dpY2FsIGRvbWFpbiwgd2hpY2ggcmVwcmVzZW50cyB0aGUgZnVuY3Rpb25hbCBjYXBhYmlsaXR5DQogICAgb2YgdGhlIGRlcGxveWVkIFJBTiB0aGF0IGFyZSByZWxldmFudCB0byByQXBwcyB1c2UgY2FzZXMuIjsNCg0KICAgIHJldmlzaW9uICIyMDI0LTA1LTAyIiB7DQogICAgICAgIGRlc2NyaXB0aW9uICJJbml0aWFsIHJldmlzaW9uLiI7DQogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsNCiAgICB9DQoNCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIEVRVUlQTUVOVDsNCg0KICAgIGxpc3QgQW50ZW5uYU1vZHVsZSB7DQogICAgICAgIGRlc2NyaXB0aW9uICJBbiBBbnRlbm5hIE1vZHVsZSByZXByZXNlbnRzIHRoZQ0KICAgICAgICAgICAgICAgICAgICBwaHlzaWNhbCBhc3BlY3Qgb2YgYW4gYW50ZW5uYS4iOw0KDQogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7DQogICAgICAgIGtleSBpZDsNCg0KICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7DQogICAgICAgICAgICBsZWFmIGZkbiB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgRnVsbCBEaXN0aW5ndWlzaGVkIE5hbWUgKEZETikgaWRlbnRpZmllcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBBbnRlbm5hU3ViVW5pdCBNTy4gSXQgY29udGFpbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgZnVsbCBwYXRoIGZyb20gdGhlIFN1Ym5ldHdvcmsgdG8gdGhlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQW50ZW5uYVN1YlVuaXQuIjsNCiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYgYW50ZW5uYU1vZGVsTnVtYmVyIHsNCiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVmVuZG9yLXNwZWNpZmljIGFudGVubmEgbW9kZWwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZGVudGlmaWVyLiBUaGlzIGF0dHJpYnV0ZSBpcyBwYXJ0IG9mDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQUlTRyB2MyBBREIgU3RhbmRhcmQgYW5kIGhhcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vIG9wZXJhdGlvbmFsIGltcGFjdC4iOw0KICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBsZWFmIG1lY2hhbmljYWxBbnRlbm5hQmVhcmluZyB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgYmVhcmluZyBvbiBhbnRlbm5hIHN1YnVuaXQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGVyZSBhbnRlbm5hIHVuaXQgaXMgaW5zdGFsbGVkLiI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYgbWVjaGFuaWNhbEFudGVubmFUaWx0IHsNCiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhlIGZpeGVkIGFudGVubmEgdGlsdCBvZiB0aGUgaW5zdGFsbGF0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmluZWQgYXMgdGhlIGluY2xpbmF0aW9uIG9mIHRoZSBhbnRlbm5hDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudCByZXNwZWN0IHRvIHRoZSB2ZXJ0aWNhbCBwbGFuZS4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBJdCBpcyBhIHNpZ25lZCB2YWx1ZS4gUG9zaXRpdmUgaW5kaWNhdGVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZG93bnRpbHQsIGFuZCBuZWdhdGl2ZSBpbmRpY2F0ZXMgdXB0aWx0LiI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYgcG9zaXRpb25XaXRoaW5TZWN0b3Igew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIHVuaXQgcG9zaXRpb24gd2l0aGluIHNlY3Rvci4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGlzIGF0dHJpYnV0ZSBpcyBwYXJ0IG9mIEFJU0cgdjMgQURCDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhbmRhcmQgYW5kIGhhcyBubyBvcGVyYXRpb25hbCBpbXBhY3QuIjsNCiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgbGVhZiB0b3RhbFRpbHQgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUb3RhbCBhbnRlbm5hIGVsZXZhdGlvbiBpbmNsdWRpbmcgdGhlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5zdGFsbGVkIHRpbHQgYW5kIHRoZSB0aWx0IGFwcGxpZWQgYnkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgUmVtb3RlIEVsZWN0cmljYWwgVGlsdCAoUkVUKS4iOw0KICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBsZWFmIGVsZWN0cmljYWxBbnRlbm5hVGlsdCB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkVsZWN0cmljYWxseS1jb250cm9sbGVkIHRpbHQgb2YgbWFpbiBiZWFtIG1heGltdW0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoIHJlc3BlY3QgdG8gZGlyZWN0aW9uIG9ydGhvZ29uYWwgdG8gYW50ZW5uYQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgYXhpcyAoc2VlIDNHUFAgVFMgMjUuNDY2KS4gVmFsdWUgaXMgc2lnbmVkOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbHQgZG93biBpcyBwb3NpdGl2ZSwgdGlsdCB1cCBpcyBuZWdhdGl2ZS4iOw0KICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBsZWFmLWxpc3QgQW50ZW5uYUJlYW1XaWR0aCB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBhbmd1bGFyIHNwYW4gb2YgdGhlIG1haW4gbG9iZSBvZiB0aGUgYW50ZW5uYSByYWRpYXRpb24NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuIGluIHRoZSBob3Jpem9udGFsIHBsYW5lLiBNZWFzdXJlZCBpbiBkZWdyZWVzLiI7DQogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7DQogICAgICAgICAgICB9DQoNCiAgICAgICAgICAgIGxlYWYgZHVwbGV4VHlwZSB7DQogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkluZGljYXRvciBvZiBFVXRyYW5DZWxsIHR5cGUsIEZERCBvciBUREQiOw0KICAgICAgICAgICAgICAgIHR5cGUgZW51bWVyYXRpb24gew0KICAgICAgICAgICAgICAgICAgICBlbnVtIHR5cGUxIHsNCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDA7DQogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAidHlwZTEiOw0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQogICAgfQ0KDQogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBBTlRFTk5BTU9EVUxFX1VTRVNfQU5URU5OQU1PRFVMRSB7IC8vIFNhbWUgZW50aXR5ICgwLi4xIHRvIDAuLjEpDQoNCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsNCiAgICAgICAga2V5IGlkOw0KDQogICAgICAgIGxlYWYtbGlzdCB1c2VkLWJ5LWFudGVubmFNb2R1bGUgew0KICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgTW9kdWxlIHJlYWxpc2VkIGJ5IEFudGVubmEgTW9kdWxlLiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQW50ZW5uYU1vZHVsZTsNCiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsNCiAgICAgICB9DQoNCiAgICAgICAgbGVhZi1saXN0IHVzZWQtYW50ZW5uYU1vZHVsZSB7DQogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBNb2R1bGUgcmVhbGlzZXMgQW50ZW5uYSBNb2R1bGUuIjsNCiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBBbnRlbm5hTW9kdWxlOw0KICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOw0KICAgICAgIH0NCiAgICB9DQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-cloud	urn:o-ran:smo-teiv-cloud	CLOUD	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNsb3VkIHsNCiAgICB5YW5nLXZlcnNpb24gMS4xOw0KICAgIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LWNsb3VkIjsNCiAgICBwcmVmaXggb3ItdGVpdi1jbG91ZDsNCg0KICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyB7cHJlZml4IG9yLXRlaXYtdHlwZXM7IH0NCg0KICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9DQoNCiAgICBpbXBvcnQgaWV0Zi1nZW8tbG9jYXRpb24gew0KICAgICAgICBwcmVmaXggZ2VvOw0KICAgICAgICByZWZlcmVuY2UgIlJGQyA5MTc5OiBBIFlBTkcgR3JvdXBpbmcgZm9yIEdlb2dyYXBoaWMgTG9jYXRpb25zIjsNCiAgICB9DQoNCiAgICBvcmdhbml6YXRpb24gIkVyaWNzc29uIEFCIjsNCiAgICBjb250YWN0ICJFcmljc3NvbiBmaXJzdCBsaW5lIHN1cHBvcnQgdmlhIGVtYWlsIjsNCiAgICBkZXNjcmlwdGlvbg0KICAgICJSQU4gQ2xvdWQgdG9wb2xvZ3kgbW9kZWwuDQoNCiAgICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQoNCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQ0KICAgIFJBTiBDTE9VRCBkb21haW4sIHdoaWNoIGNvbXByaXNlcyBjbG91ZCBpbmZyYXN0cnVjdHVyZSBhbmQNCiAgICBkZXBsb3ltZW50IGFzcGVjdHMgdGhhdCBjYW4gYmUgdXNlZCBpbiB0aGUgdG9wb2xvZ3kgbW9kZWwuIjsNCg0KICAgIHJldmlzaW9uICIyMDI0LTA1LTAyIiB7DQogICAgICAgIGRlc2NyaXB0aW9uICJJbml0aWFsIHJldmlzaW9uLiI7DQogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsNCiAgICB9DQoNCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIENMT1VEOw0KDQogICAgbGlzdCBDbG91ZFNpdGUgew0KICAgICAgICBkZXNjcmlwdGlvbiAiUmVwcmVzZW50cyB0aGUgaW5mcmFzdHJ1Y3R1cmUgdGhhdA0KICAgICAgICAgICAgICAgICAgICBob3N0cyB0aGUgTkYgRGVwbG95bWVudC4iOw0KDQogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7DQogICAgICAgIGtleSBpZDsNCg0KICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7DQogICAgICAgICAgICBsZWFmIG5hbWUgew0KICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOYW1lIG9mIENsb3VkIFNpdGUiOw0KICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICB1c2VzIGdlbzpnZW8tbG9jYXRpb247DQogICAgICAgIH0NCiAgICB9DQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-equipment-to-ran	urn:o-ran:smo-teiv-equipment-to-ran	EQUIPMENT_TO_RAN	["o-ran-smo-teiv-equipment", "o-ran-smo-teiv-ran"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWVxdWlwbWVudC10by1yYW4gew0KICAgIHlhbmctdmVyc2lvbiAxLjE7DQogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtZXF1aXBtZW50LXRvLXJhbiI7DQogICAgcHJlZml4IG9yLXRlaXYtZXF1aXB0b3JhbjsNCg0KICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyB7cHJlZml4IG9yLXRlaXYtdHlwZXM7IH0NCg0KICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9DQoNCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtZXF1aXBtZW50IHtwcmVmaXggb3ItdGVpdi1lcXVpcDsgfQ0KDQogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LXJhbiB7cHJlZml4IG9yLXRlaXYtcmFuOyB9DQoNCiAgICBvcmdhbml6YXRpb24gIkVyaWNzc29uIEFCIjsNCiAgICBjb250YWN0ICJFcmljc3NvbiBmaXJzdCBsaW5lIHN1cHBvcnQgdmlhIGVtYWlsIjsNCiAgICBkZXNjcmlwdGlvbg0KICAgICJSQU4gTG9naWNhbCB0byBFcXVpcG1lbnQgdG9wb2xvZ3kgbW9kZWwuDQoNCiAgICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQoNCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSBSQU4gTG9naWNhbCB0byBFcXVpcG1lbnQgdG9wb2xvZ3kNCiAgICBlbnRpdGllcyBhbmQgcmVsYXRpb25zLiI7DQoNCiAgICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgew0KICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOw0KICAgICAgICBvci10ZWl2LXlleHQ6bGFiZWwgMC4zLjA7DQogICAgfQ0KDQogICAgb3ItdGVpdi15ZXh0OmRvbWFpbiBFUVVJUE1FTlRfVE9fUkFOOw0KDQogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBBTlRFTk5BTU9EVUxFX1NFUlZFU19BTlRFTk5BQ0FQQUJJTElUWSB7IC8vIDAuLm4gdG8gMC4ubQ0KDQogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7DQogICAgICAgIGtleSBpZDsNCg0KICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtYW50ZW5uYUNhcGFiaWxpdHkgew0KICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSBzZXJ2aWNlZCBieSB0aGlzIEFudGVubmEgTW9kdWxlLiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1lcXVpcDpBbnRlbm5hTW9kdWxlOw0KICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOw0KICAgICAgICB9DQoNCiAgICAgICAgbGVhZi1saXN0IHNlcnZpbmctYW50ZW5uYU1vZHVsZSB7DQogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBNb2R1bGUgc2VydmVzIHRoaXMgQW50ZW5uYSBDYXBhYmlsaXR5LiI7DQogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1yYW46QW50ZW5uYUNhcGFiaWxpdHk7DQogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7DQogICAgICAgIH0NCiAgICB9DQp9DQo=	BUILT_IN_MODULE	IN_USAGE
+\.
+
+COPY ties_model.entity_info("name", "moduleReferenceName") FROM stdin;
+AntennaModule	o-ran-smo-teiv-equipment
+CloudSite	o-ran-smo-teiv-cloud
+ENodeBFunction	o-ran-smo-teiv-ran
+AntennaCapability	o-ran-smo-teiv-ran
+LTESectorCarrier	o-ran-smo-teiv-ran
+\.
+
+COPY ties_model.relationship_info("name", "aSideAssociationName", "aSideMOType", "aSideMinCardinality", "aSideMaxCardinality", "bSideAssociationName", "bSideMOType", "bSideMinCardinality", "bSideMaxCardinality", "associationKind", "relationshipDataLocation", "connectSameEntity", "moduleReferenceName") FROM stdin;
+ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	provided-lteSectorCarrier	ENodeBFunction	1	1	provided-by-enodebFunction	LTESectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+\.
+
+;
+
+COMMIT;
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/expected-db-schema/result_00_init-oran-smo-teiv-data.sql b/pgsql-schema-generator/src/test/resources/expected-db-schema/result_00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..c3da7c1
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/expected-db-schema/result_00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,460 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+-- Update data schema exec status
+INSERT INTO ties_model.entity_info("schema", "status") VALUES ('ties_data', 'success');
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaCapability"			VARCHAR(511),
+	"bSide_AntennaCapability"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaModule"			VARCHAR(511),
+	"bSide_AntennaCapability"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNAMODULE_USES_ANTENNAMODULE" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaModule"			VARCHAR(511),
+	"bSide_AntennaModule"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_USES_ANTENNAMODULE" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_USES_ANTENNAMODULE" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_USES_ANTENNAMODULE" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."AntennaCapability" (
+	"id"			VARCHAR(511),
+	"geranFqBands"			jsonb,
+	"nRFqBands"			jsonb,
+	"eUtranFqBands"			jsonb,
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."AntennaModule" (
+	"id"			VARCHAR(511),
+	"positionWithinSector"			TEXT,
+	"electricalAntennaTilt"			BIGINT,
+	"mechanicalAntennaBearing"			BIGINT,
+	"antennaBeamWidth"			jsonb,
+	"mechanicalAntennaTilt"			BIGINT,
+	"antennaModelNumber"			TEXT,
+	"totalTilt"			BIGINT,
+	"geo-location"	geography,
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ENodeBFunction" (
+	"id"			VARCHAR(511),
+	"eNBId"			BIGINT,
+	"eNodeBPlmnId"			jsonb,
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "eNBId" SET DEFAULT '11';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBDUFunction" (
+	"id"			VARCHAR(511),
+	"dUpLMNId"			jsonb,
+	"gNBDUId"			BIGINT,
+	"gNBIdLength"			BIGINT,
+	"gNBId"			BIGINT,
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb,
+);
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."LTESectorCarrier" (
+	"id"			VARCHAR(511),
+	"sectorCarrierType"			TEXT,
+	"CD_sourceIds"			jsonb,
+	"REL_FK_provided-by-enodebFunction"			VARCHAR(511),
+	"REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"			VARCHAR(511),
+	"REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"			jsonb,
+	"REL_FK_used-antennaCapability"			VARCHAR(511),
+	"REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY"			VARCHAR(511),
+	"REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb,
+	"REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" jsonb,
+    "REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY" jsonb,
+    "REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" jsonb,
+    "REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY" jsonb
+);
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."NRSectorCarrier" (
+	"id"			VARCHAR(511),
+	"frequencyDL"			BIGINT,
+	"arfcnDL"			BIGINT,
+	"arfcnUL"			BIGINT,
+	"bSChannelBwDL"			BIGINT,
+	"frequencyUL"			BIGINT,
+	"CD_sourceIds"			jsonb,
+	"REL_FK_used-antennaCapability"			VARCHAR(511),
+	"REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY"			VARCHAR(511),
+	"REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb,
+	"REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY" jsonb,
+    "REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY" jsonb
+);
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaCapability"			VARCHAR(511),
+	"bSide_AntennaCapability"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaCapability"			VARCHAR(511),
+	"bSide_AntennaCapability"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNACAPABILITY_USES_ANTENNACAPABILITY" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaCapability"			VARCHAR(511),
+	"bSide_AntennaCapability"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"CD_classifiers"			jsonb,
+	"CD_decorators"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_USES_ANTENNACAPABILITY" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_USES_ANTENNACAPABILITY" ALTER COLUMN "CD_classifiers" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_USES_ANTENNACAPABILITY" ALTER COLUMN "CD_decorators" SET DEFAULT '{}';
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY',
+ 'PK_ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY_id',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY" ADD CONSTRAINT "PK_ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_SERVES_ANTENNACAPABILITY',
+ 'PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_USES_ANTENNAMODULE',
+ 'PK_ANTENNAMODULE_USES_ANTENNAMODULE_id',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_USES_ANTENNAMODULE" ADD CONSTRAINT "PK_ANTENNAMODULE_USES_ANTENNAMODULE_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaCapability',
+ 'PK_AntennaCapability_id',
+ 'ALTER TABLE ties_data."AntennaCapability" ADD CONSTRAINT "PK_AntennaCapability_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaModule',
+ 'PK_AntennaModule_id',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "PK_AntennaModule_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ENodeBFunction',
+ 'PK_ENodeBFunction_id',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "PK_ENodeBFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBDUFunction',
+ 'PK_GNBDUFunction_id',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "PK_GNBDUFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'PK_LTESectorCarrier_id',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "PK_LTESectorCarrier_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'PK_NRSectorCarrier_id',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "PK_NRSectorCarrier_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY',
+ 'PK_ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY_id',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY" ADD CONSTRAINT "PK_ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY',
+ 'PK_ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY_id',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "PK_ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_USES_ANTENNACAPABILITY',
+ 'PK_ANTENNACAPABILITY_USES_ANTENNACAPABILITY_id',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_USES_ANTENNACAPABILITY" ADD CONSTRAINT "PK_ANTENNACAPABILITY_USES_ANTENNACAPABILITY_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY',
+ 'FK_59989F20BF725E08F0327C7C555B1CF7B4F8661C',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY" ADD CONSTRAINT "FK_59989F20BF725E08F0327C7C555B1CF7B4F8661C" FOREIGN KEY ("aSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY',
+ 'FK_8B87C4FA55D9F0A4164C35942D91E2E4E0B6140D',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY" ADD CONSTRAINT "FK_8B87C4FA55D9F0A4164C35942D91E2E4E0B6140D" FOREIGN KEY ("bSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY',
+ 'FK_F407B43F3D94FFE0CBDF7E2BFAEAD9A4047DF252',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_F407B43F3D94FFE0CBDF7E2BFAEAD9A4047DF252" FOREIGN KEY ("aSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY',
+ 'FK_73581B1E05EA3AC4C029F090C067BD88029F1195',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_73581B1E05EA3AC4C029F090C067BD88029F1195" FOREIGN KEY ("bSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY',
+ 'FK_3613A8C84275763DE5294B04DB6E6BF74E9412F4',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_3613A8C84275763DE5294B04DB6E6BF74E9412F4" FOREIGN KEY ("aSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY',
+ 'FK_C21710428B73A144CC8DE4063CB24D4852D2EFE1',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_C21710428B73A144CC8DE4063CB24D4852D2EFE1" FOREIGN KEY ("bSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_USES_ANTENNACAPABILITY',
+ 'FK_0F27D391D210980029D4A879344BFC1DF7E56047',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_USES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_0F27D391D210980029D4A879344BFC1DF7E56047" FOREIGN KEY ("aSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_USES_ANTENNACAPABILITY',
+ 'FK_C66086ACCFA9455ED438AE9381A7E4B0668EA027',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_USES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_C66086ACCFA9455ED438AE9381A7E4B0668EA027" FOREIGN KEY ("bSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_SERVES_ANTENNACAPABILITY',
+ 'FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule" FOREIGN KEY ("aSide_AntennaModule") REFERENCES ties_data."AntennaModule" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_SERVES_ANTENNACAPABILITY',
+ 'FK_AB3CEA707D389B107F1D10BC724542418E02ABEC',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_SERVES_ANTENNACAPABILITY" ADD CONSTRAINT "FK_AB3CEA707D389B107F1D10BC724542418E02ABEC" FOREIGN KEY ("bSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_USES_ANTENNAMODULE',
+ 'FK_ANTENNAMODULE_USES_ANTENNAMODULE_aSide_AntennaModule',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_USES_ANTENNAMODULE" ADD CONSTRAINT "FK_ANTENNAMODULE_USES_ANTENNAMODULE_aSide_AntennaModule" FOREIGN KEY ("aSide_AntennaModule") REFERENCES ties_data."AntennaModule" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_USES_ANTENNAMODULE',
+ 'FK_ANTENNAMODULE_USES_ANTENNAMODULE_bSide_AntennaModule',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_USES_ANTENNAMODULE" ADD CONSTRAINT "FK_ANTENNAMODULE_USES_ANTENNAMODULE_bSide_AntennaModule" FOREIGN KEY ("bSide_AntennaModule") REFERENCES ties_data."AntennaModule" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction" FOREIGN KEY ("REL_FK_provided-by-enodebFunction") REFERENCES ties_data."ENodeBFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9" UNIQUE ("REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_used-antennaCapability',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_used-antennaCapability" FOREIGN KEY ("REL_FK_used-antennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88" UNIQUE ("REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'FK_NRSectorCarrier_REL_FK_used-antennaCapability',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "FK_NRSectorCarrier_REL_FK_used-antennaCapability" FOREIGN KEY ("REL_FK_used-antennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991" UNIQUE ("REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY");'
+);
+
+COMMIT;
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/expected-db-schema/result_01_init-oran-smo-teiv-model.sql b/pgsql-schema-generator/src/test/resources/expected-db-schema/result_01_init-oran-smo-teiv-model.sql
new file mode 100644
index 0000000..bd3b338
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/expected-db-schema/result_01_init-oran-smo-teiv-model.sql
@@ -0,0 +1,214 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+BEGIN;
+
+DROP SCHEMA IF EXISTS ties_model cascade;
+CREATE SCHEMA IF NOT EXISTS ties_model;
+ALTER SCHEMA ties_model OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+CREATE TABLE IF NOT EXISTS ties_model.execution_status (
+    "schema" VARCHAR(127) PRIMARY KEY,
+    "status" VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.hash_info (
+    "name"        VARCHAR(511) PRIMARY KEY,
+    "hashedValue" VARCHAR(511) NOT NULL,
+    "type"        VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.module_reference (
+    "name"            VARCHAR(511) PRIMARY KEY,
+    "namespace"       VARCHAR(511),
+    "domain"          VARCHAR(511),
+    "includedModules" jsonb DEFAULT '[]'::jsonb,
+    "revision"        VARCHAR(511) NOT NULL,
+    "content"         TEXT NOT NULL,
+    "ownerAppId"      VARCHAR(511) NOT NULL,
+    "status"          VARCHAR(127) NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.entity_info (
+    "name"                VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName" VARCHAR(511) NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.relationship_info (
+    "name"                     VARCHAR(511) PRIMARY KEY,
+    "aSideAssociationName"     TEXT NOT NULL,
+    "aSideMOType"              TEXT NOT NULL,
+    "aSideMinCardinality"      BIGINT NOT NULL,
+    "aSideMaxCardinality"      BIGINT NOT NULL,
+    "bSideAssociationName"     TEXT NOT NULL,
+    "bSideMOType"              TEXT NOT NULL,
+    "bSideMinCardinality"      BIGINT NOT NULL,
+    "bSideMaxCardinality"      BIGINT NOT NULL,
+    "associationKind"          TEXT NOT NULL,
+    "relationshipDataLocation" TEXT NOT NULL,
+    "connectSameEntity"        BOOLEAN NOT NULL,
+    "moduleReferenceName"      TEXT NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.decorators (
+    "name"                VARCHAR(511) PRIMARY KEY,
+    "dataType"            VARCHAR(511) NOT NULL,
+    "moduleReferenceName" VARCHAR(511) NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.classifiers (
+    "name"                VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName" VARCHAR(511) NOT NULL,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+-- Update model schema exec status
+INSERT INTO ties_model.execution_status("schema", "status") VALUES ('ties_model', 'success');
+
+COPY ties_model.hash_info("name", "hashedValue", "type") FROM stdin;
+eNodeBPlmnId	eNodeBPlmnId	COLUMN
+PK_NRSectorCarrier_id	PK_NRSectorCarrier_id	CONSTRAINT
+UNIQUE_LTESectorCarrier_REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9	CONSTRAINT
+PK_ENodeBFunction_id	PK_ENodeBFunction_id	CONSTRAINT
+CD_classifiers	CD_classifiers	COLUMN
+mechanicalAntennaBearing	mechanicalAntennaBearing	COLUMN
+frequencyDL	frequencyDL	COLUMN
+AntennaModule	AntennaModule	TABLE
+ENodeBFunction	ENodeBFunction	TABLE
+LTESectorCarrier	LTESectorCarrier	TABLE
+antennaModelNumber	antennaModelNumber	COLUMN
+NRSectorCarrier	NRSectorCarrier	TABLE
+REL_FK_used-antennaCapability	REL_FK_used-antennaCapability	COLUMN
+FK_LTESectorCarrier_REL_FK_used-antennaCapability	FK_LTESectorCarrier_REL_FK_used-antennaCapability	CONSTRAINT
+aSide_AntennaModule	aSide_AntennaModule	COLUMN
+REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_classifiers_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+dUpLMNId	dUpLMNId	COLUMN
+frequencyUL	frequencyUL	COLUMN
+bSChannelBwDL	bSChannelBwDL	COLUMN
+CD_sourceIds	CD_sourceIds	COLUMN
+REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+geranFqBands	geranFqBands	COLUMN
+PK_ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY_id	PK_ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY_id	CONSTRAINT
+arfcnUL	arfcnUL	COLUMN
+PK_LTESectorCarrier_id	PK_LTESectorCarrier_id	CONSTRAINT
+PK_GNBDUFunction_id	PK_GNBDUFunction_id	CONSTRAINT
+UNIQUE_NRSectorCarrier_REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991	CONSTRAINT
+PK_AntennaCapability_id	PK_AntennaCapability_id	CONSTRAINT
+nRFqBands	nRFqBands	COLUMN
+ANTENNACAPABILITY_USES_ANTENNACAPABILITY	ANTENNACAPABILITY_USES_ANTENNACAPABILITY	TABLE
+FK_NRSectorCarrier_REL_FK_used-antennaCapability	FK_NRSectorCarrier_REL_FK_used-antennaCapability	CONSTRAINT
+geo-location	geo-location	COLUMN
+PK_ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY_id	PK_ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY_id	CONSTRAINT
+arfcnDL	arfcnDL	COLUMN
+FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	CONSTRAINT
+id	id	COLUMN
+gNBId	gNBId	COLUMN
+REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+ANTENNAMODULE_USES_ANTENNAMODULE	ANTENNAMODULE_USES_ANTENNAMODULE	TABLE
+ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY	ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY	TABLE
+bSide_AntennaModule	bSide_AntennaModule	COLUMN
+REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+eNBId	eNBId	COLUMN
+positionWithinSector	positionWithinSector	COLUMN
+aSide_AntennaCapability	aSide_AntennaCapability	COLUMN
+FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_bSide_AntennaCapability	FK_AB3CEA707D389B107F1D10BC724542418E02ABEC	CONSTRAINT
+REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_decorators_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+PK_ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY_id	PK_ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY_id	CONSTRAINT
+FK_ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY_aSide_AntennaCapability	FK_3613A8C84275763DE5294B04DB6E6BF74E9412F4	CONSTRAINT
+PK_ANTENNACAPABILITY_USES_ANTENNACAPABILITY_id	PK_ANTENNACAPABILITY_USES_ANTENNACAPABILITY_id	CONSTRAINT
+FK_ANTENNAMODULE_USES_ANTENNAMODULE_aSide_AntennaModule	FK_ANTENNAMODULE_USES_ANTENNAMODULE_aSide_AntennaModule	CONSTRAINT
+CD_decorators	CD_decorators	COLUMN
+PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id	PK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_id	CONSTRAINT
+totalTilt	totalTilt	COLUMN
+FK_ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY_bSide_AntennaCapability	FK_C21710428B73A144CC8DE4063CB24D4852D2EFE1	CONSTRAINT
+REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_decorators_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+gNBIdLength	gNBIdLength	COLUMN
+AntennaCapability	AntennaCapability	TABLE
+FK_ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY_bSide_AntennaCapability	FK_73581B1E05EA3AC4C029F090C067BD88029F1195	CONSTRAINT
+REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+bSide_AntennaCapability	bSide_AntennaCapability	COLUMN
+PK_ANTENNAMODULE_USES_ANTENNAMODULE_id	PK_ANTENNAMODULE_USES_ANTENNAMODULE_id	CONSTRAINT
+FK_ANTENNAMODULE_USES_ANTENNAMODULE_bSide_AntennaModule	FK_ANTENNAMODULE_USES_ANTENNAMODULE_bSide_AntennaModule	CONSTRAINT
+FK_ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY_bSide_AntennaCapability	FK_8B87C4FA55D9F0A4164C35942D91E2E4E0B6140D	CONSTRAINT
+REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_decorators_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+FK_ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY_aSide_AntennaCapability	FK_F407B43F3D94FFE0CBDF7E2BFAEAD9A4047DF252	CONSTRAINT
+PK_AntennaModule_id	PK_AntennaModule_id	CONSTRAINT
+REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_classifiers_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+antennaBeamWidth	antennaBeamWidth	COLUMN
+UNIQUE_LTESectorCarrier_REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88	CONSTRAINT
+sectorCarrierType	sectorCarrierType	COLUMN
+REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_classifiers_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule	FK_ANTENNAMODULE_SERVES_ANTENNACAPABILITY_aSide_AntennaModule	CONSTRAINT
+GNBDUFunction	GNBDUFunction	TABLE
+mechanicalAntennaTilt	mechanicalAntennaTilt	COLUMN
+electricalAntennaTilt	electricalAntennaTilt	COLUMN
+ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY	ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY	TABLE
+REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+FK_ANTENNACAPABILITY_USES_ANTENNACAPABILITY_aSide_AntennaCapability	FK_0F27D391D210980029D4A879344BFC1DF7E56047	CONSTRAINT
+FK_ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY_aSide_AntennaCapability	FK_59989F20BF725E08F0327C7C555B1CF7B4F8661C	CONSTRAINT
+REL_FK_provided-by-enodebFunction	REL_FK_provided-by-enodebFunction	COLUMN
+gNBDUId	gNBDUId	COLUMN
+ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY	ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY	TABLE
+FK_ANTENNACAPABILITY_USES_ANTENNACAPABILITY_bSide_AntennaCapability	FK_C66086ACCFA9455ED438AE9381A7E4B0668EA027	CONSTRAINT
+eUtranFqBands	eUtranFqBands	COLUMN
+REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+ANTENNAMODULE_SERVES_ANTENNACAPABILITY	ANTENNAMODULE_SERVES_ANTENNACAPABILITY	TABLE
+\.
+
+COPY ties_model.module_reference("name", "namespace", "domain", "includedModules", "revision", "content", "ownerAppId", "status") FROM stdin;
+o-ran-smo-teiv-common-yang-extensions	urn:o-ran:smo-teiv-common-yang-extensions	\N	[]	2024-05-14	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMgewogICAgeWFuZy12ZXJzaW9uIDEuMTsKICAgIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMiOwogICAgcHJlZml4IG9yLXRlaXYteWV4dDsKCiAgICBvcmdhbml6YXRpb24gIk9SQU4iOwogICAgY29udGFjdCAiVGhlIEF1dGhvcnMiOwogICAgZGVzY3JpcHRpb24KICAgICJUb3BvbG9neSBhbmQgSW52ZW50b3J5IFlBTkcgZXh0ZW5zaW9ucyBtb2RlbC4KCiAgICBDb3B5cmlnaHQgKEMpIDIwMjQgRXJpY3Nzb24KICAgIE1vZGlmaWNhdGlvbnMgQ29weXJpZ2h0IChDKSAyMDI0IE9wZW5JbmZyYSBGb3VuZGF0aW9uIEV1cm9wZQoKICAgIFRoaXMgbW9kZWwgY29udGFpbnMgZXh0ZW5zaW9ucyB0byB0aGUgWUFORyBsYW5ndWFnZSB0aGF0IHRvcG9sb2d5IGFuZAogICAgaW52ZW50b3J5IG1vZGVscyB3aWxsIHVzZSB0byBkZWZpbmUgYW5kIGFubm90YXRlIHR5cGVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMTQiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBleHRlbnNpb24gYmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIHsKICAgICAgICBkZXNjcmlwdGlvbgogICAgICAgICAgICAiRGVmaW5lcyBhIGJpLWRpcmVjdGlvbmFsIHJlbGF0aW9uc2hpcCBpbiB0aGUgdG9wb2xvZ3kuCgogICAgICAgICAgICBBIGJpLWRpcmVjdGlvbmFsLWFzc29jaWF0aW9uIChCREEpIGlzIGEgcmVsYXRpb25zaGlwIGNvbXByaXNpbmcgb2YgYW4KICAgICAgICAgICAgQS1zaWRlIGFuZCBhIEItc2lkZS4gVGhlIEEtc2lkZSBpcyBjb25zaWRlcmVkIHRoZSBvcmlnaW5hdGluZyBzaWRlIG9mCiAgICAgICAgICAgIHRoZSByZWxhdGlvbnNoaXA7IHRoZSBCLXNpZGUgaXMgY29uc2lkZXJlZCB0aGUgdGVybWluYXRpbmcgc2lkZSBvZiB0aGUKICAgICAgICAgICAgcmVsYXRpb25zaGlwLiBUaGUgb3JkZXIgb2YgQS1zaWRlIGFuZCBCLXNpZGUgaXMgb2YgaW1wb3J0YW5jZSBhbmQgTVVTVAogICAgICAgICAgICBOT1QgYmUgY2hhbmdlZCBvbmNlIGRlZmluZWQuCgogICAgICAgICAgICBCb3RoIEEtc2lkZSBhbmQgQi1zaWRlIGFyZSBkZWZpbmVkIG9uIGEgdHlwZSwgYW5kIGFyZSBnaXZlbiBhIHJvbGUuIEEKICAgICAgICAgICAgdHlwZSBtYXkgaGF2ZSBtdWx0aXBsZSBvcmlnaW5hdGluZyBhbmQvb3IgdGVybWluYXRpbmcgc2lkZXMgb2YgYQogICAgICAgICAgICByZWxhdGlvbnNoaXAsIGFsbCBkaXN0aW5ndWlzaGVkIGJ5IHJvbGUgbmFtZS4KCiAgICAgICAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZSAnbW9kdWxlJyBzdGF0ZW1lbnQuCiAgICAgICAgICAgIE11bHRpcGxlICdiaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIHN0YXRlbWVudHMgYXJlIGFsbG93ZWQKICAgICAgICAgICAgcGVyIHBhcmVudCBzdGF0ZW1lbnQuCgogICAgICAgICAgICBTdWJzdGF0ZW1lbnRzIHRvIHRoZSAnYmktZGlyZWN0aW9uYWwtdG9wb2xvZ3ktcmVsYXRpb25zaGlwJyBkZWZpbmUgdGhlCiAgICAgICAgICAgIEEtc2lkZSBhbmQgdGhlIEItc2lkZSwgcmVzcGVjdGl2ZWx5LCBhbmQgb3B0aW9uYWxseSBwcm9wZXJ0aWVzIG9mIHRoZQogICAgICAgICAgICByZWxhdGlvbnNoaXAuIERhdGEgbm9kZXMgb2YgdHlwZXMgJ2xlYWYnIGFuZCAnbGVhZi1saXN0JyBhcmUgdXNlZCBmb3IKICAgICAgICAgICAgdGhpcyBwdXJwb3NlLiBPbmUgb2YgdGhlIGRhdGEgbm9kZXMgTVVTVCBiZSBhbm5vdGF0ZWQgd2l0aCB0aGUgJ2Etc2lkZScKICAgICAgICAgICAgZXh0ZW5zaW9uOyBhbm90aGVyIGRhdGEgbm9kZSBNVVNUIGJlIGFubm90YXRlZCB3aXRoIHRoZSAnYi1zaWRlJwogICAgICAgICAgICBleHRlbnNpb24uIE90aGVyIGRhdGEgbm9kZXMgZGVmaW5lIHByb3BlcnRpZXMgb2YgdGhlIHJlbGF0aW9uc2hpcC4KCiAgICAgICAgICAgIFRoZSBhcmd1bWVudCBpcyB0aGUgbmFtZSBvZiB0aGUgcmVsYXRpb25zaGlwLiBUaGUgcmVsYXRpb25zaGlwIG5hbWUgaXMKICAgICAgICAgICAgc2NvcGVkIHRvIHRoZSBuYW1lc3BhY2Ugb2YgdGhlIGRlY2xhcmluZyBtb2R1bGUgYW5kIE1VU1QgYmUgdW5pcXVlCiAgICAgICAgICAgIHdpdGhpbiB0aGUgc2NvcGUuIjsKCiAgICAgICAgYXJndW1lbnQgcmVsYXRpb25zaGlwTmFtZTsKICAgIH0KCiAgICBleHRlbnNpb24gYVNpZGUgewogICAgICAgIGRlc2NyaXB0aW9uCiAgICAgICAgICAgICJEZWZpbmVzIHRoZSBBLXNpZGUgb2YgYSByZWxhdGlvbnNoaXAuCgogICAgICAgICAgICBUaGUgc3RhdGVtZW50IE1VU1Qgb25seSBiZSBhIHN1YnN0YXRlbWVudCBvZiBhICdsZWFmJyBvciAnbGVhZi1saXN0JwogICAgICAgICAgICBzdGF0ZW1lbnQsIHdoaWNoIGl0c2VsZiBtdXN0IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZQogICAgICAgICAgICAndW5pLWRpcmVjdGlvbmFsLXRvcG9sb2d5LXJlbGF0aW9uc2hpcCcgc3RhdGVtZW50LgoKICAgICAgICAgICAgVGhlIGRhdGEgdHlwZSBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBNVVNUIGJlCiAgICAgICAgICAgICdpbnN0YW5jZS1pZGVudGlmaWVyJy4gQ29uc3RyYWludHMgTUFZIGJlIHVzZWQgYXMgcGFydCBvZiB0aGUgcGFyZW50CiAgICAgICAgICAgICdsZWFmJyBvciAnbGVhZi1saXN0JyB0byBlbmZvcmNlIGNhcmRpbmFsaXR5LgoKICAgICAgICAgICAgVGhlIGlkZW50aWZpZXIgb2YgdGhlIHBhcmVudCAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgaXMgdXNlZCBhcyBuYW1lIG9mCiAgICAgICAgICAgIHRoZSByb2xlIG9mIHRoZSBBLXNpZGUgb2YgdGhlIHJlbGF0aW9uc2hpcC4gVGhlIG5hbWUgb2YgdGhlIHJvbGUgaXMKICAgICAgICAgICAgc2NvcGVkIHRvIHRoZSB0eXBlIG9uIHdoaWNoIHRoZSBBLXNpZGUgaXMgZGVmaW5lZCBhbmQgTVVTVCBiZSB1bmlxdWUKICAgICAgICAgICAgd2l0aGluIHRoZSBzY29wZS4KCiAgICAgICAgICAgIFdoaWxlIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIGRvZXMgbm90IHJlc3VsdCBpbiBhIHByb3BlcnR5IG9mCiAgICAgICAgICAgIHRoZSByZWxhdGlvbnNoaXAsIGl0IGlzIFJFQ09NTUVOREVEIHRvIGF2b2lkIHVzaW5nIHRoZSBuYW1lIG9mIGFuCiAgICAgICAgICAgIGV4aXN0aW5nIHR5cGUgcHJvcGVydHkgYXMgcm9sZSBuYW1lIHRvIGF2b2lkIHBvdGVudGlhbCBhbWJpZ3VpdGllcwogICAgICAgICAgICBiZXR3ZWVuIHByb3BlcnRpZXMgb2YgYSB0eXBlLCBhbmQgcm9sZXMgb2YgYSByZWxhdGlvbnNoaXAgb24gdGhlIHR5cGUuCgogICAgICAgICAgICBUaGUgYXJndW1lbnQgaXMgdGhlIG5hbWUgb2YgdGhlIHR5cGUgb24gd2hpY2ggdGhlIEEtc2lkZSByZXNpZGVzLiBJZiB0aGUKICAgICAgICAgICAgdHlwZSBpcyBkZWNsYXJlZCBpbiBhbm90aGVyIG1vZHVsZSwgdGhlIHR5cGUgbXVzdCBiZSBwcmVmaXhlZCwgYW5kIGEKICAgICAgICAgICAgY29ycmVzcG9uZGluZyAnaW1wb3J0JyBzdGF0ZW1lbnQgYmUgdXNlZCB0byBkZWNsYXJlIHRoZSBwcmVmaXguIjsKCiAgICAgICAgYXJndW1lbnQgYVNpZGVUeXBlOwogICAgfQoKICAgIGV4dGVuc2lvbiBiU2lkZSB7CiAgICAgICAgZGVzY3JpcHRpb24KICAgICAgICAgICAgIkRlZmluZXMgdGhlIEItc2lkZSBvZiBhIHJlbGF0aW9uc2hpcC4KCiAgICAgICAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIGEgJ2xlYWYnIG9yICdsZWFmLWxpc3QnCiAgICAgICAgICAgIHN0YXRlbWVudCwgd2hpY2ggaXRzZWxmIG11c3QgYmUgYSBzdWJzdGF0ZW1lbnQgb2YgdGhlCiAgICAgICAgICAgICd1bmktZGlyZWN0aW9uYWwtdG9wb2xvZ3ktcmVsYXRpb25zaGlwJyBzdGF0ZW1lbnQuCgogICAgICAgICAgICBUaGUgZGF0YSB0eXBlIG9mIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIE1VU1QgYmUKICAgICAgICAgICAgJ2luc3RhbmNlLWlkZW50aWZpZXInLiBDb25zdHJhaW50cyBNQVkgYmUgdXNlZCBhcyBwYXJ0IG9mIHRoZSBwYXJlbnQKICAgICAgICAgICAgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIHRvIGVuZm9yY2UgY2FyZGluYWxpdHkuCgogICAgICAgICAgICBUaGUgaWRlbnRpZmllciBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBpcyB1c2VkIGFzIG5hbWUgb2YKICAgICAgICAgICAgdGhlIHJvbGUgb2YgdGhlIEItc2lkZSBvZiB0aGUgcmVsYXRpb25zaGlwLiBUaGUgbmFtZSBvZiB0aGUgcm9sZSBpcwogICAgICAgICAgICBzY29wZWQgdG8gdGhlIHR5cGUgb24gd2hpY2ggdGhlIEItc2lkZSBpcyBkZWZpbmVkIGFuZCBNVVNUIGJlIHVuaXF1ZQogICAgICAgICAgICB3aXRoaW4gdGhlIHNjb3BlLgoKICAgICAgICAgICAgV2hpbGUgdGhlIHBhcmVudCAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgZG9lcyBub3QgcmVzdWx0IGluIGEgcHJvcGVydHkgb2YKICAgICAgICAgICAgdGhlIHJlbGF0aW9uc2hpcCwgaXQgaXMgUkVDT01NRU5ERUQgdG8gYXZvaWQgdXNpbmcgdGhlIG5hbWUgb2YgYW4KICAgICAgICAgICAgZXhpc3RpbmcgdHlwZSBwcm9wZXJ0eSBhcyByb2xlIG5hbWUgdG8gYXZvaWQgcG90ZW50aWFsIGFtYmlndWl0aWVzCiAgICAgICAgICAgIGJldHdlZW4gcHJvcGVydGllcyBvZiBhIHR5cGUsIGFuZCByb2xlcyBvZiBhIHJlbGF0aW9uc2hpcCBvbiB0aGUgdHlwZS4KCiAgICAgICAgICAgIFRoZSBhcmd1bWVudCBpcyB0aGUgbmFtZSBvZiB0aGUgdHlwZSBvbiB3aGljaCB0aGUgQi1zaWRlIHJlc2lkZXMuIElmIHRoZQogICAgICAgICAgICB0eXBlIGlzIGRlY2xhcmVkIGluIGFub3RoZXIgbW9kdWxlLCB0aGUgdHlwZSBtdXN0IGJlIHByZWZpeGVkLCBhbmQgYQogICAgICAgICAgICBjb3JyZXNwb25kaW5nICdpbXBvcnQnIHN0YXRlbWVudCBiZSB1c2VkIHRvIGRlY2xhcmUgdGhlIHByZWZpeC4iOwoKICAgICAgICBhcmd1bWVudCBiU2lkZVR5cGU7CiAgICB9CgogICAgZXh0ZW5zaW9uIGRvbWFpbiB7CiAgICAgICAgZGVzY3JpcHRpb24gIktleXdvcmQgdXNlZCB0byBjYXJyeSBkb21haW4gaW5mb3JtYXRpb24uIjsKICAgICAgICBhcmd1bWVudCBkb21haW5OYW1lOwogICAgfQoKICAgIGV4dGVuc2lvbiBsYWJlbCB7CiAgICAgICAgZGVzY3JpcHRpb24KICAgICAgICAgICAgIlRoZSBsYWJlbCBjYW4gYmUgdXNlZCB0byBnaXZlIG1vZHVsZXMgYW5kIHN1Ym1vZHVsZXMgYSBzZW1hbnRpYyB2ZXJzaW9uLCBpbiBhZGRpdGlvbiB0byB0aGVpciByZXZpc2lvbi4KCiAgICAgICAgICAgIFRoZSBmb3JtYXQgb2YgdGhlIGxhYmVsIGlzIOKAmHgueS564oCZIOKAkyBleHByZXNzZWQgYXMgcGF0dGVybiwgaXQgaXMgWzAtOV0rXFwuWzAtOV0rXFwuWzAtOV0rCgogICAgICAgICAgICBUaGUgc3RhdGVtZW50IE1VU1Qgb25seSBiZSBhIHN1YnN0YXRlbWVudCBvZiB0aGUgcmV2aXNpb24gc3RhdGVtZW50LiAgWmVybyBvciBvbmUgcmV2aXNpb24gbGFiZWwgc3RhdGVtZW50cwogICAgICAgICAgICBwZXIgcGFyZW50IHN0YXRlbWVudCBhcmUgYWxsb3dlZC4KCiAgICAgICAgICAgIFJldmlzaW9uIGxhYmVscyBNVVNUIGJlIHVuaXF1ZSBhbW9uZ3N0IGFsbCByZXZpc2lvbnMgb2YgYSBtb2R1bGUgb3Igc3VibW9kdWxlLiI7CgogICAgICAgIGFyZ3VtZW50IHNlbXZlcnNpb247CiAgICB9Cn0=	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-common-yang-types	urn:o-ran:smo-teiv-common-yang-types	\N	[]	2024-05-14	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHsKCiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMiOwogICAgcHJlZml4IG9yLXRlaXYtdHlwZXM7CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMgeyBwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IF8zZ3BwLWNvbW1vbi15YW5nLXR5cGVzIHsgcHJlZml4IHR5cGVzM2dwcDsgfQoKICBvcmdhbml6YXRpb24gIk9SQU4iOwogIGNvbnRhY3QgIlRoZSBBdXRob3JzIjsKICAgIGRlc2NyaXB0aW9uCiAgICAiVG9wb2xvZ3kgYW5kIEludmVudG9yeSBjb21tb24gdHlwZXMgbW9kZWwuCgogIENvcHlyaWdodCAoQykgMjAyNCBFcmljc3NvbgogIE1vZGlmaWNhdGlvbnMgQ29weXJpZ2h0IChDKSAyMDI0IE9wZW5JbmZyYSBGb3VuZGF0aW9uIEV1cm9wZQoKICAgIFRoaXMgbW9kZWwgY29udGFpbnMgcmUtdXNhYmxlIGRhdGEgdHlwZXMgdGhhdCB0b3BvbG9neSBhbmQgaW52ZW50b3J5IG1vZGVscwogICAgd2lsbCBmcmVxdWVudGx5IHVzZSBhcyBwYXJ0IG9mIHR5cGVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMTQiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBncm91cGluZyBUb3BfR3JwX1R5cGUgewogICAgICAgIGRlc2NyaXB0aW9uICJHcm91cGluZyBjb250YWluaW5nIHRoZSBrZXkgYXR0cmlidXRlIGNvbW1vbiB0byBhbGwgdHlwZXMuIEFsbCB0eXBlcwogICAgICAgICAgICAgICAgICAgIE1VU1QgdXNlIHRoaXMgZ3JvdXBpbmcuIjsKCiAgICAgICAgbGVhZiBpZCB7CiAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICBkZXNjcmlwdGlvbiAiVW5pcXVlIGlkZW50aWZpZXIgb2YgdG9wb2xvZ3kgZW50aXRpZXMuIFJlcHJlc2VudHMgdGhlIEVudGl0eSBJbnN0YW5jZSBJZGVudGlmaWVyLiI7CiAgICAgICAgfQogICAgfQoKICAgIGNvbnRhaW5lciBkZWNvcmF0b3JzIHsKICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBjb250YWluZXIgc2VydmVzIGFzIGV4dGVuc2lvbiBwb2ludCBmb3IgYXBwbGljYXRpb25zIHdpc2hpbmcgdG8gZGVmaW5lIHRoZWlyIG93biBkZWNvcmF0b3JzLgogICAgICAgICAgICAgICAgICAgIFRoaXMgaXMgZG9uZSB2aWEgYXVnbWVudGF0aW9ucy4gVGhleSBjYW4gb25seSBiZSBkZWZpbmVkIGluIG5hbWUgdmFsdWUgcGFpci4KCiAgICAgICAgICAgICAgICAgICAgVGhpcyBpcyBhIGNvbnN1bWVyIGRhdGEgYW5kIGNhbiBiZSBhdHRhY2hlZCB0byBUb3BvbG9neSBFbnRpdHkgb3IgVG9wb2xvZ3kgUmVsYXRpb24gaW5zdGFuY2UsCiAgICAgICAgICAgICAgICAgICAgb3V0c2lkZSBvZiB0aGUgZGVjbGFyZWQgVG9wb2xvZ3kgRW50aXR5IG9yIFRvcG9sb2d5IFJlbGF0aW9uc2hpcCdzIGF0dHJpYnV0ZXMuIFRoaXMgY2Fubm90IGJlCiAgICAgICAgICAgICAgICAgICAgaW5zdGFudGlhdGVkLCBhbmQgaXQgTVVTVCBOT1QgYmUgYXVnbWVudGVkIG9yIGRldmlhdGVkIGluIGFueSB3YXksIHVubGVzcyBzdGF0ZWQgb3RoZXJ3aXNlLiI7CiAgICB9CgogICAgbGVhZi1saXN0IGNsYXNzaWZpZXJzIHsKICAgICAgICBkZXNjcmlwdGlvbiAiQ29uc3VtZXIgZGVmaW5lZCB0YWdzIHRvIHRvcG9sb2d5IGVudGl0aWVzIGFuZCByZWxhdGlvbnNoaXBzLgoKICAgICAgICAgICAgICAgICAgICBUaGlzIGlzIGEgY29uc3VtZXIgZGF0YSBhbmQgY2FuIGJlIGF0dGFjaGVkIHRvIFRvcG9sb2d5IEVudGl0eSBvciBUb3BvbG9neSBSZWxhdGlvbiBpbnN0YW5jZSwKICAgICAgICAgICAgICAgICAgICBvdXRzaWRlIG9mIHRoZSBkZWNsYXJlZCBUb3BvbG9neSBFbnRpdHkgb3IgVG9wb2xvZ3kgUmVsYXRpb25zaGlwJ3MgYXR0cmlidXRlcy4gVGhpcyBjYW5ub3QgYmUKICAgICAgICAgICAgICAgICAgICBpbnN0YW50aWF0ZWQsIGFuZCBpdCBNVVNUIE5PVCBiZSBhdWdtZW50ZWQgb3IgZGV2aWF0ZWQgaW4gYW55IHdheSwgdW5sZXNzIHN0YXRlZCBvdGhlcndpc2UuIjsKCiAgICAgICAgdHlwZSBpZGVudGl0eXJlZiB7IGJhc2UgY2xhc3NpZmllcjsgfQogICAgfQoKICAgIGxlYWYtbGlzdCBzb3VyY2VJZHMgewogICAgICAgIGRlc2NyaXB0aW9uICJBbiBvcmRlcmVkIGxpc3Qgb2YgaWRlbnRpdGllcyB0aGF0IHJlcHJlc2VudCB0aGUgc2V0IG9mIG5hdGl2ZSBzb3VyY2UgaWRlbnRpZmllcnMgZm9yIHBhcnRpY2lwYXRpbmcKICAgICAgICAgICAgICAgICAgICBlbnRpdGllcy4KCiAgICAgICAgICAgICAgICAgICAgVGhpcyBpcyBhIGNvbnN1bWVyIGRhdGEgYW5kIGNhbiBiZSBhdHRhY2hlZCB0byBUb3BvbG9neSBFbnRpdHkgb3IgVG9wb2xvZ3kgUmVsYXRpb24gaW5zdGFuY2UsCiAgICAgICAgICAgICAgICAgICAgb3V0c2lkZSBvZiB0aGUgZGVjbGFyZWQgVG9wb2xvZ3kgRW50aXR5IG9yIFRvcG9sb2d5IFJlbGF0aW9uc2hpcCdzIGF0dHJpYnV0ZXMuIFRoaXMgY2Fubm90IGJlCiAgICAgICAgICAgICAgICAgICAgaW5zdGFudGlhdGVkLCBhbmQgaXQgTVVTVCBOT1QgYmUgYXVnbWVudGVkIG9yIGRldmlhdGVkIGluIGFueSB3YXksIHVubGVzcyBzdGF0ZWQgb3RoZXJ3aXNlLiI7CgogICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgIG9yZGVyZWQtYnkgdXNlcjsKICAgIH0KCiAgICBjb250YWluZXIgbWV0YWRhdGEgewogICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIGNvbnRhaW5lciBzZXJ2ZXMgYXMgZXh0ZW5zaW9uIHBvaW50IHRvIGRlZmluZSBtZXRhZGF0YS4gVGhleSBjYW4gb25seSBiZSBkZWZpbmVkIGluIG5hbWUgdmFsdWUKICAgICAgICAgICAgICAgICAgICBwYWlyLgoKICAgICAgICAgICAgICAgICAgICBUaGlzIGlzIGEgY29uc3VtZXIgZGF0YSBhbmQgY2FuIGJlIGF0dGFjaGVkIHRvIFRvcG9sb2d5IEVudGl0eSBvciBUb3BvbG9neSBSZWxhdGlvbiBpbnN0YW5jZSwKICAgICAgICAgICAgICAgICAgICBvdXRzaWRlIG9mIHRoZSBkZWNsYXJlZCBUb3BvbG9neSBFbnRpdHkgb3IgVG9wb2xvZ3kgUmVsYXRpb25zaGlwJ3MgYXR0cmlidXRlcy4gVGhpcyBjYW5ub3QgYmUKICAgICAgICAgICAgICAgICAgICBpbnN0YW50aWF0ZWQsIGFuZCBpdCBNVVNUIE5PVCBiZSBhdWdtZW50ZWQgb3IgZGV2aWF0ZWQgaW4gYW55IHdheSwgdW5sZXNzIHN0YXRlZCBvdGhlcndpc2UuIjsKICAgIH0KCiAgICBpZGVudGl0eSBjbGFzc2lmaWVyewogICAgICAgIGRlc2NyaXB0aW9uICAiVGhlIGNsYXNzaWZpZXIgaXMgdXNlZCBhcyBhIGJhc2UgdG8gcHJvdmlkZSBhbGwgY2xhc3NpZmllcnMgd2l0aCBpZGVudGl0eS4gIjsKICAgIH0KfQ==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-ran	urn:o-ran:smo-teiv-ran	RAN	[]	2024-05-14	bW9kdWxlIG8tcmFuLXNtby10ZWl2LXJhbiB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtcmFuIjsKICAgIHByZWZpeCBvci10ZWl2LXJhbjsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgXzNncHAtY29tbW9uLXlhbmctdHlwZXMgeyBwcmVmaXggdHlwZXMzZ3BwOyB9CgogICAgb3JnYW5pemF0aW9uICJPUkFOIjsKICAgIGNvbnRhY3QgIk9SQU4gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBMb2dpY2FsIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoQykgMjAyNCBFcmljc3NvbgogICAgTW9kaWZpY2F0aW9ucyBDb3B5cmlnaHQgKEMpIDIwMjQgT3BlbkluZnJhIEZvdW5kYXRpb24gRXVyb3BlCgogICAgVGhpcyBtb2RlbCBjb250YWlucyB0aGUgdG9wb2xvZ3kgZW50aXRpZXMgYW5kIHJlbGF0aW9ucyBpbiB0aGUKICAgIFJBTiBkb21haW4sIHdoaWNoIHJlcHJlc2VudHMgdGhlIGZ1bmN0aW9uYWwgY2FwYWJpbGl0eQogICAgb2YgdGhlIGRlcGxveWVkIFJBTiB0aGF0IGFyZSByZWxldmFudCB0byByQXBwcyB1c2UgY2FzZXMuIjsKCiAgICByZXZpc2lvbiAiMjAyNC0wNS0xNCIgewogICAgICAgIGRlc2NyaXB0aW9uICJJbml0aWFsIHJldmlzaW9uLiI7CiAgICAgICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogICAgfQoKICAgIG9yLXRlaXYteWV4dDpkb21haW4gUkFOOwoKICAgIGxpc3QgR05CRFVGdW5jdGlvbiB7CiAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQiBEaXN0cmlidXRlZCBVbml0IChnTkItRFUpLgoKICAgICAgICAgICAgICAgICAgICBBIGdOQiBtYXkgY29uc2lzdCBvZiBhIGdOQi1DZW50cmFsaXplZCBVbml0CiAgICAgICAgICAgICAgICAgICAgKGdOQi1DVSkgYW5kIGEgZ05CLURVLiBUaGUgQ1UgcHJvY2Vzc2VzIG5vbi1yZWFsCiAgICAgICAgICAgICAgICAgICAgdGltZSBwcm90b2NvbHMgYW5kIHNlcnZpY2VzLCBhbmQgdGhlIERVIHByb2Nlc3NlcwogICAgICAgICAgICAgICAgICAgIFBIWSBsZXZlbCBwcm90b2NvbCBhbmQgcmVhbCB0aW1lIHNlcnZpY2VzLiBUaGUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UgYW5kIHRoZSBnTkItRFUgdW5pdHMgYXJlIGNvbm5lY3RlZCB2aWEKICAgICAgICAgICAgICAgICAgICBGMSBsb2dpY2FsIGludGVyZmFjZS4KCiAgICAgICAgICAgICAgICAgICAgVGhlIGZvbGxvd2luZyBpcyB0cnVlIGZvciBhIGdOQi1EVToKICAgICAgICAgICAgICAgICAgICBJcyBjb25uZWN0ZWQgdG8gdGhlIGdOQi1DVS1DUCB0aHJvdWdoIHRoZSBGMS1DCiAgICAgICAgICAgICAgICAgICAgaW50ZXJmYWNlLklzIGNvbm5lY3RlZCB0byB0aGUgZ05CLUNVLVVQIHRocm91Z2gKICAgICAgICAgICAgICAgICAgICB0aGUgRjEtVSBpbnRlcmZhY2UuIE9uZSBnTkItRFUgaXMgY29ubmVjdGVkIHRvIG9ubHkKICAgICAgICAgICAgICAgICAgICBvbmUgZ05CLUNVLUNQLiBPbmUgZ05CLURVIGNhbiBiZSBjb25uZWN0ZWQgdG8KICAgICAgICAgICAgICAgICAgICBtdWx0aXBsZSBnTkItQ1UtVVBzIHVuZGVyIHRoZSBjb250cm9sIG9mIHRoZSBzYW1lCiAgICAgICAgICAgICAgICAgICAgZ05CLUNVLUNQLgogICAgICAgICAgICAgICAgICAgIE5vdGU6IEEgZ05CIG1heSBjb25zaXN0IG9mIGEgZ05CLUNVLUNQLCBtdWx0aXBsZQogICAgICAgICAgICAgICAgICAgIGdOQi1DVS1VUHMgYW5kIG11bHRpcGxlIGdOQi1EVXMuIGdOQi1EVSBpcyBhIGNvbmNyZXRlCiAgICAgICAgICAgICAgICAgICAgY2xhc3MgdGhhdCBleHRlbmRzIHRoZSBORy1SQU4gbm9kZSBvYmplY3QuIEluIFRvcG9sb2d5LCB5b3UKICAgICAgICAgICAgICAgICAgICBjYW4gY3JlYXRlLCByZWFkLCB1cGRhdGUsIGFuZCBkZWxldGUgdGhlIGdOQi1EVSBvYmplY3QuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgY29udGFpbmVyIGRVcExNTklkIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQTE1OIGlkZW50aWZpZXIgdXNlZCBhcyBwYXJ0IG9mIFBNIEV2ZW50cyBkYXRhIjsKICAgICAgICAgICAgICAgIHVzZXMgdHlwZXMzZ3BwOlBMTU5JZDsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJEVUlkIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhlIERVIHdpdGhpbiBhIGdOb2RlQiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSWRlbnRpdHkgb2YgZ05vZGVCIHdpdGhpbiBhIFBMTU4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZ05CSWRMZW5ndGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxlbmd0aCBvZiBnTkJJZCBiaXQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgRU5vZGVCRnVuY3Rpb24gewogICAgICAgIGRlc2NyaXB0aW9uICJBbiBFdm9sdmVkIE5vZGUgQiAoZU5vZGVCKSBpcyB0aGUgb25seSBtYW5kYXRvcnkKICAgICAgICAgICAgICAgICAgICBub2RlIGluIHRoZSByYWRpbyBhY2Nlc3MgbmV0d29yayAoUkFOKSBvZiBMb25nLVRlcm0KICAgICAgICAgICAgICAgICAgICBFdm9sdXRpb24gKExURSkuIFRoZSBlTm9kZUIgaXMgYSBjb21wbGV4IGJhc2UKICAgICAgICAgICAgICAgICAgICBzdGF0aW9uIHRoYXQgaGFuZGxlcyByYWRpbyBjb21tdW5pY2F0aW9ucwogICAgICAgICAgICAgICAgICAgIGluIHRoZSBjZWxsIGFuZCBjYXJyaWVzIG91dCByYWRpbyByZXNvdXJjZQogICAgICAgICAgICAgICAgICAgIG1hbmFnZW1lbnQgYW5kIGhhbmRvdmVyIGRlY2lzaW9ucy4gVW5saWtlIDIvM0cKICAgICAgICAgICAgICAgICAgICB3aXJlbGVzcyBSQU4sIHRoZXJlIGlzIG5vIGNlbnRyYWxpemVkIHJhZGlvIG5ldHdvcmsKICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVyIGluIExURS4gSXQgaXMgdGhlIGhhcmR3YXJlIHRoYXQgaXMgY29ubmVjdGVkCiAgICAgICAgICAgICAgICAgICAgdG8gdGhlIG1vYmlsZSBwaG9uZSBuZXR3b3JrIHRoYXQgY29tbXVuaWNhdGVzCiAgICAgICAgICAgICAgICAgICAgZGlyZWN0bHkgd2l0aCBtb2JpbGUgaGFuZHNldHMgKFVzZXIgRXF1aXBtZW50KSwgbGlrZSBhIGJhc2UKICAgICAgICAgICAgICAgICAgICB0cmFuc2NlaXZlciBzdGF0aW9uIChCVFMpIGluIEdTTSBuZXR3b3Jrcy4gVGhpcyBzaW1wbGlmaWVzCiAgICAgICAgICAgICAgICAgICAgdGhlIGFyY2hpdGVjdHVyZSBhbmQgYWxsb3dzIGxvd2VyIHJlc3BvbnNlIHRpbWVzLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZU5CSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFTm9kZUIgSUQgdGhhdCBmb3JtcyBwYXJ0IG9mCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgQ2VsbCBHbG9iYWwgSWRlbnRpdHksIGFuZCBpcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxzbyB1c2VkIHRvIGlkZW50aWZ5IHRoZSBub2RlIG92ZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBTMSBpbnRlcmZhY2UiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgICAgICBkZWZhdWx0IDExOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgZU5vZGVCUGxtbklkIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGUgRU5vZGVCIFB1YmxpYyBMYW5kIE1vYmlsZSBOZXR3b3JrCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoUExNTikgSUQgdGhhdCBmb3JtcyBwYXJ0IG9mIHRoZSBFTm9kZUIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdsb2JhbCBJRCB1c2VkIHRvIGlkZW50aWZ5IHRoZSBub2RlIG92ZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBTMSBpbnRlcmZhY2UuIE5vdGU6IFRoZSB2YWx1ZSAoTUNDPTAwMSwgTU5DPTAxKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kaWNhdGVzIHRoYXQgdGhlIFBMTU4gaXMgbm90IGluaXRpYXRlZC4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRoZSB2YWx1ZSBjYW4gbm90IGJlIHVzZWQgYXMgYSB2YWxpZCBQTE1OIElkZW50aXR5LiI7CgogICAgICAgICAgICAgICAgbGVhZiBtY2MgewogICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGUgTUNDIHBhcnQgb2YgYSBQTE1OIGlkZW50aXR5CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlZCBpbiB0aGUgcmFkaW8gbmV0d29yay4iOwogICAgICAgICAgICAgICAgICAgIHR5cGUgaW50MzIgewogICAgICAgICAgICAgICAgICAgICAgICByYW5nZSAwLi45OTk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgbGVhZiBtbmMgewogICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGUgTU5DIHBhcnQgb2YgYSBQTE1OIGlkZW50aXR5CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlZCBpbiB0aGUgcmFkaW8gbmV0d29yay4iOwogICAgICAgICAgICAgICAgICAgIHR5cGUgaW50MzIgewogICAgICAgICAgICAgICAgICAgICAgICByYW5nZSAwLi45OTk7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgbGVhZiBtbmNMZW5ndGggewogICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGUgbGVuZ3RoIG9mIHRoZSBNTkMgcGFydCBvZiBhCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUExNTiBpZGVudGl0eSB1c2VkIGluIHRoZSByYWRpbyBuZXR3b3JrLiI7CiAgICAgICAgICAgICAgICAgICAgdHlwZSBpbnQzMiB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlIDIuLjM7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgQW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIE1PIHNlcnZlcyBhcyBhIG1hcHBpbmcgYmV0d2VlbiB0aGUgY2VsbAogICAgICAgICAgICAgICAgICAgIGFuZCB0aGUgUkJTIGVxdWlwbWVudCB1c2VkIHRvIHByb3ZpZGUgY292ZXJhZ2UKICAgICAgICAgICAgICAgICAgICBpbiBhIGNlcnRhaW4gZ2VvZ3JhcGhpY2FsIGFyZWEuIFRoZSBNTyBhbHNvCiAgICAgICAgICAgICAgICAgICAgY29udHJvbHMgdGhlIG1heGltdW0gb3V0cHV0IHBvd2VyIG9mIHRoZSBzZWN0b3IuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZi1saXN0IGVVdHJhbkZxQmFuZHMgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxpc3Qgb2YgTFRFIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdCBhc3NvY2lhdGVkIGhhcmR3YXJlIHN1cHBvcnRzIjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmLWxpc3QgZ2VyYW5GcUJhbmRzIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIEdFUkFOIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdCBhc3NvY2lhdGVkIGhhcmR3YXJlIHN1cHBvcnRzIjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmLWxpc3QgblJGcUJhbmRzIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIE5SIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzb2NpYXRlZCBoYXJkd2FyZSBzdXBwb3J0cyI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IExURVNlY3RvckNhcnJpZXIgewogICAgICAgIGRlc2NyaXB0aW9uICJUaGUgTFRFIFNlY3RvciBDYXJyaWVyIG9iamVjdCBwcm92aWRlcyB0aGUKICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGVzIGZvciBkZWZpbmluZyB0aGUgbG9naWNhbCBjaGFyYWN0ZXJpc3RpY3MKICAgICAgICAgICAgICAgICAgICBvZiBhIGNhcnJpZXIgKGNlbGwpIGluIGEgc2VjdG9yLiBBIHNlY3RvciBpcyBhIGNvdmVyYWdlCiAgICAgICAgICAgICAgICAgICAgYXJlYSBhc3NvY2lhdGVkIHdpdGggYSBiYXNlIHN0YXRpb24gaGF2aW5nCiAgICAgICAgICAgICAgICAgICAgaXRzIG93biBhbnRlbm5hcywgcmFkaW8gcG9ydHMsIGFuZCBjb250cm9sIGNoYW5uZWxzLgogICAgICAgICAgICAgICAgICAgIFRoZSBjb25jZXB0IG9mIHNlY3RvcnMgd2FzIGRldmVsb3BlZCB0byBpbXByb3ZlIGNvLWNoYW5uZWwKICAgICAgICAgICAgICAgICAgICBpbnRlcmZlcmVuY2UgaW4gY2VsbHVsYXIgc3lzdGVtcywgYW5kIG1vc3Qgd2lyZWxlc3Mgc3lzdGVtcwogICAgICAgICAgICAgICAgICAgIHVzZSB0aHJlZSBzZWN0b3IgY2VsbHMuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBzZWN0b3JDYXJyaWVyVHlwZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSW5kaWNhdGVzIHdoZXRoZXIgb3Igbm90IHRoZSBzZWN0b3IgY2FycmllcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxsZWQgYnkgTU8gU2VjdG9yQ2FycmllciBpcyBhIGRpZ2l0YWwgc2VjdG9yLiI7CiAgICAgICAgICAgICAgICB0eXBlIGVudW1lcmF0aW9uIHsKICAgICAgICAgICAgICAgICAgICBlbnVtIG5vcm1hbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAwOwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTm90IGEgZGlnaXRhbCBzZWN0b3IiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIGxlZnRfZGlnaXRhbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAxOwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTGVmdCBkaWdpdGFsIHNlY3RvciBmb3IgMkRTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSByaWdodF9kaWdpdGFsX3NlY3RvciB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDI7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSaWdodCBkaWdpdGFsIHNlY3RvciBmb3IgMkRTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSBsZWZ0X2RpZ2l0YWxfc2VjdG9yXzNkcyB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDM7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMZWZ0IGRpZ2l0YWwgc2VjdG9yIGZvciAzRFMiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIHJpZ2h0X2RpZ2l0YWxfc2VjdG9yXzNkcyB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDQ7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSaWdodCBkaWdpdGFsIHNlY3RvciBmb3IgM0RTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSBtaWRkbGVfZGlnaXRhbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA1OwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWlkZGxlIGRpZ2l0YWwgc2VjdG9yIGZvciAzRFMiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IE5SU2VjdG9yQ2FycmllciB7CiAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBOUiBTZWN0b3IgQ2FycmllciBvYmplY3QgcHJvdmlkZXMKICAgICAgICAgICAgICAgICAgICB0aGUgYXR0cmlidXRlcyBmb3IgZGVmaW5pbmcgdGhlIGxvZ2ljYWwKICAgICAgICAgICAgICAgICAgICBjaGFyYWN0ZXJpc3RpY3Mgb2YgYSBjYXJyaWVyIChjZWxsKSBpbiBhCiAgICAgICAgICAgICAgICAgICAgc2VjdG9yLiBBIHNlY3RvciBpcyBhIGNvdmVyYWdlIGFyZWEgYXNzb2NpYXRlZAogICAgICAgICAgICAgICAgICAgIHdpdGggYSBiYXNlIHN0YXRpb24gaGF2aW5nIGl0cyBvd24gYW50ZW5uYXMsCiAgICAgICAgICAgICAgICAgICAgcmFkaW8gcG9ydHMsIGFuZCBjb250cm9sIGNoYW5uZWxzLiBUaGUgY29uY2VwdAogICAgICAgICAgICAgICAgICAgIG9mIHNlY3RvcnMgd2FzIGRldmVsb3BlZCB0byBpbXByb3ZlIGNvLWNoYW5uZWwKICAgICAgICAgICAgICAgICAgICBpbnRlcmZlcmVuY2UgaW4gY2VsbHVsYXIgc3lzdGVtcywgYW5kIG1vc3Qgd2lyZWxlc3MKICAgICAgICAgICAgICAgICAgICBzeXN0ZW1zIHVzZSB0aHJlZSBzZWN0b3IgY2VsbHMuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBhcmZjbkRMIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBBYnNvbHV0ZSBSYWRpbyBGcmVxdWVuY3kgQ2hhbm5lbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgTnVtYmVyIChOUi1BUkZDTikgZm9yIGRvd25saW5rIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGFyZmNuVUwgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5SIEFic29sdXRlIFJhZGlvIGZyZXF1ZW5jeSBDaGFubmVsIE51bWJlcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgKE5SLUFSRkNOKSBmb3IgdXBsaW5rLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBmcmVxdWVuY3lETCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiUkYgUmVmZXJlbmNlIEZyZXF1ZW5jeSBvZiBkb3dubGluayBjaGFubmVsIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGZyZXF1ZW5jeVVMIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSRiBSZWZlcmVuY2UgRnJlcXVlbmN5IG9mIHVwbGluayBjaGFubmVsIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGJTQ2hhbm5lbEJ3REwgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkJTIENoYW5uZWwgYmFuZHdpZHRoIGluIE1IeiBmb3IgZG93bmxpbmsuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTFRFU0VDVE9SQ0FSUklFUl9VU0VTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gMC4uMSB0byAwLi4xCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmIHVzZWQtYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTFRFIFNlY3RvciBDYXJyaWVyIHVzZXMgQW50ZW5uYSBDYXBhYmlsaXR5LiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBMVEVTZWN0b3JDYXJyaWVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHVzZWQtYnktbHRlU2VjdG9yQ2FycmllciB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIENwYWJpbGl0eSB1c2VkIGJ5IExURSBTZWN0b3IgQ2Fycmllci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBFTk9ERUJGVU5DVElPTl9QUk9WSURFU19MVEVTRUNUT1JDQVJSSUVSIHsgLy8gMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgcHJvdmlkZWQtbHRlU2VjdG9yQ2FycmllciB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJlTm9kZUIgRnVuY3Rpb24gcHJvdmlkZXMgTFRFIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBFTm9kZUJGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBwcm92aWRlZC1ieS1lbm9kZWJGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMVEUgU2VjdG9yIENhcnJpZXIgcHJvdmlkZWQgYnkgZU5vZGVCIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBMVEVTZWN0b3JDYXJyaWVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1hbmRhdG9yeSB0cnVlOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5SU0VDVE9SQ0FSUklFUl9VU0VTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gMC4ubiB0byAwLi4xCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmIHVzZWQtYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgU2VjdG9yIENhcnJpZXIgdXNlcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIE5SU2VjdG9yQ2FycmllcjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IHVzZWQtYnktbnJTZWN0b3JDYXJyaWVyIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSB1c2VkIGJ5IE5SIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBBbnRlbm5hQ2FwYWJpbGl0eTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIEFOVEVOTkFDQVBBQklMSVRZX1VTRVNfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyBTYW1lIGVudGl0eSAoMC4uMSB0byAwLi4xKQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZiB1c2VkLWFudGVubmFDYXBhYmlsaXR5IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlZCBieSBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIEFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHVzZWQtYnktYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHJlYWxpc2VzIEFudGVubmEgQ2FwYWJpbGl0eS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBBTlRFTk5BQ0FQQUJJTElUWV9QUk9WSURFU19BTlRFTk5BQ0FQQUJJTElUWSB7IC8vIFNhbWUgZW50aXR5ICgwLi4xIHRvIDAuLm4pCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmIHByb3ZpZGVkLWFudGVubmFDYXBhYmlsaXR5IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlZCBieSBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIEFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3QgcHJvdmlkZWQtYnktYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHJlYWxpc2VzIEFudGVubmEgQ2FwYWJpbGl0eS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBBTlRFTk5BQ0FQQUJJTElUWV9TRVJWRVNfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyBTYW1lIGVudGl0eSAoMC4ubiB0byAwLi4xKQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHNlcnZpY2VkLWFudGVubmFDYXBhYmlsaXR5IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlZCBieSBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIEFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHNlcnZpY2VkLWJ5LWFudGVubmFDYXBhYmlsaXR5IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgQU5URU5OQUNBUEFCSUxJVFlfUkVBTElTRURfQllfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyBTYW1lIGVudGl0eSAoMC4ubiB0byAwLi5tKQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHJlYWxpc2VkLWJ5LWFudGVubmFDYXBhYmlsaXR5IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgQ2FwYWJpbGl0eSByZWFsaXNlZCBieSBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIEFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3QgcmVhbGlzZWQtYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHJlYWxpc2VzIEFudGVubmEgQ2FwYWJpbGl0eS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgQW50ZW5uYUNhcGFiaWxpdHk7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgIH0KICAgIH0KfQ==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-rel-equipment-ran	urn:o-ran:smo-teiv-rel-equipment-ran	REL_EQUIPMENT_RAN	["o-ran-smo-teiv-equipment", "o-ran-smo-teiv-ran"]	2024-05-14	bW9kdWxlIG8tcmFuLXNtby10ZWl2LXJlbC1lcXVpcG1lbnQtcmFuIHsKICAgIHlhbmctdmVyc2lvbiAxLjE7CiAgICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1yZWwtZXF1aXBtZW50LXJhbiI7CiAgICBwcmVmaXggb3ItdGVpdi1yZWwtZXF1aXByYW47CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHsgcHJlZml4IG9yLXRlaXYtdHlwZXM7IH0KCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctZXh0ZW5zaW9ucyB7IHByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtZXF1aXBtZW50IHsgcHJlZml4IG9yLXRlaXYtZXF1aXA7IH0KCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtcmFuIHsgcHJlZml4IG9yLXRlaXYtcmFuOyB9CgogICAgb3JnYW5pemF0aW9uICJPUkFOIjsKICAgIGNvbnRhY3QgIlRoZSBBdXRob3JzIjsKICAgIGRlc2NyaXB0aW9uCiAgICAiRXF1aXBtZW50IGFuZCBSQU4gdG9wb2xvZ3kgcmVsYXRpb24gbW9kZWwuCgogICAgQ29weXJpZ2h0IChDKSAyMDI0IEVyaWNzc29uCiAgICBNb2RpZmljYXRpb25zIENvcHlyaWdodCAoQykgMjAyNCBPcGVuSW5mcmEgRm91bmRhdGlvbiBFdXJvcGUKCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSByZWxhdGlvbnMgYmV0d2VlbiBFcXVpcG1lbnQgYW5kIFJBTi4iOwoKICAgIHJldmlzaW9uICIyMDI0LTA1LTE0IiB7CiAgICAgICAgZGVzY3JpcHRpb24gIkluaXRpYWwgcmV2aXNpb24uIjsKICAgICAgICBvci10ZWl2LXlleHQ6bGFiZWwgMC4zLjA7CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmRvbWFpbiBSRUxfRVFVSVBNRU5UX1JBTjsKCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIEFOVEVOTkFNT0RVTEVfU0VSVkVTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gMC4ubiB0byAwLi5tCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHNlcnZpY2VkIGJ5IHRoaXMgQW50ZW5uYSBNb2R1bGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtZXF1aXA6QW50ZW5uYU1vZHVsZTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IHNlcnZpbmctYW50ZW5uYU1vZHVsZSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIE1vZHVsZSBzZXJ2ZXMgdGhpcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQp9Cg==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-equipment	urn:o-ran:smo-teiv-equipment	EQUIPMENT	[]	2024-05-14	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWVxdWlwbWVudCB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtZXF1aXBtZW50IjsKICAgIHByZWZpeCBvci10ZWl2LWVxdWlwOwoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyB7IHByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMgeyBwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IGlldGYtZ2VvLWxvY2F0aW9uIHsKICAgICAgICBwcmVmaXggZ2VvOwogICAgICAgIHJlZmVyZW5jZSAiUkZDIDkxNzk6IEEgWUFORyBHcm91cGluZyBmb3IgR2VvZ3JhcGhpYyBMb2NhdGlvbnMiOwogICAgfQoKICAgIG9yZ2FuaXphdGlvbiAiT1JBTiI7CiAgICBjb250YWN0ICJUaGUgQXV0aG9ycyI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBFcXVpcG1lbnQgdG9wb2xvZ3kgbW9kZWwuCgogICAgQ29weXJpZ2h0IChDKSAyMDI0IEVyaWNzc29uCiAgICBNb2RpZmljYXRpb25zIENvcHlyaWdodCAoQykgMjAyNCBPcGVuSW5mcmEgRm91bmRhdGlvbiBFdXJvcGUKCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgRXF1aXBtZW50IGRvbWFpbiwgd2hpY2ggaXMgbW9kZWxsZWQgdG8gdW5kZXJzdGFuZCB0aGUgcGh5c2ljYWwKICAgIGxvY2F0aW9uIG9mIGVxdWlwbWVudCBzdWNoIGFzIGFudGVubmFzIGFzc29jaWF0ZWQgd2l0aCBhIGNlbGwvY2FycmllcgogICAgYW5kIHRoZWlyIHJlbGV2YW50IHByb3BlcnRpZXMgZS5nLiB0aWx0LCBtYXggcG93ZXIgZXRjLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMTQiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIEVRVUlQTUVOVDsKCiAgICBsaXN0IEFudGVubmFNb2R1bGUgewogICAgICAgIGRlc2NyaXB0aW9uICJBbiBBbnRlbm5hIE1vZHVsZSByZXByZXNlbnRzIHRoZQogICAgICAgICAgICAgICAgICAgIHBoeXNpY2FsIGFzcGVjdCBvZiBhbiBhbnRlbm5hLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgYW50ZW5uYU1vZGVsTnVtYmVyIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJWZW5kb3Itc3BlY2lmaWMgYW50ZW5uYSBtb2RlbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnRpZmllci4gVGhpcyBhdHRyaWJ1dGUgaXMgcGFydCBvZgogICAgICAgICAgICAgICAgICAgICAgICAgICAgQUlTRyB2MyBBREIgU3RhbmRhcmQgYW5kIGhhcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgbm8gb3BlcmF0aW9uYWwgaW1wYWN0LiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBtZWNoYW5pY2FsQW50ZW5uYUJlYXJpbmcgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgYmVhcmluZyBvbiBhbnRlbm5hIHN1YnVuaXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZXJlIGFudGVubmEgdW5pdCBpcyBpbnN0YWxsZWQuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIG1lY2hhbmljYWxBbnRlbm5hVGlsdCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhlIGZpeGVkIGFudGVubmEgdGlsdCBvZiB0aGUgaW5zdGFsbGF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmaW5lZCBhcyB0aGUgaW5jbGluYXRpb24gb2YgdGhlIGFudGVubmEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgcmVzcGVjdCB0byB0aGUgdmVydGljYWwgcGxhbmUuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBJdCBpcyBhIHNpZ25lZCB2YWx1ZS4gUG9zaXRpdmUgaW5kaWNhdGVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb3dudGlsdCwgYW5kIG5lZ2F0aXZlIGluZGljYXRlcyB1cHRpbHQuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIHBvc2l0aW9uV2l0aGluU2VjdG9yIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIHVuaXQgcG9zaXRpb24gd2l0aGluIHNlY3Rvci4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRoaXMgYXR0cmlidXRlIGlzIHBhcnQgb2YgQUlTRyB2MyBBREIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YW5kYXJkIGFuZCBoYXMgbm8gb3BlcmF0aW9uYWwgaW1wYWN0LiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiB0b3RhbFRpbHQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRvdGFsIGFudGVubmEgZWxldmF0aW9uIGluY2x1ZGluZyB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluc3RhbGxlZCB0aWx0IGFuZCB0aGUgdGlsdCBhcHBsaWVkIGJ5CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgUmVtb3RlIEVsZWN0cmljYWwgVGlsdCAoUkVUKS4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZWxlY3RyaWNhbEFudGVubmFUaWx0IHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJFbGVjdHJpY2FsbHktY29udHJvbGxlZCB0aWx0IG9mIG1haW4gYmVhbSBtYXhpbXVtCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoIHJlc3BlY3QgdG8gZGlyZWN0aW9uIG9ydGhvZ29uYWwgdG8gYW50ZW5uYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudCBheGlzIChzZWUgM0dQUCBUUyAyNS40NjYpLiBWYWx1ZSBpcyBzaWduZWQ7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWx0IGRvd24gaXMgcG9zaXRpdmUsIHRpbHQgdXAgaXMgbmVnYXRpdmUuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmLWxpc3QgYW50ZW5uYUJlYW1XaWR0aCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhlIGFuZ3VsYXIgc3BhbiBvZiB0aGUgbWFpbiBsb2JlIG9mIHRoZSBhbnRlbm5hIHJhZGlhdGlvbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiBpbiB0aGUgaG9yaXpvbnRhbCBwbGFuZS4gTWVhc3VyZWQgaW4gZGVncmVlcy4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHVzZXMgZ2VvOmdlby1sb2NhdGlvbjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBBTlRFTk5BTU9EVUxFX1VTRVNfQU5URU5OQU1PRFVMRSB7IC8vIFNhbWUgZW50aXR5ICgwLi4xIHRvIDAuLjEpCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgdXNlZC1ieS1hbnRlbm5hTW9kdWxlIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkFudGVubmEgTW9kdWxlIHJlYWxpc2VkIGJ5IEFudGVubmEgTW9kdWxlLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBBbnRlbm5hTW9kdWxlOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICB9CgogICAgICAgIGxlYWYtbGlzdCB1c2VkLWFudGVubmFNb2R1bGUgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBNb2R1bGUgcmVhbGlzZXMgQW50ZW5uYSBNb2R1bGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEFudGVubmFNb2R1bGU7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgIH0KICAgIH0KfQ==	BUILT_IN_MODULE	IN_USAGE
+\.
+
+COPY ties_model.entity_info("name", "moduleReferenceName") FROM stdin;
+GNBDUFunction	o-ran-smo-teiv-ran
+ENodeBFunction	o-ran-smo-teiv-ran
+AntennaCapability	o-ran-smo-teiv-ran
+LTESectorCarrier	o-ran-smo-teiv-ran
+NRSectorCarrier	o-ran-smo-teiv-ran
+AntennaModule	o-ran-smo-teiv-equipment
+\.
+
+COPY ties_model.relationship_info("name", "aSideAssociationName", "aSideMOType", "aSideMinCardinality", "aSideMaxCardinality", "bSideAssociationName", "bSideMOType", "bSideMinCardinality", "bSideMaxCardinality", "associationKind", "relationshipDataLocation", "connectSameEntity", "moduleReferenceName") FROM stdin;
+LTESECTORCARRIER_USES_ANTENNACAPABILITY	used-antennaCapability	LTESectorCarrier	0	1	used-by-lteSectorCarrier	AntennaCapability	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-ran
+ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	provided-lteSectorCarrier	ENodeBFunction	1	1	provided-by-enodebFunction	LTESectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+NRSECTORCARRIER_USES_ANTENNACAPABILITY	used-antennaCapability	NRSectorCarrier	0	9223372036854775807	used-by-nrSectorCarrier	AntennaCapability	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-ran
+ANTENNACAPABILITY_USES_ANTENNACAPABILITY	used-antennaCapability	AntennaCapability	0	1	used-by-antennaCapability	AntennaCapability	0	1	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-ran
+ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY	provided-antennaCapability	AntennaCapability	0	9223372036854775807	provided-by-antennaCapability	AntennaCapability	0	1	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-ran
+ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY	serviced-antennaCapability	AntennaCapability	0	1	serviced-by-antennaCapability	AntennaCapability	0	9223372036854775807	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-ran
+ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY	realised-by-antennaCapability	AntennaCapability	0	9223372036854775807	realised-antennaCapability	AntennaCapability	0	9223372036854775807	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-ran
+ANTENNAMODULE_SERVES_ANTENNACAPABILITY	serviced-antennaCapability	AntennaModule	0	9223372036854775807	serving-antennaModule	AntennaCapability	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-rel-equipment-ran
+ANTENNAMODULE_USES_ANTENNAMODULE	used-by-antennaModule	AntennaModule	0	9223372036854775807	used-antennaModule	AntennaModule	0	9223372036854775807	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-equipment
+\.
+
+;
+
+COMMIT;
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-common-yang-extensions.yang b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-common-yang-extensions.yang
new file mode 100644
index 0000000..a8f4dc8
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-common-yang-extensions.yang
@@ -0,0 +1,130 @@
+module o-ran-smo-teiv-common-yang-extensions {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-common-yang-extensions";
+    prefix or-teiv-yext;
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "Topology and Inventory YANG extensions model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains extensions to the YANG language that topology and
+    inventory models will use to define and annotate types and relationships.";
+
+    revision "2024-05-14" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    extension biDirectionalTopologyRelationship {
+        description
+            "Defines a bi-directional relationship in the topology.
+
+            A bi-directional-association (BDA) is a relationship comprising of an
+            A-side and a B-side. The A-side is considered the originating side of
+            the relationship; the B-side is considered the terminating side of the
+            relationship. The order of A-side and B-side is of importance and MUST
+            NOT be changed once defined.
+
+            Both A-side and B-side are defined on a type, and are given a role. A
+            type may have multiple originating and/or terminating sides of a
+            relationship, all distinguished by role name.
+
+            The statement MUST only be a substatement of the 'module' statement.
+            Multiple 'bi-directional-topology-relationship' statements are allowed
+            per parent statement.
+
+            Substatements to the 'bi-directional-topology-relationship' define the
+            A-side and the B-side, respectively, and optionally properties of the
+            relationship. Data nodes of types 'leaf' and 'leaf-list' are used for
+            this purpose. One of the data nodes MUST be annotated with the 'a-side'
+            extension; another data node MUST be annotated with the 'b-side'
+            extension. Other data nodes define properties of the relationship.
+
+            The argument is the name of the relationship. The relationship name is
+            scoped to the namespace of the declaring module and MUST be unique
+            within the scope.";
+
+        argument relationshipName;
+    }
+
+    extension aSide {
+        description
+            "Defines the A-side of a relationship.
+
+            The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+            statement, which itself must be a substatement of the
+            'uni-directional-topology-relationship' statement.
+
+            The data type of the parent 'leaf' or 'leaf-list' MUST be
+            'instance-identifier'. Constraints MAY be used as part of the parent
+            'leaf' or 'leaf-list' to enforce cardinality.
+
+            The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+            the role of the A-side of the relationship. The name of the role is
+            scoped to the type on which the A-side is defined and MUST be unique
+            within the scope.
+
+            While the parent 'leaf' or 'leaf-list' does not result in a property of
+            the relationship, it is RECOMMENDED to avoid using the name of an
+            existing type property as role name to avoid potential ambiguities
+            between properties of a type, and roles of a relationship on the type.
+
+            The argument is the name of the type on which the A-side resides. If the
+            type is declared in another module, the type must be prefixed, and a
+            corresponding 'import' statement be used to declare the prefix.";
+
+        argument aSideType;
+    }
+
+    extension bSide {
+        description
+            "Defines the B-side of a relationship.
+
+            The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+            statement, which itself must be a substatement of the
+            'uni-directional-topology-relationship' statement.
+
+            The data type of the parent 'leaf' or 'leaf-list' MUST be
+            'instance-identifier'. Constraints MAY be used as part of the parent
+            'leaf' or 'leaf-list' to enforce cardinality.
+
+            The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+            the role of the B-side of the relationship. The name of the role is
+            scoped to the type on which the B-side is defined and MUST be unique
+            within the scope.
+
+            While the parent 'leaf' or 'leaf-list' does not result in a property of
+            the relationship, it is RECOMMENDED to avoid using the name of an
+            existing type property as role name to avoid potential ambiguities
+            between properties of a type, and roles of a relationship on the type.
+
+            The argument is the name of the type on which the B-side resides. If the
+            type is declared in another module, the type must be prefixed, and a
+            corresponding 'import' statement be used to declare the prefix.";
+
+        argument bSideType;
+    }
+
+    extension domain {
+        description "Keyword used to carry domain information.";
+        argument domainName;
+    }
+
+    extension label {
+        description
+            "The label can be used to give modules and submodules a semantic version, in addition to their revision.
+
+            The format of the label is ‘x.y.z’ – expressed as pattern, it is [0-9]+\\.[0-9]+\\.[0-9]+
+
+            The statement MUST only be a substatement of the revision statement.  Zero or one revision label statements
+            per parent statement are allowed.
+
+            Revision labels MUST be unique amongst all revisions of a module or submodule.";
+
+        argument semversion;
+    }
+}
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-common-yang-types.yang b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-common-yang-types.yang
new file mode 100644
index 0000000..72c2820
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-common-yang-types.yang
@@ -0,0 +1,80 @@
+module o-ran-smo-teiv-common-yang-types {
+
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-common-yang-types";
+    prefix or-teiv-types;
+
+    import o-ran-smo-teiv-common-yang-extensions { prefix or-teiv-yext; }
+
+    import _3gpp-common-yang-types { prefix types3gpp; }
+
+  organization "ORAN";
+  contact "The Authors";
+    description
+    "Topology and Inventory common types model.
+
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains re-usable data types that topology and inventory models
+    will frequently use as part of types and relationships.";
+
+    revision "2024-05-14" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    grouping Top_Grp_Type {
+        description "Grouping containing the key attribute common to all types. All types
+                    MUST use this grouping.";
+
+        leaf id {
+            type string;
+            description "Unique identifier of topology entities. Represents the Entity Instance Identifier.";
+        }
+    }
+
+    container decorators {
+        description "This container serves as extension point for applications wishing to define their own decorators.
+                    This is done via augmentations. They can only be defined in name value pair.
+
+                    This is a consumer data and can be attached to Topology Entity or Topology Relation instance,
+                    outside of the declared Topology Entity or Topology Relationship's attributes. This cannot be
+                    instantiated, and it MUST NOT be augmented or deviated in any way, unless stated otherwise.";
+    }
+
+    leaf-list classifiers {
+        description "Consumer defined tags to topology entities and relationships.
+
+                    This is a consumer data and can be attached to Topology Entity or Topology Relation instance,
+                    outside of the declared Topology Entity or Topology Relationship's attributes. This cannot be
+                    instantiated, and it MUST NOT be augmented or deviated in any way, unless stated otherwise.";
+
+        type identityref { base classifier; }
+    }
+
+    leaf-list sourceIds {
+        description "An ordered list of identities that represent the set of native source identifiers for participating
+                    entities.
+
+                    This is a consumer data and can be attached to Topology Entity or Topology Relation instance,
+                    outside of the declared Topology Entity or Topology Relationship's attributes. This cannot be
+                    instantiated, and it MUST NOT be augmented or deviated in any way, unless stated otherwise.";
+
+        type string;
+        ordered-by user;
+    }
+
+    container metadata {
+        description "This container serves as extension point to define metadata. They can only be defined in name value
+                    pair.
+
+                    This is a consumer data and can be attached to Topology Entity or Topology Relation instance,
+                    outside of the declared Topology Entity or Topology Relationship's attributes. This cannot be
+                    instantiated, and it MUST NOT be augmented or deviated in any way, unless stated otherwise.";
+    }
+
+    identity classifier{
+        description  "The classifier is used as a base to provide all classifiers with identity. ";
+    }
+}
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-equipment.yang b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-equipment.yang
new file mode 100644
index 0000000..55e0071
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-equipment.yang
@@ -0,0 +1,115 @@
+module o-ran-smo-teiv-equipment {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-equipment";
+    prefix or-teiv-equip;
+
+    import o-ran-smo-teiv-common-yang-types { prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions { prefix or-teiv-yext; }
+
+    import ietf-geo-location {
+        prefix geo;
+        reference "RFC 9179: A YANG Grouping for Geographic Locations";
+    }
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "RAN Equipment topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the topology entities and relations in the
+    Equipment domain, which is modelled to understand the physical
+    location of equipment such as antennas associated with a cell/carrier
+    and their relevant properties e.g. tilt, max power etc.";
+
+    revision "2024-05-14" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain EQUIPMENT;
+
+    list AntennaModule {
+        description "An Antenna Module represents the
+                    physical aspect of an antenna.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf antennaModelNumber {
+                description "Vendor-specific antenna model
+                            identifier. This attribute is part of
+                            AISG v3 ADB Standard and has
+                            no operational impact.";
+                type string;
+            }
+
+            leaf mechanicalAntennaBearing {
+                description "Antenna bearing on antenna subunit
+                            where antenna unit is installed.";
+                type uint32;
+            }
+
+            leaf mechanicalAntennaTilt {
+                description "The fixed antenna tilt of the installation,
+                            defined as the inclination of the antenna
+                            element respect to the vertical plane.
+                            It is a signed value. Positive indicates
+                            downtilt, and negative indicates uptilt.";
+                type uint32;
+            }
+
+            leaf positionWithinSector {
+                description "Antenna unit position within sector.
+                            This attribute is part of AISG v3 ADB
+                            Standard and has no operational impact.";
+                type string;
+            }
+
+            leaf totalTilt {
+                description "Total antenna elevation including the
+                            installed tilt and the tilt applied by
+                            the Remote Electrical Tilt (RET).";
+                type uint32;
+            }
+
+            leaf electricalAntennaTilt {
+                description "Electrically-controlled tilt of main beam maximum
+                            with respect to direction orthogonal to antenna
+                            element axis (see 3GPP TS 25.466). Value is signed;
+                            tilt down is positive, tilt up is negative.";
+                type uint32;
+            }
+
+            leaf-list antennaBeamWidth {
+                description "The angular span of the main lobe of the antenna radiation
+                            pattern in the horizontal plane. Measured in degrees.";
+                type uint32;
+            }
+
+            uses geo:geo-location;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNAMODULE_USES_ANTENNAMODULE { // Same entity (0..1 to 0..1)
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list used-by-antennaModule {
+            description "Antenna Module realised by Antenna Module.";
+            or-teiv-yext:aSide AntennaModule;
+            type instance-identifier;
+       }
+
+        leaf-list used-antennaModule {
+            description "Antenna Module realises Antenna Module.";
+            or-teiv-yext:bSide AntennaModule;
+            type instance-identifier;
+       }
+    }
+}
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-ran.yang b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-ran.yang
new file mode 100644
index 0000000..00fee0e
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-ran.yang
@@ -0,0 +1,386 @@
+module o-ran-smo-teiv-ran {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-ran";
+    prefix or-teiv-ran;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import _3gpp-common-yang-types { prefix types3gpp; }
+
+    organization "ORAN";
+    contact "ORAN first line support via email";
+    description
+    "RAN Logical topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the topology entities and relations in the
+    RAN domain, which represents the functional capability
+    of the deployed RAN that are relevant to rApps use cases.";
+
+    revision "2024-05-14" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain RAN;
+
+    list GNBDUFunction {
+        description "gNodeB Distributed Unit (gNB-DU).
+
+                    A gNB may consist of a gNB-Centralized Unit
+                    (gNB-CU) and a gNB-DU. The CU processes non-real
+                    time protocols and services, and the DU processes
+                    PHY level protocol and real time services. The
+                    gNB-CU and the gNB-DU units are connected via
+                    F1 logical interface.
+
+                    The following is true for a gNB-DU:
+                    Is connected to the gNB-CU-CP through the F1-C
+                    interface.Is connected to the gNB-CU-UP through
+                    the F1-U interface. One gNB-DU is connected to only
+                    one gNB-CU-CP. One gNB-DU can be connected to
+                    multiple gNB-CU-UPs under the control of the same
+                    gNB-CU-CP.
+                    Note: A gNB may consist of a gNB-CU-CP, multiple
+                    gNB-CU-UPs and multiple gNB-DUs. gNB-DU is a concrete
+                    class that extends the NG-RAN node object. In Topology, you
+                    can create, read, update, and delete the gNB-DU object.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            container dUpLMNId {
+                description "PLMN identifier used as part of PM Events data";
+                uses types3gpp:PLMNId;
+            }
+
+            leaf gNBDUId {
+                description "Unique identifier for the DU within a gNodeB";
+                type uint32;
+            }
+
+            leaf gNBId {
+                description "Identity of gNodeB within a PLMN";
+                type uint32;
+            }
+
+            leaf gNBIdLength {
+                description "Length of gNBId bit string representation";
+                type uint32;
+            }
+        }
+    }
+
+    list ENodeBFunction {
+        description "An Evolved Node B (eNodeB) is the only mandatory
+                    node in the radio access network (RAN) of Long-Term
+                    Evolution (LTE). The eNodeB is a complex base
+                    station that handles radio communications
+                    in the cell and carries out radio resource
+                    management and handover decisions. Unlike 2/3G
+                    wireless RAN, there is no centralized radio network
+                    controller in LTE. It is the hardware that is connected
+                    to the mobile phone network that communicates
+                    directly with mobile handsets (User Equipment), like a base
+                    transceiver station (BTS) in GSM networks. This simplifies
+                    the architecture and allows lower response times.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf eNBId {
+                description "The ENodeB ID that forms part of
+                            the Cell Global Identity, and is
+                            also used to identify the node over
+                            the S1 interface";
+                type uint32;
+                default 11;
+            }
+
+            container eNodeBPlmnId {
+                description "The ENodeB Public Land Mobile Network
+                            (PLMN) ID that forms part of the ENodeB
+                            Global ID used to identify the node over
+                            the S1 interface. Note: The value (MCC=001, MNC=01)
+                            indicates that the PLMN is not initiated.
+                            The value can not be used as a valid PLMN Identity.";
+
+                leaf mcc {
+                    description "The MCC part of a PLMN identity
+                                used in the radio network.";
+                    type int32 {
+                        range 0..999;
+                    }
+                }
+                leaf mnc {
+                    description "The MNC part of a PLMN identity
+                                used in the radio network.";
+                    type int32 {
+                        range 0..999;
+                    }
+                }
+                leaf mncLength {
+                    description "The length of the MNC part of a
+                                PLMN identity used in the radio network.";
+                    type int32 {
+                        range 2..3;
+                    }
+                }
+            }
+        }
+    }
+
+    list AntennaCapability {
+        description "This MO serves as a mapping between the cell
+                    and the RBS equipment used to provide coverage
+                    in a certain geographical area. The MO also
+                    controls the maximum output power of the sector.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf-list eUtranFqBands {
+                description "List of LTE frequency bands
+                            that associated hardware supports";
+                type string;
+            }
+
+            leaf-list geranFqBands {
+                description "List of GERAN frequency bands
+                            that associated hardware supports";
+                type string;
+            }
+
+            leaf-list nRFqBands {
+                description "List of NR frequency bands
+                            associated hardware supports";
+                type string;
+            }
+        }
+    }
+
+    list LTESectorCarrier {
+        description "The LTE Sector Carrier object provides the
+                    attributes for defining the logical characteristics
+                    of a carrier (cell) in a sector. A sector is a coverage
+                    area associated with a base station having
+                    its own antennas, radio ports, and control channels.
+                    The concept of sectors was developed to improve co-channel
+                    interference in cellular systems, and most wireless systems
+                    use three sector cells.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf sectorCarrierType {
+                description "Indicates whether or not the sector carrier
+                            modelled by MO SectorCarrier is a digital sector.";
+                type enumeration {
+                    enum normal_sector {
+                        value 0;
+                        description "Not a digital sector";
+                    }
+                    enum left_digital_sector {
+                        value 1;
+                        description "Left digital sector for 2DS";
+                    }
+                    enum right_digital_sector {
+                        value 2;
+                        description "Right digital sector for 2DS";
+                    }
+                    enum left_digital_sector_3ds {
+                        value 3;
+                        description "Left digital sector for 3DS";
+                    }
+                    enum right_digital_sector_3ds {
+                        value 4;
+                        description "Right digital sector for 3DS";
+                    }
+                    enum middle_digital_sector {
+                        value 5;
+                        description "Middle digital sector for 3DS";
+                    }
+                }
+            }
+        }
+    }
+
+    list NRSectorCarrier {
+        description "The NR Sector Carrier object provides
+                    the attributes for defining the logical
+                    characteristics of a carrier (cell) in a
+                    sector. A sector is a coverage area associated
+                    with a base station having its own antennas,
+                    radio ports, and control channels. The concept
+                    of sectors was developed to improve co-channel
+                    interference in cellular systems, and most wireless
+                    systems use three sector cells.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf arfcnDL {
+                description "NR Absolute Radio Frequency Channel
+                            Number (NR-ARFCN) for downlink";
+                type uint32;
+            }
+
+            leaf arfcnUL {
+                description "NR Absolute Radio frequency Channel Number
+                            (NR-ARFCN) for uplink.";
+                type uint32;
+            }
+
+            leaf frequencyDL {
+                description "RF Reference Frequency of downlink channel";
+                type uint32;
+            }
+
+            leaf frequencyUL {
+                description "RF Reference Frequency of uplink channel";
+                type uint32;
+            }
+
+            leaf bSChannelBwDL {
+                description "BS Channel bandwidth in MHz for downlink.";
+                type uint32;
+            }
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship LTESECTORCARRIER_USES_ANTENNACAPABILITY { // 0..1 to 0..1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf used-antennaCapability {
+            description "LTE Sector Carrier uses Antenna Capability.";
+            or-teiv-yext:aSide LTESectorCarrier;
+            type instance-identifier;
+        }
+
+        leaf used-by-lteSectorCarrier {
+            description "Antenna Cpability used by LTE Sector Carrier.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER { // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list provided-lteSectorCarrier {
+            description "eNodeB Function provides LTE Sector Carrier.";
+            or-teiv-yext:aSide ENodeBFunction;
+            type instance-identifier;
+        }
+
+        leaf provided-by-enodebFunction {
+            description "LTE Sector Carrier provided by eNodeB Function.";
+            or-teiv-yext:bSide LTESectorCarrier;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NRSECTORCARRIER_USES_ANTENNACAPABILITY { // 0..n to 0..1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf used-antennaCapability {
+            description "NR Sector Carrier uses Antenna Capability.";
+            or-teiv-yext:aSide NRSectorCarrier;
+            type instance-identifier;
+        }
+
+        leaf-list used-by-nrSectorCarrier {
+            description "Antenna Capability used by NR Sector Carrier.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNACAPABILITY_USES_ANTENNACAPABILITY { // Same entity (0..1 to 0..1)
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf used-antennaCapability {
+            description "Antenna Capability realised by Antenna Capability.";
+            or-teiv-yext:aSide AntennaCapability;
+            type instance-identifier;
+        }
+
+        leaf used-by-antennaCapability {
+            description "Antenna Capability realises Antenna Capability.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNACAPABILITY_PROVIDES_ANTENNACAPABILITY { // Same entity (0..1 to 0..n)
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf provided-antennaCapability {
+            description "Antenna Capability realised by Antenna Capability.";
+            or-teiv-yext:aSide AntennaCapability;
+            type instance-identifier;
+        }
+
+        leaf-list provided-by-antennaCapability {
+            description "Antenna Capability realises Antenna Capability.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNACAPABILITY_SERVES_ANTENNACAPABILITY { // Same entity (0..n to 0..1)
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-antennaCapability {
+            description "Antenna Capability realised by Antenna Capability.";
+            or-teiv-yext:aSide AntennaCapability;
+            type instance-identifier;
+        }
+
+        leaf serviced-by-antennaCapability {
+            description "Antenna Capability realises Antenna Capability.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNACAPABILITY_REALISED_BY_ANTENNACAPABILITY { // Same entity (0..n to 0..m)
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list realised-by-antennaCapability {
+            description "Antenna Capability realised by Antenna Capability.";
+            or-teiv-yext:aSide AntennaCapability;
+            type instance-identifier;
+        }
+
+        leaf-list realised-antennaCapability {
+            description "Antenna Capability realises Antenna Capability.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+       }
+    }
+}
\ No newline at end of file
diff --git a/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-rel-equipment-ran.yang b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-rel-equipment-ran.yang
new file mode 100644
index 0000000..4d30b10
--- /dev/null
+++ b/pgsql-schema-generator/src/test/resources/generate-defaults/o-ran-smo-teiv-rel-equipment-ran.yang
@@ -0,0 +1,48 @@
+module o-ran-smo-teiv-rel-equipment-ran {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-rel-equipment-ran";
+    prefix or-teiv-rel-equipran;
+
+    import o-ran-smo-teiv-common-yang-types { prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions { prefix or-teiv-yext; }
+
+    import o-ran-smo-teiv-equipment { prefix or-teiv-equip; }
+
+    import o-ran-smo-teiv-ran { prefix or-teiv-ran; }
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "Equipment and RAN topology relation model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the topology relations between Equipment and RAN.";
+
+    revision "2024-05-14" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain REL_EQUIPMENT_RAN;
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNAMODULE_SERVES_ANTENNACAPABILITY { // 0..n to 0..m
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-antennaCapability {
+            description "Antenna Capability serviced by this Antenna Module.";
+            or-teiv-yext:aSide or-teiv-equip:AntennaModule;
+            type instance-identifier;
+        }
+
+        leaf-list serving-antennaModule {
+            description "Antenna Module serves this Antenna Capability.";
+            or-teiv-yext:bSide or-teiv-ran:AntennaCapability;
+            type instance-identifier;
+        }
+    }
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..662f516
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- spotless:off -->
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<!-- spotless:on -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.2.0</version>
+        <relativePath />
+    </parent>
+    <groupId>org.oran.smo</groupId>
+    <artifactId>topology-exposure-inventory</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+        </license>
+    </licenses>
+
+    <modules>
+        <module>yang-parser</module>
+        <module>pgsql-schema-generator</module>
+        <module>teiv</module>
+    </modules>
+
+    <properties>
+        <!-- Set compiler Java version, MUST match the Dockerfile JDK version -->
+        <maven.compiler.release>17</maven.compiler.release>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <!-- 3PP Versions -->
+        <version.jackson-databind-nullable>0.2.6</version.jackson-databind-nullable>
+        <version.lombok>1.18.26</version.lombok>
+        <version.logback>6.6</version.logback>
+        <!-- Updated from 1.9.0 to comply with CVE-2022-36437 -->
+        <version.micrometer>1.10.6</version.micrometer>
+        <version.cloudevents-kafka>2.5.0</version.cloudevents-kafka>
+        <version.cloudevents-json-jackson>2.5.0</version.cloudevents-json-jackson>
+        <version.springdoc-openapi>2.1.0</version.springdoc-openapi>
+        <!-- Updated from version 1.33 to comply with CVE-2022-1471 -->
+        <version.postgresql>42.5.4</version.postgresql>
+        <jooq.version>3.18.6</jooq.version>
+        <version.saxpath>1.0-FCS</version.saxpath>
+        <!-- External Yang model source prefix URI -->
+        <source.3gpp.Rel18_SA103>https://forge.3gpp.org/rep/sa5/MnS/-/raw/Tag_Rel18_SA103/yang-models/</source.3gpp.Rel18_SA103>
+        <source.3gpp.Rel18_SA98>https://forge.3gpp.org/rep/sa5/MnS/-/raw/Tag_Rel18_SA98/yang-models/</source.3gpp.Rel18_SA98>
+        <source.3gpp.Rel17_SA97>https://forge.3gpp.org/rep/sa5/MnS/-/raw/Tag_Rel17_SA97/yang-models/</source.3gpp.Rel17_SA97>
+        <source.3gpp.Rel17_SA91>https://forge.3gpp.org/rep/sa5/MnS/-/raw/Rel-17-SA-91/yang-models/</source.3gpp.Rel17_SA91>
+        <source.ietfcatalog>https://www.ietf.org/ietf-ftp/yang/catalogmod/</source.ietfcatalog>
+
+        <!-- Test Dependencies -->
+        <version.spring-cloud>2023.0.0</version.spring-cloud>
+        <version.mockitoinline>5.2.0</version.mockitoinline>
+        <version.testcontainers>1.18.0</version.testcontainers>
+        <!-- Plugin Dependencies -->
+        <version.openapi-generator-maven-plugin>6.5.0</version.openapi-generator-maven-plugin>
+        <version.spotless-plugin>2.30.0</version.spotless-plugin>
+        <version.contract-documentation-generator-mvn-plugin>1.0.1</version.contract-documentation-generator-mvn-plugin>
+        <version.asciidoctor-maven-plugin>2.2.1</version.asciidoctor-maven-plugin>
+        <version.spring-cloud-starter-contract-verifier>3.0.2</version.spring-cloud-starter-contract-verifier>
+        <version.yang-parser-jar>1.0.0-SNAPSHOT</version.yang-parser-jar>
+        <version.yang-validator-jar>1.0.0-SNAPSHOT</version.yang-validator-jar>
+        <version.reactor-test>3.2.3.RELEASE</version.reactor-test>
+        <!-- Updated from 3.0 to comply with CVE-2023-20861, CVE-2022-22971 & 17
+            more -->
+        <version.license-maven-plugin>4.2</version.license-maven-plugin>
+        <version.sonar-maven-plugin>3.9.1.2184</version.sonar-maven-plugin>
+        <version.antrun-maven-plugin>3.1.0</version.antrun-maven-plugin>
+        <version.antlr>4.13.0</version.antlr>
+        <!-- JaCoCo plugin for Java Code Coverage -->
+        <version.jacoco-maven.plugin>0.8.8</version.jacoco-maven.plugin>
+        <!-- Minimum ratio or percentage of instructions to be covered, used by
+            JaCoCo plugin. Industry standard is 0.8 or 80% which allows at least 80%
+            of the code to be covered by the test cases. -->
+        <jacoco-maven-plugin.coveredratio.minimum>0.8</jacoco-maven-plugin.coveredratio.minimum>
+    </properties>
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>com.mycila</groupId>
+                    <artifactId>license-maven-plugin</artifactId>
+                    <version>${version.license-maven-plugin}</version>
+                    <configuration>
+                        <licenseSets>
+                            <licenseSet>
+                                <header>${project.parent.basedir}/license/copyright-2024.txt</header>
+                                <validHeaders>
+                                    <validHeader>${project.parent.basedir}/license/copyright-2024.txt</validHeader>
+                                </validHeaders>
+                                <excludes>
+                                    <exclude>**/*.html</exclude>
+                                    <exclude>**/*.tpl</exclude>
+                                    <exclude>**/*.tgz</exclude>
+                                    <exclude>**/VERSION*</exclude>
+                                    <exclude>license/copyright*</exclude>
+                                    <exclude>**/*.txt</exclude>
+                                    <exclude>**/*.config</exclude>
+                                    <exclude>**/*.yang</exclude>
+                                    <exclude>settings.xml</exclude>
+                                    <exclude>**/*.openapi-generator-ignore</exclude>
+                                    <exclude>**/src/main/resources/v1/.openapi-generator/*</exclude>
+                                    <exclude>generated/*</exclude>
+                                    <exclude>generated*/</exclude>
+                                    <exclude>dependencies/*</exclude>
+                                    <exclude>dependencies*/</exclude>
+                                </excludes>
+                            </licenseSet>
+                        </licenseSets>
+                        <headerDefinitions>
+                            <headerDefinition>${project.parent.basedir}/license/javaHeaderDefinition.xml</headerDefinition>
+                            <headerDefinition>${project.parent.basedir}/license/xmlHeaderDefinition.xml</headerDefinition>
+                        </headerDefinitions>
+                        <mapping>
+                            <java>JAVADOC_STYLE</java>
+                            <groovy>JAVADOC_STYLE</groovy>
+                            <g4>JAVADOC_STYLE</g4>
+                            <xml>XML_STYLE</xml>
+                        </mapping>
+                    </configuration>
+                </plugin>
+                <plugin>
+                    <groupId>org.sonarsource.scanner.maven</groupId>
+                    <artifactId>sonar-maven-plugin</artifactId>
+                    <version>${version.sonar-maven-plugin}</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>com.diffplug.spotless</groupId>
+                <artifactId>spotless-maven-plugin</artifactId>
+                <version>${version.spotless-plugin}</version>
+                <configuration>
+                    <formats>
+                        <format>
+                            <includes>
+                                <include>pom.xml</include>
+                            </includes>
+                            <eclipseWtp>
+                                <type>XML</type>
+                            </eclipseWtp>
+                            <toggleOffOn>
+                                <off>spotless:off</off>
+                                <on>spotless:on</on>
+                            </toggleOffOn>
+                            <indent>
+                                <spaces>true</spaces>
+                                <spacesPerTab>4</spacesPerTab>
+                            </indent>
+                            <trimTrailingWhitespace />
+                            <endWithNewline />
+                        </format>
+                        <format>
+                            <includes>
+                                <include>**/*.json</include>
+                            </includes>
+                            <excludes>
+                                <exclude>target/**/*.json</exclude>
+                                <exclude>build/**/*.json</exclude>
+                            </excludes>
+                            <eclipseWtp>
+                                <type>JSON</type>
+                            </eclipseWtp>
+                            <endWithNewline />
+                            <indent>
+                                <spaces>true</spaces>
+                                <spacesPerTab>4</spacesPerTab>
+                            </indent>
+                            <trimTrailingWhitespace />
+                        </format>
+                    </formats>
+                    <java>
+                        <eclipse>
+                            <file>${project.parent.basedir}/code_conventions.xml</file>
+                        </eclipse>
+                        <toggleOffOn>
+                            <off>spotless:off</off>
+                            <on>spotless:on</on>
+                        </toggleOffOn>
+                        <trimTrailingWhitespace />
+                        <removeUnusedImports />
+                        <endWithNewline />
+                        <licenseHeader>
+                            <file>${project.parent.basedir}/CopyrightSample.txt</file>
+                        </licenseHeader>
+                    </java>
+                    <groovy>
+                        <includes>
+                            <include>**/*.groovy</include>
+                        </includes>
+                        <greclipse>
+                            <file>${project.parent.basedir}/code_conventions.xml</file>
+                        </greclipse>
+                        <licenseHeader>
+                            <file>${project.parent.basedir}/CopyrightSample.txt</file>
+                        </licenseHeader>
+                        <endWithNewline />
+                    </groovy>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/teiv/Dockerfile b/teiv/Dockerfile
new file mode 100644
index 0000000..bb6c576
--- /dev/null
+++ b/teiv/Dockerfile
@@ -0,0 +1,53 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+FROM debian:bullseye-slim
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends \
+    openjdk-17-jdk-headless && \
+    rm -rf /var/lib/apt/lists/*
+
+ARG USER_ID=40514
+RUN echo "$USER_ID:!::0:::::" >>/etc/shadow
+
+ARG USER_NAME="topology-exposure-inventory"
+RUN echo "$USER_ID:x:$USER_ID:0:An Identity for $USER_NAME:/nonexistent:/bin/false" >>/etc/passwd
+
+# TODO version in the jar file should be moved out
+ARG JAR_FILE="target/topology-exposure-inventory-jar-0.0.1-SNAPSHOT.jar"
+ADD $JAR_FILE topology-exposure-inventory-app.jar
+
+RUN find / -perm /u=s,g=s -type f -exec chmod a-s {} \; || true
+
+USER $USER_ID
+
+CMD ["/bin/sh", "-c", "java ${JAVA_OPTS} -jar topology-exposure-inventory-app.jar"]
+
+ARG COMMIT
+ARG BUILD_DATE
+ARG APP_VERSION
+LABEL \
+    org.opencontainers.image.title=topology-exposure-inventory-jsb \
+    org.opencontainers.image.created=$BUILD_DATE \
+    org.opencontainers.image.revision=$COMMIT \
+    org.opencontainers.image.vendor=ORAN \
+    org.opencontainers.image.version=$APP_VERSION
diff --git a/teiv/pom.xml b/teiv/pom.xml
new file mode 100644
index 0000000..ae25513
--- /dev/null
+++ b/teiv/pom.xml
@@ -0,0 +1,514 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- spotless:off -->
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<!-- spotless:on -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.oran.smo</groupId>
+        <artifactId>topology-exposure-inventory</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+    <groupId>org.oran.smo.teiv</groupId>
+    <artifactId>topology-exposure-inventory-jar</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <!-- External Yang model destination location -->
+        <src.models.import>${project.basedir}/src/main/resources/models/import/</src.models.import>
+    </properties>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+        </license>
+    </licenses>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${version.spring-cloud}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    <dependencies>
+        <dependency>
+            <groupId>org.openapitools</groupId>
+            <artifactId>jackson-databind-nullable</artifactId>
+            <version>${version.jackson-databind-nullable}</version>
+        </dependency>
+        <dependency>
+            <groupId>net.logstash.logback</groupId>
+            <artifactId>logstash-logback-encoder</artifactId>
+            <version>${version.logback}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-core</artifactId>
+            <version>${version.micrometer}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+            <version>${version.micrometer}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.cloudevents</groupId>
+            <artifactId>cloudevents-kafka</artifactId>
+            <version>${version.cloudevents-kafka}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jersey</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+            <version>${version.springdoc-openapi}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>${version.postgresql}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jooq</groupId>
+            <artifactId>jooq</artifactId>
+            <version>${jooq.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>jakarta.persistence</groupId>
+                    <artifactId>jakarta.persistence-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>jakarta.xml.bind</groupId>
+                    <artifactId>jakarta.xml.bind-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>${version.lombok}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aspects</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+            <version>${version.antlr}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.oran.smo.yangtools.parser</groupId>
+            <artifactId>yang-parser-jar</artifactId>
+            <version>${version.yang-parser-jar}</version>
+        </dependency>
+        <!-- Test Dependencies -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>${version.testcontainers}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-contract-verifier</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-inline</artifactId>
+            <version>${version.mockitoinline}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <version>4.2.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-test</artifactId>
+            <version>${version.reactor-test}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.cloudevents</groupId>
+            <artifactId>cloudevents-json-jackson</artifactId>
+            <version>${version.cloudevents-json-jackson}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <filtering>true</filtering>
+                <directory>src/main/resources</directory>
+                <excludes>
+                    <exclude>**/topology-exposure-inventory-openapi.zip</exclude>
+                </excludes>
+            </resource>
+        </resources>
+        <testResources>
+            <testResource>
+                <directory>${project.basedir}/src/test/resources</directory>
+            </testResource>
+        </testResources>
+        <plugins>
+            <!-- TODO internaltools.devops plugin which generates .adoc of contract
+                test -->
+            <plugin>
+                <groupId>org.asciidoctor</groupId>
+                <artifactId>asciidoctor-maven-plugin</artifactId>
+                <version>${version.asciidoctor-maven-plugin}</version>
+                <configuration>
+                    <sourceDirectory>${project.basedir}/target/generated-contract-docs</sourceDirectory>
+                    <outputDirectory>${project.basedir}/doc/contracts-ties</outputDirectory>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>generate-docs</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>process-asciidoc</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.openapitools</groupId>
+                <artifactId>openapi-generator-maven-plugin</artifactId>
+                <version>${version.openapi-generator-maven-plugin}</version>
+                <executions>
+                    <execution>
+                        <id>openapi-generate-html</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/src/main/resources/v1/topology-exposure-inventory-openapi.yaml</inputSpec>
+                            <generatorName>html</generatorName>
+                            <output>src/main/resources/v1</output>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>openapi-generate-pojos</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <inputSpec>
+                                ${project.basedir}/src/main/resources/v1/topology-exposure-inventory-openapi.yaml</inputSpec>
+                            <generatorName>spring</generatorName>
+                            <modelNamePrefix>oran-teiv</modelNamePrefix>
+                            <configOptions>
+                                <generatedConstructorWithRequiredArgs>false</generatedConstructorWithRequiredArgs>
+                                <generateSupportingFiles>true</generateSupportingFiles>
+                                <sourceFolder>src/java/main</sourceFolder>
+                                <dateLibrary>java8</dateLibrary> <!-- java8 is a valid option from https://openapi-generator.tech/docs/generators/java/ -->
+                                <library>spring-boot</library>
+                                <interfaceOnly>true</interfaceOnly>
+                                <skipOverwrite>false</skipOverwrite>
+                                <useTags>true</useTags>
+                                <useBeanValidation>true</useBeanValidation>
+                                <useSpringBoot3>true</useSpringBoot3>
+                                <additionalModelTypeAnnotations>@lombok.Builder;
+                                    @lombok.NoArgsConstructor; @lombok.AllArgsConstructor</additionalModelTypeAnnotations>
+                            </configOptions>
+                            <apiPackage>org.oran.smo.teiv.api</apiPackage>
+                            <modelPackage>org.oran.smo.teiv.api.model</modelPackage>
+                            <groupId>${project.groupId}</groupId>
+                            <artifactId>${project.artifactId}</artifactId>
+                            <artifactVersion>${project.version}</artifactVersion>
+                            <environmentVariables>
+                                <enablePostProcessFile>true</enablePostProcessFile>
+                            </environmentVariables>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-contract-maven-plugin</artifactId>
+                <version>4.0.2</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <baseClassForTests>org.oran.smo.teiv.exposure.api.contract.TopologyExposureApiBase</baseClassForTests>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <useFile>false</useFile>
+                    <includes>
+                        <include>**/*Test.java</include>
+                    </includes>
+                    <testSourceDirectory>target/generated-test-sources</testSourceDirectory>
+                </configuration>
+            </plugin>
+            <!-- JaCoCo plugin for Java Code Coverage -->
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <version>${version.jacoco-maven.plugin}</version>
+                <configuration>
+                    <append>true</append>
+                    <excludes>
+                        <exclude>**/teiv/api/**/*</exclude>
+                        <exclude>**/models/*.*</exclude>
+                    </excludes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>jacoco-check</id>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                        <phase>test</phase>
+                        <configuration>
+                            <rules>
+                                <rule implementation="org.jacoco.maven.RuleConfiguration">
+                                    <element>BUNDLE</element>
+                                    <limits>
+                                        <limit implementation="org.jacoco.report.check.Limit">
+                                            <counter>INSTRUCTION</counter>
+                                            <value>COVEREDRATIO</value>
+                                            <minimum>${jacoco-maven-plugin.coveredratio.minimum}</minimum>
+                                        </limit>
+                                    </limits>
+                                </rule>
+                            </rules>
+                            <excludes>
+                                <exclude>**/teiv/api/**/*</exclude>
+                                <exclude>**/models/*.*</exclude>
+                            </excludes>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>agent-for-ut</id>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                        <configuration>
+                            <excludes>
+                                <exclude>**/teiv/api/**/*</exclude>
+                                <exclude>**/models/*.*</exclude>
+                            </excludes>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>agent-for-it</id>
+                        <goals>
+                            <goal>prepare-agent-integration</goal>
+                        </goals>
+                        <configuration>
+                            <excludes>
+                                <exclude>**/teiv/api/**/*</exclude>
+                                <exclude>**/models/*.*</exclude>
+                            </excludes>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>jacoco-site</id>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                        <phase>verify</phase>
+                        <configuration>
+                            <excludes>
+                                <exclude>**/teiv/api/**/*</exclude>
+                                <exclude>**/models/*.*</exclude>
+                            </excludes>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.build.directory}/generated-sources/annotations/</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.mycila</groupId>
+                <artifactId>license-maven-plugin</artifactId>
+                <version>${version.license-maven-plugin}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.diffplug.spotless</groupId>
+                <artifactId>spotless-maven-plugin</artifactId>
+                <version>${version.spotless-plugin}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4-maven-plugin</artifactId>
+                <version>${version.antlr}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>antlr4</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>${version.antrun-maven-plugin}</version>
+                <executions>
+                    <execution>
+                        <id>download-external-yang-models</id>
+                        <phase>initialize</phase>
+                        <configuration>
+                            <target>
+                                <mkdir dir="${src.models.import}" />
+
+                                <resources id="3gpp-yang-downloads">
+                                    <url
+                                        url="${source.3gpp.Rel17_SA97}_3gpp-common-yang-types.yang" />
+                                    <url
+                                        url="${source.3gpp.Rel17_SA97}_3gpp-common-yang-extensions.yang" />
+                                </resources>
+                                <get dest="${src.models.import}" skipexisting="true">
+                                    <resources refid="3gpp-yang-downloads" />
+                                </get>
+
+                                <resources id="ietf-yang-downloads">
+                                    <url
+                                        url="${source.ietfcatalog}ietf-inet-types@2013-07-15.yang" />
+                                    <url
+                                        url="${source.ietfcatalog}ietf-geo-location@2022-02-11.yang" />
+                                    <url
+                                        url="${source.ietfcatalog}ietf-yang-types@2013-07-15.yang" />
+                                </resources>
+                                <get dest="${src.models.import}" skipexisting="true">
+                                    <resources refid="ietf-yang-downloads" />
+                                    <mapper type="regexp" from="^.*/([^/@]+)@[^/.]+(\..+)$"
+                                        to="\1\2" />
+                                </get>
+
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/teiv/src/main/antlr4/org/oran/smo/teiv/antlr4/tiesPath.g4 b/teiv/src/main/antlr4/org/oran/smo/teiv/antlr4/tiesPath.g4
new file mode 100644
index 0000000..8a4046c
--- /dev/null
+++ b/teiv/src/main/antlr4/org/oran/smo/teiv/antlr4/tiesPath.g4
@@ -0,0 +1,168 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+/*
+ The contents of this file were inspired by https://github.com/onap/cps/blob/master/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4, which falls under the Apache 2.0 license:
+ ** The original copyright is as follows
+ **  ============LICENSE_START=======================================================
+ **  Copyright (C) 2021-2023 Nordix Foundation
+ **  Modifications Copyright (C) 2023 TechMahindra Ltd
+ **  ================================================================================
+ **  Licensed under the Apache License, Version 2.0 (the "License");
+ **  you may not use this file except in compliance with the License.
+ **  You may obtain a copy of the License at
+ **
+ **        http://www.apache.org/licenses/LICENSE-2.0
+ **
+ **  Unless required by applicable law or agreed to in writing, software
+ **  distributed under the License is distributed on an "AS IS" BASIS,
+ **  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ **  See the License for the specific language governing permissions and
+ **  limitations under the License.
+ **
+ **  SPDX-License-Identifier: Apache-2.0
+ **  ============LICENSE_END=========================================================
+ */
+
+/*
+ * Parser Rules
+ * Some of the parser rules below are inspired by
+ * https://github.com/antlr/grammars-v4/blob/master/xpath/xpath31/XPath31Parser.g4
+ */
+
+grammar tiesPath ;
+
+tiesPath : ( prefix | incorrectPrefix ) multipleLeafConditions? textFunctionCondition? containsFunctionCondition? ancestorAxis? invalidPostFix? containerName? fieldLeaf?;
+
+ancestorAxis : SLASH KW_ANCESTOR COLONCOLON ancestorPath ;
+
+ancestorPath : yangElement ( SLASH yangElement)* ;
+
+textFunctionCondition : SLASH leafName OB KW_TEXT_FUNCTION EQ StringLiteral CB ;
+
+containsFunctionCondition : OB KW_CONTAINS_FUNCTION OP AT leafName COMMA StringLiteral CP CB ;
+
+parent : ( SLASH yangElement)* ;
+
+prefix : parent SLASH containerName ;
+
+incorrectPrefix : SLASH SLASH+ ;
+
+yangElement : containerName listElementRef? ;
+
+containerName : QName ;
+
+listElementRef :  OB leafCondition ( booleanOperators leafCondition)* CB ;
+
+multipleLeafConditions : OB leafCondition ( booleanOperators leafCondition)* CB ;
+
+leafCondition : AT leafName comparativeOperators ( IntegerLiteral | StringLiteral) ;
+
+leafName : QName ;
+
+booleanOperators : ( KW_AND | KW_OR ) ;
+
+comparativeOperators : ( EQ | GT | LT | GE | LE ) ;
+
+invalidPostFix : (AT | CB | COLONCOLON | comparativeOperators ).+ ;
+
+fieldLeaf : OP leafName ( COMMA leafName)* CP;
+
+/*
+ * Lexer Rules
+ * Most of the lexer rules below are inspired by
+ * https://github.com/antlr/grammars-v4/blob/master/xpath/xpath31/XPath31Lexer.g4
+ */
+
+AT : '@' ;
+CB : ']' ;
+COLONCOLON : '::' ;
+EQ : '=' ;
+OB : '[' ;
+SLASH : '/' ;
+COMMA : ',' ;
+OP : '(' ;
+CP : ')' ;
+GT : '>' ;
+LT : '<' ;
+GE : '>=' ;
+LE : '<=' ;
+
+// KEYWORDS
+
+KW_ANCESTOR : 'ancestor' ;
+KW_AND : 'and' ;
+KW_TEXT_FUNCTION: 'text()' ;
+KW_OR : 'or' ;
+KW_CONTAINS_FUNCTION: 'contains' ;
+
+IntegerLiteral : FragDigits ;
+// Add below type definitions for leafvalue comparision in https://jira.onap.org/browse/CPS-440
+DecimalLiteral : ('.' FragDigits) | (FragDigits '.' [0-9]*) ;
+DoubleLiteral : (('.' FragDigits) | (FragDigits ('.' [0-9]*)?)) [eE] [+-]? FragDigits ;
+StringLiteral : '"' (~["] | FragEscapeQuot)* '"' | '\'' (~['] | FragEscapeApos)* '\'' ;
+fragment FragEscapeQuot : '""' ;
+fragment FragEscapeApos : '\'\'';
+fragment FragDigits : [0-9]+ ;
+
+QName  : FragQName ;
+NCName : FragmentNCName ;
+fragment FragQName : FragPrefixedName | FragUnprefixedName ;
+fragment FragPrefixedName : FragPrefix ':' FragLocalPart ;
+fragment FragUnprefixedName : FragLocalPart ;
+fragment FragPrefix : FragmentNCName ;
+fragment FragLocalPart : FragmentNCName ;
+fragment FragNCNameStartChar
+  :  'A'..'Z'
+  |  '_'
+  | 'a'..'z'
+  | '\u00C0'..'\u00D6'
+  | '\u00D8'..'\u00F6'
+  | '\u00F8'..'\u02FF'
+  | '\u0370'..'\u037D'
+  | '\u037F'..'\u1FFF'
+  | '\u200C'..'\u200D'
+  | '\u2070'..'\u218F'
+  | '\u2C00'..'\u2FEF'
+  | '\u3001'..'\uD7FF'
+  | '\uF900'..'\uFDCF'
+  | '\uFDF0'..'\uFFFD'
+  | '\u{10000}'..'\u{EFFFF}'
+  ;
+fragment FragNCNameChar
+  :  FragNCNameStartChar | '-' | '.' | '0'..'9'
+  |  '\u00B7' | '\u0300'..'\u036F'
+  |  '\u203F'..'\u2040'
+  ;
+fragment FragmentNCName : FragNCNameStartChar FragNCNameChar* ;
+
+// https://www.w3.org/TR/REC-xml/#NT-Char
+
+fragment FragChar : '\u0009' | '\u000a' | '\u000d'
+  | '\u0020'..'\ud7ff'
+  | '\ue000'..'\ufffd'
+  | '\u{10000}'..'\u{10ffff}'
+  ;
+
+// Skip all Whitespace
+Whitespace : ('\u000d' | '\u000a' | '\u0020' | '\u0009')+ -> skip ;
+
+// handle characters which failed to match any other token (otherwise Antlr will ignore them)
+ErrorCharacter : . ;
diff --git a/teiv/src/main/java/org/oran/smo/teiv/CoreApplication.java b/teiv/src/main/java/org/oran/smo/teiv/CoreApplication.java
new file mode 100644
index 0000000..12b64b9
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/CoreApplication.java
@@ -0,0 +1,105 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv;
+
+import io.micrometer.core.aop.TimedAspect;
+import io.micrometer.core.instrument.MeterRegistry;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import org.oran.smo.teiv.service.JSONBSerializer;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import org.springframework.cache.annotation.EnableCaching;
+
+/**
+ * Core Application, the starting point of the application.
+ */
+@SpringBootApplication
+@EnableAsync
+@EnableCaching
+@EnableScheduling
+@EnableAspectJAutoProxy
+public class CoreApplication {
+
+    /**
+     * Main entry point of the application.
+     *
+     * @param args
+     *     Command line arguments
+     */
+    public static void main(final String[] args) {
+        SpringApplication.run(CoreApplication.class, args);
+    }
+
+    /**
+     * Making a RestTemplate, using the RestTemplateBuilder, to use for consumption of RESTful
+     * interfaces.
+     *
+     * @param restTemplateBuilder
+     *     RestTemplateBuilder instance
+     *
+     * @return RestTemplate
+     */
+    @Bean
+    public RestTemplate restTemplate(final RestTemplateBuilder restTemplateBuilder) {
+        return restTemplateBuilder.build();
+    }
+
+    /**
+     * Configuration bean for Web MVC.
+     *
+     * @return WebMvcConfigurer
+     */
+    @Bean
+    public WebMvcConfigurer webConfigurer() {
+        return new WebMvcConfigurer() {
+        };
+    }
+
+    /**
+     * Bean to create the default timedAspect in ApplicationContext.
+     *
+     * @param registry
+     *     Meter Registry
+     * @return TimedAspect
+     */
+    @Bean
+    public TimedAspect timedAspect(final MeterRegistry registry) {
+        return new TimedAspect(registry);
+    }
+
+    @Bean
+    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
+        return builder -> builder.serializationInclusion(JsonInclude.Include.USE_DEFAULTS).serializers(
+                new JSONBSerializer());
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/CustomMetrics.java b/teiv/src/main/java/org/oran/smo/teiv/CustomMetrics.java
new file mode 100644
index 0000000..859dfe5
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/CustomMetrics.java
@@ -0,0 +1,543 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Timer;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.Getter;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+public class CustomMetrics {
+
+    @Getter(AccessLevel.PRIVATE)
+    private final AtomicLong tiesSubscriptionGaugeCounter = new AtomicLong(0L);
+
+    private final MeterRegistry meterRegistry;
+
+    private final Counter numReceivedCloudEventCreate;
+
+    private final Counter numReceivedCloudEventMerge;
+
+    private final Counter numReceivedCloudEventDelete;
+
+    private final Counter numReceivedCloudEventSourceEntityDelete;
+
+    private final Counter numReceivedCloudEventNotSupported;
+
+    private final Timer cloudEventMergePersistTime;
+
+    private final Timer cloudEventCreatePersistTime;
+
+    private final Timer cloudEventDeletePersistTime;
+
+    private final Timer cloudEventSourceEntityDeletePersistTime;
+
+    private final Timer cloudEventMergeParseTime;
+
+    private final Timer cloudEventCreateParseTime;
+
+    private final Timer cloudEventDeleteParseTime;
+
+    private final Timer cloudEventSourceEntityDeleteParseTime;
+
+    private final Counter numSuccessfullyParsedMergeCloudEvents;
+
+    private final Counter numSuccessfullyParsedDeleteCloudEvents;
+
+    private final Counter numSuccessfullyParsedSourceEntityDeleteCloudEvents;
+
+    private final Counter numSuccessfullyParsedCreateCloudEvents;
+
+    private final Counter numUnsuccessfullyParsedMergeCloudEvents;
+
+    private final Counter numUnsuccessfullyParsedCreateCloudEvents;
+
+    private final Counter numUnsuccessfullyParsedDeleteCloudEvents;
+
+    private final Counter numUnsuccessfullyParsedSourceEntityDeleteCloudEvents;
+
+    private final Counter numSuccessfullyPersistedMergeCloudEvents;
+
+    private final Counter numSuccessfullyPersistedCreateCloudEvents;
+
+    private final Counter numSuccessfullyPersistedDeleteCloudEvents;
+
+    private final Counter numSuccessfullyPersistedSourceEntityDeleteCloudEvents;
+
+    private final Counter numUnsuccessfullyPersistedMergeCloudEvents;
+
+    private final Counter numUnsuccessfullyPersistedCreateCloudEvents;
+
+    private final Counter numUnsuccessfullyPersistedDeleteCloudEvents;
+
+    private final Counter numUnsuccessfullyPersistedSourceEntityDeleteCloudEvents;
+
+    private final Counter numUnsuccessfullyExposedRelationshipsByEntityId;
+
+    private final Counter numUnsuccessfullyExposedEntityById;
+
+    private final Counter numUnsuccessfullyExposedEntitiesByType;
+
+    private final Counter numUnsuccessfullyExposedEntitiesByDomain;
+
+    private final Counter numUnsuccessfullyExposedRelationshipById;
+
+    private final Counter numUnsuccessfullyExposedRelationshipsByType;
+
+    private final Counter numUnsuccessfullyExposedRelationshipTypes;
+
+    private final Counter numUnsuccessfullyExposedEntityTypes;
+
+    private final Counter numUnsuccessfullyExposedDomainTypes;
+
+    private final Counter numIgnoredAttributes;
+
+    public CustomMetrics(MeterRegistry meterRegistry) {
+
+        this.meterRegistry = meterRegistry;
+
+        numReceivedCloudEventCreate = Counter.builder("ties_ingestion_event_topology_create_total").register(meterRegistry);
+
+        numReceivedCloudEventMerge = Counter.builder("ties_ingestion_event_topology_merge_total").register(meterRegistry);
+
+        numReceivedCloudEventDelete = Counter.builder("ties_ingestion_event_topology_delete_total").register(meterRegistry);
+
+        numReceivedCloudEventSourceEntityDelete = Counter.builder(
+                "ties_ingestion_event_topology_source_entity_delete_total").register(meterRegistry);
+
+        numReceivedCloudEventNotSupported = Counter.builder("ties_ingestion_event_topology_not_supported_total").register(
+                meterRegistry);
+
+        numSuccessfullyParsedMergeCloudEvents = Counter.builder("ties_ingestion_event_topology_merge_parse_success_total")
+                .register(meterRegistry);
+
+        numSuccessfullyParsedCreateCloudEvents = Counter.builder("ties_ingestion_event_topology_create_parse_success_total")
+                .register(meterRegistry);
+
+        numSuccessfullyParsedDeleteCloudEvents = Counter.builder("ties_ingestion_event_topology_delete_parse_success_total")
+                .register(meterRegistry);
+
+        numSuccessfullyParsedSourceEntityDeleteCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_source_entity_delete_parse_success_total").register(meterRegistry);
+
+        numUnsuccessfullyParsedMergeCloudEvents = Counter.builder("ties_ingestion_event_topology_merge_parse_fail_total")
+                .register(meterRegistry);
+
+        numUnsuccessfullyParsedCreateCloudEvents = Counter.builder("ties_ingestion_event_topology_create_parse_fail_total")
+                .register(meterRegistry);
+
+        numUnsuccessfullyParsedDeleteCloudEvents = Counter.builder("ties_ingestion_event_topology_delete_parse_fail_total")
+                .register(meterRegistry);
+
+        numUnsuccessfullyParsedSourceEntityDeleteCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_source_entity_delete_parse_fail_total").register(meterRegistry);
+
+        numSuccessfullyPersistedMergeCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_merge_persist_success_total").register(meterRegistry);
+
+        numSuccessfullyPersistedCreateCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_create_persist_success_total").register(meterRegistry);
+
+        numSuccessfullyPersistedDeleteCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_delete_persist_success_total").register(meterRegistry);
+
+        numSuccessfullyPersistedSourceEntityDeleteCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_source_entity_delete_persist_success_total").register(meterRegistry);
+
+        numUnsuccessfullyPersistedMergeCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_merge_persist_fail_total").register(meterRegistry);
+
+        numUnsuccessfullyPersistedCreateCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_create_persist_fail_total").register(meterRegistry);
+
+        numUnsuccessfullyPersistedDeleteCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_delete_persist_fail_total").register(meterRegistry);
+
+        numUnsuccessfullyPersistedSourceEntityDeleteCloudEvents = Counter.builder(
+                "ties_ingestion_event_topology_source_entity_delete_persist_fail_total").register(meterRegistry);
+
+        numUnsuccessfullyExposedRelationshipsByEntityId = Counter.builder(
+                "ties_exposure_http_get_relationships_by_entity_id_fail_total").register(meterRegistry);
+
+        numUnsuccessfullyExposedEntityById = Counter.builder("ties_exposure_http_get_entity_by_id_fail_total").register(
+                meterRegistry);
+
+        numUnsuccessfullyExposedEntitiesByType = Counter.builder("ties_exposure_http_get_entities_by_type_fail_total")
+                .register(meterRegistry);
+
+        numUnsuccessfullyExposedEntitiesByDomain = Counter.builder("ties_exposure_http_get_entities_by_domain_fail_total")
+                .register(meterRegistry);
+
+        numUnsuccessfullyExposedRelationshipById = Counter.builder("ties_exposure_http_get_relationship_by_id_fail_total")
+                .register(meterRegistry);
+
+        numUnsuccessfullyExposedRelationshipsByType = Counter.builder(
+                "ties_exposure_http_get_relationships_by_type_fail_total").register(meterRegistry);
+
+        numUnsuccessfullyExposedRelationshipTypes = Counter.builder("ties_exposure_http_get_relationship_types_fail_total")
+                .register(meterRegistry);
+
+        numUnsuccessfullyExposedEntityTypes = Counter.builder("ties_exposure_http_get_entity_types_fail_total").register(
+                meterRegistry);
+
+        numUnsuccessfullyExposedDomainTypes = Counter.builder("ties_exposure_http_get_domain_types_fail_total").register(
+                meterRegistry);
+
+        cloudEventMergePersistTime = Timer.builder("ties_ingestion_event_topology_merge_persist_seconds").register(
+                meterRegistry);
+
+        cloudEventCreatePersistTime = Timer.builder("ties_ingestion_event_topology_create_persist_seconds").register(
+                meterRegistry);
+
+        cloudEventDeletePersistTime = Timer.builder("ties_ingestion_event_topology_delete_persist_seconds").register(
+                meterRegistry);
+
+        cloudEventSourceEntityDeletePersistTime = Timer.builder(
+                "ties_ingestion_event_topology_source_entity_delete_persist_seconds").register(meterRegistry);
+
+        cloudEventMergeParseTime = Timer.builder("ties_ingestion_event_topology_merge_parse_seconds").register(
+                meterRegistry);
+
+        cloudEventCreateParseTime = Timer.builder("ties_ingestion_event_topology_create_parse_seconds").register(
+                meterRegistry);
+
+        cloudEventDeleteParseTime = Timer.builder("ties_ingestion_event_topology_delete_parse_seconds").register(
+                meterRegistry);
+
+        cloudEventSourceEntityDeleteParseTime = Timer.builder(
+                "ties_ingestion_event_topology_source_entity_delete_parse_seconds").register(meterRegistry);
+
+        numIgnoredAttributes = Counter.builder("ties_ingestion_event_ignored_attributes_total").register(meterRegistry);
+    }
+
+    /**
+     * It increments the metric that counts the received "create" type events from Kafka
+     */
+    public void incrementNumReceivedCloudEventCreate() {
+        numReceivedCloudEventCreate.increment();
+    }
+
+    /**
+     * It increments the metric that counts the received "merge" type events from Kafka
+     */
+    public void incrementNumReceivedCloudEventMerge() {
+        numReceivedCloudEventMerge.increment();
+    }
+
+    /**
+     * It increments the metric that counts the received "delete" type events from Kafka
+     */
+    public void incrementNumReceivedCloudEventDelete() {
+        numReceivedCloudEventDelete.increment();
+    }
+
+    /**
+     * It increments the metric that counts the received "source-entity-delete" type events from Kafka
+     */
+    public void incrementNumReceivedCloudEventSourceEntityDelete() {
+        numReceivedCloudEventSourceEntityDelete.increment();
+    }
+
+    /**
+     * It increments the metric that counts the received not supported or erroneous events from Kafka
+     */
+    public void incrementNumReceivedCloudEventNotSupported() {
+        numReceivedCloudEventNotSupported.increment();
+    }
+
+    /**
+     * It records a time for the cloudEventMergePersistTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventMergePersistTime(long nanoseconds) {
+        cloudEventMergePersistTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It records a time for the cloudEventDeletePersistTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventDeletePersistTime(long nanoseconds) {
+        cloudEventDeletePersistTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It records a time for the cloudEventSourceEntityDeletePersistTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventSourceEntityDeletePersistTime(long nanoseconds) {
+        cloudEventSourceEntityDeletePersistTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It records a time for the cloudEventCreatePersistTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventCreatePersistTime(long nanoseconds) {
+        cloudEventCreatePersistTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It records a time for the cloudEventMergeParseTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventMergeParseTime(long nanoseconds) {
+        cloudEventMergeParseTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It records a time for the cloudEventCreateParseTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventCreateParseTime(long nanoseconds) {
+        cloudEventCreateParseTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It records a time for the cloudEventDeleteParseTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventDeleteParseTime(long nanoseconds) {
+        cloudEventDeleteParseTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It records a time for the cloudEventSourceEntityDeleteParseTime metric in nanoseconds
+     *
+     * @param nanoseconds
+     *     time to record
+     */
+    public void recordCloudEventSourceEntityDeleteParseTime(long nanoseconds) {
+        cloudEventSourceEntityDeleteParseTime.record(nanoseconds, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * It increments the numSuccessfullyParsedCreateCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyParsedCreateCloudEvents() {
+        numSuccessfullyParsedCreateCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numSuccessfullyParsedMergeCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyParsedMergeCloudEvents() {
+        numSuccessfullyParsedMergeCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numSuccessfullyParsedDeleteCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyParsedDeleteCloudEvents() {
+        numSuccessfullyParsedDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numSuccessfullyParsedSourceEntityDeleteCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyParsedSourceEntityDeleteCloudEvents() {
+        numSuccessfullyParsedSourceEntityDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyParsedCreateCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyParsedCreateCloudEvents() {
+        numUnsuccessfullyParsedCreateCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyParsedMergeCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyParsedMergeCloudEvents() {
+        numUnsuccessfullyParsedMergeCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyParsedDeleteCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyParsedDeleteCloudEvents() {
+        numUnsuccessfullyParsedDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyParsedSourceEntityDeleteCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents() {
+        numUnsuccessfullyParsedSourceEntityDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numSuccessfullyPersistedCreateCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyPersistedCreateCloudEvents() {
+        numSuccessfullyPersistedCreateCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numSuccessfullyPersistedMergeCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyPersistedMergeCloudEvents() {
+        numSuccessfullyPersistedMergeCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numSuccessfullyPersistedDeleteCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyPersistedDeleteCloudEvents() {
+        numSuccessfullyPersistedDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numSuccessfullyPersistedSourceEntityDeleteCloudEvents metric.
+     */
+    public void incrementNumSuccessfullyPersistedSourceEntityDeleteCloudEvents() {
+        numSuccessfullyPersistedSourceEntityDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyPersistedCreateCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyPersistedCreateCloudEvents() {
+        numUnsuccessfullyPersistedCreateCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyPersistedMergeCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyPersistedMergeCloudEvents() {
+        numUnsuccessfullyPersistedMergeCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyPersistedDeleteCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyPersistedDeleteCloudEvents() {
+        numUnsuccessfullyPersistedDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyPersistedSourceEntityDeleteCloudEvents metric.
+     */
+    public void incrementNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents() {
+        numUnsuccessfullyPersistedSourceEntityDeleteCloudEvents.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedAllRelationshipsByEntityId metric.
+     */
+    public void incrementNumUnsuccessfullyExposedAllRelationshipsByEntityId() {
+        numUnsuccessfullyExposedRelationshipsByEntityId.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedEntityById metric.
+     */
+    public void incrementNumUnsuccessfullyExposedEntityById() {
+        numUnsuccessfullyExposedEntityById.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedEntitiesByType metric.
+     */
+    public void incrementNumUnsuccessfullyExposedEntitiesByType() {
+        numUnsuccessfullyExposedEntitiesByType.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedEntitiesByDomain metric.
+     */
+    public void incrementNumUnsuccessfullyExposedEntitiesByDomain() {
+        numUnsuccessfullyExposedEntitiesByDomain.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedRelationshipById metric.
+     */
+    public void incrementNumUnsuccessfullyExposedRelationshipById() {
+        numUnsuccessfullyExposedRelationshipById.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedRelationshipsByType metric.
+     */
+    public void incrementNumUnsuccessfullyExposedRelationshipsByType() {
+        numUnsuccessfullyExposedRelationshipsByType.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedRelationshipTypes metric.
+     */
+    public void incrementNumUnsuccessfullyExposedRelationshipTypes() {
+        numUnsuccessfullyExposedRelationshipTypes.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedEntityTypes metric.
+     */
+    public void incrementNumUnsuccessfullyExposedEntityTypes() {
+        numUnsuccessfullyExposedEntityTypes.increment();
+    }
+
+    /**
+     * It increments the numUnsuccessfullyExposedDomainTypes metric.
+     */
+    public void incrementNumUnsuccessfullyExposedDomainTypes() {
+        numUnsuccessfullyExposedDomainTypes.increment();
+    }
+
+    public void incrementNumReceivedTiesSubscriptions(int amountToAdd) {
+        tiesSubscriptionGaugeCounter.addAndGet(amountToAdd);
+    }
+
+    public void resetNumReceivedTiesSubscriptions() {
+        tiesSubscriptionGaugeCounter.set(0);
+    }
+
+    public void setNumReceivedTiesSubscriptions(int amount) {
+        tiesSubscriptionGaugeCounter.set(amount);
+    }
+
+    public void incrementNumIgnoredAttributes() {
+        numIgnoredAttributes.increment();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/availability/DependentServiceAvailability.java b/teiv/src/main/java/org/oran/smo/teiv/availability/DependentServiceAvailability.java
new file mode 100644
index 0000000..46291ff
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/availability/DependentServiceAvailability.java
@@ -0,0 +1,55 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.availability;
+
+import org.springframework.retry.support.RetryTemplate;
+
+import org.oran.smo.teiv.exception.UnsatisfiedExternalDependencyException;
+import org.oran.smo.teiv.utils.RetryOperationUtils;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public abstract class DependentServiceAvailability {
+    protected String serviceName;
+
+    protected int retryIntervalMs;
+
+    protected int retryAttempts;
+
+    /**
+     * Check if service can be reached
+     *
+     * @return true once service is reached, false if max retries exhausted
+     */
+    public boolean checkService() {
+        RetryTemplate retryTemplate = RetryOperationUtils.getRetryTemplate(serviceName,
+                UnsatisfiedExternalDependencyException.class, retryAttempts, retryIntervalMs);
+        try {
+            return retryTemplate.execute(retryContext -> isServiceAvailable());
+        } catch (UnsatisfiedExternalDependencyException e) {
+            log.error("Hit max retry attempts {}: {}", retryAttempts, e.getMessage());
+        }
+        return false; // exhausted retries
+    }
+
+    abstract boolean isServiceAvailable() throws UnsatisfiedExternalDependencyException;
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/availability/DependentServiceAvailabilityKafka.java b/teiv/src/main/java/org/oran/smo/teiv/availability/DependentServiceAvailabilityKafka.java
new file mode 100644
index 0000000..2af2d33
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/availability/DependentServiceAvailabilityKafka.java
@@ -0,0 +1,85 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.availability;
+
+import org.apache.kafka.clients.admin.AdminClient;
+import org.apache.kafka.clients.admin.ListTopicsOptions;
+import org.apache.kafka.clients.admin.ListTopicsResult;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Profile;
+import org.springframework.kafka.core.KafkaAdmin;
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.config.KafkaAdminConfig;
+import org.oran.smo.teiv.exception.UnsatisfiedExternalDependencyException;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+@Profile("ingestion")
+public class DependentServiceAvailabilityKafka extends DependentServiceAvailability {
+
+    @Getter
+    private final KafkaAdminConfig kafkaAdminConfig;
+
+    @Getter
+    private final KafkaAdmin kafkaAdmin;
+
+    @Setter
+    private Integer listTopicTimeout = null;
+
+    public DependentServiceAvailabilityKafka(KafkaAdminConfig kafkaAdminConfig, KafkaAdmin kafkaAdmin) {
+        this.kafkaAdminConfig = kafkaAdminConfig;
+        this.kafkaAdmin = kafkaAdmin;
+        serviceName = "Kafka";
+    }
+
+    @Value("${kafka.availability.retry-interval-ms}")
+    protected void setRetryInterval(int retryIntervalMs) {
+        super.retryIntervalMs = retryIntervalMs;
+    }
+
+    @Value("${kafka.availability.retry-attempts}")
+    protected void setRetryAttempts(int retryAttempts) {
+        super.retryAttempts = retryAttempts;
+    }
+
+    @Override
+    boolean isServiceAvailable() throws UnsatisfiedExternalDependencyException {
+        log.debug("Checking if Kafka is reachable, bootstrap server: '{}'", kafkaAdminConfig.getBootstrapServer());
+
+        try (AdminClient client = AdminClient.create(kafkaAdmin.getConfigurationProperties())) {
+            ListTopicsResult topics = client.listTopics(new ListTopicsOptions().timeoutMs(listTopicTimeout));
+            topics.names().get();
+            return true;
+        } catch (InterruptedException e) {
+            log.error("Interrupted Error Reaching Kafka {}: {}", kafkaAdminConfig.getBootstrapServer(), e.getMessage());
+            Thread.currentThread().interrupt();
+            throw new UnsatisfiedExternalDependencyException("Interrupted Error Reaching Kafka", e);
+        } catch (Exception e) {
+            log.error("Execution Error Reaching Kafka {}: ", kafkaAdminConfig.getBootstrapServer(), e);
+            throw new UnsatisfiedExternalDependencyException("Kafka Unreachable", e);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/config/DataSourceConfig.java b/teiv/src/main/java/org/oran/smo/teiv/config/DataSourceConfig.java
new file mode 100644
index 0000000..a926a0f
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/config/DataSourceConfig.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.config;
+
+import org.jooq.DSLContext;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import javax.sql.DataSource;
+
+@Configuration
+public class DataSourceConfig {
+
+    @Primary
+    @Bean(name = "writeDataSource")
+    @ConfigurationProperties("spring.datasource.write")
+    public DataSource dataSourceWrite() {
+        return DataSourceBuilder.create().build();
+    }
+
+    @Bean(name = "readDataSource")
+    @ConfigurationProperties("spring.datasource.read")
+    public DataSource dataSourceRead() {
+        return DataSourceBuilder.create().build();
+    }
+
+    @Bean(name = "writeDataDslContext")
+    public DSLContext dslContextWrite() {
+        return DSL.using(dataSourceWrite(), SQLDialect.POSTGRES);
+    }
+
+    @Bean(name = "readDataDslContext")
+    public DSLContext dslContextRead() {
+        return DSL.using(dataSourceRead(), SQLDialect.POSTGRES);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/config/KafkaAdminConfig.java b/teiv/src/main/java/org/oran/smo/teiv/config/KafkaAdminConfig.java
new file mode 100644
index 0000000..66beb64
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/config/KafkaAdminConfig.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+import lombok.Data;
+
+import org.oran.smo.teiv.service.kafka.KafkaAddressSupplier;
+
+@Configuration
+@Data
+@Profile("ingestion")
+@Slf4j
+public class KafkaAdminConfig {
+
+    private String bootstrapServer;
+
+    @Value("${kafka.admin.retry}")
+    private int retries;
+
+    @Value("${kafka.admin.retry-backoff-ms}")
+    private int retryBackoffMs;
+
+    @Value("${kafka.admin.reconnect-backoff-ms}")
+    private int reconnectBackoffMs;
+
+    @Value("${kafka.admin.reconnect-backoff-max-ms}")
+    private int reconnectBackoffMaxMs;
+
+    @Value("${kafka.admin.request-timeout-ms}")
+    private int requestTimeoutMs;
+
+    public KafkaAdminConfig(KafkaAddressSupplier messageBus) {
+        bootstrapServer = messageBus.getBootstrapServer();
+        log.info("The following address will be used for Kafka: {}", bootstrapServer);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/config/KafkaConfig.java b/teiv/src/main/java/org/oran/smo/teiv/config/KafkaConfig.java
new file mode 100644
index 0000000..b43f4b6
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/config/KafkaConfig.java
@@ -0,0 +1,77 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+
+@Configuration
+@Data
+@Profile("ingestion")
+public class KafkaConfig {
+
+    private final TopologyIngestion topologyIngestion;
+
+    @Data
+    @Configuration
+    public static class TopologyIngestion {
+        @Value("${kafka.topology-ingestion.consumer.topic.name}")
+        private String topicName;
+
+        @Value("${kafka.topology-ingestion.consumer.topic.partitions}")
+        private int partitions;
+
+        @Value("${kafka.topology-ingestion.consumer.topic.replicas}")
+        private int replicas;
+
+        @Value("${kafka.topology-ingestion.consumer.topic.retention-ms}")
+        private String retention;
+
+        @Value("${kafka.topology-ingestion.consumer.group-id}")
+        private String groupId;
+
+        @Value("${kafka.topology-ingestion.consumer.auto-offset-reset}")
+        private String autoOffsetReset;
+
+        @Value("${kafka.topology-ingestion.consumer.max-poll-records}")
+        private int maxPollRecords;
+
+        @Value("${kafka.topology-ingestion.consumer.max-poll-interval-ms}")
+        private int maxPollIntervalMs;
+
+        @Value("${kafka.topology-ingestion.consumer.fetch-min-bytes}")
+        private int fetchMinBytes;
+
+        @Value("${kafka.topology-ingestion.consumer.fetch-max-wait-ms}")
+        private int fetchMaxWaitMs;
+
+        @Value("${kafka.topology-ingestion.consumer.retry-attempts}")
+        private int retryAttempts;
+
+        @Value("${kafka.topology-ingestion.consumer.retry-backoff-ms}")
+        private int retryBackoffMs;
+
+        @Value("${kafka.topology-ingestion.consumer.concurrency}")
+        private int concurrency;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/controller/health/HealthStatus.java b/teiv/src/main/java/org/oran/smo/teiv/controller/health/HealthStatus.java
new file mode 100644
index 0000000..3a835be
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/controller/health/HealthStatus.java
@@ -0,0 +1,39 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.controller.health;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class HealthStatus {
+
+    private final AtomicBoolean schemaInitialized = new AtomicBoolean(false);
+
+    public void setSchemaInitialized(boolean isSchemaInitialized) {
+        schemaInitialized.set(isSchemaInitialized);
+    }
+
+    public boolean isSchemaInitialized() {
+        return schemaInitialized.get();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/controller/health/TiesExposureHealthIndicator.java b/teiv/src/main/java/org/oran/smo/teiv/controller/health/TiesExposureHealthIndicator.java
new file mode 100644
index 0000000..1863ff7
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/controller/health/TiesExposureHealthIndicator.java
@@ -0,0 +1,57 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.controller.health;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+
+/**
+ * Health Check component for TIES exposure.
+ */
+
+@RequiredArgsConstructor
+@Component
+@Slf4j
+@Profile("!ingestion")
+public class TiesExposureHealthIndicator implements HealthIndicator {
+
+    private final HealthStatus healthStatus;
+
+    private static final String SERVICE_NAME = "topology-exposure-inventory";
+
+    @Override
+    public Health health() {
+        if (!healthStatus.isSchemaInitialized()) {
+            String errorMessage = SERVICE_NAME + " is DOWN because: Schema is yet to be initialized.";
+            log.error(errorMessage);
+            return Health.down().withDetail("Error", errorMessage).build();
+        } else {
+            String message = SERVICE_NAME + " is UP and Healthy.";
+            log.debug(message);
+            return Health.up().withDetail("UP", message).build();
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/controller/health/TiesIngestionHealthIndicator.java b/teiv/src/main/java/org/oran/smo/teiv/controller/health/TiesIngestionHealthIndicator.java
new file mode 100644
index 0000000..fbedaa0
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/controller/health/TiesIngestionHealthIndicator.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.controller.health;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.availability.DependentServiceAvailabilityKafka;
+
+/**
+ * Health Check component for TIES ingestion.
+ */
+
+@RequiredArgsConstructor
+@Component
+@Slf4j
+@Profile("ingestion")
+public class TiesIngestionHealthIndicator implements HealthIndicator {
+
+    private final HealthStatus healthStatus;
+
+    private final DependentServiceAvailabilityKafka dependentServiceAvailabilityKafka;
+
+    private static final String SERVICE_NAME = "top-exp-inv-ingestion";
+
+    @Override
+    public Health health() {
+        String errorMessage = SERVICE_NAME + " is DOWN because:";
+        boolean isHealthy = true;
+
+        if (!healthStatus.isSchemaInitialized()) {
+            errorMessage += " Schema is yet to be initialized.";
+            isHealthy = false;
+        }
+
+        if (!checkKafkaHealth()) {
+            errorMessage += " Kafka is unavailable.";
+            isHealthy = false;
+        }
+
+        if (!isHealthy) {
+            log.error(errorMessage);
+            return Health.down().withDetail("Error", errorMessage).build();
+        } else {
+            log.debug(SERVICE_NAME + " is UP and Healthy.");
+            return Health.up().withDetail("UP", SERVICE_NAME + " is UP and Healthy.").build();
+        }
+    }
+
+    private boolean checkKafkaHealth() {
+        return dependentServiceAvailabilityKafka.checkService();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalManyToManyRelationshipUpdateException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalManyToManyRelationshipUpdateException.java
new file mode 100644
index 0000000..4ed1697
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalManyToManyRelationshipUpdateException.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+import java.text.MessageFormat;
+
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+
+public class IllegalManyToManyRelationshipUpdateException extends IllegalRelationshipUpdateException {
+    private static final String DESCRIPTION = "A relationship with id={0} already exists, but with a different A or B side. It\'s not possible to update the sides of an existing relationship, because the relationship ID should be derived from the identities of both sides";
+
+    public IllegalManyToManyRelationshipUpdateException(final Relationship relationship) {
+        super(MessageFormat.format(DESCRIPTION, relationship.getId()));
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalOneToManyRelationshipUpdateException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalOneToManyRelationshipUpdateException.java
new file mode 100644
index 0000000..993cfe8
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalOneToManyRelationshipUpdateException.java
@@ -0,0 +1,36 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+import java.text.MessageFormat;
+
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+
+public class IllegalOneToManyRelationshipUpdateException extends IllegalRelationshipUpdateException {
+    private static final String DESCRIPTION = "Could not update relationship with id {0} after trying to insert the {1} side entity with id = {2}";
+
+    public IllegalOneToManyRelationshipUpdateException(final Relationship relationship, final boolean storingSide) {
+        super(storingSide ?
+                MessageFormat.format(DESCRIPTION, relationship.getId(), "storing", relationship.getStoringSideEntityId()) :
+                MessageFormat.format(DESCRIPTION, relationship.getId(), "not storing", relationship
+                        .getNotStoringSideEntityId()));
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalRelationshipUpdateException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalRelationshipUpdateException.java
new file mode 100644
index 0000000..764ad32
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/IllegalRelationshipUpdateException.java
@@ -0,0 +1,27 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+public class IllegalRelationshipUpdateException extends RuntimeException {
+    public IllegalRelationshipUpdateException(final String message) {
+        super(message);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidCategoryInPersistedTopologyException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidCategoryInPersistedTopologyException.java
new file mode 100644
index 0000000..36d3f27
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidCategoryInPersistedTopologyException.java
@@ -0,0 +1,31 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+public class InvalidCategoryInPersistedTopologyException extends Exception {
+    public InvalidCategoryInPersistedTopologyException(final String message) {
+        super(message);
+    }
+
+    public InvalidCategoryInPersistedTopologyException(final String message, final Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidFieldInYangDataException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidFieldInYangDataException.java
new file mode 100644
index 0000000..80beccc
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidFieldInYangDataException.java
@@ -0,0 +1,32 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+public class InvalidFieldInYangDataException extends Exception {
+
+    public InvalidFieldInYangDataException(final String message) {
+        super(message);
+    }
+
+    public InvalidFieldInYangDataException(final String message, final Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidOperationInPersistedTopologyException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidOperationInPersistedTopologyException.java
new file mode 100644
index 0000000..198859e
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/InvalidOperationInPersistedTopologyException.java
@@ -0,0 +1,32 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+public class InvalidOperationInPersistedTopologyException extends Exception {
+    public InvalidOperationInPersistedTopologyException(final String message) {
+        super(message);
+    }
+
+    public InvalidOperationInPersistedTopologyException(final String message, final Throwable e) {
+        super(message, e);
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/RelationshipIdCollisionException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/RelationshipIdCollisionException.java
new file mode 100644
index 0000000..a2701f5
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/RelationshipIdCollisionException.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+import java.text.MessageFormat;
+
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+
+public class RelationshipIdCollisionException extends IllegalRelationshipUpdateException {
+    public static final String DESCRIPTION = "A relationship with the given id already exists, cannot process the incoming relationship: id={0}, aSide={1}, bSide={2}. It's not possible to update the sides of an existing relationship, because the relationship ID should be derived from the identities of both sides";
+
+    public RelationshipIdCollisionException(Relationship relationship) {
+        super(MessageFormat.format(DESCRIPTION, relationship.getId(), relationship.getASide(), relationship.getBSide()));
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/TiesException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/TiesException.java
new file mode 100644
index 0000000..481a2b6
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/TiesException.java
@@ -0,0 +1,114 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+import java.util.Collection;
+
+import org.springframework.http.HttpStatus;
+
+import lombok.Getter;
+
+@Getter
+public class TiesException extends RuntimeException {
+
+    private final HttpStatus status;
+    private final String message;
+    private final String details;
+    private final Exception exception;
+
+    public static TiesException unknownModule(final String module) {
+        return clientException("Unknown module", String.format("Unknown module: %s", module));
+    }
+
+    //  Request validation
+    public static TiesException unknownDomain(final String domain, final Collection<String> domains) {
+        return clientException("Unknown domain", String.format("Unknown domain: %s, known domains: %s", domain, domains));
+    }
+
+    public static TiesException unknownEntityType(final String entityType, final Collection<String> entityTypes) {
+        return clientException("Unknown entity type", String.format(
+                "Entity type %s is not part of the model, known entity types: %s", entityType, entityTypes));
+    }
+
+    public static TiesException unknownEntityTypeInDomain(final String entityType, final String domain,
+            final Collection<String> entityTypesInDomain) {
+        return clientException("Unknown entity type", String.format(
+                "Entity type %s is not part of the domain %s, known entity types: %s", entityType, domain,
+                entityTypesInDomain));
+    }
+
+    public static TiesException unknownRelationshipType(final String relationshipType,
+            final Collection<String> relationshipTypes) {
+        return clientException("Unknown relationship type", String.format(
+                "Relationship type %s is not part of the model, known relationship types: %s", relationshipType,
+                relationshipTypes));
+    }
+
+    public static TiesException unknownRelationshipTypeInDomain(final String relationshipType, final String domain,
+            final Collection<String> relationshipTypesInDomain) {
+        return clientException("Unknown relationship type", String.format(
+                "Relationship type %s is not part of the domain %s, known relationship types: %s", relationshipType, domain,
+                relationshipTypesInDomain));
+    }
+
+    // Schema validation
+    public static TiesException invalidSchema(final String name) {
+        return clientException("Invalid schema name", String.format("Invalid schema name: %s", name));
+    }
+
+    public static TiesException schemaNotOwned(final String name) {
+        return new TiesException("Forbidden", String.format("Schema %s is not owned by user", name), HttpStatus.FORBIDDEN,
+                null);
+    }
+
+    public static TiesException serverSQLException() {
+        return serverException("Sql exception during query execution", "Please check the logs for more details", null);
+    }
+
+    public static TiesException resourceNotFoundException() {
+        return new TiesException("Resource Not Found", "The requested resource is not found", HttpStatus.NOT_FOUND, null);
+    }
+
+    public static TiesException invalidValueException(String valueName, Integer valueLimit, Boolean isLowerLimit) {
+        return clientException("Invalid Value", String.format("%s cannot be %s than %d", valueName, isLowerLimit ?
+                "larger" :
+                "lower", valueLimit));
+    }
+
+    public static TiesException serverException(String message, String details, Exception exception) {
+        return new TiesException(message, details, HttpStatus.INTERNAL_SERVER_ERROR, exception);
+    }
+
+    public static TiesException notImplementedException(String details, Exception exception) {
+        return new TiesException("Not Implemented", details, HttpStatus.NOT_IMPLEMENTED, exception);
+    }
+
+    public static TiesException clientException(String message, String details) {
+        return new TiesException(message, details, HttpStatus.BAD_REQUEST, null);
+    }
+
+    private TiesException(String message, String details, HttpStatus status, Exception exception) {
+        this.status = status;
+        this.message = message;
+        this.details = details;
+        this.exception = exception;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/UniqueRelationshipIdConstraintException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/UniqueRelationshipIdConstraintException.java
new file mode 100644
index 0000000..66d9f4c
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/UniqueRelationshipIdConstraintException.java
@@ -0,0 +1,34 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+import java.text.MessageFormat;
+
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+
+public class UniqueRelationshipIdConstraintException extends IllegalRelationshipUpdateException {
+
+    private static final String DESCRIPTION = "A relationship with the given id already exists, cannot process the incoming relationship: id={0}, aSide={1}, bSide={2}. It's not possible to update the sides of an existing relationship, because the relationship ID should be derived from the identities of both sides";
+
+    public UniqueRelationshipIdConstraintException(Relationship relationship) {
+        super(MessageFormat.format(DESCRIPTION, relationship.getId(), relationship.getASide(), relationship.getBSide()));
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/UnsatisfiedExternalDependencyException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/UnsatisfiedExternalDependencyException.java
new file mode 100644
index 0000000..ee6f01a
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/UnsatisfiedExternalDependencyException.java
@@ -0,0 +1,31 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+public class UnsatisfiedExternalDependencyException extends Exception {
+    public UnsatisfiedExternalDependencyException(final String message) {
+        super(message);
+    }
+
+    public UnsatisfiedExternalDependencyException(final String message, final Throwable e) {
+        super(message, e);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exception/YangModelException.java b/teiv/src/main/java/org/oran/smo/teiv/exception/YangModelException.java
new file mode 100644
index 0000000..9f7d321
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exception/YangModelException.java
@@ -0,0 +1,41 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exception;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+
+@Slf4j
+public class YangModelException extends Exception {
+
+    public YangModelException(final String message) {
+        super(message);
+    }
+
+    public YangModelException(final String message, FindingsManager findingsManager) {
+        super(message);
+        for (Finding f : findingsManager.getAllFindings()) {
+            log.error("Finding: {}", f);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/classifiers/rest/controller/ClassifiersRestController.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/classifiers/rest/controller/ClassifiersRestController.java
new file mode 100644
index 0000000..8d4f66f
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/classifiers/rest/controller/ClassifiersRestController.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.classifiers.rest.controller;
+
+import org.oran.smo.teiv.api.ClassifiersApi;
+import org.oran.smo.teiv.utils.TiesConstants;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(TiesConstants.REQUEST_MAPPING)
+public class ClassifiersRestController implements ClassifiersApi {
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/collection/rest/controller/CollectionsRestController.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/collection/rest/controller/CollectionsRestController.java
new file mode 100644
index 0000000..2a06663
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/collection/rest/controller/CollectionsRestController.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.collection.rest.controller;
+
+import org.oran.smo.teiv.api.CollectionsApi;
+import org.oran.smo.teiv.utils.TiesConstants;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(TiesConstants.REQUEST_MAPPING)
+public class CollectionsRestController implements CollectionsApi {
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/data/api/DataService.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/data/api/DataService.java
new file mode 100644
index 0000000..85d5c48
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/data/api/DataService.java
@@ -0,0 +1,151 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.data.api;
+
+import org.oran.smo.teiv.api.model.OranTeivDomains;
+import org.oran.smo.teiv.api.model.OranTeivEntitiesResponseMessage;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+
+import java.util.Map;
+
+public interface DataService {
+
+    /**
+     * Get all the available topology domain types.
+     *
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a collection of domain types
+     */
+    OranTeivDomains getDomainTypes(final PaginationDTO paginationDTO);
+
+    /**
+     * Get all entity types in a topology domain types.
+     *
+     * @param domain
+     *     domain name
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a collection of domain types
+     */
+    OranTeivEntityTypes getTopologyEntityTypes(final String domain, final PaginationDTO paginationDTO);
+
+    /**
+     * Get all relationship types in a topology domain types.
+     *
+     * @param domain
+     *     domain name
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a collection of relationship types
+     */
+    OranTeivRelationshipTypes getTopologyRelationshipTypes(final String domain, final PaginationDTO paginationDTO);
+
+    /**
+     * Get topology for entity type with specified id.
+     *
+     * @param entityType
+     *     type of entity, e.g. NRCellDU
+     * @param id
+     *     unique identifier of entity
+     *
+     * @return a topology entity
+     */
+    Map<String, Object> getTopologyById(final String entityType, final String id);
+
+    /**
+     * Get topology entities that match target, scope and relationships filters.
+     *
+     * @param entityType
+     *     type of entity, e.g. NRCellDU
+     * @param targetFilter
+     *     specifies the entity type and attributes to be returned to the REST response
+     * @param scopeFilter
+     *     specifies the attributes to match on
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a collection of entity data and attributes
+     */
+    OranTeivEntitiesResponseMessage getTopologyByType(final String entityType, final String targetFilter,
+            final String scopeFilter, final PaginationDTO paginationDTO);
+
+    /**
+     *
+     * @param domain
+     *     domain name
+     * @param targetFilter
+     *     specifies the entity type and attributes to be returned to the REST response
+     * @param scopeFilter
+     *     specifies the attributes to match on
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a collection of entity data and attributes
+     */
+    OranTeivEntitiesResponseMessage getEntitiesByDomain(final String domain, final String targetFilter,
+            final String scopeFilter, final PaginationDTO paginationDTO);
+
+    /**
+     * Get all relationships for entityType with specified id
+     *
+     * @param entityType
+     *     type of entity, e.g. NRCellDU
+     * @param id
+     *     unique identifier of entity
+     *
+     * @return a collection of relationships for entity type
+     */
+    OranTeivRelationshipsResponseMessage getAllRelationshipsForObjectId(final String entityType, final String id,
+            final PaginationDTO paginationDTO);
+
+    /**
+     * Get relationship with specified id
+     *
+     * @param relationshipType
+     *     type of relationship
+     * @param id
+     *     unique identifier of the relationships
+     *
+     * @return a topology relationship
+     */
+    Map<String, Object> getRelationshipById(final String relationshipType, final String id);
+
+    /**
+     *
+     * @param relationshipType
+     *     type of relationship
+     * @param scopeFilter
+     *     specifies the attributes to match on
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return relationships by relationship type
+     */
+    OranTeivRelationshipsResponseMessage getRelationshipsByType(final String relationshipType, final String scopeFilter,
+            final PaginationDTO paginationDTO);
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/data/api/impl/DataServiceImpl.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/data/api/impl/DataServiceImpl.java
new file mode 100644
index 0000000..1c6f220
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/data/api/impl/DataServiceImpl.java
@@ -0,0 +1,259 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.data.api.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.stereotype.Service;
+
+import org.oran.smo.teiv.api.model.OranTeivDomains;
+import org.oran.smo.teiv.api.model.OranTeivDomainsItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivEntitiesResponseMessage;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypes;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivHref;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+import org.oran.smo.teiv.exposure.data.api.DataService;
+import org.oran.smo.teiv.exposure.spi.DataPersistanceService;
+import org.oran.smo.teiv.exposure.spi.mapper.MapperUtility;
+import org.oran.smo.teiv.exposure.spi.mapper.PageMetaData;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DataServiceImpl implements DataService {
+    private final DataPersistanceService dataPersistanceService;
+    private final MapperUtility mapperUtility;
+
+    @Override
+    public OranTeivDomains getDomainTypes(final PaginationDTO paginationDTO) {
+        final Map<String, Object> result = mapperUtility.wrapList(new ArrayList<>(SchemaRegistry.getDomains()),
+                paginationDTO);
+        final List<OranTeivDomainsItemsInner> items = new ArrayList<>();
+        final List<Object> itemsList = (List<Object>) result.get("items");
+        itemsList.forEach(domain -> items.add(OranTeivDomainsItemsInner.builder().name(domain.toString()).entityTypes(
+                OranTeivHref.builder().href(paginationDTO.getBasePath() + "/" + domain + "/entity-types").build())
+                .relationshipTypes(OranTeivHref.builder().href(paginationDTO
+                        .getBasePath() + "/" + domain + "/relationship-types").build()).build()));
+        return getDomainsResponseMessage(result, items, paginationDTO.getLimit(), paginationDTO.getOffset());
+    }
+
+    @Override
+    public OranTeivEntityTypes getTopologyEntityTypes(final String domain, final PaginationDTO paginationDTO) {
+        final Map<String, Object> result = mapperUtility.wrapList(new ArrayList<>(SchemaRegistry.getEntityNamesByDomain(
+                domain)), paginationDTO);
+        final List<OranTeivEntityTypesItemsInner> items = new ArrayList<>();
+        final List<String> entities = SchemaRegistry.getEntityNamesByDomain(domain);
+        entities.stream().forEach(entity -> {
+            OranTeivEntityTypesItemsInner inner = new OranTeivEntityTypesItemsInner();
+            OranTeivHref entitiesHref = new OranTeivHref();
+            entitiesHref.setHref(paginationDTO.getBasePath() + "/" + entity + "/entities");
+            inner.setName(entity);
+            inner.setEntities(entitiesHref);
+            items.add(inner);
+        });
+        return getEntityTypesResponseMessage(result, items, paginationDTO.getLimit(), paginationDTO.getOffset());
+    }
+
+    @Override
+    public OranTeivRelationshipTypes getTopologyRelationshipTypes(final String domain, final PaginationDTO paginationDTO) {
+        final Map<String, Object> result = mapperUtility.wrapList(new ArrayList<>(SchemaRegistry.getRelationNamesByDomain(
+                domain)), paginationDTO);
+        final List<OranTeivRelationshipTypesItemsInner> items = new ArrayList<>();
+        final List<String> relationships = SchemaRegistry.getRelationNamesByDomain(domain);
+        relationships.stream().forEach(relationship -> {
+            OranTeivRelationshipTypesItemsInner inner = new OranTeivRelationshipTypesItemsInner();
+            OranTeivHref relationshipsHref = new OranTeivHref();
+            relationshipsHref.setHref(paginationDTO.getBasePath() + "/" + relationship + "/relationships");
+            inner.setName(relationship);
+            inner.setRelationships(relationshipsHref);
+            items.add(inner);
+        });
+        return getRelationshipTypesResponseMessage(result, items, paginationDTO.getLimit(), paginationDTO.getOffset());
+    }
+
+    @Override
+    public Map<String, Object> getTopologyById(final String entityName, final String id) {
+        final EntityType entityType = SchemaRegistry.getEntityTypeByName(entityName);
+        return dataPersistanceService.getTopology(entityType, id);
+    }
+
+    @Override
+    public OranTeivEntitiesResponseMessage getTopologyByType(final String entityName, final String target,
+            final String scope, final PaginationDTO paginationDTO) {
+        final Map<String, Object> response = dataPersistanceService.getTopologyByType(entityName, target, scope,
+                paginationDTO);
+        return getEntitiesResponseMessage(response);
+    }
+
+    @Override
+    public OranTeivEntitiesResponseMessage getEntitiesByDomain(final String domain, final String fields,
+            final String filters, final PaginationDTO paginationDTO) {
+        final Map<String, Object> response = dataPersistanceService.getEntitiesByDomain(domain, fields, filters,
+                paginationDTO);
+        return getEntitiesResponseMessage(response);
+    }
+
+    @Override
+    public OranTeivRelationshipsResponseMessage getAllRelationshipsForObjectId(final String entityName, final String id,
+            final PaginationDTO paginationDTO) {
+        final EntityType entityType = SchemaRegistry.getEntityTypeByName(entityName);
+        final List<RelationType> relationTypes = SchemaRegistry.getRelationTypesByEntityName(entityName);
+        final Map<String, Object> response = dataPersistanceService.getAllRelationships(entityType, relationTypes, id,
+                paginationDTO);
+        return getRelationshipsResponseMessage(response);
+    }
+
+    @Override
+    public Map<String, Object> getRelationshipById(final String relationName, final String id) {
+        return dataPersistanceService.getRelationshipWithSpecifiedId(id, SchemaRegistry.getRelationTypeByName(
+                relationName));
+    }
+
+    @Override
+    public OranTeivRelationshipsResponseMessage getRelationshipsByType(final String relationName, final String scopeFilter,
+            final PaginationDTO paginationDTO) {
+        final Map<String, Object> response = dataPersistanceService.getRelationshipsByType(SchemaRegistry
+                .getRelationTypeByName(relationName), scopeFilter, paginationDTO);
+        return getRelationshipsResponseMessage(response);
+    }
+
+    private OranTeivEntitiesResponseMessage getEntitiesResponseMessage(Map<String, Object> response) {
+        OranTeivEntitiesResponseMessage result = new OranTeivEntitiesResponseMessage();
+        List<Object> items = (List<Object>) response.get("items");
+        PageMetaData self = (PageMetaData) response.get("self");
+        PageMetaData first = (PageMetaData) response.get("first");
+        PageMetaData prev = (PageMetaData) response.get("prev");
+        PageMetaData next = (PageMetaData) response.get("next");
+        PageMetaData last = (PageMetaData) response.get("last");
+        Integer totalCount = (Integer) response.get("totalCount");
+
+        result.setItems(items);
+
+        OranTeivHref selfHref = new OranTeivHref();
+        OranTeivHref firstHref = new OranTeivHref();
+        OranTeivHref prevHref = new OranTeivHref();
+        OranTeivHref nextHref = new OranTeivHref();
+        OranTeivHref lastHref = new OranTeivHref();
+
+        selfHref.setHref(self.getHref());
+        firstHref.setHref(first.getHref());
+        prevHref.setHref(prev.getHref());
+        nextHref.setHref(next.getHref());
+        lastHref.setHref(last.getHref());
+
+        result.setSelf(selfHref);
+        result.setFirst(firstHref);
+        result.setPrev(prevHref);
+        result.setNext(nextHref);
+        result.setLast(lastHref);
+        result.setTotalCount(totalCount);
+        return result;
+    }
+
+    private OranTeivRelationshipsResponseMessage getRelationshipsResponseMessage(Map<String, Object> response) {
+        OranTeivRelationshipsResponseMessage result = new OranTeivRelationshipsResponseMessage();
+        List<Object> items = (List<Object>) response.get("items");
+        PageMetaData self = (PageMetaData) response.get("self");
+        PageMetaData first = (PageMetaData) response.get("first");
+        PageMetaData prev = (PageMetaData) response.get("prev");
+        PageMetaData next = (PageMetaData) response.get("next");
+        PageMetaData last = (PageMetaData) response.get("last");
+        Integer totalCount = (Integer) response.get("totalCount");
+
+        result.setItems(items);
+
+        OranTeivHref selfHref = new OranTeivHref();
+        OranTeivHref firstHref = new OranTeivHref();
+        OranTeivHref prevHref = new OranTeivHref();
+        OranTeivHref nextHref = new OranTeivHref();
+        OranTeivHref lastHref = new OranTeivHref();
+
+        selfHref.setHref(self.getHref());
+        firstHref.setHref(first.getHref());
+        prevHref.setHref(prev.getHref());
+        nextHref.setHref(next.getHref());
+        lastHref.setHref(last.getHref());
+
+        result.setSelf(selfHref);
+        result.setFirst(firstHref);
+        result.setPrev(prevHref);
+        result.setNext(nextHref);
+        result.setLast(lastHref);
+        result.setTotalCount(totalCount);
+        return result;
+    }
+
+    private OranTeivDomains getDomainsResponseMessage(Map<String, Object> response, List<OranTeivDomainsItemsInner> items,
+            final Integer limit, final Integer offset) {
+        PageMetaData self = (PageMetaData) response.get("self");
+        PageMetaData first = (PageMetaData) response.get("first");
+        PageMetaData prev = (PageMetaData) response.get("prev");
+        PageMetaData next = (PageMetaData) response.get("next");
+        PageMetaData last = (PageMetaData) response.get("last");
+
+        return OranTeivDomains.builder().items(items.subList(offset, Math.min(offset + limit, items.size()))).first(
+                OranTeivHref.builder().href(first.getHref()).build()).prev(OranTeivHref.builder().href(prev.getHref())
+                        .build()).self(OranTeivHref.builder().href(self.getHref()).build()).next(OranTeivHref.builder()
+                                .href(next.getHref()).build()).last(OranTeivHref.builder().href(last.getHref()).build())
+                .totalCount(items.size()).build();
+    }
+
+    private OranTeivEntityTypes getEntityTypesResponseMessage(Map<String, Object> response,
+            List<OranTeivEntityTypesItemsInner> items, final Integer limit, final Integer offset) {
+        PageMetaData self = (PageMetaData) response.get("self");
+        PageMetaData first = (PageMetaData) response.get("first");
+        PageMetaData prev = (PageMetaData) response.get("prev");
+        PageMetaData next = (PageMetaData) response.get("next");
+        PageMetaData last = (PageMetaData) response.get("last");
+
+        return OranTeivEntityTypes.builder().items(items.subList(offset, Math.min(offset + limit, items.size()))).first(
+                OranTeivHref.builder().href(first.getHref()).build()).prev(OranTeivHref.builder().href(prev.getHref())
+                        .build()).self(OranTeivHref.builder().href(self.getHref()).build()).next(OranTeivHref.builder()
+                                .href(next.getHref()).build()).last(OranTeivHref.builder().href(last.getHref()).build())
+                .totalCount(items.size()).build();
+    }
+
+    private OranTeivRelationshipTypes getRelationshipTypesResponseMessage(Map<String, Object> response,
+            List<OranTeivRelationshipTypesItemsInner> items, final Integer limit, final Integer offset) {
+        PageMetaData self = (PageMetaData) response.get("self");
+        PageMetaData first = (PageMetaData) response.get("first");
+        PageMetaData prev = (PageMetaData) response.get("prev");
+        PageMetaData next = (PageMetaData) response.get("next");
+        PageMetaData last = (PageMetaData) response.get("last");
+
+        return OranTeivRelationshipTypes.builder().items(items.subList(offset, Math.min(offset + limit, items.size())))
+                .first(OranTeivHref.builder().href(first.getHref()).build()).prev(OranTeivHref.builder().href(prev
+                        .getHref()).build()).self(OranTeivHref.builder().href(self.getHref()).build()).next(OranTeivHref
+                                .builder().href(next.getHref()).build()).last(OranTeivHref.builder().href(last.getHref())
+                                        .build()).totalCount(items.size()).build();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/data/rest/controller/DataRestController.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/data/rest/controller/DataRestController.java
new file mode 100644
index 0000000..b4cc9c3
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/data/rest/controller/DataRestController.java
@@ -0,0 +1,190 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.data.rest.controller;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.api.EntitiesAndRelationshipsApi;
+import org.oran.smo.teiv.api.model.OranTeivDomains;
+import org.oran.smo.teiv.api.model.OranTeivEntitiesResponseMessage;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+import org.oran.smo.teiv.exposure.data.api.DataService;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.exposure.utils.RequestValidator;
+import org.oran.smo.teiv.utils.TiesConstants;
+
+import io.micrometer.core.annotation.Timed;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.function.Supplier;
+
+@Slf4j
+@RestController
+@RequestMapping(TiesConstants.REQUEST_MAPPING)
+@RequiredArgsConstructor
+public class DataRestController implements EntitiesAndRelationshipsApi {
+
+    private final RequestValidator requestValidator;
+    private final DataService dataService;
+    private final CustomMetrics customMetrics;
+
+    @Override
+    @Timed("ties_exposure_http_get_domain_types_seconds")
+    public ResponseEntity<OranTeivDomains> getAllDomains(@NotNull String accept, @Min(0) @Valid final Integer offset,
+            @Min(1) @Max(500) @Valid final Integer limit) {
+        return runWithFailCheck(() -> new ResponseEntity<>(dataService.getDomainTypes(PaginationDTO.builder().offset(offset)
+                .limit(limit).basePath("/domains").build()), HttpStatus.OK),
+                customMetrics::incrementNumUnsuccessfullyExposedDomainTypes);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_relationships_by_type_seconds")
+    public ResponseEntity<OranTeivRelationshipsResponseMessage> getRelationshipsByType(@NotNull String accept,
+            String domain, String relationshipType, @Valid String targetFilter, @Valid String scopeFilter,
+            @Min(0) @Valid final Integer offset, @Min(1) @Max(500) @Valid final Integer limit) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            requestValidator.validateRelationshipType(relationshipType);
+            requestValidator.validateRelationshipTypeInDomain(relationshipType, domain);
+            requestValidator.validateFiltersForRelationships(targetFilter, scopeFilter);
+            return ResponseEntity.ok(dataService.getRelationshipsByType(relationshipType, scopeFilter, PaginationDTO
+                    .builder().offset(offset).limit(limit).addPathParameters("relationshipType", relationshipType).basePath(
+                            String.format("/domains/%s/relationship-types/%s/relationships", domain, relationshipType))
+                    .addPathParameters("domain", domain).addQueryParameters("scopeFilter", scopeFilter).build()));
+        }, customMetrics::incrementNumUnsuccessfullyExposedRelationshipsByType);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_entity_types_seconds")
+    public ResponseEntity<OranTeivEntityTypes> getTopologyEntityTypes(@NotNull String accept, String domain,
+            @Min(0) @Valid final Integer offset, @Min(1) @Max(500) @Valid final Integer limit) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            return new ResponseEntity<>(dataService.getTopologyEntityTypes(domain, PaginationDTO.builder().offset(offset)
+                    .limit(limit).basePath(String.format("/domains/%s/entity-types", domain)).addPathParameters("domain",
+                            domain).build()), HttpStatus.OK);
+        }, customMetrics::incrementNumUnsuccessfullyExposedEntityTypes);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_relationship_types_seconds")
+    public ResponseEntity<OranTeivRelationshipTypes> getTopologyRelationshipTypes(@NotNull String accept, String domain,
+            @Min(0) @Valid final Integer offset, @Min(1) @Max(500) @Valid final Integer limit) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            return new ResponseEntity<>(dataService.getTopologyRelationshipTypes(domain, PaginationDTO.builder().offset(
+                    offset).limit(limit).basePath(String.format("/domains/%s/relationship-types", domain))
+                    .addPathParameters("domain", domain).build()), HttpStatus.OK);
+        }, customMetrics::incrementNumUnsuccessfullyExposedRelationshipTypes);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_entity_by_id_seconds")
+    public ResponseEntity<Object> getTopologyById(@NotNull final String accept, final String domain,
+            final String entityType, final String id) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            requestValidator.validateEntityType(entityType);
+            requestValidator.validateEntityTypeInDomain(entityType, domain);
+            return new ResponseEntity<>(dataService.getTopologyById(entityType, id), HttpStatus.OK);
+        }, customMetrics::incrementNumUnsuccessfullyExposedEntityById);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_entities_by_type_seconds")
+    public ResponseEntity<OranTeivEntitiesResponseMessage> getTopologyByEntityTypeName(@NotNull final String accept,
+            final String domain, final String entityType, @Valid final String targetFilter, @Valid final String scopeFilter,
+            @Min(0) @Valid final Integer offset, @Min(1) @Max(500) @Valid final Integer limit) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            requestValidator.validateEntityType(entityType);
+            requestValidator.validateEntityTypeInDomain(entityType, domain);
+            return ResponseEntity.ok(dataService.getTopologyByType(entityType, targetFilter, scopeFilter, PaginationDTO
+                    .builder().offset(offset).limit(limit).basePath(String.format("/domains/%s/entity-types/%s/entities",
+                            domain, entityType)).addPathParameters("domain", domain).addQueryParameters("targetFilter",
+                                    targetFilter).addQueryParameters("scopeFilter", scopeFilter).build()));
+        }, customMetrics::incrementNumUnsuccessfullyExposedEntitiesByType);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_entities_by_domain_seconds")
+    public ResponseEntity<OranTeivEntitiesResponseMessage> getEntitiesByDomain(@NotNull final String accept,
+            final String domain, @Valid final String targetFilter, @Valid final String scopeFilter,
+            @Min(0) @Valid final Integer offset, @Min(1) @Max(500) @Valid final Integer limit) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            return ResponseEntity.ok(dataService.getEntitiesByDomain(domain, targetFilter, scopeFilter, PaginationDTO
+                    .builder().offset(offset).limit(limit).basePath("/domains/" + domain + "/entities").addPathParameters(
+                            "domain", domain).addQueryParameters("targetFilter", targetFilter).addQueryParameters(
+                                    "scopeFilter", scopeFilter).build()));
+        }, customMetrics::incrementNumUnsuccessfullyExposedEntitiesByDomain);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_relationships_by_entity_id_seconds")
+    public ResponseEntity<OranTeivRelationshipsResponseMessage> getAllRelationshipsForEntityId(@NotNull final String accept,
+            final String domain, final String entityType, final String id, @Min(0) @Valid final Integer offset,
+            @Min(1) @Max(500) @Valid final Integer limit) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            requestValidator.validateEntityType(entityType);
+            requestValidator.validateEntityTypeInDomain(entityType, domain);
+            return ResponseEntity.ok(dataService.getAllRelationshipsForObjectId(entityType, id, PaginationDTO.builder()
+                    .offset(offset).limit(limit).basePath(String.format(
+                            "/domains/%s/entity-types/%s/entities/%s/relationships", domain, entityType, id))
+                    .addPathParameters("domain", domain).addPathParameters("entityType", entityType).addPathParameters("id",
+                            id).build()));
+        }, customMetrics::incrementNumUnsuccessfullyExposedAllRelationshipsByEntityId);
+    }
+
+    @Override
+    @Timed("ties_exposure_http_get_relationship_by_id_seconds")
+    public ResponseEntity<Object> getRelationshipById(final String accept, final String domain,
+            final String relationshipType, final String id) {
+        return runWithFailCheck(() -> {
+            requestValidator.validateDomain(domain);
+            requestValidator.validateRelationshipType(relationshipType);
+            requestValidator.validateRelationshipTypeInDomain(relationshipType, domain);
+            return ResponseEntity.ok(dataService.getRelationshipById(relationshipType, id));
+        }, customMetrics::incrementNumUnsuccessfullyExposedRelationshipById);
+    }
+
+    protected <T> T runWithFailCheck(final Supplier<T> supp, final Runnable runnable) {
+        try {
+            return supp.get();
+        } catch (Exception ex) {
+            log.error("Exception during service call", ex);
+            runnable.run();
+            throw ex;
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/decorators/rest/controller/DecoratorsRestController.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/decorators/rest/controller/DecoratorsRestController.java
new file mode 100644
index 0000000..df158f5
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/decorators/rest/controller/DecoratorsRestController.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.decorators.rest.controller;
+
+import org.oran.smo.teiv.api.DecoratorsApi;
+import org.oran.smo.teiv.utils.TiesConstants;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(TiesConstants.REQUEST_MAPPING)
+public class DecoratorsRestController implements DecoratorsApi {
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/exception/ApplicationExceptionHandler.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/exception/ApplicationExceptionHandler.java
new file mode 100644
index 0000000..b2486c7
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/exception/ApplicationExceptionHandler.java
@@ -0,0 +1,94 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.exception;
+
+import org.oran.smo.teiv.api.model.OranTeivErrorMessage;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+import jakarta.validation.ConstraintViolationException;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
+
+@Slf4j
+@ControllerAdvice
+public class ApplicationExceptionHandler extends ResponseEntityExceptionHandler {
+
+    @ResponseBody
+    @ExceptionHandler(TiesException.class)
+    public ResponseEntity<OranTeivErrorMessage> handleTiesException(final TiesException exception) {
+        if (exception.getException() != null) {
+            log.error(exception.getMessage(), exception.getException());
+        }
+        return new ResponseEntity<>(new OranTeivErrorMessage().message(exception.getMessage()).details(exception
+                .getDetails()).status(exception.getStatus().name()), exception.getStatus());
+    }
+
+    @ResponseBody
+    @ExceptionHandler(TiesPathException.class)
+    public ResponseEntity<Object> handleTiesPathException(final TiesPathException exception) {
+        if (exception.getResponse() != null) {
+            return new ResponseEntity<>(exception.getResponse(), HttpStatus.OK);
+        } else {
+            return new ResponseEntity<>(new OranTeivErrorMessage().message(exception.getMessage()).details(exception
+                    .getDetails()).status(exception.getHttpStatus().name()), exception.getHttpStatus());
+        }
+    }
+
+    @ResponseBody
+    @ExceptionHandler(Exception.class)
+    protected ResponseEntity<OranTeivErrorMessage> handleGeneralException(final Exception ex) {
+        log.error("Handling general exception", ex);
+        return new ResponseEntity<>(new OranTeivErrorMessage().status(HttpStatus.INTERNAL_SERVER_ERROR.name()),
+                HttpStatus.INTERNAL_SERVER_ERROR);
+    }
+
+    @ResponseBody
+    @ExceptionHandler(ConstraintViolationException.class)
+    public ResponseEntity<OranTeivErrorMessage> handleConstraintViolationException(ConstraintViolationException exception) {
+        return new ResponseEntity<>(new OranTeivErrorMessage().message(exception.getMessage()).status(HttpStatus.BAD_REQUEST
+                .name()), HttpStatus.BAD_REQUEST);
+    }
+
+    @Override
+    protected ResponseEntity<Object> handleNoResourceFoundException(NoResourceFoundException exception, HttpHeaders headers,
+            HttpStatusCode status, WebRequest request) {
+        return new ResponseEntity<>(new OranTeivErrorMessage().message(exception.getMessage()).status(HttpStatus.BAD_REQUEST
+                .name()), HttpStatus.BAD_REQUEST);
+    }
+
+    @Override
+    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException exception,
+            HttpHeaders headers, HttpStatusCode status, WebRequest request) {
+        return new ResponseEntity<>(new OranTeivErrorMessage().message(exception.getMessage()).status(HttpStatus.BAD_REQUEST
+                .name()), HttpStatus.BAD_REQUEST);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/geography/rest/controller/GeoQueryRestController.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/geography/rest/controller/GeoQueryRestController.java
new file mode 100644
index 0000000..6e6426c
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/geography/rest/controller/GeoQueryRestController.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.geography.rest.controller;
+
+import org.oran.smo.teiv.api.GeoQueryApi;
+import org.oran.smo.teiv.utils.TiesConstants;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(TiesConstants.REQUEST_MAPPING)
+public class GeoQueryRestController implements GeoQueryApi {
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/model/api/ModelSchemaService.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/model/api/ModelSchemaService.java
new file mode 100644
index 0000000..416d19b
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/model/api/ModelSchemaService.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.model.api;
+
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.api.model.OranTeivSchemaList;
+import org.springframework.web.multipart.MultipartFile;
+
+public interface ModelSchemaService {
+
+    /**
+     * Create schema.
+     *
+     * @param yangFile
+     *     the yang content
+     */
+    void createSchema(final MultipartFile yangFile);
+
+    /**
+     * Get all schemas extracted from yang models
+     *
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a map of all schemas
+     */
+    OranTeivSchemaList getSchemas(final PaginationDTO paginationDTO);
+
+    /**
+     * Get all schemas in a domain
+     *
+     * @param domain
+     *     domain name
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a map of all schemas in a domain
+     */
+    OranTeivSchemaList getSchemasInDomain(final String domain, final PaginationDTO paginationDTO);
+
+    /**
+     * Get a yang schema name
+     *
+     * @param schema
+     *     schema name
+     *
+     * @return a schema in a string format
+     */
+    String getSchemaByName(final String schema);
+
+    /**
+     * Delete schema.
+     *
+     * @param name
+     *     the schema name
+     */
+    void deleteSchema(final String name);
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/model/api/impl/ModelSchemaServiceImpl.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/model/api/impl/ModelSchemaServiceImpl.java
new file mode 100644
index 0000000..b43a85f
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/model/api/impl/ModelSchemaServiceImpl.java
@@ -0,0 +1,117 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.model.api.impl;
+
+import org.oran.smo.teiv.api.model.OranTeivHref;
+import org.oran.smo.teiv.api.model.OranTeivSchema;
+import org.oran.smo.teiv.api.model.OranTeivSchemaList;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.spi.DataPersistanceService;
+import org.oran.smo.teiv.exposure.spi.impl.StoredSchema;
+import org.oran.smo.teiv.exposure.spi.mapper.PageMetaData;
+import org.oran.smo.teiv.exposure.model.api.ModelSchemaService;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.*;
+
+import static org.oran.smo.teiv.utils.TiesConstants.IN_USAGE;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ModelSchemaServiceImpl implements ModelSchemaService {
+
+    private final DataPersistanceService dataPersistanceService;
+
+    @Override
+    public void createSchema(MultipartFile yangFile) {
+        log.trace("yang file: {}", yangFile);
+    }
+
+    @Override
+    public OranTeivSchemaList getSchemas(final PaginationDTO paginationDTO) {
+        return getSchemaListResponseMessage(dataPersistanceService.getSchemas(paginationDTO));
+    }
+
+    @Override
+    public OranTeivSchemaList getSchemasInDomain(final String domainName, final PaginationDTO paginationDTO) {
+        return getSchemaListResponseMessage(dataPersistanceService.getSchemas(domainName, paginationDTO));
+    }
+
+    @Override
+    public String getSchemaByName(final String schemaName) {
+        final StoredSchema schema = dataPersistanceService.getSchema(schemaName);
+        if (schema == null || !schema.getStatus().equals(IN_USAGE)) {
+            throw TiesException.invalidSchema(schemaName);
+        }
+        return schema.getContent();
+    }
+
+    @Override
+    public void deleteSchema(String name) {
+        final StoredSchema schema = dataPersistanceService.getSchema(name);
+        if (schema == null) {
+            throw TiesException.invalidSchema(name);
+        }
+        if (schema.getOwnerAppId().equals("BUILT_IN_MODULE")) {
+            throw TiesException.schemaNotOwned(name);
+        }
+        dataPersistanceService.setSchemaToDeleting(name);
+    }
+
+    private OranTeivSchemaList getSchemaListResponseMessage(Map<String, Object> response) {
+        OranTeivSchemaList result = new OranTeivSchemaList();
+        List<OranTeivSchema> items = (List<OranTeivSchema>) response.get("items");
+        PageMetaData self = (PageMetaData) response.get("self");
+        PageMetaData first = (PageMetaData) response.get("first");
+        PageMetaData prev = (PageMetaData) response.get("prev");
+        PageMetaData next = (PageMetaData) response.get("next");
+        PageMetaData last = (PageMetaData) response.get("last");
+        Integer totalCount = (Integer) response.get("totalCount");
+
+        result.setItems(items);
+
+        OranTeivHref selfHref = new OranTeivHref();
+        OranTeivHref firstHref = new OranTeivHref();
+        OranTeivHref prevHref = new OranTeivHref();
+        OranTeivHref nextHref = new OranTeivHref();
+        OranTeivHref lastHref = new OranTeivHref();
+
+        selfHref.setHref(self.getHref());
+        firstHref.setHref(first.getHref());
+        prevHref.setHref(prev.getHref());
+        nextHref.setHref(next.getHref());
+        lastHref.setHref(last.getHref());
+
+        result.setSelf(selfHref);
+        result.setFirst(firstHref);
+        result.setPrev(prevHref);
+        result.setNext(nextHref);
+        result.setLast(lastHref);
+        result.setTotalCount(totalCount);
+        return result;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/model/rest/controller/ModelSchemaRestController.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/model/rest/controller/ModelSchemaRestController.java
new file mode 100644
index 0000000..ffd2e9e
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/model/rest/controller/ModelSchemaRestController.java
@@ -0,0 +1,85 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.model.rest.controller;
+
+import org.oran.smo.teiv.api.SchemasApi;
+import org.oran.smo.teiv.api.model.OranTeivSchemaList;
+import org.oran.smo.teiv.exposure.model.api.ModelSchemaService;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.utils.TiesConstants;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotNull;
+import java.util.Objects;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@RequestMapping(TiesConstants.REQUEST_MAPPING)
+@RequiredArgsConstructor
+public class ModelSchemaRestController implements SchemasApi {
+
+    private final ModelSchemaService modelSchemaService;
+
+    @Override
+    public ResponseEntity<Void> createSchema(String accept, String contentType, MultipartFile file) {
+        modelSchemaService.createSchema(file);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+
+    /**
+     * Return a list of all schemas/schemas filtered by domain extracted from yang models
+     */
+    @Override
+    public ResponseEntity<OranTeivSchemaList> getSchemas(@NotNull final String accept, @Valid final String domain,
+            @Min(0) @Valid final Integer offset, @Min(1) @Max(500) @Valid final Integer limit) {
+        final PaginationDTO.PaginationDTOBuilder builder = PaginationDTO.builder().offset(offset).limit(limit);
+        if (Objects.isNull(domain)) {
+            return new ResponseEntity<>(modelSchemaService.getSchemas(builder.basePath("/schemas").build()), HttpStatus.OK);
+        } else {
+            return new ResponseEntity<>(modelSchemaService.getSchemasInDomain(domain, builder.basePath("/schemas")
+                    .addPathParameters("domain", domain).build()), HttpStatus.OK);
+        }
+    }
+
+    /**
+     * Return a schema by schema name
+     */
+    @Override
+    @SneakyThrows
+    public ResponseEntity<String> getSchemaByName(@NotNull final String accept, final String schemaName) {
+        final String module = modelSchemaService.getSchemaByName(schemaName);
+        return new ResponseEntity<>(module, HttpStatus.OK);
+    }
+
+    @Override
+    public ResponseEntity<Void> deleteSchema(String accept, String schemaName) {
+        modelSchemaService.deleteSchema(schemaName);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/DataPersistanceService.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/DataPersistanceService.java
new file mode 100644
index 0000000..df347dd
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/DataPersistanceService.java
@@ -0,0 +1,197 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.oran.smo.teiv.exposure.spi.impl.StoredSchema;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.schema.DataType;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+
+public interface DataPersistanceService {
+    /**
+     * Gets topology.
+     *
+     * @param entityType
+     *     the entityType
+     * @param id
+     *     the id
+     *
+     * @return the topology
+     */
+    Map<String, Object> getTopology(EntityType entityType, String id);
+
+    /**
+     * Gets topology by type.
+     *
+     * @param entityName
+     *     type of entity, e.g. NrCellDU
+     * @param targetFilter
+     *     specifies the entity type and attributes to be returned in the REST response
+     * @param scopeFilter
+     *     specifies the attributes to match on
+     * @param relationshipsFilter
+     *     specifies the relationships to match on
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return the all entities of type that match the filter criteria
+     */
+    Map<String, Object> getTopologyByType(final String entityName, final String targetFilter, final String scopeFilter,
+            final PaginationDTO paginationDTO);
+
+    /**
+     * Gets all relationships for objectType with specified id.
+     *
+     * @param entityType
+     *     the entity type
+     * @param relationTypes
+     *     the relation type
+     * @param id
+     *     the id
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return the all relationships
+     */
+    Map<String, Object> getAllRelationships(final EntityType entityType, final List<RelationType> relationTypes,
+            final String id, final PaginationDTO paginationDTO);
+
+    /**
+     * Gets relationship by id
+     *
+     * @param id
+     *     the relationType id
+     * @param relationType
+     *     the relationType
+     *
+     * @return relationship
+     */
+    Map<String, Object> getRelationshipWithSpecifiedId(final String id, final RelationType relationType);
+
+    /**
+     * Gets relationships for given edge.
+     *
+     * @param relationType
+     *     represents the actual relationship type
+     * @param scopeFilter
+     *     for filtering
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return filtered relationships by given relationship type
+     */
+    Map<String, Object> getRelationshipsByType(final RelationType relationType, final String scopeFilter,
+            final PaginationDTO paginationDTO);
+
+    /**
+     * Get topology entities by domain, using specified targetFilter as mandatory query parameter
+     *
+     * @param domain
+     *     specifies the domain
+     * @param targetFilter
+     *     specifies the entity type and attributes to be returned in the REST response
+     * @param scopeFilter
+     *     specifies the attributes to match on
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return the all entities of type that match the filter criteria
+     */
+    Map<String, Object> getEntitiesByDomain(final String domain, final String targetFilter, final String scopeFilter,
+            final PaginationDTO paginationDTO);
+
+    /**
+     * Load classifiers set.
+     *
+     * @return the classifiers
+     */
+    Set<String> loadClassifiers();
+
+    /**
+     * Load decorators map.
+     *
+     * @return the decorators
+     */
+    Map<String, DataType> loadDecorators();
+
+    /**
+     * Gets schemas.
+     *
+     * @param paginationDTO
+     *     the pagination dto
+     * @return the schemas
+     */
+    Map<String, Object> getSchemas(final PaginationDTO paginationDTO);
+
+    /**
+     * Gets schemas.
+     *
+     * @param domain
+     *     the domain
+     * @param paginationDTO
+     *     the pagination dto
+     * @return the schemas
+     */
+    Map<String, Object> getSchemas(final String domain, final PaginationDTO paginationDTO);
+
+    /**
+     * Gets schema.
+     *
+     * @param name
+     *     the name
+     * @return the schema
+     */
+    StoredSchema getSchema(final String name);
+
+    /**
+     * Post schema.
+     *
+     * @param name
+     *     the name
+     * @param namespace
+     *     the namespace
+     * @param domain
+     *     the domain
+     * @param includedModules
+     *     the included modules
+     * @param content
+     *     the content
+     * @param ownerAppId
+     *     the owner App id
+     */
+    void postSchema(final String name, final String namespace, final String domain, final List<String> includedModules,
+            final String content, final String ownerAppId);
+
+    /**
+     * Sets schema to deleting.
+     */
+    void setSchemaToDeleting(final String name);
+
+    /**
+     * Delete schema.
+     */
+    void deleteSchema(final String name);
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/RelationMappedRecordsDTO.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/RelationMappedRecordsDTO.java
new file mode 100644
index 0000000..4f7a8bc
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/RelationMappedRecordsDTO.java
@@ -0,0 +1,34 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi;
+
+import org.jooq.Record;
+
+import org.oran.smo.teiv.schema.RelationType;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class RelationMappedRecordsDTO {
+    RelationType relationType;
+    Record record;
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/impl/DataPersistanceServiceImpl.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/impl/DataPersistanceServiceImpl.java
new file mode 100644
index 0000000..1ee5811
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/impl/DataPersistanceServiceImpl.java
@@ -0,0 +1,289 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.impl;
+
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getModelledName;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.RELATION;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_MODEL;
+import static org.jooq.impl.DSL.exists;
+import static org.jooq.impl.DSL.field;
+import static org.jooq.impl.DSL.select;
+import static org.jooq.impl.DSL.table;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.oran.smo.teiv.schema.DataType;
+import org.oran.smo.teiv.utils.TiesConstants;
+import org.jooq.DSLContext;
+import org.jooq.JSONB;
+import org.jooq.Record;
+import org.jooq.Record1;
+import org.jooq.Result;
+import org.jooq.ResultQuery;
+import org.jooq.tools.json.JSONArray;
+import org.jooq.SelectConditionStep;
+import org.springframework.stereotype.Service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.spi.DataPersistanceService;
+import org.oran.smo.teiv.exposure.spi.RelationMappedRecordsDTO;
+import org.oran.smo.teiv.exposure.spi.mapper.MapperUtility;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.utils.query.QueryMonad;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DataPersistanceServiceImpl implements DataPersistanceService {
+
+    private final DSLContext readDataDslContext;
+    private final DSLContext writeDataDslContext;
+    private final MapperUtility mapperUtility;
+
+    @Override
+    public Map<String, Object> getTopology(final EntityType entityType, final String eiId) {
+        return runMethodSafe(() -> {
+            final Result<Record> result = readDataDslContext.select(entityType.getAllFieldsWithId()).from(entityType
+                    .getTableName()).where(field(ID_COLUMN_NAME).eq(eiId)).fetch();
+            if (result.isEmpty()) {
+                throw TiesException.resourceNotFoundException();
+            }
+            return mapperUtility.mapEntity(entityType, result);
+        });
+    }
+
+    @Override
+    public Map<String, Object> getTopologyByType(final String entityType, final String target, final String scope,
+            final PaginationDTO paginationDTO) {
+        final QueryMonad queryMonad = QueryMonad.builder().managedObject(entityType).targets(target).scope(scope).build();
+        final ResultQuery<Record1<Integer>> queryCount = queryMonad.countWithSchema().apply(readDataDslContext);
+        paginationDTO.setTotalSize(runMethodSafe(() -> (int) queryCount.fetch().get(0).getValue(0)));
+        final ResultQuery<Record> query = queryMonad.withSchema(paginationDTO).apply(readDataDslContext);
+        log.trace("SQL ::  " + query.getSQL());
+        return runMethodSafe(() -> mapperUtility.mapComplexQuery(query.fetch(), paginationDTO));
+    }
+
+    @Override
+    public Map<String, Object> getAllRelationships(final EntityType entityType, final List<RelationType> relationTypes,
+            final String id, final PaginationDTO paginationDTO) {
+        List<RelationMappedRecordsDTO> relationMappedRecordsDTOS = new ArrayList<>();
+        int resultSize = 0;
+
+        for (RelationType relationType : relationTypes) {
+            String columnNameToFindBy;
+            String columnNameToCheckIfNull;
+
+            if (relationType.getASide().equals(entityType)) {
+                columnNameToFindBy = relationType.aSideColumnName();
+                columnNameToCheckIfNull = relationType.bSideColumnName();
+            } else {
+                columnNameToFindBy = relationType.bSideColumnName();
+                columnNameToCheckIfNull = relationType.aSideColumnName();
+            }
+
+            Result<Record> result = runMethodSafe(() -> readDataDslContext.select(relationType.getBaseFieldsWithId()).from(
+                    table(relationType.getTableName())).where(field(String.format(QUOTED_STRING, columnNameToFindBy)).eq(id)
+                            .and(field(String.format(QUOTED_STRING, columnNameToCheckIfNull)).isNotNull())).fetch());
+
+            if (result.isNotEmpty()) {
+                result.forEach(record -> relationMappedRecordsDTOS.add(RelationMappedRecordsDTO.builder().relationType(
+                        relationType).record(record).build()));
+                resultSize += result.size();
+            } else if (!checkIfEntityWithIdExists(entityType, id)) {
+                throw TiesException.resourceNotFoundException();
+
+            }
+
+        }
+
+        paginationDTO.setTotalSize(resultSize);
+        return mapperUtility.wrapRelationships(relationMappedRecordsDTOS, relationTypes, readDataDslContext, paginationDTO);
+    }
+
+    @Override
+    public Map<String, Object> getRelationshipWithSpecifiedId(final String id, final RelationType relationType) {
+        return runMethodSafe(() -> {
+            final Result<Record> result = readDataDslContext.select(relationType.getAllFieldsWithId()).from(table(
+                    relationType.getTableName())).where(field(String.format(QUOTED_STRING, relationType.getIdColumnName()))
+                            .eq(id)).fetch();
+            if (result.isEmpty()) {
+                throw TiesException.resourceNotFoundException();
+            }
+            return mapperUtility.mapRelationship(result, relationType);
+        });
+    }
+
+    @Override
+    public Map<String, Object> getRelationshipsByType(final RelationType relationType, final String scopeFilter,
+            final PaginationDTO paginationDTO) {
+        return runMethodSafe(() -> {
+            String attribute1;
+            String attribute2;
+            if (!relationType.getRelationshipStorageLocation().equals(RELATION)) {
+                attribute1 = relationType.getIdColumnName();
+                attribute2 = relationType.aSideColumnName().equals("id") ?
+                        relationType.bSideColumnName() :
+                        relationType.aSideColumnName();
+            } else {
+                attribute1 = relationType.aSideColumnName();
+                attribute2 = relationType.bSideColumnName();
+            }
+            final QueryMonad queryMonad = QueryMonad.builder().managedObject(relationType.getTableNameWithoutSchema())
+                    .targets(String.format("/id;/attributes(%s,%s)", getModelledName(attribute1), getModelledName(
+                            attribute2))).scope(scopeFilter).relationships(relationType.getName()).build();
+            final ResultQuery<Record1<Integer>> queryCount = queryMonad.countWithSchema().apply(readDataDslContext);
+            paginationDTO.setTotalSize(runMethodSafe(() -> (int) queryCount.fetch().get(0).getValue(0)));
+            final ResultQuery<Record> query = queryMonad.withSchema(paginationDTO).apply(readDataDslContext);
+            log.trace("SQL ::  " + query.getSQL());
+            return mapperUtility.wrapMapObject(mapperUtility.mapRelationships(query.fetch(), relationType), paginationDTO);
+        });
+    }
+
+    @Override
+    public Map<String, Object> getEntitiesByDomain(final String domain, final String targetFilter, final String scopeFilter,
+            final PaginationDTO paginationDTO) {
+        final QueryMonad queryMonad = QueryMonad.builder().managedObject(null).targets(targetFilter).scope(scopeFilter)
+                .domain(domain).build();
+        final ResultQuery<Record> query = queryMonad.withSchema(paginationDTO).apply(readDataDslContext);
+        final ResultQuery<Record1<Integer>> queryCount = queryMonad.countWithSchema().apply(readDataDslContext);
+        paginationDTO.setTotalSize(runMethodSafe(() -> (int) queryCount.fetch().get(0).getValue(0)));
+        log.trace("SQL ::  " + query.getSQL());
+        return runMethodSafe(() -> mapperUtility.mapComplexQuery(query.fetch(), paginationDTO));
+    }
+
+    @Override
+    public Set<String> loadClassifiers() {
+        SelectConditionStep<Record> availableClassifiers = runMethodSafe(() -> readDataDslContext.select().from(String
+                .format(TIES_MODEL, "classifiers")).join(String.format(TIES_MODEL, "module_reference")).on(field(
+                        "\"moduleReferenceName\"").eq(field(String.format(TIES_MODEL, "module_reference") + ".name")))
+                .where(field("status").like(TiesConstants.IN_USAGE)));
+        Set<String> result = new HashSet<>();
+        for (Record record : availableClassifiers) {
+            result.add((String) record.get("name"));
+        }
+        return result;
+    }
+
+    @Override
+    public Map<String, DataType> loadDecorators() {
+        SelectConditionStep<Record> availableDecorators = runMethodSafe(() -> readDataDslContext.select().from(String
+                .format(TIES_MODEL, "decorators")).join(String.format(TIES_MODEL, "module_reference")).on(field(
+                        "\"moduleReferenceName\"").eq(field(String.format(TIES_MODEL, "module_reference") + ".name")))
+                .where(field("status").like(TiesConstants.IN_USAGE)));
+        Map<String, DataType> result = new HashMap<>();
+        for (Record record : availableDecorators) {
+            result.put((String) record.get("name"), DataType.fromDbDataType("" + record.get("dataType")));
+        }
+        return result;
+    }
+
+    @Override
+    public Map<String, Object> getSchemas(PaginationDTO paginationDTO) {
+        final List<StoredSchema> schemas = runMethodSafe(() -> readDataDslContext.select().from(table(String.format(
+                TIES_MODEL, "module_reference"))).where(field("status").eq(TiesConstants.IN_USAGE)).fetchInto(
+                        StoredSchema.class));
+
+        return mapperUtility.wrapSchema(new ArrayList<>(schemas), paginationDTO);
+    }
+
+    @Override
+    public Map<String, Object> getSchemas(String domain, PaginationDTO paginationDTO) {
+        final List<StoredSchema> schemas = runMethodSafe(() -> readDataDslContext.select().from(table(String.format(
+                TIES_MODEL, "module_reference"))).where(field("status").eq(TiesConstants.IN_USAGE)).fetchInto(
+                        StoredSchema.class));
+
+        return mapperUtility.wrapSchema(schemas.stream().filter(s -> s.getDomain() != null && s.getDomain().matches(domain))
+                .toList(), paginationDTO);
+    }
+
+    @Override
+    public StoredSchema getSchema(String name) {
+        List<StoredSchema> schemas = readDataDslContext.select().from(table(String.format(TIES_MODEL, "module_reference")))
+                .where(field("name").eq(name)).fetchInto(StoredSchema.class);
+        if (schemas.isEmpty()) {
+            return null;
+        }
+
+        schemas.get(0).setContent(new String(Base64.getDecoder().decode(schemas.get(0).getContent()),
+                StandardCharsets.UTF_8));
+
+        return schemas.get(0);
+    }
+
+    @Override
+    public void postSchema(String name, String namespace, String domain, List<String> includedModules, String content,
+            String ownerAppId) {
+        writeDataDslContext.insertInto(table(String.format(TIES_MODEL, "module_reference"))).set(field("name"), name).set(
+                field("namespace"), namespace).set(field("domain"), domain).set(field("\"includedModules\""), JSONB.valueOf(
+                        JSONArray.toJSONString(includedModules))).set(field("content"), new String(Base64.getEncoder()
+                                .encode(content.replaceAll("\\r\\n?", "\n").getBytes(StandardCharsets.UTF_8)),
+                                StandardCharsets.UTF_8)).set(field("\"ownerAppId\""), ownerAppId).set(field("status"),
+                                        TiesConstants.IN_USAGE).execute();
+    }
+
+    @Override
+    public void setSchemaToDeleting(String name) {
+        writeDataDslContext.update(table(String.format(TIES_MODEL, "module_reference"))).set(field("status"), "DELETING")
+                .where(field("name").eq(name)).execute();
+    }
+
+    @Override
+    public void deleteSchema(String name) {
+        writeDataDslContext.deleteFrom(table(String.format(TIES_MODEL, "module_reference"))).where(field("name").eq(name))
+                .execute();
+    }
+
+    private boolean checkIfEntityWithIdExists(final EntityType entityType, final String id) {
+        return readDataDslContext.select(exists(select(field("1")).from(table(entityType.getTableName())).where(field(
+                ID_COLUMN_NAME).eq(id)))).fetch().get(0).value1();
+    }
+
+    protected <T> T runMethodSafe(Supplier<T> supp) {
+        try {
+            return supp.get();
+        } catch (TiesException ex) {
+            throw ex;
+        } catch (TiesPathException ex) {
+            log.error("Exception during query construction", ex);
+            throw ex;
+        } catch (Exception ex) {
+            log.error("Sql exception during query execution", ex);
+            throw TiesException.serverSQLException();
+        }
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/impl/StoredSchema.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/impl/StoredSchema.java
new file mode 100644
index 0000000..3d57139
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/impl/StoredSchema.java
@@ -0,0 +1,37 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.impl;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class StoredSchema {
+    private String name;
+    private String namespace;
+    private String domain;
+    private String revision;
+    private List<String> includedModules;
+    private String content;
+    private String ownerAppId;
+    private String status;
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/ComplexMapper.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/ComplexMapper.java
new file mode 100644
index 0000000..b4dac6d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/ComplexMapper.java
@@ -0,0 +1,102 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getModelledName;
+import static org.oran.smo.teiv.utils.TiesConstants.ATTRIBUTES;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Result;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.teiv.schema.SchemaRegistry;
+
+@RequiredArgsConstructor
+@Slf4j
+public class ComplexMapper extends ResponseMapper {
+
+    /**
+     * Maps the results of the queries created by the QueryModal to a REST response
+     *
+     * @param results
+     *     results of the query
+     * @return a map of the results
+     */
+    @Override
+    public Map<String, Object> map(Result<Record> results) {
+        final Map<String, List<Map<String, Object>>> response = new HashMap<>();
+        results.forEach(result -> {
+            Map<String, Object> record = new HashMap<>();
+            Map<String, Object> mappedRecords = new HashMap<>();
+            String currentObject = "";
+            String objectName = "";
+            for (Field field : result.fields()) {
+                String[] nameTokens = field.getName().split("\\.");
+                objectName = nameTokens[1].substring(1, nameTokens[1].length() - 1);
+
+                if (!currentObject.isEmpty() && !objectName.equals(currentObject)) {
+                    fillResult(currentObject, response, mappedRecords, record);
+                    mappedRecords.clear();
+                    record.clear();
+                }
+                fillRecord(nameTokens[2], record, mappedRecords, result, field);
+                currentObject = objectName;
+            }
+            fillResult(currentObject, response, mappedRecords, record);
+        });
+        return Collections.unmodifiableMap(response);
+    }
+
+    private void fillRecord(String nameToken, Map<String, Object> record, Map<String, Object> mappedRecords, Record result,
+            Field field) {
+        if (nameToken.replace("\"", "").equals(ID_COLUMN_NAME)) {
+            record.put(nameToken.replace("\"", ""), result.getValue(field));
+        } else {
+            mappedRecords.put(getModelledName(nameToken.replace("\"", "")), mapField(result, field));
+        }
+    }
+
+    private void fillResult(String currentObject, Map<String, List<Map<String, Object>>> response,
+            Map<String, Object> mappedRecords, Map<String, Object> record) {
+        if (!mappedRecords.values().stream().allMatch(Objects::isNull) || !record.values().stream().allMatch(
+                Objects::isNull)) {
+            String qualifiedName = SchemaRegistry.getEntityTypeByName(getModelledName(currentObject))
+                    .getFullyQualifiedName();
+            response.putIfAbsent(qualifiedName, new ArrayList<>());
+            if (!mappedRecords.values().stream().allMatch(Objects::isNull)) {
+                record.put(ATTRIBUTES, new HashMap<>(mappedRecords));
+            }
+            response.get(qualifiedName).add(new HashMap<>(record));
+        }
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/EntityMapper.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/EntityMapper.java
new file mode 100644
index 0000000..4e303db
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/EntityMapper.java
@@ -0,0 +1,70 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getModelledName;
+import static org.oran.smo.teiv.utils.TiesConstants.ATTRIBUTES;
+import static org.oran.smo.teiv.utils.TiesConstants.CONSUMER_DATA_PREFIX;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Record;
+import org.jooq.Result;
+
+import lombok.RequiredArgsConstructor;
+
+import org.oran.smo.teiv.schema.EntityType;
+
+@RequiredArgsConstructor
+public class EntityMapper extends ResponseMapper {
+
+    final EntityType entityType;
+
+    /**
+     * Maps the query results to an api response
+     *
+     * @param result
+     *     result of the query
+     * @return response
+     */
+    @Override
+    public Map<String, Object> map(final Result<Record> result) {
+        final Map<String, Object> responseData = new HashMap<>();
+        final Map<String, Object> mappedRecords = new HashMap<>();
+        result.forEach(record -> Arrays.stream(record.fields()).forEach(field -> {
+            if (getModelledName(field.getName()).equals(ID_COLUMN_NAME)) {
+                responseData.put(getModelledName(field.getName()), record.getValue(field));
+            } else if (getModelledName(field.getName()).startsWith(CONSUMER_DATA_PREFIX)) {
+                responseData.put(getModelledName(field.getName()).substring(CONSUMER_DATA_PREFIX.length()), mapField(record,
+                        field));
+            } else {
+                mappedRecords.put(getModelledName(field.getName()), mapField(record, field));
+            }
+        }));
+        responseData.put(ATTRIBUTES, mappedRecords);
+        return Map.of(entityType.getFullyQualifiedName(), List.of(responseData));
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/MapperUtility.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/MapperUtility.java
new file mode 100644
index 0000000..b044516
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/MapperUtility.java
@@ -0,0 +1,209 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.spi.impl.StoredSchema;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+
+import java.util.Collections;
+import java.util.stream.Collectors;
+import org.jooq.DSLContext;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.springframework.stereotype.Service;
+
+import org.oran.smo.teiv.exposure.spi.RelationMappedRecordsDTO;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class MapperUtility {
+
+    /**
+     * Maps the query results to an api response
+     *
+     * @param entityType
+     *     entityType
+     * @param result
+     *     result of the query
+     *
+     * @return response
+     */
+    public Map<String, Object> mapEntity(final EntityType entityType, final Result<Record> result) {
+        return new EntityMapper(entityType).map(result);
+    }
+
+    /**
+     * Maps all relationships
+     *
+     * @param result
+     * @param relationType
+     * @return all relationships
+     */
+    public Map<String, Object> mapRelationships(final Result<Record> result, final RelationType relationType) {
+        return new RelationshipsMapper(relationType).map(result);
+    }
+
+    /**
+     * Maps one relationship
+     *
+     * @param result
+     * @param relationType
+     * @return one relationship
+     */
+    public Map<String, Object> mapRelationship(final Result<Record> result, final RelationType relationType) {
+        return new RelationshipMapper(relationType).map(result);
+    }
+
+    /**
+     * Maps the results of the queries created by the QueryModal to a REST response
+     *
+     * @param results
+     *     results of the query
+     * @param paginationDTO
+     *     pagination data
+     *
+     * @return a map of the results
+     */
+    public Map<String, Object> mapComplexQuery(final Result<Record> results, final PaginationDTO paginationDTO) {
+        return wrapResponse(results, new ComplexMapper(), paginationDTO);
+    }
+
+    public Map<String, Object> wrapMapObject(final Map<String, Object> results, final PaginationDTO paginationDTO) {
+
+        validateOffset(paginationDTO);
+
+        Map<String, Object> response = new HashMap<>();
+        response.put("items", List.of(results));
+
+        PaginationMetaData paginationMetaData = new PaginationMetaData();
+        response.putAll(paginationMetaData.getObjectList(paginationDTO));
+
+        response.put("query", queryPart(paginationDTO));
+        return response;
+    }
+
+    public Map<String, Object> wrapList(final List<Object> objectsList, final PaginationDTO paginationDTO) {
+        Map<String, Object> response = new HashMap<>();
+        paginationDTO.setTotalSize(objectsList.size());
+
+        if (objectsList.size() <= paginationDTO.getOffset() && !objectsList.isEmpty()) {
+            throw TiesException.invalidValueException("Offset", objectsList.size() - 1, true);
+        } else {
+            response.put("items", objectsList.subList(paginationDTO.getOffset(), Math.min(paginationDTO
+                    .getOffset() + paginationDTO.getLimit(), objectsList.size())));
+        }
+
+        PaginationMetaData paginationMetaData = new PaginationMetaData();
+        response.putAll(paginationMetaData.getObjectList(paginationDTO));
+
+        return response;
+    }
+
+    public Map<String, Object> wrapSchema(final List<StoredSchema> schemaList, final PaginationDTO paginationDTO) {
+        List<Map<String, Object>> response = new ArrayList<>();
+
+        for (StoredSchema schema : schemaList) {
+            Map<String, Object> innerResponse = new HashMap<>();
+            innerResponse.put("name", schema.getName());
+            innerResponse.put("domain", schema.getDomain() == null ?
+                    Collections.emptyList() :
+                    Collections.singletonList(schema.getDomain()));
+            innerResponse.put("revision", schema.getRevision());
+            innerResponse.put("content", Collections.singletonMap("href", "/schemas/" + schema.getName() + "/content"));
+            response.add(innerResponse);
+        }
+
+        return wrapList(new ArrayList<>(response), paginationDTO);
+    }
+
+    private Map<String, Object> wrapResponse(final Result<Record> results, final ResponseMapper responseMapper,
+            final PaginationDTO paginationDTO) {
+        validateOffset(paginationDTO);
+
+        Map<String, Object> response = new HashMap<>();
+        response.put("items", List.of(responseMapper.map(results)));
+
+        PaginationMetaData paginationMetaData = new PaginationMetaData();
+        response.putAll(paginationMetaData.getObjectList(paginationDTO));
+
+        response.put("query", queryPart(paginationDTO));
+        return response;
+    }
+
+    private Map<String, Object> queryPart(final PaginationDTO paginationDTO) {
+        Map<String, Object> response = new HashMap<>();
+        response.putAll(paginationDTO.getPathParameters());
+        Map<String, String> notNullQueryParameters = paginationDTO.getQueryParameters().entrySet().stream().filter(
+                entry -> entry.getValue() != null).collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry
+                        .getValue()));
+        response.putAll(notNullQueryParameters);
+
+        return response;
+    }
+
+    public Map<String, Object> wrapRelationships(List<RelationMappedRecordsDTO> records, List<RelationType> relationTypes,
+            DSLContext readDataDslContext, final PaginationDTO paginationDTO) {
+        Map<String, Object> response = new HashMap<>();
+
+        if (paginationDTO.getTotalSize() <= paginationDTO.getOffset() && !records.isEmpty()) {
+            throw TiesException.invalidValueException("Offset", records.size() - 1, true);
+        } else {
+            //TODO: Refactor the logic since RelationMappedRecordsDTO already contains the relation type
+            List<RelationMappedRecordsDTO> pagedRecords = records.subList(paginationDTO.getOffset(), Math.min(paginationDTO
+                    .getOffset() + paginationDTO.getLimit(), records.size()));
+            Map<String, Result<Record>> batch = new HashMap<>();
+            for (RelationMappedRecordsDTO record : pagedRecords) {
+                RelationType relTypeForCurrentRecord = record.getRelationType();
+                if (!batch.containsKey(relTypeForCurrentRecord.getFullyQualifiedName())) {
+                    batch.put(relTypeForCurrentRecord.getFullyQualifiedName(), readDataDslContext.newResult());
+                }
+                batch.get(relTypeForCurrentRecord.getFullyQualifiedName()).add(record.getRecord());
+            }
+            List<Map<String, Object>> mappedResults = new ArrayList<>();
+            for (Map.Entry<String, Result<Record>> entry : batch.entrySet()) {
+                mappedResults.add(mapRelationships(entry.getValue(), relationTypes.stream().filter(relType -> relType
+                        .getFullyQualifiedName().equals(entry.getKey())).findFirst().orElseThrow()));
+            }
+            response.put("items", mappedResults);
+
+        }
+
+        PaginationMetaData paginationMetaData = new PaginationMetaData();
+        response.putAll(paginationMetaData.getObjectList(paginationDTO));
+
+        return response;
+    }
+
+    private void validateOffset(PaginationDTO paginationDTO) {
+        if (paginationDTO.getTotalSize() < paginationDTO.getOffset()) {
+            throw TiesException.invalidValueException("Offset", paginationDTO.getTotalSize() - 1, true);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/PageMetaData.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/PageMetaData.java
new file mode 100644
index 0000000..b0d6ca5
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/PageMetaData.java
@@ -0,0 +1,51 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import lombok.Getter;
+
+import java.util.Map;
+
+@Getter
+public class PageMetaData {
+
+    private final String href;
+
+    public PageMetaData(final PaginationDTO paginationDTO) {
+        this(paginationDTO.getOffset(), paginationDTO.getLimit(), paginationDTO);
+    }
+
+    public PageMetaData(final int offset, final PaginationDTO paginationDTO) {
+        this(offset, paginationDTO.getLimit(), paginationDTO);
+    }
+
+    public PageMetaData(final int offset, final int limit, final PaginationDTO paginationDTO) {
+        StringBuilder stringBuilder = new StringBuilder(paginationDTO.getBasePath() + String.format("?offset=%s&limit=%s",
+                offset, limit));
+        for (Map.Entry<String, String> entry : paginationDTO.getQueryParameters().entrySet()) {
+            if (entry.getValue() != null) {
+                stringBuilder.append("&").append(entry.getKey()).append("=").append(entry.getValue());
+            }
+        }
+        this.href = stringBuilder.toString();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/PaginationMetaData.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/PaginationMetaData.java
new file mode 100644
index 0000000..3a44586
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/PaginationMetaData.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class PaginationMetaData {
+
+    public Map<String, Object> getObjectList(final PaginationDTO paginationDTO) {
+        Map<String, Object> innerResponse = new HashMap<>();
+        PageMetaData self = new PageMetaData(paginationDTO);
+        innerResponse.put("self", self);
+
+        innerResponse.put("next", hasNextPage(paginationDTO) ?
+                new PageMetaData(Math.min(paginationDTO.getOffset() + paginationDTO.getLimit(), paginationDTO
+                        .getTotalSize()), paginationDTO) :
+                self);
+
+        innerResponse.put("last", hasNextPage(paginationDTO) ?
+                new PageMetaData(calculateLastPageOffset(paginationDTO), paginationDTO) :
+                self);
+
+        innerResponse.put("first", new PageMetaData(0, paginationDTO));
+
+        innerResponse.put("prev", hasPrevPage(paginationDTO) ?
+                new PageMetaData(Math.max(paginationDTO.getOffset() - paginationDTO.getLimit(), 0), paginationDTO) :
+                self);
+
+        innerResponse.put("totalCount", paginationDTO.getTotalSize());
+
+        return innerResponse;
+    }
+
+    private boolean hasNextPage(final PaginationDTO paginationDTO) {
+        return (paginationDTO.getOffset() + paginationDTO.getLimit()) < paginationDTO.getTotalSize() && paginationDTO
+                .getTotalSize() > 0;
+    }
+
+    private boolean hasPrevPage(final PaginationDTO paginationDTO) {
+        return paginationDTO.getOffset() > 0 && paginationDTO.getTotalSize() > 0;
+    }
+
+    private int calculateLastPageOffset(final PaginationDTO paginationDTO) {
+        int diff = paginationDTO.getTotalSize() - paginationDTO.getOffset();
+
+        if (diff % paginationDTO.getLimit() == 0) {
+            return (diff / paginationDTO.getLimit() - 1) * paginationDTO.getLimit() + paginationDTO.getOffset();
+        }
+
+        return (diff / paginationDTO.getLimit()) * paginationDTO.getLimit() + paginationDTO.getOffset();
+
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/QueryMetaData.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/QueryMetaData.java
new file mode 100644
index 0000000..92287a1
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/QueryMetaData.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import lombok.AllArgsConstructor;
+
+import static org.oran.smo.teiv.utils.TiesConstants.QUERY;
+import static org.oran.smo.teiv.utils.TiesConstants.SCOPE_FILTER;
+import static org.oran.smo.teiv.utils.TiesConstants.TARGET_FILTER;
+
+@AllArgsConstructor
+public class QueryMetaData {
+
+    private String targetFilter;
+    private String scopeFilter;
+
+    public Map<String, Object> getObjectList() {
+        Map<String, Object> response = new HashMap<>();
+        Map<String, Object> innerResponse = new HashMap<>();
+
+        boolean hasResponse = false;
+
+        if (!targetFilter.isEmpty()) {
+            innerResponse.put(TARGET_FILTER, targetFilter);
+            hasResponse = true;
+
+        }
+        if (!scopeFilter.isEmpty()) {
+            innerResponse.put(SCOPE_FILTER, scopeFilter);
+            hasResponse = true;
+        }
+        if (hasResponse) {
+            response.put(QUERY, innerResponse);
+        }
+        return response;
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipMapper.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipMapper.java
new file mode 100644
index 0000000..bfbe520
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipMapper.java
@@ -0,0 +1,44 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Record;
+import org.jooq.Result;
+
+import org.oran.smo.teiv.schema.RelationType;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public class RelationshipMapper extends ResponseMapper {
+    final RelationType relationType;
+
+    @Override
+    public Map<String, Object> map(final Result<Record> record) {
+        final Map<String, List<Object>> relationshipMap = new HashMap<>();
+        relationshipMap.put(relationType.getFullyQualifiedName(), List.of(createProperties(record.get(0), relationType)));
+        return Collections.unmodifiableMap(relationshipMap);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipsMapper.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipsMapper.java
new file mode 100644
index 0000000..9a6baf1
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipsMapper.java
@@ -0,0 +1,50 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Record;
+import org.jooq.Result;
+
+import org.oran.smo.teiv.schema.RelationType;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public class RelationshipsMapper extends ResponseMapper {
+
+    final RelationType relationType;
+
+    @Override
+    public Map<String, Object> map(final Result<Record> result) {
+        final Map<String, List<Object>> relationshipsMap = new HashMap<>();
+        final List<Object> relationships = new ArrayList<>();
+        result.stream().filter(record -> Arrays.stream(record.valuesRow().fields()).noneMatch(field -> field.getName()
+                .equals("null"))).forEach(record -> relationships.add(createProperties(record, relationType)));
+        relationshipsMap.put(relationType.getFullyQualifiedName(), relationships);
+        return Collections.unmodifiableMap(relationshipsMap);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/ResponseMapper.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/ResponseMapper.java
new file mode 100644
index 0000000..0316f8d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/spi/mapper/ResponseMapper.java
@@ -0,0 +1,72 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+import static org.oran.smo.teiv.utils.TiesConstants.PROPERTY_A_SIDE;
+import static org.oran.smo.teiv.utils.TiesConstants.PROPERTY_B_SIDE;
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.SOURCE_IDS;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Field;
+import org.jooq.JSONB;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.exception.DataTypeException;
+
+import org.oran.smo.teiv.schema.RelationType;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public abstract class ResponseMapper {
+    public abstract Map<String, Object> map(final Result<Record> result);
+
+    protected Map<String, Object> createProperties(final Record record, RelationType relationType) {
+        final Map<String, Object> dataMap = new HashMap<>();
+        dataMap.put(ID_COLUMN_NAME, String.valueOf(record.get(relationType.getTableName() + "." + String.format(
+                QUOTED_STRING, relationType.getIdColumnName()))));
+        dataMap.put(PROPERTY_A_SIDE, String.valueOf(record.get(relationType.getTableName() + "." + String.format(
+                QUOTED_STRING, relationType.aSideColumnName()))));
+        dataMap.put(PROPERTY_B_SIDE, String.valueOf(record.get(relationType.getTableName() + "." + String.format(
+                QUOTED_STRING, relationType.bSideColumnName()))));
+
+        Field<?> sourceIds = record.field(relationType.getTableName() + "." + String.format(QUOTED_STRING, relationType
+                .getSourceIdsColumnName()));
+        if (sourceIds != null) {
+            dataMap.put(SOURCE_IDS, mapField(record, sourceIds));
+        }
+
+        return dataMap;
+    }
+
+    protected Object mapField(Record record, org.jooq.Field<?> field) {
+        try {
+            return !field.getType().equals(JSONB.class) ? record.getValue(field) : record.get(field, Map.class);
+        } catch (DataTypeException e) {
+            log.trace("Mapped as list", e);
+            return record.get(field, List.class);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/AndLogicalBlock.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/AndLogicalBlock.java
new file mode 100644
index 0000000..2e6c9c5
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/AndLogicalBlock.java
@@ -0,0 +1,32 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import lombok.EqualsAndHashCode;
+import org.jooq.Condition;
+
+@EqualsAndHashCode(callSuper = true)
+public class AndLogicalBlock extends AndOrLogicalBlock {
+    @Override
+    public Condition getCondition() {
+        return children.get(0).getCondition().and(children.get(1).getCondition());
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/AndOrLogicalBlock.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/AndOrLogicalBlock.java
new file mode 100644
index 0000000..c68279c
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/AndOrLogicalBlock.java
@@ -0,0 +1,43 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.jooq.util.xml.jaxb.Table;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public abstract class AndOrLogicalBlock extends LogicalBlock {
+    protected List<LogicalBlock> children = new ArrayList<>();
+
+    public Set<Table> getTables() {
+        Set<Table> tables = new HashSet<>();
+        tables.addAll(children.get(0).getTables());
+        tables.addAll(children.get(1).getTables());
+        return tables;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ContainerType.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ContainerType.java
new file mode 100644
index 0000000..46de5ff
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ContainerType.java
@@ -0,0 +1,50 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import jakarta.annotation.Nullable;
+import lombok.Getter;
+
+@Getter
+public enum ContainerType {
+    ATTRIBUTES("attributes"),
+    DECORATORS("decorators"),
+    CLASSIFIERS("classifiers"),
+    ID("id"),
+    SOURCE_IDS("sourceIds"),
+    ASSOCIATION("association");
+
+    private final String value;
+
+    ContainerType(String value) {
+        this.value = value;
+    }
+
+    @Nullable
+    public static ContainerType fromValue(String value) {
+        for (ContainerType containerType : ContainerType.values()) {
+            if (containerType.getValue().equals(value)) {
+                return containerType;
+            }
+        }
+        return null;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/EmptyLogicalBlock.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/EmptyLogicalBlock.java
new file mode 100644
index 0000000..5ee9223
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/EmptyLogicalBlock.java
@@ -0,0 +1,50 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import java.util.Collections;
+import java.util.Set;
+import org.jooq.Condition;
+import org.jooq.util.xml.jaxb.Table;
+
+public class EmptyLogicalBlock extends LogicalBlock {
+    private static EmptyLogicalBlock emptyLogicalBlock = null;
+
+    private EmptyLogicalBlock() {
+    }
+
+    public static EmptyLogicalBlock getInstance() {
+        if (emptyLogicalBlock == null) {
+            emptyLogicalBlock = new EmptyLogicalBlock();
+        }
+        return emptyLogicalBlock;
+    }
+
+    @Override
+    public Condition getCondition() {
+        return null;
+    }
+
+    @Override
+    public Set<Table> getTables() {
+        return Collections.emptySet();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/FilterCriteria.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/FilterCriteria.java
new file mode 100644
index 0000000..56bb0ce
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/FilterCriteria.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.jooq.Condition;
+import org.jooq.SelectField;
+import org.jooq.util.xml.jaxb.Table;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Data
+@Slf4j
+public class FilterCriteria {
+    private final String domain;
+    private List<TargetObject> targets = new ArrayList<>();
+    private LogicalBlock scope;
+
+    public FilterCriteria(String domain) {
+        this.domain = domain;
+    }
+
+    public Condition getCondition() {
+        return scope.getCondition();
+    }
+
+    public Set<Table> getTables() {
+        Set<Table> tables = new HashSet<>();
+        tables.addAll(scope.getTables());
+
+        targets.forEach(t -> tables.add(getTablesFromTarget(t)));
+
+        return tables;
+    }
+
+    public Set<SelectField> getSelects() {
+        Set<SelectField> selectFields = new HashSet<>();
+
+        targets.forEach(t -> selectFields.add(getSelectFromTarget(t)));
+
+        return selectFields;
+    }
+
+    private SelectField getSelectFromTarget(TargetObject t) {
+        log.trace(t.toString());
+        return null;
+    }
+
+    @SuppressWarnings("squid:S4144")
+    private Table getTablesFromTarget(TargetObject t) {
+        log.trace(t.toString());
+        return null;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/LogicalBlock.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/LogicalBlock.java
new file mode 100644
index 0000000..b5154f7
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/LogicalBlock.java
@@ -0,0 +1,36 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import lombok.Data;
+import org.jooq.Condition;
+import org.jooq.util.xml.jaxb.Table;
+
+import java.util.Set;
+
+@Data
+public abstract class LogicalBlock {
+    private boolean isValid = true;
+
+    public abstract Condition getCondition();
+
+    public abstract Set<Table> getTables();
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/OrLogicalBlock.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/OrLogicalBlock.java
new file mode 100644
index 0000000..5cc7d57
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/OrLogicalBlock.java
@@ -0,0 +1,32 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import lombok.EqualsAndHashCode;
+import org.jooq.Condition;
+
+@EqualsAndHashCode(callSuper = true)
+public class OrLogicalBlock extends AndOrLogicalBlock {
+    @Override
+    public Condition getCondition() {
+        return children.get(0).getCondition().or(children.get(1).getCondition());
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/PathObject.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/PathObject.java
new file mode 100644
index 0000000..025e12d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/PathObject.java
@@ -0,0 +1,39 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import lombok.Data;
+
+@Data
+public class PathObject {
+    private String id;
+    private String topologyObject;
+    private TopologyObjectType topologyObjectType = TopologyObjectType.UNDEFINED;
+
+    public PathObject(String topologyObject) {
+        this(topologyObject, topologyObject);
+    }
+
+    public PathObject(String topologyObject, String id) {
+        this.topologyObject = topologyObject;
+        this.id = id;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/QueryFunction.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/QueryFunction.java
new file mode 100644
index 0000000..fee1f36
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/QueryFunction.java
@@ -0,0 +1,26 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+public enum QueryFunction {
+    EQ,
+    CONTAINS
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ScopeLogicalBlock.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ScopeLogicalBlock.java
new file mode 100644
index 0000000..373b858
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ScopeLogicalBlock.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import java.util.Collections;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+import org.jooq.Condition;
+import org.jooq.util.xml.jaxb.Table;
+
+import java.util.Set;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@RequiredArgsConstructor
+public class ScopeLogicalBlock extends LogicalBlock {
+    private final ScopeObject scopeObject;
+
+    @Override
+    public Condition getCondition() {
+        return null;
+    }
+
+    @Override
+    public Set<Table> getTables() {
+        return Collections.emptySet();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ScopeObject.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ScopeObject.java
new file mode 100644
index 0000000..f2a51f7
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/ScopeObject.java
@@ -0,0 +1,54 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import org.oran.smo.teiv.schema.DataType;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class ScopeObject {
+    private String topologyObject;
+    private TopologyObjectType topologyObjectType = TopologyObjectType.UNDEFINED;
+    private ContainerType container;
+    private List<String> innerContainer = new ArrayList<>(); // in first round it is not supported
+    private String leaf;
+    private QueryFunction queryFunction;
+    private String parameter;
+    private DataType dataType;
+
+    public ScopeObject(String topologyObject, ContainerType container, QueryFunction queryFunction, String parameter,
+            DataType dataType) {
+        this(topologyObject, container, null, queryFunction, parameter, dataType);
+    }
+
+    public ScopeObject(String topologyObject, ContainerType container, String leaf, QueryFunction queryFunction,
+            String parameter, DataType dataType) {
+        this.topologyObject = topologyObject;
+        this.container = container;
+        this.leaf = leaf;
+        this.queryFunction = queryFunction;
+        this.parameter = parameter;
+        this.dataType = dataType;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/TargetObject.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/TargetObject.java
new file mode 100644
index 0000000..815babb
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/TargetObject.java
@@ -0,0 +1,42 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder(builderMethodName = "hiddenBuilder")
+public class TargetObject {
+    private String topologyObject;
+    @Builder.Default
+    private TopologyObjectType topologyObjectType = TopologyObjectType.UNDEFINED;
+    @Builder.Default
+    private ContainerType container = ContainerType.ID;
+    @Builder.Default
+    private List<String> params = List.of();
+
+    public static TargetObjectBuilder builder(String topologyObject) {
+        return hiddenBuilder().topologyObject(topologyObject);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/TopologyObjectType.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/TopologyObjectType.java
new file mode 100644
index 0000000..535be61
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/TopologyObjectType.java
@@ -0,0 +1,27 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+public enum TopologyObjectType {
+    ENTITY,
+    RELATION,
+    UNDEFINED
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/BasePathRefinement.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/BasePathRefinement.java
new file mode 100644
index 0000000..755aca2
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/BasePathRefinement.java
@@ -0,0 +1,306 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.refiner;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.AndOrLogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ContainerType;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.EmptyLogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.FilterCriteria;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.LogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ScopeLogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ScopeObject;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.TopologyObjectType;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.TargetObject;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+
+import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.NotImplementedException;
+
+import static org.oran.smo.teiv.utils.TiesConstants.ITEMS;
+
+@UtilityClass
+@Slf4j
+public class BasePathRefinement {
+
+    @SuppressWarnings("squid:S4144")
+    public static void resolveWildCardObjectsInScopeAndTarget(FilterCriteria filterCriteria) {
+        // change every * to the possible topology object
+        // get the intersection of all possibilities to resolve the * (base set come from domain)
+        // there are topology objects in TO or SO-s we only can work with them
+        // there is no matching entity for the * throw error!
+        // on multiple match connect with OR
+        log.trace(filterCriteria.toString());
+        throw new NotImplementedException(filterCriteria.toString());
+    }
+
+    /**
+     * Resolve undefined topology object types to either relation or entity in scope and target.
+     * In case there is no match or multiple match error is thrown.
+     *
+     * @param filterCriteria
+     *     the filter criteria
+     */
+    public static void resolveUndefinedTopologyObjectTypes(FilterCriteria filterCriteria) {
+        resolveUndefinedObjectTypesInTarget(filterCriteria);
+        resolveUndefinedObjectTypesInScope(filterCriteria);
+    }
+
+    private static void resolveUndefinedObjectTypesInScope(FilterCriteria filterCriteria) {
+        runOnTree(filterCriteria.getScope(), filterCriteria.getDomain(),
+                BasePathRefinement::defineTopologyObjectTypeInScope);
+    }
+
+    private static void resolveUndefinedObjectTypesInTarget(FilterCriteria filterCriteria) {
+        filterCriteria.getTargets().stream().filter(targetObject -> targetObject.getTopologyObjectType().equals(
+                TopologyObjectType.UNDEFINED)).forEach(targetObject -> defineTopologyObjectTypeForTarget(targetObject,
+                        filterCriteria.getDomain()));
+    }
+
+    private static void defineTopologyObjectTypeInScope(ScopeLogicalBlock scopeLogicalBlock, String domain) {
+        if (scopeLogicalBlock.getScopeObject().getTopologyObjectType().equals(TopologyObjectType.UNDEFINED)) {
+            boolean isResolved = false;
+            if (SchemaRegistry.getEntityNamesByDomain(domain).contains(scopeLogicalBlock.getScopeObject()
+                    .getTopologyObject())) {
+                scopeLogicalBlock.getScopeObject().setTopologyObjectType(TopologyObjectType.ENTITY);
+                isResolved = true;
+            }
+            if (SchemaRegistry.getRelationNamesByDomain(domain).contains(scopeLogicalBlock.getScopeObject()
+                    .getTopologyObject())) {
+                if (!isResolved) {
+                    scopeLogicalBlock.getScopeObject().setTopologyObjectType(TopologyObjectType.RELATION);
+                    isResolved = true;
+                } else {
+                    throw TiesPathException.ambiguousTopologyObject(scopeLogicalBlock.getScopeObject().getTopologyObject());
+                }
+            }
+            if (!isResolved) {
+                throw TiesPathException.invalidTopologyObject(scopeLogicalBlock.getScopeObject().getTopologyObject());
+            }
+        }
+    }
+
+    private static void defineTopologyObjectTypeForTarget(TargetObject targetObject, String domain) {
+        boolean isResolved = false;
+        if (SchemaRegistry.getEntityNamesByDomain(domain).contains(targetObject.getTopologyObject())) {
+            targetObject.setTopologyObjectType(TopologyObjectType.ENTITY);
+            isResolved = true;
+        }
+        if (SchemaRegistry.getRelationNamesByDomain(domain).contains(targetObject.getTopologyObject())) {
+            if (!isResolved) {
+                targetObject.setTopologyObjectType(TopologyObjectType.RELATION);
+                isResolved = true;
+            } else {
+                throw TiesPathException.ambiguousTopologyObject(targetObject.getTopologyObject());
+            }
+        }
+        if (!isResolved) {
+            throw TiesPathException.invalidTopologyObject(targetObject.getTopologyObject());
+        }
+    }
+
+    /**
+     * Validates containers of targetObjects and scopeObjects through
+     * checking whether the topologyObject with the selected containerType has the parameters that are listed in either
+     * scopeObjects' leaf or targetObjects' params list.
+     *
+     * @param filterCriteria
+     *     the filter criteria
+     */
+    public static void validateContainers(FilterCriteria filterCriteria) {
+        filterCriteria.getTargets().stream().forEach(targetObject -> validateContainerWithMatchingParameters(targetObject
+                .getContainer(), targetObject.getParams(), targetObject.getTopologyObject(), targetObject
+                        .getTopologyObjectType(), Collections.emptyList()));
+        runOnTree(filterCriteria.getScope(), filterCriteria.getDomain(), BasePathRefinement::validateScope);
+    }
+
+    private static void validateScope(LogicalBlock logicalBlock, String domain) {
+        ScopeObject scopeObject = ((ScopeLogicalBlock) logicalBlock).getScopeObject();
+        validateContainerWithMatchingParameters(scopeObject.getContainer(), new ArrayList<>(Arrays.asList(scopeObject
+                .getLeaf())), scopeObject.getTopologyObject(), scopeObject.getTopologyObjectType(), scopeObject
+                        .getInnerContainer());
+    }
+
+    private static void validateContainerWithMatchingParameters(ContainerType containerType, List<String> params,
+            String topologyObject, TopologyObjectType topologyObjectType, List<String> innerContainer) {
+        switch (containerType) {
+            case ID:
+                if (!params.isEmpty()) {
+                    throw TiesPathException.grammarError("Adding parameters for id container is not supported");
+                }
+                break;
+            case ATTRIBUTES:
+                checkAttributesOfTopologyObject(params, topologyObject, topologyObjectType);
+                break;
+            case SOURCE_IDS:
+                checkSourceIdTopologyObject(params, topologyObject);
+                break;
+            case ASSOCIATION:
+                checkAssociationTopologyObject(params, topologyObject, topologyObjectType, innerContainer);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private static void checkAssociationTopologyObject(List<String> params, String topologyObject,
+            TopologyObjectType topologyObjectType, List<String> innerContainer) {
+        if (innerContainer.isEmpty()) {
+            throw TiesPathException.grammarError("Missing association name");
+        }
+        RelationType relation;
+        switch (topologyObjectType) {
+            case ENTITY:
+                relation = SchemaRegistry.getRelationTypes().stream().filter(relationType -> (relationType.getASide()
+                        .getName().equals(topologyObject) && relationType.getBSideAssociation().getName().equals(
+                                innerContainer.get(0))) || (relationType.getBSide().getName().equals(
+                                        topologyObject) && relationType.getASideAssociation().getName().equals(
+                                                innerContainer.get(0)))).findFirst().orElseThrow(() -> TiesPathException
+                                                        .invalidAssociation(topologyObject, innerContainer.get(0)));
+                break;
+            case RELATION:
+                relation = SchemaRegistry.getRelationTypeByName(topologyObject);
+                if (!relation.getASideAssociation().getName().equals(innerContainer.get(0)) && !relation
+                        .getBSideAssociation().getName().equals(innerContainer.get(0))) {
+                    throw TiesPathException.invalidAssociation(topologyObject, innerContainer.get(0));
+                }
+
+                break;
+            default:
+                throw TiesPathException.containerValidationWithUndefinedTopologyObjectType(topologyObject);
+        }
+        if (!params.isEmpty() && params.get(0) != null) {
+            checkParamsForAssociation(relation, innerContainer.get(0), params);
+        }
+    }
+
+    private static void checkParamsForAssociation(RelationType relationType, String associationName, List<String> params) {
+        if ((relationType.getASideAssociation().getName().equals(associationName) && !params.stream().allMatch(
+                param -> relationType.getASide().getFields().containsKey(param))) || (relationType.getBSideAssociation()
+                        .getName().equals(associationName) && !params.stream().allMatch(param -> relationType.getBSide()
+                                .getFields().containsKey(param)))) {
+            throw TiesPathException.invalidParamsForAssociation(associationName);
+        }
+    }
+
+    private static void checkSourceIdTopologyObject(List<String> params, String topologyObject) {
+        if (params.stream().anyMatch(param -> !param.equals(ITEMS))) {
+            throw TiesPathException.sourceIdNameError(topologyObject);
+        }
+    }
+
+    private static void checkAttributesOfTopologyObject(List<String> params, String topologyObject,
+            TopologyObjectType topologyObjectType) {
+        switch (topologyObjectType) {
+            case ENTITY:
+                EntityType entityType = SchemaRegistry.getEntityTypeByName(topologyObject);
+                List<String> notMatchingParams = params.stream().filter(a -> !entityType.getAttributeNames().contains(a))
+                        .toList();
+                if (!notMatchingParams.isEmpty()) {
+                    throw TiesPathException.columnNamesError(topologyObject, notMatchingParams);
+                }
+                break;
+            case RELATION:
+                RelationType relationType = SchemaRegistry.getRelationTypeByName(topologyObject);
+                List<String> notMatchingParams2 = params.stream().filter(a -> !relationType.getAttributes().containsKey(a))
+                        .toList();
+                if (!notMatchingParams2.isEmpty()) {
+                    throw TiesPathException.columnNamesError(topologyObject, notMatchingParams2);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    @SuppressWarnings("squid:S4144")
+    public static void validateScopeParametersDataType(FilterCriteria filterCriteria) {
+        // can parameter parse as the given type, check given data type and stored dataType
+        // throw error
+        log.trace(filterCriteria.toString());
+        throw new NotImplementedException(filterCriteria.toString());
+    }
+
+    //// End of syntax check
+
+    /**
+     * Check if target's topologyObjects match with scope's topologyObjects.
+     *
+     * @param filterCriteria
+     *
+     */
+    @SuppressWarnings("squid:S4144")
+    public static void checkIfTargetMatchesWithScope(FilterCriteria filterCriteria) {
+        if (filterCriteria.getScope() instanceof EmptyLogicalBlock || filterCriteria.getTargets().isEmpty()) {
+            return;
+        }
+
+        Set<String> scopeTopologyObjects = new HashSet<>();
+        runOnTree(filterCriteria.getScope(), filterCriteria.getDomain(), (ScopeLogicalBlock lb,
+                String domain) -> scopeTopologyObjects.add(lb.getScopeObject().getTopologyObject()));
+
+        Set<String> targetTopologyObjects = filterCriteria.getTargets().stream().map(TargetObject::getTopologyObject)
+                .collect(Collectors.toSet());
+
+        if (targetTopologyObjects.size() == scopeTopologyObjects.size()) {
+            scopeTopologyObjects.removeAll(targetTopologyObjects);
+            if (!scopeTopologyObjects.isEmpty()) {
+                throw TiesPathException.notMatchingScopeAndTargetFilter();
+            }
+        } else {
+            throw TiesPathException.notMatchingScopeAndTargetFilter();
+        }
+    }
+
+    @SuppressWarnings("squid:S4144")
+    public static boolean validateQuery(FilterCriteria filterCriteria) {
+        // remove invalid LB, when an AND block has an invalid LB set the AND block to invalid
+        // when an or has an invalid block, replace the OR block with the other child
+        // throw error when the last LB became invalid
+        log.trace(filterCriteria.toString());
+        throw new NotImplementedException(filterCriteria.toString());
+    }
+
+    public static void runOnTree(LogicalBlock logicalBlock, String domain, BiConsumer<ScopeLogicalBlock, String> func) {
+        if (!logicalBlock.isValid() || logicalBlock instanceof EmptyLogicalBlock) {
+            return;
+        }
+        if (logicalBlock instanceof AndOrLogicalBlock andOrLogicalBlock) {
+            andOrLogicalBlock.getChildren().forEach(l -> runOnTree(l, domain, func));
+            return;
+        }
+        func.accept((ScopeLogicalBlock) logicalBlock, domain);
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/PathToJooqRefinement.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/PathToJooqRefinement.java
new file mode 100644
index 0000000..19e5ef3
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/PathToJooqRefinement.java
@@ -0,0 +1,55 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.refiner;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.FilterCriteria;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.LogicalBlock;
+import lombok.experimental.UtilityClass;
+import org.apache.commons.lang3.NotImplementedException;
+import org.jooq.Condition;
+import org.jooq.SelectJoinStep;
+
+@UtilityClass
+public class PathToJooqRefinement {
+
+    /**
+     * Converts LogicalBlocks of InnerLanguageDTO to SelectJoinStep
+     *
+     * @param filterCriteria
+     *     the InnerLanguageDTO
+     * @return the select join step
+     */
+    public static SelectJoinStep toJooq(FilterCriteria filterCriteria) {
+        throw new NotImplementedException(filterCriteria.toString());
+    }
+
+    /**
+     * Converts LogicalBlock to JooQ query part
+     *
+     * @param logicalBlock
+     *     the LogicalBlock
+     * @return the condition
+     */
+    public static Condition logicalBlockToJooq(LogicalBlock logicalBlock) {
+        // convert LB to JOOQ condition recursive!
+        throw new NotImplementedException(logicalBlock.toString());
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/TiesPathQueryRefinement.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/TiesPathQueryRefinement.java
new file mode 100644
index 0000000..c1411fd
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/refiner/TiesPathQueryRefinement.java
@@ -0,0 +1,44 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.refiner;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.FilterCriteria;
+import org.oran.smo.teiv.utils.path.TiesPathQuery;
+import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.NotImplementedException;
+
+@UtilityClass
+@Slf4j
+public class TiesPathQueryRefinement {
+
+    /**
+     * Parses tiesPathQuery to innerLanguageDTO.
+     *
+     * @param tiesPathQuery
+     *     the ties path query
+     * @return the inner language dto
+     */
+    public static FilterCriteria parseTiesPathQuery(TiesPathQuery tiesPathQuery) {
+        log.trace(tiesPathQuery.toString());
+        throw new NotImplementedException();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/resolver/PathResolver.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/resolver/PathResolver.java
new file mode 100644
index 0000000..506656f
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/resolver/PathResolver.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.resolver;
+
+import java.util.List;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ContainerType;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+import jakarta.annotation.Nullable;
+import lombok.NonNull;
+
+public interface PathResolver<T> {
+
+    String NULL_ROOT_OBJECT = "*";
+
+    T resolve(String rootObject, @NonNull String filter);
+
+    default String getTopologyObject(String rootObject, List<String> containerNames) {
+        int noOfContainers = containerNames.size();
+        if (noOfContainers > 2) {
+            throw TiesPathException.grammarError("More than two level deep path is not allowed");
+        } else if (noOfContainers == 2) {
+            return getTopologyObjectWhenTwoContainers(rootObject, containerNames.get(0));
+        }
+        return isRootObjectNullOrEmpty(rootObject) ? NULL_ROOT_OBJECT : rootObject;
+    }
+
+    default String getTopologyObjectWhenTwoContainers(String rootObject, String firstContainer) {
+        if (isRootObjectNullOrEmpty(rootObject) || firstContainer.equals(rootObject)) {
+            return firstContainer;
+        } else {
+            throw TiesPathException.grammarError(
+                    "Target filter can only contain Root Object types mentioned in the path parameter");
+        }
+    }
+
+    default boolean isRootObjectNullOrEmpty(String rootObjectType) {
+        return rootObjectType == null || rootObjectType.isEmpty();
+    }
+
+    @Nullable
+    default ContainerType getContainerType(List<String> containerNames) {
+        return ContainerType.fromValue(containerNames.get(containerNames.size() - 1));
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/resolver/TargetResolver.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/resolver/TargetResolver.java
new file mode 100644
index 0000000..588599a
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/tiespath/resolver/TargetResolver.java
@@ -0,0 +1,109 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.resolver;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.TargetObject;
+import org.oran.smo.teiv.utils.path.TiesPathQuery;
+import org.oran.smo.teiv.utils.path.TiesPathUtil;
+import org.oran.smo.teiv.utils.path.exception.PathParsingException;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class TargetResolver implements PathResolver<List<TargetObject>> {
+
+    /**
+     * Process filter and root objectType . Populates List of Target Object
+     *
+     * @param rootObject
+     *     rootObject in the path parameter
+     * @param filter
+     *     filter in the query parameter
+     * @return Immutable list of filter objects
+     */
+    public List<TargetObject> resolve(String rootObject, @NonNull String filter) {
+        preCheck(filter);
+        if (filter.isEmpty()) {
+            final String topologyObject = isRootObjectNullOrEmpty(rootObject) ? NULL_ROOT_OBJECT : rootObject;
+            return List.of(TargetObject.builder(topologyObject).build());
+        } else {
+            List<TargetObject> targetObjects = new ArrayList<>();
+            Arrays.stream(filter.split(";")).forEach(targetToken -> {
+                final TiesPathQuery tiesPathQuery;
+                try {
+                    tiesPathQuery = TiesPathUtil.getTiesPathQuery(targetToken);
+                } catch (ParseCancellationException | PathParsingException e) {
+                    log.error("Parsing error on target {} :", targetToken, e);
+                    throw TiesPathException.grammarError(e.getMessage());
+                }
+
+                final int noOfContainers = tiesPathQuery.getContainerNames().size();
+                if (noOfContainers == 0) {
+                    //invalid scenario
+                    throw TiesException.serverException("Server unknown exception",
+                            "Requested query could not be processed", null);
+                }
+
+                Optional.ofNullable(getContainerType(tiesPathQuery.getContainerNames())).ifPresentOrElse(
+                        containerType -> targetObjects.add(TargetObject.builder(getTopologyObject(rootObject, tiesPathQuery
+                                .getContainerNames())).container(containerType).params(tiesPathQuery.getAttributeNames())
+                                .build()), () -> targetObjects.add(checkIfSingleContainerAndValidTopologyObject(rootObject,
+                                        tiesPathQuery.getContainerNames(), tiesPathQuery.getAttributeNames())));
+            });
+            return Collections.unmodifiableList(targetObjects);
+        }
+    }
+
+    private void preCheck(String target) {
+        if (target.contains("|")) {
+            throw TiesPathException.grammarError("OR (|) is not supported for target filter");
+        }
+    }
+
+    private TargetObject checkIfSingleContainerAndValidTopologyObject(String rootObject, List<String> containerNames,
+            List<String> attributeNames) {
+        final int noOfContainers = containerNames.size();
+        if (noOfContainers == 1 && (isRootObjectNullOrEmpty(rootObject) || rootObject.equals(containerNames.get(0)))) {
+            assertAttributesApplicableForContainer(attributeNames);
+            return TargetObject.builder(containerNames.get(0)).build();
+        }
+        throw TiesPathException.grammarError(
+                "Invalid Container name or Root Object name does not match to the path parameter");
+    }
+
+    private void assertAttributesApplicableForContainer(List<String> attrNames) {
+        if (!attrNames.isEmpty()) {
+            throw TiesPathException.grammarError("Attributes cannot be associated at this level");
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/utils/PaginationDTO.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/utils/PaginationDTO.java
new file mode 100644
index 0000000..22eff16
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/utils/PaginationDTO.java
@@ -0,0 +1,89 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.utils;
+
+import lombok.Data;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Data
+public class PaginationDTO {
+    private int limit;
+    private int offset;
+    private int totalSize;
+    private Map<String, String> queryParameters = new HashMap<>();
+    private Map<String, String> pathParameters = new HashMap<>();
+    private String basePath;
+
+    private PaginationDTO(int limit, int offset, Map<String, String> queryParameters, Map<String, String> pathParameters,
+            String basePath) {
+        this.limit = limit;
+        this.offset = offset;
+        this.queryParameters.putAll(queryParameters);
+        this.pathParameters.putAll(pathParameters);
+        this.basePath = basePath;
+    }
+
+    public static PaginationDTOBuilder builder() {
+        return new PaginationDTOBuilder();
+    }
+
+    public static class PaginationDTOBuilder {
+        private int limit;
+        private int offset;
+        private final Map<String, String> queryParameters = new HashMap<>();
+        private final Map<String, String> pathParameters = new HashMap<>();
+        private String basePath;
+
+        PaginationDTOBuilder() {
+        }
+
+        public PaginationDTOBuilder limit(int limit) {
+            this.limit = limit;
+            return this;
+        }
+
+        public PaginationDTOBuilder offset(int offset) {
+            this.offset = offset;
+            return this;
+        }
+
+        public PaginationDTOBuilder addQueryParameters(String key, String value) {
+            queryParameters.put(key, value);
+            return this;
+        }
+
+        public PaginationDTOBuilder addPathParameters(String key, String value) {
+            pathParameters.put(key, value);
+            return this;
+        }
+
+        public PaginationDTOBuilder basePath(String basePath) {
+            this.basePath = basePath;
+            return this;
+        }
+
+        public PaginationDTO build() {
+            return new PaginationDTO(limit, offset, queryParameters, pathParameters, basePath);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/exposure/utils/RequestValidator.java b/teiv/src/main/java/org/oran/smo/teiv/exposure/utils/RequestValidator.java
new file mode 100644
index 0000000..37f496b
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/exposure/utils/RequestValidator.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.utils;
+
+import org.springframework.stereotype.Service;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import lombok.RequiredArgsConstructor;
+
+@Service
+@RequiredArgsConstructor
+public class RequestValidator {
+
+    public void validateDomain(String domain) {
+        if (!SchemaRegistry.getDomains().contains(domain)) {
+            throw TiesException.unknownDomain(domain, SchemaRegistry.getDomains());
+        }
+    }
+
+    public void validateEntityType(String entityType) {
+        if (!SchemaRegistry.getEntityNames().contains(entityType)) {
+            throw TiesException.unknownEntityType(entityType, SchemaRegistry.getEntityNames());
+        }
+    }
+
+    public void validateEntityTypeInDomain(String entityType, String domain) {
+        if (!SchemaRegistry.getEntityNamesByDomain(domain).contains(entityType)) {
+            throw TiesException.unknownEntityTypeInDomain(entityType, domain, SchemaRegistry.getEntityNamesByDomain(
+                    domain));
+        }
+    }
+
+    public void validateRelationshipType(String relationShipType) {
+        if (!SchemaRegistry.getRelationNames().contains(relationShipType)) {
+            throw TiesException.unknownRelationshipType(relationShipType, SchemaRegistry.getRelationNames());
+        }
+    }
+
+    public void validateRelationshipTypeInDomain(String relationshipType, String domain) {
+        if (!SchemaRegistry.getRelationNamesByDomain(domain).contains(relationshipType)) {
+            throw TiesException.unknownRelationshipTypeInDomain(relationshipType, domain, SchemaRegistry
+                    .getRelationNamesByDomain(domain));
+        }
+    }
+
+    public void validateFiltersForRelationships(String targetFilter, String scopeFilter) {
+        if (targetFilter != null) {
+            throw TiesException.notImplementedException("Using targetFilter for this endpoint is not implemented.", null);
+        }
+        if (scopeFilter != null && scopeFilter.startsWith("/attributes")) {
+            throw TiesException.notImplementedException(
+                    "Using scopeFilter for filtering relationship attributes is not implemented.", null);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/ingestion/DeadlockRetryPolicy.java b/teiv/src/main/java/org/oran/smo/teiv/ingestion/DeadlockRetryPolicy.java
new file mode 100644
index 0000000..c103a83
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/ingestion/DeadlockRetryPolicy.java
@@ -0,0 +1,81 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.ingestion;
+
+import java.util.Map;
+
+import org.jooq.exception.DataAccessException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.retry.RetryContext;
+import org.springframework.retry.policy.SimpleRetryPolicy;
+import org.springframework.stereotype.Component;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class DeadlockRetryPolicy extends SimpleRetryPolicy {
+    public static final String POSTGRES_DEADLOCK_ERROR_CODE = "40P01";
+    static final long serialVersionUID = 1;
+
+    @Getter
+    @Value("${database.retry-policies.deadlock.retry-backoff-ms}")
+    private int retryBackoffMs;
+
+    public DeadlockRetryPolicy(@Value("${database.retry-policies.deadlock.retry-attempts}") int maxRetryAttemps) {
+        super(maxRetryAttemps, Map.of(DataAccessException.class, true));
+    }
+
+    @Override
+    public boolean canRetry(RetryContext context) {
+        Throwable lastThrowable = context.getLastThrowable();
+        if (lastThrowable instanceof DataAccessException) {
+            return isThrowableCausedByDeadlock(lastThrowable) && super.canRetry(context);
+        }
+        return super.canRetry(context);
+    }
+
+    @Override
+    public void close(RetryContext context) {
+        if (context.getRetryCount() == super.getMaxAttempts() && isThrowableCausedByDeadlock(context.getLastThrowable())) {
+            log.error("Reached the maximum number of retry attempts ({}) for a deadlock.", super.getMaxAttempts());
+        }
+        super.close(context);
+    }
+
+    @Override
+    public void registerThrowable(RetryContext context, Throwable throwable) {
+        super.registerThrowable(context, throwable);
+        if (isThrowableCausedByDeadlock(throwable)) {
+            log.warn("Deadlock occurred during the database transaction. Retry attempt: {}/{}. Cause: {}", context
+                    .getRetryCount(), super.getMaxAttempts(), throwable.getMessage());
+        }
+    }
+
+    private boolean isThrowableCausedByDeadlock(Throwable throwable) {
+        if (throwable instanceof DataAccessException) {
+            DataAccessException e = (DataAccessException) throwable;
+            return e.sqlState().equals(POSTGRES_DEADLOCK_ERROR_CODE);
+        }
+        return false;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidator.java b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidator.java
new file mode 100644
index 0000000..59766d2
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidator.java
@@ -0,0 +1,180 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.ingestion.validation;
+
+import static org.oran.smo.teiv.utils.TiesConstants.INFINITE_MAXIMUM_CARDINALITY;
+import java.util.List;
+
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
+public class IngestionOperationValidator {
+    enum MAXIMUM_CARDINALITY_CASE {
+        ONE_ONE,
+        ONE_CONST,
+        ONE_INFINITE,
+        CONST_ONE,
+        CONST_CONST,
+        CONST_INFINITE,
+        INFINITE_ONE,
+        INFINITE_CONST,
+        INFINITE_INFINITE
+    }
+
+    private final TiesDbServiceForValidation tiesDbServiceForValidation;
+
+    public void validate(ParsedCloudEventData parsedCloudEventData) throws MaximumCardinalityViolationException {
+        validateRelationshipMaximumCardinality(parsedCloudEventData.getRelationships());
+    }
+
+    private void validateRelationshipMaximumCardinality(List<Relationship> relationshipList)
+            throws MaximumCardinalityViolationException {
+        for (Relationship relationship : relationshipList) {
+            RelationType relationType = SchemaRegistry.getRelationTypeByName(relationship.getType());
+            long aSideMax = relationType.getASideAssociation().getMaxCardinality();
+            long bSideMax = relationType.getBSideAssociation().getMaxCardinality();
+            MAXIMUM_CARDINALITY_CASE cardinalityCase = determineMaxCardinalityCase(aSideMax, bSideMax);
+
+            boolean isValid = false;
+            switch (relationType.getRelationshipStorageLocation()) {
+                case RELATION:
+                    isValid = validateRelationshipInSeparateTable(cardinalityCase, relationType, relationship);
+                    break;
+                case A_SIDE:
+                    isValid = validateRelationshipInASideTable(cardinalityCase, relationType, relationship);
+                    break;
+                case B_SIDE:
+                    isValid = validateRelationshipInBSideTable(cardinalityCase, relationType, relationship);
+                    break;
+                default:
+                    throw new UnsupportedOperationException(String.format(
+                            "Unhandled relationship storage location case: %s. The relationship is invalid.",
+                            cardinalityCase));
+            }
+            if (isValid) {
+                log.debug("Relationship (id={}) is valid.", relationship.getId());
+            } else {
+                throw new MaximumCardinalityViolationException(String.format(
+                        "Maximum cardinality validation failed for relationship (id=%s).", relationship.getId()));
+            }
+        }
+    }
+
+    static MAXIMUM_CARDINALITY_CASE determineMaxCardinalityCase(long aSideMax, long bSideMax) {
+        validateMaxCardinalityArguments(aSideMax, bSideMax);
+        if (aSideMax == 1 && bSideMax == 1) {
+            return MAXIMUM_CARDINALITY_CASE.ONE_ONE;
+        } else if (aSideMax == 1 && bSideMax < INFINITE_MAXIMUM_CARDINALITY) {
+            return MAXIMUM_CARDINALITY_CASE.ONE_CONST;
+        } else if (aSideMax < INFINITE_MAXIMUM_CARDINALITY && bSideMax == 1) {
+            return MAXIMUM_CARDINALITY_CASE.CONST_ONE;
+        } else if (aSideMax == 1 && bSideMax >= INFINITE_MAXIMUM_CARDINALITY) {
+            return MAXIMUM_CARDINALITY_CASE.ONE_INFINITE;
+        } else if (aSideMax >= INFINITE_MAXIMUM_CARDINALITY && bSideMax == 1) {
+            return MAXIMUM_CARDINALITY_CASE.INFINITE_ONE;
+        } else if (aSideMax < INFINITE_MAXIMUM_CARDINALITY && bSideMax < INFINITE_MAXIMUM_CARDINALITY) {
+            return MAXIMUM_CARDINALITY_CASE.CONST_CONST;
+        } else if (aSideMax < INFINITE_MAXIMUM_CARDINALITY) {
+            return MAXIMUM_CARDINALITY_CASE.CONST_INFINITE;
+        } else if (bSideMax < INFINITE_MAXIMUM_CARDINALITY) {
+            return MAXIMUM_CARDINALITY_CASE.INFINITE_CONST;
+        } else {
+            return MAXIMUM_CARDINALITY_CASE.INFINITE_INFINITE;
+        }
+    }
+
+    private static void validateMaxCardinalityArguments(long aSideMax, long bSideMax) {
+        if (aSideMax <= 0 || bSideMax <= 0) {
+            throw new IllegalArgumentException(String.format("Invalid maximum cardinalities: aSideMax=%s, bSideMax=%s",
+                    aSideMax, bSideMax));
+        }
+    }
+
+    private boolean validateRelationshipInSeparateTable(MAXIMUM_CARDINALITY_CASE cardinalityCase, RelationType relationType,
+            Relationship relationship) {
+        switch (cardinalityCase) {
+            case INFINITE_INFINITE:
+                return true;
+            case ONE_ONE, ONE_CONST, CONST_ONE, CONST_CONST:
+                return validateASideCardinality(relationType, relationship) && validateBSideCardinality(relationType,
+                        relationship);
+            case ONE_INFINITE, CONST_INFINITE:
+                return validateASideCardinality(relationType, relationship);
+            case INFINITE_ONE, INFINITE_CONST:
+                return validateBSideCardinality(relationType, relationship);
+            default:
+                log.error("Unhandled relationship cardinality case: {}. The relationship is invalid.", cardinalityCase);
+                return false;
+        }
+    }
+
+    private boolean validateASideCardinality(RelationType relationType, Relationship relationship) {
+        return executeValidationQuery(relationType.getTableName(), relationType.bSideColumnName(), relationship.getBSide(),
+                relationType.getBSide().getTableName(), relationType.getASideAssociation().getMaxCardinality());
+    }
+
+    private boolean validateBSideCardinality(RelationType relationType, Relationship relationship) {
+        return executeValidationQuery(relationType.getTableName(), relationType.aSideColumnName(), relationship.getASide(),
+                relationType.getASide().getTableName(), relationType.getBSideAssociation().getMaxCardinality());
+    }
+
+    private boolean validateRelationshipInASideTable(MAXIMUM_CARDINALITY_CASE cardinalityCase, RelationType relationType,
+            Relationship relationship) {
+        switch (cardinalityCase) {
+            case INFINITE_ONE:
+                return true;
+            case ONE_ONE, CONST_ONE:
+                return validateASideCardinality(relationType, relationship);
+            default:
+                throw new UnsupportedOperationException(String.format("Can not store cardinalityCase=%s on the A side.",
+                        cardinalityCase));
+        }
+    }
+
+    private boolean validateRelationshipInBSideTable(MAXIMUM_CARDINALITY_CASE cardinalityCase, RelationType relationType,
+            Relationship relationship) {
+        switch (cardinalityCase) {
+            case ONE_INFINITE:
+                return true;
+            case ONE_ONE, ONE_CONST:
+                return validateBSideCardinality(relationType, relationship);
+            default:
+                throw new UnsupportedOperationException(String.format("Can not store cardinalityCase=%s on the B side.",
+                        cardinalityCase));
+        }
+    }
+
+    private boolean executeValidationQuery(String tableName, String foreignKeyColumnName, String foreignKeyValue,
+            String tableReferencedFromForeignKeyColumn, long maxOccurrence) {
+        tiesDbServiceForValidation.acquireEntityInstanceExclusiveLock(tableReferencedFromForeignKeyColumn, foreignKeyValue);
+        return tiesDbServiceForValidation.executeValidationQuery(tableName, foreignKeyColumnName, foreignKeyValue,
+                maxOccurrence);
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidatorFactory.java b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidatorFactory.java
new file mode 100644
index 0000000..6fb56f6
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidatorFactory.java
@@ -0,0 +1,31 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.ingestion.validation;
+
+import org.jooq.DSLContext;
+import org.springframework.stereotype.Component;
+
+@Component
+public class IngestionOperationValidatorFactory {
+    public IngestionOperationValidator createValidator(DSLContext dslContext) {
+        return new IngestionOperationValidator(new TiesDbServiceForValidation(dslContext));
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/MaximumCardinalityViolationException.java b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/MaximumCardinalityViolationException.java
new file mode 100644
index 0000000..70ea463
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/MaximumCardinalityViolationException.java
@@ -0,0 +1,27 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.ingestion.validation;
+
+public class MaximumCardinalityViolationException extends RuntimeException {
+    public MaximumCardinalityViolationException(String message) {
+        super(message);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/TiesDbServiceForValidation.java b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/TiesDbServiceForValidation.java
new file mode 100644
index 0000000..7a979c7
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/ingestion/validation/TiesDbServiceForValidation.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.ingestion.validation;
+
+import static org.jooq.impl.DSL.count;
+import static org.jooq.impl.DSL.field;
+import static org.jooq.impl.DSL.name;
+
+import org.jooq.DSLContext;
+import org.jooq.Field;
+import org.jooq.Record1;
+
+import org.oran.smo.teiv.utils.TiesConstants;
+
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
+public class TiesDbServiceForValidation {
+
+    private final DSLContext dslContext;
+
+    /**
+     * Acquire a row level FOR UPDATE lock for a single entity instance.
+     *
+     * @param tableName
+     *     The name of the table where the entity is stored
+     * @param entityId
+     *     Unique id of the entity
+     */
+    public void acquireEntityInstanceExclusiveLock(String tableName, String entityId) {
+        Field<Object> idField = field(TiesConstants.ID_COLUMN_NAME);
+        dslContext.select(idField).from(tableName).where(idField.eq(entityId)).forUpdate().execute();
+    }
+
+    public boolean executeValidationQuery(String tableName, String foreignKeyColumnName, String foreignKeyValue,
+            long maxOccurrence) {
+        int maxCount;
+        try {
+            maxCount = Math.toIntExact(maxOccurrence);
+        } catch (ArithmeticException e) {
+            log.error("Maximum cardinality can't be greater than {}, but it was {}", Integer.MAX_VALUE, maxOccurrence, e);
+            return false;
+        }
+        Field<Object> foreignKeyColumn = field(name(foreignKeyColumnName));
+        //spotless:off
+        Record1<Boolean> result = dslContext
+            .select(field(count(foreignKeyColumn).lessOrEqual(maxCount)))
+            .from(tableName)
+            .where(foreignKeyColumn.eq(foreignKeyValue))
+            .groupBy(foreignKeyColumn)
+            .fetchOne();
+        //spotless:on
+        return result.value1();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/CreateTopologyProcessor.java b/teiv/src/main/java/org/oran/smo/teiv/listener/CreateTopologyProcessor.java
new file mode 100644
index 0000000..27a6010
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/CreateTopologyProcessor.java
@@ -0,0 +1,77 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import io.cloudevents.CloudEvent;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.exception.InvalidFieldInYangDataException;
+import org.oran.smo.teiv.service.TiesDbOperations;
+import org.oran.smo.teiv.service.cloudevent.CloudEventParser;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.utils.CloudEventUtil;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StopWatch;
+
+@Component
+@Slf4j
+@Profile("ingestion")
+@AllArgsConstructor
+public class CreateTopologyProcessor implements TopologyProcessor {
+
+    private final CloudEventParser cloudEventParser;
+    private final CustomMetrics customMetrics;
+    private final TiesDbOperations tiesDbOperations;
+
+    @Override
+    public void process(final CloudEvent cloudEvent, final String messageKey) {
+        final StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        if (null == parsedCloudEventData) {
+            customMetrics.incrementNumUnsuccessfullyParsedCreateCloudEvents();
+            return;
+        }
+        stopWatch.stop();
+        customMetrics.recordCloudEventCreateParseTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyParsedCreateCloudEvents();
+
+        stopWatch.start();
+        try {
+            tiesDbOperations.executeEntityAndRelationshipMergeOperations(parsedCloudEventData);
+        } catch (InvalidFieldInYangDataException e) {
+            log.error("Invalid field in yang data. Discarded CloudEvent: {}. Used kafka message key: {}. Reason: {}",
+                    CloudEventUtil.cloudEventToPrettyString(cloudEvent), messageKey, e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyPersistedCreateCloudEvents();
+            return;
+        } catch (RuntimeException e) {
+            log.error("Failed to process a CloudEvent. Discarded CloudEvent: {}. Used kafka message key: {}. Reason: {}",
+                    CloudEventUtil.cloudEventToPrettyString(cloudEvent), messageKey, e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyPersistedCreateCloudEvents();
+            return;
+        }
+        stopWatch.stop();
+        customMetrics.incrementNumSuccessfullyPersistedCreateCloudEvents();
+        customMetrics.recordCloudEventCreatePersistTime(stopWatch.lastTaskInfo().getTimeNanos());
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/DeleteTopologyProcessor.java b/teiv/src/main/java/org/oran/smo/teiv/listener/DeleteTopologyProcessor.java
new file mode 100644
index 0000000..fc401ae
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/DeleteTopologyProcessor.java
@@ -0,0 +1,111 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import io.cloudevents.CloudEvent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.jooq.DSLContext;
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.TiesDbOperations;
+import org.oran.smo.teiv.service.TiesDbService;
+import org.oran.smo.teiv.service.cloudevent.CloudEventParser;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.service.models.OperationResult;
+import org.oran.smo.teiv.utils.CloudEventUtil;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StopWatch;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+@Profile("ingestion")
+public class DeleteTopologyProcessor implements TopologyProcessor {
+
+    private final CloudEventParser cloudEventParser;
+    private final TiesDbService tiesDbService;
+    private final TiesDbOperations tiesDbOperations;
+    private final CustomMetrics customMetrics;
+
+    //spotless:off
+    @Override
+    public void process(final CloudEvent cloudEvent, final String messageKey) {
+        final StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        if (parsedCloudEventData == null) {
+            customMetrics.incrementNumUnsuccessfullyParsedDeleteCloudEvents();
+            return;
+        }
+        stopWatch.stop();
+        customMetrics.recordCloudEventDeleteParseTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyParsedDeleteCloudEvents();
+
+        stopWatch.start();
+
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        List<OperationResult> operationResults = new ArrayList<>();
+
+        parsedCloudEventData.getEntities().forEach(entity -> {
+            EntityType entityType = SchemaRegistry.getEntityTypeByName(entity.getType());
+            dbOperations.add(dslContext -> operationResults.addAll(
+                    tiesDbOperations.deleteEntity(dslContext, entityType, entity.getId())));
+        });
+
+        parsedCloudEventData.getRelationships().forEach(relationship -> {
+            RelationType relationType = SchemaRegistry.getRelationTypeByName(relationship.getType());
+            switch (Objects.requireNonNull(relationType).getRelationshipStorageLocation()) {
+                case RELATION -> dbOperations.add(dslContext -> {
+                    Optional<OperationResult> operationResult = tiesDbOperations.deleteManyToManyRelationByRelationId(
+                            dslContext, relationType.getTableName(), relationship.getId());
+                    operationResult.ifPresent(operationResults::add);
+                });
+                case A_SIDE, B_SIDE -> dbOperations.add(dslContext -> {
+                    Optional<OperationResult> operationResult = tiesDbOperations.deleteRelationFromEntityTableByRelationId(
+                            dslContext, relationship.getId(), relationType);
+                    operationResult.ifPresent(operationResults::add);
+                });
+            }
+        });
+
+        try {
+            tiesDbService.execute(dbOperations);
+        } catch (RuntimeException e) {
+            log.error("Failed to process a CloudEvent. Discarded CloudEvent: {}. Used kafka message key: {}. Reason: {}",
+                    CloudEventUtil.cloudEventToPrettyString(cloudEvent), messageKey, e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyPersistedDeleteCloudEvents();
+            return;
+        }
+        stopWatch.stop();
+        customMetrics.recordCloudEventDeletePersistTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyPersistedDeleteCloudEvents();
+    }
+    //spotless:on
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/ListenerStarter.java b/teiv/src/main/java/org/oran/smo/teiv/listener/ListenerStarter.java
new file mode 100644
index 0000000..c5dd7ca
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/ListenerStarter.java
@@ -0,0 +1,70 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import java.text.MessageFormat;
+import java.util.Objects;
+
+import org.springframework.context.annotation.Profile;
+import org.springframework.kafka.config.KafkaListenerEndpointRegistry;
+import org.springframework.kafka.listener.MessageListenerContainer;
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.config.KafkaConfig;
+import org.oran.smo.teiv.service.kafka.KafkaTopicService;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+@Profile("ingestion")
+public class ListenerStarter {
+
+    private KafkaListenerEndpointRegistry registry;
+
+    private KafkaConfig kafkaConfig;
+
+    private KafkaTopicService kafkaTopicService;
+
+    //spotless:off
+    public void startKafkaListeners() {
+        startKafkaListener(kafkaTopicService.checkTopologyIngestionTopic(), kafkaConfig.getTopologyIngestion().getGroupId());
+    }
+    //spotless:on
+
+    private void startKafkaListener(boolean isTopicCreated, String groupId) {
+        if (isTopicCreated) {
+            log.info("Starting Kafka Listener. GroupId: {}", groupId);
+            MessageListenerContainer messageListenerContainer = registry.getListenerContainer(groupId);
+
+            if (Objects.nonNull(messageListenerContainer) && !messageListenerContainer
+                    .isAutoStartup() && !messageListenerContainer.isRunning()) {
+                messageListenerContainer.start();
+                log.info("Kafka Listener Started. {}", groupId);
+            }
+        } else {
+            log.error(MessageFormat.format("Failed to start topology listener with {0} groupId", groupId));
+        }
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/MergeTopologyProcessor.java b/teiv/src/main/java/org/oran/smo/teiv/listener/MergeTopologyProcessor.java
new file mode 100644
index 0000000..095c599
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/MergeTopologyProcessor.java
@@ -0,0 +1,88 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.oran.smo.teiv.CustomMetrics;
+
+import org.oran.smo.teiv.service.models.OperationResult;
+import org.oran.smo.teiv.utils.CloudEventUtil;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import io.cloudevents.CloudEvent;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.teiv.exception.InvalidFieldInYangDataException;
+import org.oran.smo.teiv.service.TiesDbOperations;
+import org.oran.smo.teiv.service.cloudevent.CloudEventParser;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+
+import org.springframework.util.StopWatch;
+
+@AllArgsConstructor
+@Component
+@Profile("ingestion")
+@Slf4j
+
+public class MergeTopologyProcessor implements TopologyProcessor {
+
+    private final CloudEventParser cloudEventParser;
+    private final CustomMetrics customMetrics;
+    private final TiesDbOperations tiesDbOperations;
+
+    //spotless:off
+    @Override
+    public void process(final CloudEvent cloudEvent, final String messageKey) {
+        final StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        if (null == parsedCloudEventData) {
+            customMetrics.incrementNumUnsuccessfullyParsedMergeCloudEvents();
+            return;
+        }
+        stopWatch.stop();
+        customMetrics.recordCloudEventMergeParseTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyParsedMergeCloudEvents();
+
+        stopWatch.start();
+        List<OperationResult> operationResults = new ArrayList<>();
+        try {
+            operationResults = tiesDbOperations.executeEntityAndRelationshipMergeOperations(parsedCloudEventData);
+        } catch (InvalidFieldInYangDataException e) {
+            log.error("Invalid field in yang data. Discarded CloudEvent: {}. Used kafka message key: {}. Reason: {}",
+                    CloudEventUtil.cloudEventToPrettyString(cloudEvent), messageKey, e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyPersistedMergeCloudEvents();
+            return;
+        } catch (RuntimeException e) {
+            log.error("Failed to process a CloudEvent. Discarded CloudEvent: {}. Used kafka message key: {}. Reason: {}",
+                    CloudEventUtil.cloudEventToPrettyString(cloudEvent), messageKey, e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyPersistedMergeCloudEvents();
+            return;
+        }
+        stopWatch.stop();
+
+        customMetrics.incrementNumSuccessfullyPersistedMergeCloudEvents();
+        customMetrics.recordCloudEventMergePersistTime(stopWatch.lastTaskInfo().getTimeNanos());
+    }
+    //spotless:on
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessor.java b/teiv/src/main/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessor.java
new file mode 100644
index 0000000..91171bf
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessor.java
@@ -0,0 +1,115 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.oran.smo.teiv.service.models.OperationResult;
+import org.oran.smo.teiv.utils.CloudEventUtil;
+import org.jooq.DSLContext;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StopWatch;
+
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import io.cloudevents.CloudEvent;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.service.TiesDbOperations;
+import org.oran.smo.teiv.service.TiesDbService;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+@Profile("ingestion")
+
+public class SourceEntityDeleteTopologyProcessor implements TopologyProcessor {
+
+    private final TiesDbService tiesDbService;
+    private final ObjectMapper objectMapper;
+    private final CustomMetrics customMetrics;
+    private final TiesDbOperations tiesDbOperations;
+
+    @Override
+    public void process(CloudEvent cloudEvent, String messageKey) {
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+
+        SourceEntityDelete sourceEntityDelete;
+        try {
+            sourceEntityDelete = objectMapper.readValue(cloudEvent.getData().toBytes(), SourceEntityDelete.class);
+        } catch (IOException e) {
+            log.error("Error while parsing the {} event.", e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents();
+            return;
+        }
+
+        //currently only cmHandle delete supported
+        if (!"cmHandle".equalsIgnoreCase(sourceEntityDelete.type)) {
+            log.error("Unsupported type: {} for source-entity-delete event. Event: {}", sourceEntityDelete.type,
+                    cloudEvent);
+            customMetrics.incrementNumReceivedCloudEventNotSupported();
+            return;
+        }
+
+        stopWatch.stop();
+        customMetrics.recordCloudEventSourceEntityDeleteParseTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyParsedSourceEntityDeleteCloudEvents();
+
+        stopWatch.start();
+        List<OperationResult> operationResults = new ArrayList<>();
+        try {
+            List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+            SchemaRegistry.getEntityTypesWithCmId().forEach(entityType -> dbOperations.add(dslContext -> {
+                List<String> results = tiesDbOperations.selectByCmHandle(dslContext, entityType.getTableName(),
+                        sourceEntityDelete.value);
+                if (!results.isEmpty()) {
+                    for (String result : results) {
+                        operationResults.addAll(tiesDbOperations.deleteEntity(dslContext, entityType, result));
+                    }
+                }
+            }));
+            tiesDbService.execute(dbOperations);
+        } catch (RuntimeException e) {
+            log.error("Failed to process a CloudEvent. Discarded CloudEvent: {}. Used kafka message key: {}. Reason: {}",
+                    CloudEventUtil.cloudEventToPrettyString(cloudEvent), messageKey, e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents();
+            return;
+        }
+
+        stopWatch.stop();
+        customMetrics.recordCloudEventSourceEntityDeletePersistTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyPersistedSourceEntityDeleteCloudEvents();
+    }
+
+    @JsonIgnoreProperties(ignoreUnknown = true)
+    record SourceEntityDelete(@JsonProperty(value = "type", required = true) String type,
+                              @JsonProperty(value = "value", required = true) String value) {
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorV1.java b/teiv/src/main/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorV1.java
new file mode 100644
index 0000000..f3fb9fc
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorV1.java
@@ -0,0 +1,112 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import org.oran.smo.teiv.service.models.OperationResult;
+import org.oran.smo.teiv.utils.CloudEventUtil;
+import org.jooq.DSLContext;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StopWatch;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.TiesDbOperations;
+import org.oran.smo.teiv.service.TiesDbService;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.cloudevents.CloudEvent;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+@Profile("ingestion")
+public class SourceEntityDeleteTopologyProcessorV1 implements TopologyProcessor {
+    private final TiesDbService tiesDbService;
+    private final ObjectMapper objectMapper;
+    private final CustomMetrics customMetrics;
+    private final TiesDbOperations tiesDbOperations;
+
+    @Override
+    public void process(CloudEvent cloudEvent, String messageKey) {
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+
+        SourceEntityDeleteV1 sourceEntityDelete;
+        try {
+            sourceEntityDelete = objectMapper.readValue(cloudEvent.getData().toBytes(), SourceEntityDeleteV1.class);
+        } catch (IOException e) {
+            log.error("Error while parsing the {} event.", e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents();
+            return;
+        }
+
+        //currently only cmHandle delete supported
+        if (!"cmHandle".equalsIgnoreCase(sourceEntityDelete.type)) {
+            log.error("Unsupported type: {} for source-entity-delete event. Event: {}", sourceEntityDelete.type,
+                    cloudEvent);
+            customMetrics.incrementNumReceivedCloudEventNotSupported();
+            return;
+        }
+
+        stopWatch.stop();
+        customMetrics.recordCloudEventSourceEntityDeleteParseTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyParsedSourceEntityDeleteCloudEvents();
+
+        stopWatch.start();
+        List<OperationResult> operationResults = new ArrayList<>();
+        try {
+            List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+            SchemaRegistry.getEntityTypes().forEach(entityType -> dbOperations.add(dslContext -> {
+                List<String> results = tiesDbOperations.selectByCmHandleFormSourceIds(dslContext, entityType.getTableName(),
+                        sourceEntityDelete.value);
+                if (!results.isEmpty()) {
+                    for (String result : results) {
+                        operationResults.addAll(tiesDbOperations.deleteEntity(dslContext, entityType, result));
+                    }
+                }
+            }));
+            tiesDbService.execute(dbOperations);
+        } catch (RuntimeException e) {
+            log.error("Failed to process a CloudEvent. Discarded CloudEvent: {}. Used kafka message key: {}. Reason: {}",
+                    CloudEventUtil.cloudEventToPrettyString(cloudEvent), messageKey, e.getMessage());
+            customMetrics.incrementNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents();
+            return;
+        }
+
+        stopWatch.stop();
+        customMetrics.recordCloudEventSourceEntityDeletePersistTime(stopWatch.lastTaskInfo().getTimeNanos());
+        customMetrics.incrementNumSuccessfullyPersistedSourceEntityDeleteCloudEvents();
+    }
+
+    @JsonIgnoreProperties(ignoreUnknown = true)
+    record SourceEntityDeleteV1(@JsonProperty(value = "type", required = true) String type,
+                                @JsonProperty(value = "value", required = true) String value) {
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyListener.java b/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyListener.java
new file mode 100644
index 0000000..3cc7530
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyListener.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.springframework.context.annotation.Profile;
+import org.springframework.core.log.LogAccessor;
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.kafka.support.serializer.DeserializationException;
+import org.springframework.kafka.support.serializer.SerializationUtils;
+import org.springframework.stereotype.Component;
+import io.cloudevents.CloudEvent;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.teiv.CustomMetrics;
+
+@Component
+@Slf4j
+@Profile("ingestion")
+@AllArgsConstructor
+public class TopologyListener {
+    private final CustomMetrics metrics;
+    private final TopologyProcessorRegistry topologyProcessorRegistry;
+    private final LogAccessor logger = new LogAccessor(TopologyListener.class);
+
+    @KafkaListener(id = "${kafka.topology-ingestion.consumer.group-id}", topics = "${kafka.topology-ingestion.consumer.topic.name}", containerFactory = "topologyListenerContainerFactory", autoStartup = "false")
+    public void processEvents(List<ConsumerRecord<String, CloudEvent>> events) {
+        log.info("Processing events: {}", events.size());
+        for (ConsumerRecord<String, CloudEvent> rec : events) {
+            if (rec.value() == null) {
+                metrics.incrementNumReceivedCloudEventNotSupported();
+                Optional<DeserializationException> deserializationException = Optional.ofNullable(SerializationUtils
+                        .getExceptionFromHeader(rec, SerializationUtils.VALUE_DESERIALIZER_EXCEPTION_HEADER, this.logger));
+                deserializationException.ifPresent(exception -> {
+                    logger.error(exception.getCause().getLocalizedMessage());
+                    logger.error(exception, "Record at offset " + rec.offset() + " could not be deserialized");
+                });
+            } else {
+                String messageKey = rec.key();
+                topologyProcessorRegistry.getProcessor(rec.value()).process(rec.value(), messageKey);
+            }
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyProcessor.java b/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyProcessor.java
new file mode 100644
index 0000000..e91aa4d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyProcessor.java
@@ -0,0 +1,32 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import org.springframework.context.annotation.Profile;
+
+import io.cloudevents.CloudEvent;
+
+@Profile("ingestion")
+public interface TopologyProcessor {
+
+    void process(final CloudEvent cloudEvent, final String messageKey);
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyProcessorRegistry.java b/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyProcessorRegistry.java
new file mode 100644
index 0000000..fe8dfde
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/TopologyProcessorRegistry.java
@@ -0,0 +1,91 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import io.cloudevents.CloudEvent;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.utils.TiesConstants;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+@Profile("ingestion")
+public class TopologyProcessorRegistry {
+
+    private final CustomMetrics metrics;
+    private final CreateTopologyProcessor createTopologyProcessor;
+    private final MergeTopologyProcessor mergeTopologyProcessor;
+    private final DeleteTopologyProcessor deleteTopologyProcessor;
+    private final SourceEntityDeleteTopologyProcessor sourceEntityDeleteTopologyProcessor;
+    private final SourceEntityDeleteTopologyProcessorV1 sourceEntityDeleteTopologyProcessorV1;
+    private final UnsupportedTopologyEventProcessor unsupportedTopologyEventProcessor;
+
+    @Value("${feature_flags.use_alternate_delete_logic}")
+    private boolean useAlternateDeleteLogic;
+
+    public TopologyProcessor getProcessor(CloudEvent event) {
+        String cloudEventType = getCloudEventType(event);
+        switch (cloudEventType) {
+            case TiesConstants.CLOUD_EVENT_WITH_TYPE_CREATE -> {
+                log.debug("Create CloudEvent received with id: {}", event.getId());
+                metrics.incrementNumReceivedCloudEventCreate();
+                return createTopologyProcessor;
+            }
+            case TiesConstants.CLOUD_EVENT_WITH_TYPE_MERGE -> {
+                log.debug("Merge CloudEvent received with id: {}", event.getId());
+                metrics.incrementNumReceivedCloudEventMerge();
+                return mergeTopologyProcessor;
+            }
+            case TiesConstants.CLOUD_EVENT_WITH_TYPE_DELETE -> {
+                log.debug("Delete CloudEvent received with id: {}", event.getId());
+                metrics.incrementNumReceivedCloudEventDelete();
+                return deleteTopologyProcessor;
+            }
+            case TiesConstants.CLOUD_EVENT_WITH_TYPE_SOURCE_ENTITY_DELETE -> {
+                log.debug("Source Entity Delete CloudEvent received with id: {}", event.getId());
+                metrics.incrementNumReceivedCloudEventSourceEntityDelete();
+                return useAlternateDeleteLogic ?
+                        sourceEntityDeleteTopologyProcessorV1 :
+                        sourceEntityDeleteTopologyProcessor;
+            }
+            default -> {
+                metrics.incrementNumReceivedCloudEventNotSupported();
+                log.error("Erroneous CloudEvent type: {}", cloudEventType);
+                return unsupportedTopologyEventProcessor;
+            }
+        }
+    }
+
+    private String getCloudEventType(final CloudEvent event) {
+        final String[] tokens = event.getType().split("\\.");
+        if (tokens.length == 2) {
+            return tokens[1];
+        } else {
+            return "UNKNOWN_EVENT";
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/listener/UnsupportedTopologyEventProcessor.java b/teiv/src/main/java/org/oran/smo/teiv/listener/UnsupportedTopologyEventProcessor.java
new file mode 100644
index 0000000..2de41e8
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/listener/UnsupportedTopologyEventProcessor.java
@@ -0,0 +1,33 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import org.springframework.stereotype.Component;
+import io.cloudevents.CloudEvent;
+
+@Component
+public class UnsupportedTopologyEventProcessor implements TopologyProcessor {
+
+    @Override
+    public void process(final CloudEvent cloudEvent, String messageKey) {
+        //DO-NOTHING
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/Association.java b/teiv/src/main/java/org/oran/smo/teiv/schema/Association.java
new file mode 100644
index 0000000..b7dcd6d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/Association.java
@@ -0,0 +1,34 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@Builder
+@ToString
+public class Association {
+    private String name;
+    private long minCardinality;
+    private long maxCardinality;
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/BidiDbNameMapper.java b/teiv/src/main/java/org/oran/smo/teiv/schema/BidiDbNameMapper.java
new file mode 100644
index 0000000..e2b6827
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/BidiDbNameMapper.java
@@ -0,0 +1,65 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import java.util.Collections;
+import java.util.Map;
+
+import lombok.experimental.UtilityClass;
+
+/**
+ * Bidirectional Database name mapper
+ */
+@UtilityClass
+public class BidiDbNameMapper {
+    //Map<Name, DbName>
+    private static Map<String, String> nameMap;
+    //Map<DbName, Name>
+    private static Map<String, String> dbNameMap;
+
+    /**
+     * Gets DB name used for the given name
+     *
+     * @param name
+     * @return the mapped DB name
+     */
+    public static String getDbName(String name) {
+        return nameMap.get(name);
+    }
+
+    /**
+     * Gets the name for the given DB name
+     *
+     * @param dbName
+     * @return the mapped name
+     */
+    public static String getModelledName(String dbName) {
+        return dbNameMap.get(dbName);
+    }
+
+    /**
+     * Loads the {@link BidiDbNameMapper} nameMap and dbNameMap
+     */
+    public static void initialize(Map<String, String> hashedNames, Map<String, String> reverseHashedNames) {
+        BidiDbNameMapper.nameMap = Collections.unmodifiableMap(hashedNames);
+        BidiDbNameMapper.dbNameMap = Collections.unmodifiableMap(reverseHashedNames);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/ConsumerDataCache.java b/teiv/src/main/java/org/oran/smo/teiv/schema/ConsumerDataCache.java
new file mode 100644
index 0000000..102ca05
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/ConsumerDataCache.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import org.oran.smo.teiv.exposure.spi.DataPersistanceService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class ConsumerDataCache {
+
+    private final DataPersistanceService dataPersistanceService;
+
+    @Cacheable("classifiers")
+    public Set<String> getClassifiers() {
+        return Collections.unmodifiableSet(dataPersistanceService.loadClassifiers());
+    }
+
+    @Cacheable("decorators")
+    public Map<String, DataType> getDecorators() {
+        return Collections.unmodifiableMap(dataPersistanceService.loadDecorators());
+    }
+
+    @Cacheable("validClassifiers")
+    public Set<String> getValidClassifiers(String partialClassifier) {
+        return getClassifiers().stream().filter(c -> c.contains(partialClassifier)).collect(Collectors.toSet());
+    }
+
+    @CacheEvict(value = { "classifiers", "decorators", "validClassifiers" }, allEntries = true)
+    @Scheduled(fixedRateString = "${spring.caching.consumer-data-ttl-ms}")
+    public void emptyConsumerDataCaches() {
+        log.debug("Emptying consumer data caches");
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/DataType.java b/teiv/src/main/java/org/oran/smo/teiv/schema/DataType.java
new file mode 100644
index 0000000..449a696
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/DataType.java
@@ -0,0 +1,42 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import java.util.Locale;
+
+public enum DataType {
+    PRIMITIVE,
+    DECIMAL,
+    BIGINT,
+    CONTAINER,
+    GEOGRAPHIC;
+
+    public static DataType fromDbDataType(final String dbDatatype) {
+        return switch (dbDatatype.toUpperCase(Locale.US)) {
+            case "TEXT", "VARCHAR" -> PRIMITIVE;
+            case "NUMERIC", "DECIMAL" -> DECIMAL;
+            case "BIGINT", "INT8" -> BIGINT;
+            case "JSONB" -> CONTAINER;
+            case "GEOGRAPHY" -> GEOGRAPHIC;
+            default -> throw new IllegalStateException("Unexpected value: " + dbDatatype.toUpperCase(Locale.US));
+        };
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/EntityType.java b/teiv/src/main/java/org/oran/smo/teiv/schema/EntityType.java
new file mode 100644
index 0000000..9211d1a
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/EntityType.java
@@ -0,0 +1,148 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import static org.jooq.impl.DSL.field;
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getDbName;
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getModelledName;
+import static org.oran.smo.teiv.schema.DataType.BIGINT;
+import static org.oran.smo.teiv.schema.DataType.CONTAINER;
+import static org.oran.smo.teiv.schema.DataType.DECIMAL;
+import static org.oran.smo.teiv.schema.DataType.GEOGRAPHIC;
+import static org.oran.smo.teiv.utils.TiesConstants.CONSUMER_DATA_PREFIX;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.REL_PREFIX;
+import static org.oran.smo.teiv.utils.TiesConstants.ST_TO_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.ST_TO_STRING_COLUMN_WITH_TABLE_NAME;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.oran.smo.teiv.utils.TiesConstants.SOURCE_IDS;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Field;
+import org.jooq.JSONB;
+
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@Builder
+@ToString
+public class EntityType implements Persistable {
+    @EqualsAndHashCode.Include
+    private final String name;
+    private final Map<String, DataType> fields;
+    private final Module module;
+
+    @Override
+    public String getTableName() {
+        return String.format(TIES_DATA, getDbName(this.name));
+    }
+
+    @Override
+    public String getIdColumnName() {
+        return getTableName() + "." + ID_COLUMN_NAME;
+    }
+
+    @Override
+    public List<String> getAttributeColumnsWithId() {
+        final List<String> columnList = new ArrayList<>();
+        this.fields.forEach((fieldName, dataType) -> {
+            if ((fieldName.startsWith(REL_PREFIX)) || fieldName.startsWith(CONSUMER_DATA_PREFIX)) {
+                return;
+            }
+            final String tableString = getTableName() + ".";
+            columnList.add(tableString + String.format(QUOTED_STRING, getDbName(fieldName)));
+        });
+        return columnList;
+    }
+
+    @Override
+    public List<Field> getAllFieldsWithId() {
+        final List<Field> fieldList = new ArrayList<>();
+        this.fields.forEach((fieldName, dataType) -> {
+            if (fieldName.startsWith(REL_PREFIX)) {
+                return;
+            }
+            if (GEOGRAPHIC.equals(dataType)) {
+                fieldList.add(field(String.format(ST_TO_STRING, getDbName(fieldName))).as(getDbName(fieldName)));
+            } else if (CONTAINER.equals(dataType)) {
+                fieldList.add(field(String.format(QUOTED_STRING, getDbName(fieldName)), JSONB.class).as(getDbName(
+                        fieldName)));
+            } else {
+                fieldList.add(field(String.format(QUOTED_STRING, getDbName(fieldName))).as(getDbName(fieldName)));
+            }
+        });
+        return fieldList;
+    }
+
+    public List<String> getAttributeNames() {
+        return this.fields.keySet().stream().filter(field -> (!field.startsWith(REL_PREFIX) || !field.startsWith(
+                CONSUMER_DATA_PREFIX))).toList();
+    }
+
+    /**
+     * Gets the fully qualified name of the entity. Format - <moduleNameReference>:<entityName>
+     *
+     * @return the fully qualified name
+     */
+    public String getFullyQualifiedName() {
+        return String.format("%s:%s", module.getName(), name);
+    }
+
+    public Field getField(String column, String prefix, String tableName) {
+        final String columnName = column.contains(".") ? column.split("\\.")[2].replace("\"", "") : column;
+        final String alias = (prefix != null ? (prefix + ".") : "") + column;
+        final String tableString = tableName != null ? (String.format(TIES_DATA, tableName) + ".") : "";
+
+        if (!this.fields.containsKey(getModelledName(columnName))) {
+            return null;
+        }
+
+        DataType type = this.fields.get(getModelledName(columnName));
+
+        if (type.equals(GEOGRAPHIC) && column.contains(TIES_DATA_SCHEMA)) {
+            return field(String.format(ST_TO_STRING_COLUMN_WITH_TABLE_NAME, column), String.class).as(alias);
+        } else if (type.equals(GEOGRAPHIC)) {
+            return field(tableString + String.format(ST_TO_STRING, column), String.class).as(alias);
+        } else if (type.equals(CONTAINER)) {
+            return field(tableString + column, JSONB.class).as(alias);
+        } else if (type.equals(DECIMAL)) {
+            return field(tableString + column, BigDecimal.class).as(alias);
+        } else if (type.equals(BIGINT)) {
+            return field(tableString + column, Long.class).as(alias);
+        } else {
+            return field(tableString + column, String.class).as(alias);
+        }
+    }
+
+    @Override
+    public String getSourceIdsColumnName() {
+        return getDbName(CONSUMER_DATA_PREFIX + SOURCE_IDS);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/Module.java b/teiv/src/main/java/org/oran/smo/teiv/schema/Module.java
new file mode 100644
index 0000000..76066e8
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/Module.java
@@ -0,0 +1,40 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import java.util.List;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Singular;
+import lombok.ToString;
+
+@Getter
+@Builder
+@ToString
+public class Module {
+    private final String name;
+    private final String namespace;
+    private final String domain;
+
+    @Singular
+    private final List<String> includedModuleNames;
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/Persistable.java b/teiv/src/main/java/org/oran/smo/teiv/schema/Persistable.java
new file mode 100644
index 0000000..0448a15
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/Persistable.java
@@ -0,0 +1,64 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import java.util.List;
+
+import org.jooq.Field;
+
+public interface Persistable {
+
+    /**
+     * Gets the fully qualified table name.
+     * Format - <schemaName>."<tableName>"
+     *
+     * @return the table name
+     */
+    String getTableName();
+
+    /**
+     * Gets the column name used for storing the unique identifier.
+     *
+     * @return the id column name
+     */
+    String getIdColumnName();
+
+    /**
+     * Gets all the column names.
+     *
+     * @return the list of column names
+     */
+    List<String> getAttributeColumnsWithId();
+
+    /**
+     * Gets all the columns names as list of {@link Field}
+     *
+     * @return the list of {@link Field}
+     */
+    List<Field> getAllFieldsWithId();
+
+    /**
+     * Gets sourceIds column name as String
+     *
+     * @return the String value of sourceIds column
+     */
+    String getSourceIdsColumnName();
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/PostgresSchemaLoader.java b/teiv/src/main/java/org/oran/smo/teiv/schema/PostgresSchemaLoader.java
new file mode 100644
index 0000000..207a32c
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/PostgresSchemaLoader.java
@@ -0,0 +1,175 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getModelledName;
+import static org.oran.smo.teiv.utils.TiesConstants.TEIV_DOMAIN;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_MODEL;
+import static org.jooq.impl.DSL.field;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.jooq.DSLContext;
+import org.jooq.JSONB;
+import org.jooq.Record;
+import org.jooq.Record3;
+import org.jooq.SelectConditionStep;
+import org.jooq.SelectJoinStep;
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.exception.TiesException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class PostgresSchemaLoader extends SchemaLoader {
+    private final DSLContext readDataDslContext;
+    private final ObjectMapper objectMapper;
+
+    public PostgresSchemaLoader(DSLContext readDataDslContext, ObjectMapper objectMapper) {
+        this.readDataDslContext = readDataDslContext;
+        this.objectMapper = objectMapper;
+    }
+
+    @Override
+    protected void loadBidiDbNameMapper() {
+        log.debug("Start loading bidirectional DB name mapper");
+        SelectJoinStep<Record> records = readDataDslContext.select().from(String.format(TIES_MODEL, "hash_info"));
+        Map<String, String> hash = new HashMap<>();
+        Map<String, String> reverseHash = new HashMap<>();
+        records.forEach(record -> {
+            hash.put((String) record.get("name"), (String) record.get("hashedValue"));
+            reverseHash.put((String) record.get("hashedValue"), (String) record.get("name"));
+        });
+        BidiDbNameMapper.initialize(hash, reverseHash);
+        log.debug("BidiDBNameMapper initialized successfully");
+    }
+
+    @Override
+    public void loadModules() throws SchemaLoaderException {
+        log.debug("Start loading modules");
+        SelectConditionStep<Record> moduleRecords = runMethodSafe(() -> readDataDslContext.select().from(String.format(
+                TIES_MODEL, "module_reference")).where(field("domain").isNotNull()));
+        Map<String, Module> moduleMap = new HashMap<>();
+        for (Record moduleRecord : moduleRecords) {
+            JSONB includedModules = (JSONB) moduleRecord.get("includedModules");
+            try {
+                List<String> modules = objectMapper.readValue(includedModules.data(), List.class);
+                Module module = Module.builder().name((String) moduleRecord.get("name")).namespace((String) moduleRecord
+                        .get("namespace")).domain((String) moduleRecord.get("domain")).includedModuleNames(modules).build();
+                moduleMap.put(module.getName(), module);
+            } catch (IOException e) {
+                log.error("Exception occurred while retrieving included modules.", e);
+                throw new SchemaLoaderException("Unable to load modules please check the logs for more details.", e);
+            }
+        }
+        //root domain includes all the available domains.
+        moduleMap.put(TEIV_DOMAIN, Module.builder().name(TEIV_DOMAIN).namespace(TEIV_DOMAIN).domain(TEIV_DOMAIN)
+                .includedModuleNames(moduleMap.keySet()).build());
+        SchemaRegistry.initializeModules(moduleMap);
+        log.debug("Modules initialized successfully");
+    }
+
+    @Override
+    public void loadEntityTypes() {
+        log.debug("Start loading entities");
+        Map<String, EntityType> entityTypeMap = new HashMap<>();
+        Map<String, EntityType.EntityTypeBuilder> entityTypeBuilderMap = new HashMap<>();
+        SelectJoinStep<Record> entityInfoRecords = runMethodSafe(() -> readDataDslContext.select().from(String.format(
+                TIES_MODEL, "entity_info")));
+        entityInfoRecords.forEach(entityInfoRecord -> {
+            String name = (String) entityInfoRecord.get("name");
+            EntityType.EntityTypeBuilder entityTypeBuilder = EntityType.builder().name(name).module(SchemaRegistry
+                    .getModuleByName((String) entityInfoRecord.get("moduleReferenceName")));
+            entityTypeBuilderMap.put(name, entityTypeBuilder);
+        });
+        //load attributes
+        String tableName = "table_name";
+        String columnName = "column_name";
+        SelectConditionStep<Record3<Object, Object, Object>> record3s = runMethodSafe(() -> readDataDslContext.select(field(
+                tableName), field(columnName), field("udt_name")).from("information_schema.columns").where(field(
+                        "table_schema").equal(TIES_DATA_SCHEMA)));
+        entityTypeBuilderMap.keySet().forEach(entityName -> {
+            Map<String, DataType> fields = new HashMap<>();
+            record3s.stream().filter(record3 -> entityName.equals(getModelledName((String) record3.get(tableName))))
+                    .forEach(record3 -> {
+                        String colName = getModelledName((String) record3.get(columnName));
+                        fields.put(colName, DataType.fromDbDataType((String) record3.get("udt_name")));
+                    });
+            entityTypeBuilderMap.get(entityName).fields(Collections.unmodifiableMap(fields));
+        });
+
+        for (var entityTypeBuilder : entityTypeBuilderMap.entrySet()) {
+            entityTypeMap.put(entityTypeBuilder.getKey(), entityTypeBuilder.getValue().build());
+        }
+
+        SchemaRegistry.initializeEntityTypes(entityTypeMap);
+        log.debug("Entities initialized successfully");
+    }
+
+    @Override
+    public void loadRelationTypes() {
+        log.debug("Start loading relations");
+        Map<String, RelationType> relationTypeMap = new HashMap<>();
+        SelectJoinStep<Record> relationInfoResult = runMethodSafe(() -> readDataDslContext.select().from(String.format(
+                TIES_MODEL, "relationship_info")));
+        relationInfoResult.forEach(result -> {
+            //build associations
+            Association aSideAssociation = Association.builder().name(((String) result.get("aSideAssociationName")))
+                    .minCardinality((long) (result.get("aSideMinCardinality"))).maxCardinality((long) (result.get(
+                            "aSideMaxCardinality"))).build();
+            Association bSideAssociation = Association.builder().name(((String) result.get("bSideAssociationName")))
+                    .minCardinality((long) (result.get("bSideMinCardinality"))).maxCardinality((long) (result.get(
+                            "bSideMaxCardinality"))).build();
+
+            RelationType relationType = RelationType.builder().name((String) result.get("name")).aSideAssociation(
+                    aSideAssociation).aSide(SchemaRegistry.getEntityTypeByName((String) result.get("aSideMOType")))
+                    .bSideAssociation(bSideAssociation).bSide(SchemaRegistry.getEntityTypeByName((String) result.get(
+                            "bSideMOType"))).relationshipStorageLocation(RelationshipDataLocation.valueOf((String) result
+                                    .get("relationshipDataLocation"))).connectsSameEntity((Boolean) (result.get(
+                                            "connectSameEntity"))).module(SchemaRegistry.getModuleByName((String) result
+                                                    .get("moduleReferenceName"))).build();
+            relationTypeMap.put(relationType.getName(), relationType);
+        });
+
+        //load registry
+        SchemaRegistry.initializeRelationTypes(relationTypeMap);
+        log.debug("Relations initialized successfully");
+    }
+
+    private <T> T runMethodSafe(Supplier<T> supp) {
+        try {
+            return supp.get();
+        } catch (TiesException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            log.error("Sql exception during query execution", ex);
+            throw TiesException.serverSQLException();
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/RelationType.java b/teiv/src/main/java/org/oran/smo/teiv/schema/RelationType.java
new file mode 100644
index 0000000..6f64579
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/RelationType.java
@@ -0,0 +1,202 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getDbName;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.RELATION;
+import static org.oran.smo.teiv.utils.TiesConstants.CONSUMER_DATA_PREFIX;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.REL_FK;
+import static org.oran.smo.teiv.utils.TiesConstants.SOURCE_IDS;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA;
+import static org.jooq.impl.DSL.field;
+
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Field;
+import org.jooq.JSONB;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Singular;
+import lombok.ToString;
+
+@Getter
+@Builder
+@ToString
+public class RelationType implements Persistable {
+    private static final String REL_ID_COL_PREFIX = "REL_ID_%s";
+    private static final String REL_FK_COL_PREFIX = "REL_FK_%s";
+    private static final String A_SIDE_PREFIX = "aSide_%s";
+    private static final String B_SIDE_PREFIX = "bSide_%s";
+    private static final String REL_SOURCE_IDS_COL_PREFIX = "REL_CD_sourceIds_%s";
+
+    private String name;
+    private Association aSideAssociation;
+    private EntityType aSide;
+    private Association bSideAssociation;
+    private EntityType bSide;
+    @Singular
+    private Map<String, DataType> attributes;
+    private boolean connectsSameEntity;
+    private RelationshipDataLocation relationshipStorageLocation;
+    private Module module;
+
+    @Override
+    public String getTableName() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> String.format(TIES_DATA, getDbName(name));
+            case A_SIDE -> aSide.getTableName();
+            case B_SIDE -> bSide.getTableName();
+        };
+    }
+
+    @Override
+    public String getIdColumnName() {
+        if (relationshipStorageLocation.equals(RELATION)) {
+            return ID_COLUMN_NAME;
+        } else {
+            return getDbName(String.format(REL_ID_COL_PREFIX, name));
+        }
+    }
+
+    @Override
+    public List<String> getAttributeColumnsWithId() {
+        // attributes are yet to be supported for relations
+        return List.of();
+    }
+
+    @Override
+    public List<Field> getAllFieldsWithId() {
+        return List.of(field(getTableName() + "." + String.format(QUOTED_STRING, aSideColumnName())), field(
+                getTableName() + "." + String.format(QUOTED_STRING, bSideColumnName())), field(getTableName() + "." + String
+                        .format(QUOTED_STRING, getIdColumnName())), field(getTableName() + "." + String.format(
+                                QUOTED_STRING, getSourceIdsColumnName()), JSONB.class));
+    }
+
+    /**
+     * Gets id, aSide and bSide column name of the relation.
+     *
+     * @return the list of {@link Field}
+     */
+    public List<Field> getBaseFieldsWithId() {
+        return List.of(field(getTableName() + "." + String.format(QUOTED_STRING, aSideColumnName())), field(
+                getTableName() + "." + String.format(QUOTED_STRING, bSideColumnName())), field(getTableName() + "." + String
+                        .format(QUOTED_STRING, getIdColumnName())));
+    }
+
+    @Override
+    public String getSourceIdsColumnName() {
+        if (relationshipStorageLocation.equals(RELATION)) {
+            return getDbName(CONSUMER_DATA_PREFIX + SOURCE_IDS);
+        } else {
+            return getDbName(String.format(REL_SOURCE_IDS_COL_PREFIX, name));
+        }
+    }
+
+    /**
+     * Gets the aSide column name of the relation.
+     *
+     * @return the aSide column name
+     */
+    public String aSideColumnName() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> getDbName(String.format(A_SIDE_PREFIX, aSide.getName()));
+            case A_SIDE -> ID_COLUMN_NAME;
+            case B_SIDE -> getDbName(String.format(REL_FK_COL_PREFIX, getBSideAssociation().getName()));
+        };
+    }
+
+    /**
+     * Gets the bSide column name of the relation.
+     *
+     * @return the bSide column name
+     */
+    public String bSideColumnName() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> getDbName(String.format(B_SIDE_PREFIX, bSide.getName()));
+            case A_SIDE -> getDbName(String.format(REL_FK_COL_PREFIX, getASideAssociation().getName()));
+            case B_SIDE -> ID_COLUMN_NAME;
+        };
+    }
+
+    /**
+     * Gets the fully qualified name of the entity.
+     * Format - <moduleNameReference>:<relationName>
+     *
+     * @return the fully qualified name
+     */
+    public String getFullyQualifiedName() {
+        return String.format("%s:%s", this.getModule().getName(), this.getName());
+    }
+
+    public String getTableNameWithoutSchema() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> name;
+            case A_SIDE -> aSide.getName();
+            case B_SIDE -> bSide.getName();
+        };
+    }
+
+    /**
+     * Gets the bSide relationship foreign key column name for the entity.
+     *
+     * @return the bSide foreign key column name, or null if not found.
+     */
+    public String getReferenceColumnOnBSide() {
+        return getDbName(REL_FK + this.getBSideAssociation().getName());
+    }
+
+    public String getNotStoringSideTableName() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> null;
+            case A_SIDE -> bSide.getTableName();
+            case B_SIDE -> aSide.getTableName();
+        };
+    }
+
+    public String getNotStoringSideEntityIdColumnNameInStoringSideTable() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> null;
+            case A_SIDE -> this.bSideColumnName();
+            case B_SIDE -> this.aSideColumnName();
+        };
+    }
+
+    public String getStoringSideEntityType() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> null;
+            case A_SIDE -> aSide.getName();
+            case B_SIDE -> bSide.getName();
+        };
+    }
+
+    public String getNotStoringSideEntityType() {
+        return switch (relationshipStorageLocation) {
+            case RELATION -> null;
+            case A_SIDE -> bSide.getName();
+            case B_SIDE -> aSide.getName();
+        };
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/RelationshipDataLocation.java b/teiv/src/main/java/org/oran/smo/teiv/schema/RelationshipDataLocation.java
new file mode 100644
index 0000000..3f9290d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/RelationshipDataLocation.java
@@ -0,0 +1,27 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+public enum RelationshipDataLocation {
+    A_SIDE,
+    B_SIDE,
+    RELATION
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaLoader.java b/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaLoader.java
new file mode 100644
index 0000000..cf22230
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaLoader.java
@@ -0,0 +1,44 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public abstract class SchemaLoader {
+    /**
+     * Template to load the {@link SchemaRegistry}
+     */
+    public final void loadSchemaRegistry() throws SchemaLoaderException {
+        loadBidiDbNameMapper();
+        loadModules();
+        loadEntityTypes();
+        loadRelationTypes();
+    }
+
+    protected abstract void loadBidiDbNameMapper() throws SchemaLoaderException;
+
+    protected abstract void loadModules() throws SchemaLoaderException;
+
+    protected abstract void loadEntityTypes() throws SchemaLoaderException;
+
+    protected abstract void loadRelationTypes() throws SchemaLoaderException;
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaLoaderException.java b/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaLoaderException.java
new file mode 100644
index 0000000..72fc124
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaLoaderException.java
@@ -0,0 +1,27 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+public class SchemaLoaderException extends Exception {
+    public SchemaLoaderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaRegistry.java b/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaRegistry.java
new file mode 100644
index 0000000..0b387d8
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/schema/SchemaRegistry.java
@@ -0,0 +1,320 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.springframework.cache.annotation.Cacheable;
+
+import jakarta.annotation.Nullable;
+import lombok.Getter;
+import lombok.experimental.UtilityClass;
+
+import org.oran.smo.teiv.exception.TiesException;
+
+@UtilityClass
+public class SchemaRegistry {
+    @Getter
+    private static Map<String, Module> moduleRegistry;
+    private static Map<String, EntityType> entityTypeRegistry;
+    private static Map<String, RelationType> relationTypeRegistry;
+
+    //Modules section
+
+    /**
+     * Initializes the modules. Once set cannot be overridden.
+     *
+     * @param moduleTypes-
+     *     module types
+     */
+    static void initializeModules(Map<String, Module> moduleTypes) {
+        moduleRegistry = Collections.unmodifiableMap(moduleTypes);
+    }
+
+    /**
+     * Gets the module by the given name.
+     *
+     * @param name
+     *     - module name
+     * @return the {@link Module}
+     */
+    public static Module getModuleByName(String name) {
+        return Optional.ofNullable(moduleRegistry.get(name)).orElseThrow(() -> TiesException.unknownModule(name));
+    }
+
+    /**
+     * Gets the module by the given domain name.
+     *
+     * @param domain
+     *     - name of the domain
+     * @return the {@link Module}
+     */
+    public static Module getModuleByDomain(String domain) {
+        return moduleRegistry.values().stream().filter(module -> module.getDomain().equals(domain)).findFirst().orElseThrow(
+                () -> TiesException.unknownDomain(domain, getDomains()));
+    }
+
+    /**
+     * Gets the included domain names for the given domain name.
+     *
+     * @param domain
+     *     - name of the domain
+     * @return the list of included domains
+     */
+    public static List<String> getIncludedDomains(String domain) {
+        return getModuleByDomain(domain).getIncludedModuleNames().stream().map(moduleName -> getModuleByName(moduleName)
+                .getDomain()).toList();
+    }
+
+    /**
+     * Gets all the supported domains based on the modules in the module registry.
+     *
+     * @return the set of domains
+     */
+    @Cacheable("availableDomains")
+    public static Set<String> getDomains() {
+        return moduleRegistry.values().stream().map(Module::getDomain).collect(Collectors.toCollection(TreeSet::new));
+    }
+
+    //Entities section
+    /**
+     * Initializes the entity types. Once set cannot be overridden.
+     *
+     * @param entityTypes
+     *     - entity types
+     */
+    static void initializeEntityTypes(Map<String, EntityType> entityTypes) {
+        entityTypeRegistry = Collections.unmodifiableMap(entityTypes);
+    }
+
+    /**
+     * Gets the list of supported {@link EntityType} from the entity type registry.
+     *
+     * @return the list of {@link EntityType}
+     */
+    public static List<EntityType> getEntityTypes() {
+        return entityTypeRegistry.values().stream().toList();
+    }
+
+    /**
+     * Gets all the supported entity names from the entity type registry.
+     *
+     * @return the set of entity names
+     */
+    public static Set<String> getEntityNames() {
+        return entityTypeRegistry.keySet();
+    }
+
+    /**
+     * Gets the {@link EntityType} by the given name.
+     *
+     * @param name
+     *     - entity name
+     * @return the {@link EntityType}
+     */
+    public static EntityType getEntityTypeByName(String name) {
+        return entityTypeRegistry.get(name);
+    }
+
+    /**
+     * Gets the list of {@link EntityType} by the given domain.
+     *
+     * @param domain
+     *     - name of the domain
+     * @return the list of {@link EntityType}
+     */
+    public static List<EntityType> getEntityTypesByDomain(String domain) {
+        List<String> domains = getIncludedDomains(domain);
+        return entityTypeRegistry.values().stream().filter(entityType -> {
+            String entityDomain = entityType.getModule().getDomain();
+            return domains.contains(entityDomain) || entityDomain.equals(domain);
+        }).toList();
+    }
+
+    /**
+     * Gets the list of entity names by the given domain.
+     *
+     * @param domain
+     *     - name of the domain
+     * @return the list of entity names
+     */
+    @Cacheable("entityTypesByDomain")
+    public static List<String> getEntityNamesByDomain(String domain) {
+        return getEntityTypesByDomain(domain).stream().map(EntityType::getName).sorted().toList();
+    }
+
+    public static boolean isValidEntityName(String entityName) {
+        return entityTypeRegistry.containsKey(entityName);
+    }
+
+    public static boolean hasDirectHopBetween(String entityName1, String entityName2) {
+        return hasDirectHopBetween(entityName1, entityName2, null);
+    }
+
+    public static boolean hasDirectHopBetween(String entity1, String entity2, List<String> relationships) {
+        return getRelationTypes().stream().anyMatch(relationType -> (relationships == null || relationships
+                .isEmpty() || relationships.contains(relationType.getName())) && ((relationType.getASide().getName().equals(
+                        entity1) && relationType.getBSide().getName().equals(entity2)) || (relationType.getASide().getName()
+                                .equals(entity2) && relationType.getBSide().getName().equals(entity1))));
+    }
+
+    /**
+     * Gets all managed objects with cmId attribute
+     *
+     * @return a list of managed objects
+     */
+    public static List<EntityType> getEntityTypesWithCmId() {
+        return entityTypeRegistry.values().stream().filter(entityType -> entityType.getFields().containsKey("cmId"))
+                .toList();
+    }
+
+    //Relations section
+    /**
+     * Initializes the relation types. Once set cannot be overridden.
+     *
+     * @param relationTypes
+     *     - relation types
+     */
+    static void initializeRelationTypes(Map<String, RelationType> relationTypes) {
+        relationTypeRegistry = Collections.unmodifiableMap(relationTypes);
+    }
+
+    /**
+     * Gets all the supported {@link RelationType} from the relation type registry.
+     *
+     * @return the list of {@link RelationType}
+     */
+    public static List<RelationType> getRelationTypes() {
+        return relationTypeRegistry.values().stream().toList();
+    }
+
+    /**
+     * Gets all the supported relation names from the relation type registry.
+     *
+     * @return the set of relation names.
+     */
+    public static Set<String> getRelationNames() {
+        return relationTypeRegistry.keySet();
+    }
+
+    /**
+     * Gets the relation type by the given name.
+     *
+     * @param relationName
+     *     - relation relationName
+     * @return the {@link RelationType}
+     */
+    @Nullable
+    public static RelationType getRelationTypeByName(String relationName) {
+        return relationTypeRegistry.get(relationName);
+    }
+
+    /**
+     * Gets all the relation types for the given entity name.
+     *
+     * @param entityName
+     *     - entity name
+     * @return the list of the {@link RelationType}
+     */
+    public static List<RelationType> getRelationTypesByEntityName(final String entityName) {
+        return relationTypeRegistry.values().stream().filter(relationType -> relationType.getASide().getName().equals(
+                entityName) || relationType.getBSide().getName().equals(entityName)).toList();
+    }
+
+    public static List<String> getRelationNamesByEntityName(final String entityName) {
+        return getRelationTypesByEntityName(entityName).stream().map(RelationType::getName).toList();
+    }
+
+    public static List<String> getAssociationNamesByEntityName(final String entityName) {
+        return getRelationTypesByEntityName(entityName).stream().map(relationType -> {
+            RelationshipDataLocation relDataLocation = relationType.getRelationshipStorageLocation();
+            if (relDataLocation.equals(RelationshipDataLocation.A_SIDE)) {
+                return relationType.getASideAssociation().getName();
+            } else {
+                return relationType.getBSideAssociation().getName();
+            }
+        }).toList();
+    }
+
+    /**
+     * Gets the relation types by the given domain.
+     *
+     * @param domain
+     *     - name of the domain
+     * @return the list of {@link RelationType}
+     */
+    public static List<RelationType> getRelationTypesByDomain(String domain) {
+        List<String> includedDomains = getIncludedDomains(domain);
+        return relationTypeRegistry.values().stream().filter(relationType -> {
+            String relDomain = relationType.getModule().getDomain();
+            return includedDomains.contains(relDomain) || relDomain.equals(domain);
+        }).toList();
+    }
+
+    /**
+     * Gets the relation names by the given domain.
+     *
+     * @param domain
+     *     - name of the domain
+     * @return the list of relation names
+     */
+    @Cacheable("relationTypesByDomain")
+    public static List<String> getRelationNamesByDomain(String domain) {
+        return getRelationTypesByDomain(domain).stream().map(RelationType::getName).sorted().toList();
+    }
+
+    public static boolean doesEntityContainsAttribute(String entityName, String attributeName) {
+        if (entityName == null) {
+            return false;
+        }
+        EntityType entityType = getEntityTypeByName(entityName);
+        if (entityType == null) {
+            return false;
+        }
+        return entityType.getAttributeNames().contains(attributeName);
+    }
+
+    public static List<RelationType> getRelationTypesBetweenEntities(String entity1, String entity2,
+            List<String> relationships) {
+        return getRelationTypes().stream().filter(relationType -> (relationships == null || relationships
+                .isEmpty() || relationships.contains(relationType.getName())) && ((relationType.getASide().getName().equals(
+                        entity1) && relationType.getBSide().getName().equals(entity2)) || (relationType.getBSide().getName()
+                                .equals(entity1) && relationType.getASide().getName().equals(entity2)))).toList();
+    }
+
+    public static Boolean isEntityPartOfRelationships(String entity, List<String> relationships) {
+        return getRelationTypes().stream().anyMatch(relationType -> relationships.isEmpty() || (relationships.contains(
+                relationType.getName()) && (relationType.getASide().getName().equals(entity) || relationType.getBSide()
+                        .getName().equals(entity))));
+    }
+
+    public static String getRelationNameByAssociationName(String associationName) {
+        return getRelationTypes().stream().filter(relationType -> relationType.getASideAssociation().getName().equals(
+                associationName) || relationType.getBSideAssociation().getName().equals(associationName)).map(
+                        RelationType::getName).findFirst().get();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/JSONBSerializer.java b/teiv/src/main/java/org/oran/smo/teiv/service/JSONBSerializer.java
new file mode 100644
index 0000000..ced8592
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/JSONBSerializer.java
@@ -0,0 +1,41 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import java.io.IOException;
+
+import org.jooq.JSONB;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+public class JSONBSerializer extends StdSerializer<JSONB> {
+    private static final long serialVersionUID = 1;
+
+    public JSONBSerializer() {
+        super(JSONB.class);
+    }
+
+    @Override
+    public void serialize(JSONB value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        gen.writeRawValue(value.data());
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/RelationshipMergeValidator.java b/teiv/src/main/java/org/oran/smo/teiv/service/RelationshipMergeValidator.java
new file mode 100644
index 0000000..c324afe
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/RelationshipMergeValidator.java
@@ -0,0 +1,45 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+
+import org.springframework.stereotype.Component;
+import org.jooq.Record;
+
+@Component
+public class RelationshipMergeValidator {
+
+    public boolean anotherRelationshipAlreadyExistsOnStoringSideEntity(Record manySideRow, RelationType relationType,
+            Relationship relationship) {
+        return !manySideRow.get(relationType.getIdColumnName()).equals(relationship.getId());
+    }
+
+    public boolean relationshipAlreadyExistsWithDifferentNotStoringSideEntity(Record manySideRow, Relationship relationship,
+            RelationType relationType) {
+        return manySideRow.get(ID_COLUMN_NAME).equals(relationship.getStoringSideEntityId()) && !manySideRow.get(
+                relationType.getNotStoringSideEntityIdColumnNameInStoringSideTable()).equals(relationship
+                        .getNotStoringSideEntityId());
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/TiesDbOperations.java b/teiv/src/main/java/org/oran/smo/teiv/service/TiesDbOperations.java
new file mode 100644
index 0000000..bb636ae
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/TiesDbOperations.java
@@ -0,0 +1,456 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getDbName;
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getModelledName;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.B_SIDE;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.RELATION;
+import static org.oran.smo.teiv.utils.TiesConstants.FOREIGN_KEY_VIOLATION_ERROR_CODE;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.UNIQUE_CONSTRAINT_VIOLATION_CODE;
+import static org.jooq.impl.DSL.field;
+import static org.jooq.impl.DSL.jsonExists;
+import static org.jooq.impl.DSL.name;
+import static org.jooq.impl.DSL.table;
+import static org.jooq.impl.SQLDataType.OTHER;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import org.oran.smo.teiv.exception.IllegalManyToManyRelationshipUpdateException;
+import org.oran.smo.teiv.exception.IllegalOneToManyRelationshipUpdateException;
+import org.jooq.Configuration;
+import org.jooq.Condition;
+import org.jooq.DSLContext;
+import org.jooq.JSON;
+import org.jooq.exception.DataAccessException;
+import org.springframework.stereotype.Component;
+
+import lombok.AllArgsConstructor;
+
+import org.jooq.Record;
+
+import org.oran.smo.teiv.exception.InvalidFieldInYangDataException;
+import org.oran.smo.teiv.exception.RelationshipIdCollisionException;
+import org.oran.smo.teiv.exception.UniqueRelationshipIdConstraintException;
+import org.oran.smo.teiv.ingestion.validation.IngestionOperationValidatorFactory;
+import org.oran.smo.teiv.ingestion.validation.MaximumCardinalityViolationException;
+import org.oran.smo.teiv.service.models.OperationResult;
+import org.oran.smo.teiv.schema.DataType;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.RelationshipDataLocation;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.cloudevent.data.Entity;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+
+import org.oran.smo.teiv.utils.ConvertToJooqTypeUtil;
+import org.oran.smo.teiv.utils.TiesConstants;
+import org.oran.smo.teiv.utils.schema.Geography;
+
+@Component
+@AllArgsConstructor
+public class TiesDbOperations {
+
+    private final TiesDbService tiesDbService;
+
+    private final IngestionOperationValidatorFactory ingestionOperationValidatorFactory;
+
+    private final RelationshipMergeValidator relationshipMergeValidator;
+
+    /**
+     * Insert or update a row in the given table.
+     * <p>
+     * Note: Free version of Jooq doesn't support spatial types like Geography. Instead of that the OTHER type is used.
+     * Instead of that the OTHER type is used.
+     * </p>
+     *
+     * @param context
+     *     The context where the database operation should be executed
+     * @param tableName
+     *     Name of the database table to use.
+     * @param values
+     *     A map of column name and value pairs. The value is converted
+     *     to the corresponding Postgres type based on the
+     *     dynamic type of the value. For
+     *     example: <"column1", 5L> means that the value 5 should be
+     *     inserted to the column1 as a BIGINT.
+     * @return The number of modified rows.
+     */
+
+    public int merge(DSLContext context, String tableName, Map<String, Object> values) {
+        Map<String, Object> valuesToMerge = new HashMap<>(values.size());
+        values.forEach((key, value) -> {
+            if (value instanceof Geography geographyValue) {
+                valuesToMerge.put(key, field("'" + geographyValue + "'", OTHER));
+            } else {
+                valuesToMerge.put(key, value);
+            }
+        });
+
+        return context.insertInto(table(tableName)).set(valuesToMerge).onConflict(field(ID_COLUMN_NAME)).doUpdate().set(
+                valuesToMerge).execute();
+    }
+
+    public List<OperationResult> deleteEntity(DSLContext context, EntityType entityType, String entityId) {
+        List<OperationResult> result = new ArrayList<>();
+        result.addAll(clearRelationshipsOnEntityDelete(context, entityType, entityId));
+
+        int affectedRows = context.delete(table(entityType.getTableName())).where(field(ID_COLUMN_NAME).eq(entityId))
+                .execute();
+        if (affectedRows > 0) {
+            result.add(new OperationResult(entityId, entityType.getName(), null));
+        }
+        return result;
+    }
+
+    public List<OperationResult> deleteRelationshipByManySideEntityId(DSLContext context, String manySideEntityId,
+            String manySideEntityIdColumn, RelationType relationType) {
+        String oneSideEntityIdColumn = relationType.getRelationshipStorageLocation().equals(B_SIDE) ?
+                relationType.aSideColumnName() :
+                relationType.bSideColumnName();
+
+        List<OperationResult> relationshipList = context.select(field(String.format(QUOTED_STRING, relationType
+                .getIdColumnName()), String.class)).from(table(relationType.getTableName())).where(field(String.format(
+                        QUOTED_STRING, manySideEntityIdColumn)).eq(manySideEntityId)).forUpdate().fetchInto(String.class)
+                .stream().filter(Objects::nonNull).map(id -> new OperationResult(id, extractTypeFromColumn(
+                        oneSideEntityIdColumn), null)).collect(Collectors.toList());
+        if (relationshipList.isEmpty()) {
+            return relationshipList;
+        } else {
+            int updateResult = context.update(table(relationType.getTableName())).setNull(field(String.format(QUOTED_STRING,
+                    relationType.getIdColumnName()))).setNull(field(String.format(QUOTED_STRING, oneSideEntityIdColumn)))
+                    .set(field(String.format(QUOTED_STRING, relationType.getSourceIdsColumnName())), ConvertToJooqTypeUtil
+                            .toJsonb(List.of())).where(field(String.format(QUOTED_STRING, manySideEntityIdColumn)).eq(
+                                    manySideEntityId)).execute();
+            return updateResult > 0 ? relationshipList : List.of();
+        }
+
+    }
+
+    public Optional<OperationResult> deleteRelationFromEntityTableByRelationId(DSLContext context, String relationshipId,
+            RelationType relationType) {
+        String oneSideEntityIdColumn = relationType.getRelationshipStorageLocation().equals(B_SIDE) ?
+                relationType.aSideColumnName() :
+                relationType.bSideColumnName();
+
+        int affectedRows = context.update(table(relationType.getTableName())).setNull(field(String.format(QUOTED_STRING,
+                relationType.getIdColumnName()))).setNull(field(String.format(QUOTED_STRING, oneSideEntityIdColumn))).set(
+                        field(String.format(QUOTED_STRING, relationType.getSourceIdsColumnName())), ConvertToJooqTypeUtil
+                                .toJsonb(List.of())).where(field(String.format(QUOTED_STRING, relationType
+                                        .getIdColumnName())).eq(relationshipId)).execute();
+        return affectedRows > 0 ?
+                Optional.of(new OperationResult(relationshipId, extractTypeFromColumn(oneSideEntityIdColumn), null)) :
+                Optional.empty();
+    }
+
+    public List<OperationResult> deleteManyToManyRelationByEntityId(DSLContext context, String tableName, String entityId,
+            String aSideColumnName, String bSideColumnName) {
+        List<String> deletedIds = context.delete(table(tableName)).where(field(String.format(QUOTED_STRING,
+                aSideColumnName)).eq(entityId).or(field(String.format(QUOTED_STRING, bSideColumnName)).eq(entityId)))
+                .returning(field(TiesConstants.ID_COLUMN_NAME)).fetch().getValues(field(TiesConstants.ID_COLUMN_NAME),
+                        String.class);
+
+        return deletedIds.stream().map(id -> new OperationResult(id, extractTypeFromTable(tableName), null)).collect(
+                Collectors.toList());
+    }
+
+    public Optional<OperationResult> deleteManyToManyRelationByRelationId(DSLContext context, String tableName,
+            String relationshipId) {
+
+        int affectedRows = context.delete(table(tableName)).where(field(ID_COLUMN_NAME).eq(relationshipId)).execute();
+        return affectedRows > 0 ?
+                Optional.of(new OperationResult(relationshipId, extractTypeFromTable(tableName), null)) :
+                Optional.empty();
+    }
+
+    public List<OperationResult> executeEntityAndRelationshipMergeOperations(ParsedCloudEventData parsedCloudEventData)
+            throws InvalidFieldInYangDataException, MaximumCardinalityViolationException {
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        List<OperationResult> results = new ArrayList<>();
+
+        for (Entity entity : parsedCloudEventData.getEntities()) {
+            dbOperations.add(getEntityOperation(entity, results));
+        }
+        for (Relationship relationship : parsedCloudEventData.getRelationships()) {
+            dbOperations.addAll(getRelationshipOperations(relationship, results));
+        }
+        dbOperations.add(dslContext -> ingestionOperationValidatorFactory.createValidator(dslContext).validate(
+                parsedCloudEventData));
+        tiesDbService.execute(dbOperations);
+        return results;
+    }
+
+    public List<String> selectByCmHandle(DSLContext context, String tableName, String cmHandle) {
+        String path = "$.** ? (@.cmHandle == \"" + cmHandle + "\")";
+        return context.select(field(String.format(QUOTED_STRING, "id"), String.class)).from(tableName).where(jsonExists(
+                field(String.format(QUOTED_STRING, "cmId"), JSON.class), path)).fetch().getValues(field(String.format(
+                        QUOTED_STRING, "id"), String.class));
+    }
+
+    public List<String> selectByCmHandleFormSourceIds(DSLContext context, String tableName, String cmHandle) {
+        String path = String.format("$[*] ? (@ == \"urn:cmHandle:/%s\")", cmHandle);
+        return context.select(field(String.format(QUOTED_STRING, "id"), String.class)).from(tableName).where(jsonExists(
+                field(String.format(QUOTED_STRING, "CD_sourceIds"), JSON.class), path)).fetch().getValues(field(String
+                        .format(QUOTED_STRING, "id"), String.class));
+    }
+
+    private Consumer<DSLContext> getEntityOperation(Entity entity, List<OperationResult> results)
+            throws InvalidFieldInYangDataException {
+        EntityType entityType = SchemaRegistry.getEntityTypeByName(entity.getType());
+        Map<String, DataType> fieldsFromModel = entityType.getFields();
+        Map<String, Object> dbMap = new HashMap<>();
+        for (Map.Entry<String, Object> entry : entity.getAttributes().entrySet()) {
+            DataType dataType = fieldsFromModel.get(entry.getKey());
+            if (dataType == null) {
+                throw new InvalidFieldInYangDataException(String.format(
+                        "Received field: %s isn't a valid field of entity type: %s", entry.getKey(), entity.getType()));
+            }
+            switch (dataType) {
+                case GEOGRAPHIC -> dbMap.put(getDbName(entry.getKey()), ConvertToJooqTypeUtil.toGeography(entry
+                        .getValue()));
+                case CONTAINER -> dbMap.put(getDbName(entry.getKey()), ConvertToJooqTypeUtil.toJsonb(entry.getValue()));
+                case PRIMITIVE, DECIMAL, BIGINT -> dbMap.put(getDbName(entry.getKey()), entry.getValue());
+            }
+        }
+        dbMap.put(ID_COLUMN_NAME, entity.getId());
+        if (entity.getSourceIds() != null) {
+            dbMap.put(entityType.getSourceIdsColumnName(), ConvertToJooqTypeUtil.toJsonb(entity.getSourceIds()));
+        }
+        return dslContext -> {
+            int affectedRows = merge(dslContext, entityType.getTableName(), dbMap);
+            if (affectedRows > 0) {
+                dbMap.remove(ID_COLUMN_NAME);
+                dbMap.remove(entityType.getSourceIdsColumnName());
+                results.add(new OperationResult(entity.getId(), entity.getType(), dbMap));
+            }
+        };
+    }
+
+    private List<Consumer<DSLContext>> getRelationshipOperations(Relationship relationship, List<OperationResult> results) {
+        List<Consumer<DSLContext>> relationshipOperations = new ArrayList<>();
+        RelationType relationType = SchemaRegistry.getRelationTypeByName(relationship.getType());
+        RelationshipDataLocation relationshipDataLocation = relationType.getRelationshipStorageLocation();
+
+        Map<String, Object> dbMap = new HashMap<>();
+        dbMap.put(relationType.getIdColumnName(), relationship.getId());
+        dbMap.put(relationType.aSideColumnName(), relationship.getASide());
+        dbMap.put(relationType.bSideColumnName(), relationship.getBSide());
+        if (relationship.getSourceIds() != null) {
+            dbMap.put(relationType.getSourceIdsColumnName(), ConvertToJooqTypeUtil.toJsonb(relationship.getSourceIds()));
+        }
+
+        if (relationshipDataLocation == RELATION) {
+            relationshipOperations.add(outer -> {
+                try {
+                    outer.dsl().transaction((Configuration nested) -> mergeManyToManyRelationship(nested.dsl(),
+                            relationship, results, relationType, dbMap));
+                } catch (DataAccessException e) {
+                    if (e.sqlState().equals(FOREIGN_KEY_VIOLATION_ERROR_CODE)) {
+                        createMissingEntities(outer, relationship, relationType, results);
+                        mergeManyToManyRelationship(outer, relationship, results, relationType, dbMap);
+                    } else {
+                        throw e;
+                    }
+                }
+            });
+        } else {
+            relationshipOperations.add(dslContext -> mergeOneToManyOrOneToOneRelationship(dslContext, relationship, results,
+                    relationType, dbMap));
+        }
+
+        return relationshipOperations;
+    }
+
+    private void mergeOneToManyOrOneToOneRelationship(DSLContext dslContext, Relationship relationship,
+            List<OperationResult> results, RelationType relationType, Map<String, Object> dbMap) {
+        AtomicBoolean isManySideEntityMissingAtTheBeginning = new AtomicBoolean(false);
+        try {
+            dslContext.dsl().transaction((Configuration nested) -> updateOneToManyRelationship(nested.dsl(), relationship,
+                    relationType, dbMap).ifPresentOrElse(results::add, () -> {
+                        Record manySideRow = selectByIdForUpdate(relationType.getTableName(), ID_COLUMN_NAME, relationship
+                                .getStoringSideEntityId(), dslContext);
+                        if (manySideRow == null) {
+                            isManySideEntityMissingAtTheBeginning.set(true);
+                            createMissingStoringSideEntity(dslContext, relationship, relationType);
+                            addEntityToOperationResults(results, relationship.getStoringSideEntityId(), relationType
+                                    .getStoringSideEntityType());
+                            updateOneToManyRelationship(dslContext, relationship, relationType, dbMap).ifPresentOrElse(
+                                    results::add, () -> {
+                                        throw new IllegalOneToManyRelationshipUpdateException(relationship, true);
+                                    });
+                        } else {
+                            handleOneToManyRelationshipFaults(manySideRow, relationship, relationType);
+                        }
+                    }));
+        } catch (DataAccessException e) {
+            if (e.sqlState().equals(UNIQUE_CONSTRAINT_VIOLATION_CODE)) {
+                throw new UniqueRelationshipIdConstraintException(relationship);
+            } else if (e.sqlState().equals(FOREIGN_KEY_VIOLATION_ERROR_CODE)) {
+                if (isManySideEntityMissingAtTheBeginning.get()) {
+                    createMissingStoringSideEntity(dslContext, relationship, relationType);
+                    addEntityToOperationResults(results, relationship.getStoringSideEntityId(), relationType
+                            .getStoringSideEntityType());
+                }
+                createMissingNotStoringSideEntity(dslContext, relationship, relationType);
+                addEntityToOperationResults(results, relationship.getNotStoringSideEntityId(), relationType
+                        .getNotStoringSideEntityType());
+                updateOneToManyRelationship(dslContext, relationship, relationType, dbMap).ifPresentOrElse(results::add,
+                        () -> {
+                            throw new IllegalOneToManyRelationshipUpdateException(relationship, false);
+                        });
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    private Optional<OperationResult> updateOneToManyRelationship(DSLContext dslContext, Relationship relationship,
+            RelationType relationType, Map<String, Object> values) {
+        Condition condition = field(ID_COLUMN_NAME).eq(relationship.getStoringSideEntityId()).and(field(name(relationType
+                .getIdColumnName())).isNull().or(field(name(relationType.getIdColumnName())).eq(relationship.getId()).and(
+                        field(name(relationType.getNotStoringSideEntityIdColumnNameInStoringSideTable())).eq(relationship
+                                .getNotStoringSideEntityId()))));
+
+        int numberOfUpdatedRows = dslContext.update(table(relationType.getTableName())).set(values).where(condition)
+                .execute();
+
+        return numberOfUpdatedRows != 0 ?
+                Optional.of(OperationResult.createFromRelationship(relationship)) :
+                Optional.empty();
+
+    }
+
+    private void handleOneToManyRelationshipFaults(Record manySideRow, Relationship relationship,
+            RelationType relationType) {
+        if (relationshipMergeValidator.anotherRelationshipAlreadyExistsOnStoringSideEntity(manySideRow, relationType,
+                relationship)) {
+            String manySideEntityType = relationType.getStoringSideEntityType();
+            String exceptionMessage = String.format(
+                    "Another relationship with id %s of type %s already exists on entity with id %s of type %s, can't override it with new relationship with id %s",
+                    manySideRow.get(relationType.getIdColumnName()), relationType.getName(), relationship
+                            .getStoringSideEntityId(), manySideEntityType, relationship.getId());
+            throw new MaximumCardinalityViolationException(exceptionMessage);
+        } else if (relationshipMergeValidator.relationshipAlreadyExistsWithDifferentNotStoringSideEntity(manySideRow,
+                relationship, relationType)) {
+            throw new RelationshipIdCollisionException(relationship);
+        }
+    }
+
+    private void mergeManyToManyRelationship(DSLContext dslContext, Relationship relationship,
+            List<OperationResult> results, RelationType relationType, Map<String, Object> dbMap) {
+        int affectedRows = dslContext.insertInto(table(relationType.getTableName())).set(dbMap).onConflict(field(
+                relationType.getIdColumnName())).doUpdate().set(dbMap).where(field(relationType.getTableName() + "." + name(
+                        relationType.aSideColumnName())).eq(relationship.getASide()).and(field(relationType
+                                .getTableName() + "." + name(relationType.bSideColumnName())).eq(relationship.getBSide())))
+                .execute();
+        if (affectedRows > 0) {
+            results.add(OperationResult.createFromRelationship(relationship));
+        } else {
+            throw new IllegalManyToManyRelationshipUpdateException(relationship);
+        }
+    }
+
+    private void createMissingEntities(DSLContext dslContext, Relationship relationship, RelationType relationType,
+            List<OperationResult> results) {
+        String aSideTableName = relationType.getASide().getTableName();
+        String aSideId = relationship.getASide();
+        String bSideTableName = relationType.getBSide().getTableName();
+        String bSideId = relationship.getBSide();
+
+        if (createMissingEntity(aSideTableName, ID_COLUMN_NAME, aSideId, dslContext) == 1) {
+            results.add(new OperationResult(aSideId, relationType.getASide().getName(), new HashMap<>()));
+        }
+        if (createMissingEntity(bSideTableName, ID_COLUMN_NAME, bSideId, dslContext) == 1) {
+            results.add(new OperationResult(bSideId, relationType.getBSide().getName(), new HashMap<>()));
+        }
+    }
+
+    private List<OperationResult> clearRelationshipsOnEntityDelete(DSLContext dslContext, EntityType entityType,
+            String entityId) {
+        List<OperationResult> deletedIds = new ArrayList<>();
+        List<RelationType> relationTypes = SchemaRegistry.getRelationTypesByEntityName(entityType.getName());
+
+        for (RelationType relationType : relationTypes) {
+            String columnNameForWhereCondition = (relationType.getASide().getName().equals(entityType.getName())) ?
+                    relationType.aSideColumnName() :
+                    relationType.bSideColumnName();
+            if (relationType.getRelationshipStorageLocation() == RELATION) {
+                deletedIds.addAll(deleteManyToManyRelationByEntityId(dslContext, relationType.getTableName(), entityId,
+                        relationType.aSideColumnName(), relationType.bSideColumnName()));
+
+            } else {
+                deletedIds.addAll(deleteRelationshipByManySideEntityId(dslContext, entityId, columnNameForWhereCondition,
+                        relationType));
+            }
+        }
+        return deletedIds;
+    }
+
+    private int createMissingEntity(String entityTableName, String entityIdColumnName, String entityId,
+            DSLContext dslContext) {
+        return dslContext.insertInto(table(entityTableName)).set(field(name(entityIdColumnName)), entityId)
+                .onConflictDoNothing().execute();
+    }
+
+    private void createMissingNotStoringSideEntity(DSLContext dslContext, Relationship relationship,
+            RelationType relationType) {
+        createMissingEntity(relationType.getNotStoringSideTableName(), ID_COLUMN_NAME, relationship
+                .getNotStoringSideEntityId(), dslContext);
+    }
+
+    private void createMissingStoringSideEntity(DSLContext dslContext, Relationship relationship,
+            RelationType relationType) {
+        createMissingEntity(relationType.getTableName(), ID_COLUMN_NAME, relationship.getStoringSideEntityId(), dslContext);
+    }
+
+    private Record selectByIdForUpdate(String tableName, String idFieldName, String manySideEntityId,
+            DSLContext dslContext) {
+        return dslContext.selectFrom(table(tableName)).where(field(idFieldName).eq(manySideEntityId)).forUpdate()
+                .fetchOne();
+    }
+
+    private void addEntityToOperationResults(List<OperationResult> results, String entityId, String entityType) {
+        OperationResult result = new OperationResult(entityId, entityType, Map.of());
+        if (!results.contains(result)) {
+            results.add(result);
+        }
+    }
+
+    private String extractTypeFromTable(String tableName) {
+        return tableName.split("\\\"")[1];
+    }
+
+    private String extractTypeFromColumn(String oneSideEntityIdColumn) {
+        String associationName = getModelledName(oneSideEntityIdColumn).replace("REL_FK_", "");
+        return SchemaRegistry.getRelationNameByAssociationName(associationName);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/TiesDbService.java b/teiv/src/main/java/org/oran/smo/teiv/service/TiesDbService.java
new file mode 100644
index 0000000..ebc4750
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/TiesDbService.java
@@ -0,0 +1,87 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import static org.jooq.impl.DSL.table;
+
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import org.jooq.DSLContext;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.impl.DSL;
+import org.springframework.retry.support.RetryTemplate;
+import org.springframework.stereotype.Service;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.ingestion.DeadlockRetryPolicy;
+import org.oran.smo.teiv.ingestion.validation.MaximumCardinalityViolationException;
+import org.oran.smo.teiv.utils.RetryOperationUtils;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class TiesDbService {
+    private final DSLContext readDataDslContext;
+    private final DSLContext writeDataDslContext;
+    private final DeadlockRetryPolicy deadlockRetryPolicy;
+
+    public void execute(List<Consumer<DSLContext>> dbOperations) {
+        runMethodSafe(() -> {
+            if (!dbOperations.isEmpty()) {
+                RetryTemplate retryTemplate = RetryOperationUtils.getRetryTemplate(deadlockRetryPolicy, deadlockRetryPolicy
+                        .getRetryBackoffMs());
+                retryTemplate.execute(retryContext -> {
+                    writeDataDslContext.transaction(configuration -> {
+                        DSLContext transactionalContext = DSL.using(configuration);
+                        dbOperations.forEach(op -> op.accept(transactionalContext));
+                    });
+                    return null;
+                });
+            }
+            return null;
+        });
+    }
+
+    protected Result<Record> selectAllRowsFromTable(final String tableName) {
+        return runMethodSafe(() -> readDataDslContext.selectFrom(table(tableName)).fetch());
+    }
+
+    private <T> T runMethodSafe(Supplier<T> supp) {
+        try {
+            return supp.get();
+        } catch (TiesException | MaximumCardinalityViolationException ex) {
+            throw ex;
+        } catch (TiesPathException ex) {
+            log.error("Exception during query construction", ex);
+            throw ex;
+        } catch (Exception ex) {
+            log.error("Sql exception during query execution", ex);
+            throw TiesException.serverSQLException();
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/CloudEventParser.java b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/CloudEventParser.java
new file mode 100644
index 0000000..45ce58e
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/CloudEventParser.java
@@ -0,0 +1,138 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.cloudevent;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import io.cloudevents.CloudEvent;
+import io.cloudevents.CloudEventData;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.teiv.service.cloudevent.data.Entity;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+import org.oran.smo.teiv.utils.YangParser;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class CloudEventParser {
+    private static final String ENTITIES = "entities";
+    private static final String RELATIONSHIPS = "relationships";
+    private final ObjectMapper objectMapper;
+
+    public ParsedCloudEventData getCloudEventData(CloudEvent cloudEvent) {
+        final CloudEventData cloudEventData = Objects.requireNonNull(cloudEvent.getData());
+        JsonNode eventPayload;
+        try {
+            eventPayload = objectMapper.readValue(cloudEventData.toBytes(), JsonNode.class);
+        } catch (IOException e) {
+            log.error("Cannot parse CloudEvent data: ", e);
+            return null;
+        }
+        final List<Entity> entities = new ArrayList<>();
+        Boolean parsedEntities = processEntities(eventPayload, entities);
+        if (parsedEntities.equals(Boolean.FALSE)) {
+            return null;
+        }
+
+        final List<Relationship> relationships = new ArrayList<>();
+        Boolean parsedRelationship = processRelationships(eventPayload, relationships);
+        if (parsedRelationship.equals(Boolean.FALSE)) {
+            return null;
+        }
+
+        return new ParsedCloudEventData(entities, relationships);
+    }
+
+    private Boolean processEntities(JsonNode eventPayload, List<Entity> entities) {
+        JsonNode entitiesJsonNode = eventPayload.get(ENTITIES);
+        if (entitiesJsonNode != null && (entitiesJsonNode.getNodeType() == JsonNodeType.ARRAY)) {
+            for (JsonNode entityNode : entitiesJsonNode) {
+                try {
+                    parseEntities(entityNode, entities);
+                } catch (IOException e) {
+                    log.error("Cannot parse entity: " + entitiesJsonNode, e);
+                    return false;
+                }
+            }
+        }
+        //TODO: Remove support for old format DnR events when RTA has been updated.
+        if (entitiesJsonNode != null && (entitiesJsonNode.getNodeType() == JsonNodeType.OBJECT)) {
+            try {
+                parseEntities(entitiesJsonNode, entities);
+            } catch (IOException e) {
+                log.error("Cannot parse entity: " + entitiesJsonNode, e);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private Boolean processRelationships(JsonNode eventPayload, List<Relationship> relationships) {
+        JsonNode relationshipJsonNode = eventPayload.get(RELATIONSHIPS);
+        if (relationshipJsonNode != null && (relationshipJsonNode.getNodeType() == JsonNodeType.ARRAY)) {
+            for (JsonNode relationshipNode : relationshipJsonNode) {
+                try {
+                    parseRelationships(relationshipNode, relationships);
+                } catch (IOException e) {
+                    log.error("Cannot parse relationship: " + relationshipNode, e);
+                    return false;
+                }
+            }
+        }
+        //TODO: Remove support for old format DnR events when RTA has been updated.
+        if (relationshipJsonNode != null && (relationshipJsonNode.getNodeType() == JsonNodeType.OBJECT)) {
+            try {
+                parseRelationships(relationshipJsonNode, relationships);
+            } catch (IOException e) {
+                log.error("Cannot parse relationship: " + relationshipJsonNode, e);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void parseEntities(JsonNode entitiesJsonNode, List<Entity> entities) throws IOException {
+        YangDataDomDocumentRoot entityDom = YangParser.getYangDataDomDocumentRoot(entitiesJsonNode);
+        entityDom.getChildren().forEach(child -> {
+            Entity entity = new Entity();
+            entity.parseObject(child);
+            entities.add(entity);
+        });
+    }
+
+    private void parseRelationships(JsonNode relationshipNode, List<Relationship> relationships) throws IOException {
+        YangDataDomDocumentRoot relDom = YangParser.getYangDataDomDocumentRoot(relationshipNode);
+        relDom.getChildren().forEach(child -> {
+            Relationship relationship = new Relationship();
+            relationship.parseObject(child);
+            relationships.add(relationship);
+        });
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/Entity.java b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/Entity.java
new file mode 100644
index 0000000..d8de9ce
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/Entity.java
@@ -0,0 +1,116 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.cloudevent.data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import lombok.Getter;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+
+public class Entity extends ModuleObject {
+
+    @Getter
+    private final Map<String, Object> attributes;
+
+    public Entity(String module, String type, String id, Map<String, Object> attributes, List<String> sourceIds) {
+        super(module, type, id, sourceIds);
+        this.attributes = new HashMap<>(attributes);
+    }
+
+    public Entity() {
+        this.attributes = new HashMap<>();
+    }
+
+    @Override
+    public void parseObject(final YangDataDomNode node) {
+        final String name = node.getName();
+        if ("attributes".equals(name)) {
+            setAttributes(node);
+        } else {
+            super.parseObject(node);
+            node.getChildren().forEach(this::parseObject);
+        }
+    }
+
+    private void setAttributes(final YangDataDomNode node) {
+        node.getChildren().forEach(this::handleJsonObjects);
+        attributes.keySet().forEach(name -> {
+            final Object v = attributes.get(name);
+            if (v instanceof List) {
+                attributes.put(name, v.toString());
+            }
+        });
+    }
+
+    private boolean isJsonObject(final YangDataDomNode node) {
+        return !node.getChildren().isEmpty();
+    }
+
+    private void handleJsonObjects(final YangDataDomNode node) {
+        final Object object = isJsonObject(node) ? jsonToString(node) : node.getValue();
+        final String name = node.getName();
+        if (attributes.containsKey(name)) {
+            Object v = attributes.get(name);
+            if (v instanceof List) {
+                ((List) v).add(object);
+            } else {
+                List<Object> l = new ArrayList<>();
+                l.add(v);
+                l.add(object);
+                attributes.put(name, l);
+            }
+        } else {
+            attributes.put(name, object);
+        }
+    }
+
+    private String jsonToString(final YangDataDomNode node) {
+        if (node.getChildren().isEmpty()) {
+            final Object value = node.getValue();
+            if (value instanceof String) {
+                return getQuotedString(value.toString());
+            }
+            return String.valueOf(value);
+        } else {
+            StringBuilder sb = new StringBuilder("{");
+            boolean first = true;
+            for (Iterator<YangDataDomNode> it = node.getChildren().iterator(); it.hasNext(); first = false) {
+                final YangDataDomNode actual = it.next();
+                if (!first) {
+                    sb.append(",");
+                }
+                sb.append(getQuotedString(actual.getName())).append(":").append(jsonToString(actual));
+            }
+            return sb.append("}").toString();
+        }
+    }
+
+    private String getQuotedString(final String str) {
+        return String.format(QUOTED_STRING, str);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/ModuleObject.java b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/ModuleObject.java
new file mode 100644
index 0000000..87f351d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/ModuleObject.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.cloudevent.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.oran.smo.teiv.utils.TiesConstants.SOURCE_IDS;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+public class ModuleObject {
+
+    private String module;
+    private String type;
+    private String id;
+    private List<String> sourceIds;
+
+    public void parseObject(final YangDataDomNode node) {
+        final String name = node.getName();
+        if (node.getChildren().isEmpty()) {
+            if (name.equals("id")) {
+                id = node.getStringValue();
+            } else if ((SOURCE_IDS).equals(name)) {
+                addSourceIds(node.getStringValue());
+            }
+        } else {
+            if (node.getParentNode() != null && node.getParentNode().getModuleName().equals("/")) {
+                module = node.getModuleName();
+                type = node.getName();
+            }
+        }
+    }
+
+    public void addSourceIds(String sourceIds) {
+        if (this.sourceIds == null) {
+            this.sourceIds = new ArrayList<>();
+        }
+        this.sourceIds.add(sourceIds);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/ParsedCloudEventData.java b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/ParsedCloudEventData.java
new file mode 100644
index 0000000..96527bb
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/ParsedCloudEventData.java
@@ -0,0 +1,34 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.cloudevent.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+public class ParsedCloudEventData {
+
+    private List<Entity> entities;
+    private List<Relationship> relationships;
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/Relationship.java b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/Relationship.java
new file mode 100644
index 0000000..47a3c8d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/cloudevent/data/Relationship.java
@@ -0,0 +1,77 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.cloudevent.data;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+
+@NoArgsConstructor
+public class Relationship extends ModuleObject {
+
+    @Getter
+    private String aSide;
+
+    @Getter
+    private String bSide;
+
+    public Relationship(String module, String type, String id, String aSide, String bSide, List<String> sourceIds) {
+        super(module, type, id, sourceIds);
+        this.aSide = aSide;
+        this.bSide = bSide;
+    }
+
+    @Override
+    public void parseObject(final YangDataDomNode node) {
+        final String name = node.getName();
+        if (name.equals("aSide")) {
+            aSide = node.getStringValue();
+        }
+        if (name.equals("bSide")) {
+            bSide = node.getStringValue();
+        }
+        super.parseObject(node);
+        node.getChildren().forEach(this::parseObject);
+    }
+
+    public String getStoringSideEntityId() {
+        RelationType relationType = SchemaRegistry.getRelationTypeByName(getType());
+        return switch (relationType.getRelationshipStorageLocation()) {
+            case RELATION -> null;
+            case A_SIDE -> getASide();
+            case B_SIDE -> getBSide();
+        };
+    }
+
+    public String getNotStoringSideEntityId() {
+        RelationType relationType = SchemaRegistry.getRelationTypeByName(getType());
+        return switch (relationType.getRelationshipStorageLocation()) {
+            case RELATION -> null;
+            case A_SIDE -> getBSide();
+            case B_SIDE -> getASide();
+        };
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaAddressSupplier.java b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaAddressSupplier.java
new file mode 100644
index 0000000..27e6219
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaAddressSupplier.java
@@ -0,0 +1,25 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.kafka;
+
+public interface KafkaAddressSupplier {
+    String getBootstrapServer();
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaAddressSupplierConfig.java b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaAddressSupplierConfig.java
new file mode 100644
index 0000000..1ca66e8
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaAddressSupplierConfig.java
@@ -0,0 +1,41 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.kafka;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Service;
+
+@Service
+@Profile("ingestion")
+public class KafkaAddressSupplierConfig implements KafkaAddressSupplier {
+
+    @Value("${kafka.server.bootstrap-server-host}")
+    private String bootstrapServerHost;
+
+    @Value("${kafka.server.bootstrap-server-port}")
+    private String bootstrapServerPort;
+
+    @Override
+    public String getBootstrapServer() {
+        return bootstrapServerHost + ":" + bootstrapServerPort;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaFactory.java b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaFactory.java
new file mode 100644
index 0000000..67dedfc
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaFactory.java
@@ -0,0 +1,111 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.kafka;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.kafka.CloudEventDeserializer;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import lombok.AllArgsConstructor;
+import org.apache.kafka.clients.admin.AdminClientConfig;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.common.serialization.StringDeserializer;
+import org.oran.smo.teiv.config.KafkaAdminConfig;
+import org.oran.smo.teiv.config.KafkaConfig;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Profile;
+import org.springframework.kafka.annotation.EnableKafka;
+import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
+import org.springframework.kafka.core.ConsumerFactory;
+import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
+import org.springframework.kafka.core.KafkaAdmin;
+import org.springframework.kafka.listener.ContainerProperties.AckMode;
+import org.springframework.kafka.listener.DefaultErrorHandler;
+import org.springframework.kafka.support.serializer.ErrorHandlingDeserializer;
+import org.springframework.stereotype.Component;
+import org.springframework.util.backoff.FixedBackOff;
+
+@Component
+@EnableKafka
+@AllArgsConstructor
+@Profile("ingestion")
+public class KafkaFactory {
+
+    private final KafkaConfig kafkaConfig;
+    private final KafkaAdminConfig kafkaAdminConfig;
+
+    @Bean
+    public KafkaAdmin kafkaAdmin() {
+        Map<String, Object> adminConfig = new HashMap<>(6);
+        adminConfig.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaAdminConfig.getBootstrapServer());
+        adminConfig.put(AdminClientConfig.RETRIES_CONFIG, kafkaAdminConfig.getRetries());
+        adminConfig.put(AdminClientConfig.RETRY_BACKOFF_MS_CONFIG, kafkaAdminConfig.getRetryBackoffMs());
+        adminConfig.put(AdminClientConfig.RECONNECT_BACKOFF_MS_CONFIG, kafkaAdminConfig.getReconnectBackoffMs());
+        adminConfig.put(AdminClientConfig.RECONNECT_BACKOFF_MAX_MS_CONFIG, kafkaAdminConfig.getReconnectBackoffMaxMs());
+        adminConfig.put(AdminClientConfig.REQUEST_TIMEOUT_MS_CONFIG, kafkaAdminConfig.getRequestTimeoutMs());
+        return new KafkaAdmin(adminConfig);
+    }
+
+    @Bean
+    public ConcurrentKafkaListenerContainerFactory<String, CloudEvent> topologyListenerContainerFactory() {
+        final ConcurrentKafkaListenerContainerFactory<String, CloudEvent> factory = new ConcurrentKafkaListenerContainerFactory<>();
+        factory.setConsumerFactory(consumerTopologyListenerFactory());
+        factory.setBatchListener(true);
+        factory.getContainerProperties().setAckMode(AckMode.BATCH);
+        factory.setConcurrency(kafkaConfig.getTopologyIngestion().getConcurrency());
+        factory.setCommonErrorHandler(new DefaultErrorHandler(new FixedBackOff(kafkaConfig.getTopologyIngestion()
+                .getRetryBackoffMs(), kafkaConfig.getTopologyIngestion().getRetryAttempts())));
+        factory.getContainerProperties().setAuthExceptionRetryInterval(Duration.ofMillis(kafkaConfig.getTopologyIngestion()
+                .getRetryBackoffMs()));
+
+        return factory;
+    }
+
+    private ConsumerFactory<String, CloudEvent> consumerTopologyListenerFactory() {
+        final KafkaConfig.TopologyIngestion topologyIngestionConfig = kafkaConfig.getTopologyIngestion();
+        Map<String, Object> config = getBaseKafkaConfig();
+        config.put(ConsumerConfig.GROUP_ID_CONFIG, topologyIngestionConfig.getGroupId());
+        config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, topologyIngestionConfig.getAutoOffsetReset());
+        config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ErrorHandlingDeserializer.class);
+        config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ErrorHandlingDeserializer.class);
+        config.put(ErrorHandlingDeserializer.KEY_DESERIALIZER_CLASS, StringDeserializer.class);
+        config.put(ErrorHandlingDeserializer.VALUE_DESERIALIZER_CLASS, CloudEventDeserializer.class);
+        config.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, topologyIngestionConfig.getMaxPollRecords());
+        config.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, topologyIngestionConfig.getMaxPollIntervalMs());
+        config.put(ConsumerConfig.FETCH_MIN_BYTES_CONFIG, topologyIngestionConfig.getFetchMinBytes());
+        config.put(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG, topologyIngestionConfig.getFetchMaxWaitMs());
+        config.put(ConsumerConfig.RETRY_BACKOFF_MS_CONFIG, topologyIngestionConfig.getRetryBackoffMs());
+        config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
+
+        return new DefaultKafkaConsumerFactory<>(config);
+    }
+
+    private Map<String, Object> getBaseKafkaConfig() {
+        final Map<String, Object> config = new HashMap<>(5);
+        config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaAdminConfig.getBootstrapServer());
+        config.put(ConsumerConfig.RETRY_BACKOFF_MS_CONFIG, kafkaAdminConfig.getRetryBackoffMs());
+        config.put(ConsumerConfig.RECONNECT_BACKOFF_MS_CONFIG, kafkaAdminConfig.getReconnectBackoffMs());
+        config.put(ConsumerConfig.RECONNECT_BACKOFF_MAX_MS_CONFIG, kafkaAdminConfig.getReconnectBackoffMaxMs());
+        config.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, kafkaAdminConfig.getRequestTimeoutMs());
+        return config;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaTopicService.java b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaTopicService.java
new file mode 100644
index 0000000..5eb992b
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/kafka/KafkaTopicService.java
@@ -0,0 +1,116 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.kafka;
+
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.admin.AdminClient;
+import org.apache.kafka.clients.admin.NewTopic;
+import org.apache.kafka.common.KafkaException;
+import org.apache.kafka.common.config.TopicConfig;
+import org.oran.smo.teiv.config.KafkaAdminConfig;
+import org.oran.smo.teiv.config.KafkaConfig;
+import org.oran.smo.teiv.utils.RetryOperationUtils;
+import org.springframework.context.annotation.Profile;
+import org.springframework.kafka.config.TopicBuilder;
+import org.springframework.kafka.core.KafkaAdmin;
+import org.springframework.retry.support.RetryTemplate;
+import org.springframework.stereotype.Component;
+
+@AllArgsConstructor
+@Component
+@Slf4j
+@Profile("ingestion")
+public class KafkaTopicService {
+
+    private final KafkaAdminConfig kafkaAdminConfig;
+
+    @Getter
+    private final KafkaAdmin kafkaAdmin;
+
+    @Getter
+    private final KafkaConfig kafkaConfig;
+
+    public boolean checkTopologyIngestionTopic() {
+        return checkTopicCreated(kafkaConfig.getTopologyIngestion().getTopicName());
+    }
+
+    public boolean isTopicCreated(String topicName) {
+        try (AdminClient client = AdminClient.create(kafkaAdmin.getConfigurationProperties())) {
+            Set<String> existingTopics = client.listTopics().names().get();
+            if (!existingTopics.contains(topicName)) {
+                log.info("Topic does not exist: {}", topicName);
+                throw new KafkaException("Topic does not exist");
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            log.error("Error checking if topic exists: {}", topicName, e);
+            Thread.currentThread().interrupt();
+            throw new KafkaException("Error checking if topic exists: " + topicName);
+        }
+        return true;
+    }
+
+    public boolean checkTopicCreated(String topicName) {
+        RetryTemplate retryTemplate = RetryOperationUtils.getRetryTemplate("kafkaListener", KafkaException.class,
+                kafkaAdminConfig.getRetries(), kafkaAdminConfig.getRetryBackoffMs());
+        boolean result = false;
+        try {
+            result = retryTemplate.execute(retryContext -> isTopicCreated(topicName));
+        } catch (KafkaException e) {
+            log.error("Hit max retry attempts {}: {}", kafkaAdminConfig.getRetries(), e);
+        }
+        return result;
+    }
+
+    public boolean buildTopics() {
+        RetryTemplate retryTemplate = RetryOperationUtils.getRetryTemplate("kafkaListener", KafkaException.class,
+                kafkaAdminConfig.getRetries(), kafkaAdminConfig.getRetryBackoffMs());
+        boolean result = false;
+        try {
+            result = retryTemplate.execute(retryContext -> createTopologyIngestionTopic());
+        } catch (KafkaException e) {
+            log.error("Hit max retry attempts {}: {}", kafkaAdminConfig.getRetries(), e);
+        }
+        return result;
+    }
+
+    private boolean createTopologyIngestionTopic() {
+        final KafkaConfig.TopologyIngestion topologyIngestionConfig = kafkaConfig.getTopologyIngestion();
+        NewTopic topic = TopicBuilder.name(topologyIngestionConfig.getTopicName()).partitions(topologyIngestionConfig
+                .getPartitions()).replicas(topologyIngestionConfig.getReplicas()).config(TopicConfig.RETENTION_MS_CONFIG,
+                        topologyIngestionConfig.getRetention()).config(TopicConfig.CLEANUP_POLICY_CONFIG,
+                                TopicConfig.CLEANUP_POLICY_DELETE).build();
+        return createTopic(topic, topologyIngestionConfig.getTopicName());
+    }
+
+    private boolean createTopic(NewTopic topic, String outputName) {
+        try {
+            kafkaAdmin.createOrModifyTopics(topic);
+            return isTopicCreated(outputName);
+        } catch (Exception e) {
+            log.error("Execution Error When Creating Kafka Topic {}: ", outputName);
+            throw new KafkaException("Kafka cannot create topic", e);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/service/models/OperationResult.java b/teiv/src/main/java/org/oran/smo/teiv/service/models/OperationResult.java
new file mode 100644
index 0000000..ef1757e
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/service/models/OperationResult.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.models;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import static org.oran.smo.teiv.utils.TiesConstants.PROPERTY_A_SIDE;
+import static org.oran.smo.teiv.utils.TiesConstants.PROPERTY_B_SIDE;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OperationResult {
+    private String id;
+    private String entryType;
+    private Map<String, Object> content;
+
+    public static OperationResult createFromRelationship(Relationship relationship) {
+        Map<String, Object> relationshipSides = new HashMap<>();
+        relationshipSides.put(PROPERTY_A_SIDE, relationship.getASide());
+        relationshipSides.put(PROPERTY_B_SIDE, relationship.getBSide());
+        return new OperationResult(relationship.getId(), relationship.getType(), relationshipSides);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/startup/AppInit.java b/teiv/src/main/java/org/oran/smo/teiv/startup/AppInit.java
new file mode 100644
index 0000000..22f249c
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/startup/AppInit.java
@@ -0,0 +1,65 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.startup;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.oran.smo.teiv.availability.DependentServiceAvailabilityKafka;
+import org.oran.smo.teiv.listener.ListenerStarter;
+import org.oran.smo.teiv.service.kafka.KafkaTopicService;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.annotation.Profile;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+@RequiredArgsConstructor
+@Component
+@Profile("!test & ingestion")
+@Slf4j
+public class AppInit {
+
+    private final DependentServiceAvailabilityKafka dependentServiceAvailabilityKafka;
+
+    @Getter
+    private final KafkaTopicService kafkaTopicService;
+
+    private final ListenerStarter listenerStarter;
+
+    /**
+     * Async Listener for when the spring boot application is started and ready.
+     * Needs to be Async so that liveliness and readiness probes are
+     * unaffected by retries.
+     */
+    @Async
+    @Order(value = 20)
+    @EventListener(value = ApplicationReadyEvent.class)
+    public void startUpHandler() {
+        if (dependentServiceAvailabilityKafka.checkService()) {
+            log.info("Building Topology and Inventory Exposure topics.");
+            kafkaTopicService.buildTopics();
+            log.info("Starting Topology and Inventory Exposure kafka listeners.");
+            listenerStarter.startKafkaListeners();
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/startup/SchemaHandler.java b/teiv/src/main/java/org/oran/smo/teiv/startup/SchemaHandler.java
new file mode 100644
index 0000000..a95bd9c
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/startup/SchemaHandler.java
@@ -0,0 +1,53 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.startup;
+
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import org.oran.smo.teiv.controller.health.HealthStatus;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class SchemaHandler {
+    private final SchemaLoader postgresSchemaLoader;
+    private final HealthStatus healthStatus;
+
+    /**
+     * Loads the schema registry at application startup.
+     */
+    @Order(value = 10)
+    @EventListener(value = ApplicationReadyEvent.class)
+    public void initializeSchema() throws SchemaLoaderException {
+        log.debug("Start schema initialization");
+        healthStatus.setSchemaInitialized(false);
+        postgresSchemaLoader.loadSchemaRegistry();
+        log.info("Schema initialized successfully...");
+        healthStatus.setSchemaInitialized(true);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/CloudEventUtil.java b/teiv/src/main/java/org/oran/smo/teiv/utils/CloudEventUtil.java
new file mode 100644
index 0000000..d511c38
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/CloudEventUtil.java
@@ -0,0 +1,41 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import io.cloudevents.CloudEvent;
+import lombok.experimental.UtilityClass;
+
+import java.nio.charset.StandardCharsets;
+
+@UtilityClass
+public class CloudEventUtil {
+
+    public static String cloudEventToPrettyString(CloudEvent cloudEvent) {
+        String cloudEventData;
+        if (cloudEvent.getData() == null) {
+            cloudEventData = "null";
+        } else {
+            cloudEventData = new String(cloudEvent.getData().toBytes(), StandardCharsets.UTF_8);
+        }
+        return String.format("CloudEvent{id=%s, source=%s, type=%s, dataschema=%s, data=%s}", cloudEvent.getId(), cloudEvent
+                .getSource(), cloudEvent.getType(), cloudEvent.getDataSchema(), cloudEventData);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/ConvertToJooqTypeUtil.java b/teiv/src/main/java/org/oran/smo/teiv/utils/ConvertToJooqTypeUtil.java
new file mode 100644
index 0000000..cbb573a
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/ConvertToJooqTypeUtil.java
@@ -0,0 +1,84 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.jooq.JSONB;
+import org.jooq.tools.json.JSONArray;
+
+import org.oran.smo.teiv.exception.InvalidFieldInYangDataException;
+import org.oran.smo.teiv.utils.schema.Geography;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class ConvertToJooqTypeUtil {
+
+    /**
+     * Creates a jooq.JSONB object from a json formatted String.
+     *
+     * The Yang Parser library parses the single element arrays as a JSON primitive.
+     * The use of yang models will solve this problem. As a temporary workaround,
+     * if one of the following is true, then the @param value is transformed into
+     * a single element json array before creating the JSONB object:
+     * - @param value is not a String, or
+     * - @param value is a String, but does not contain a JSON.
+     *
+     * @param value
+     * @return The jooq.JSONB object created from the value.
+     */
+    public static JSONB toJsonb(Object value) {
+        if (value instanceof String str && isJsonObjectOrArray(str)) {
+            return JSONB.jsonb(str);
+        } else {
+            return JSONB.jsonb(makeSingleElementJsonArray(value));
+        }
+    }
+
+    /**
+     * Creates a jooq.JSONB object from a List of strings.
+     *
+     * @param stringList
+     * @return The jooq.JSONB object created from the value.
+     */
+    public static JSONB toJsonb(List<String> stringList) {
+        return JSONB.jsonb(JSONArray.toJSONString(stringList));
+    }
+
+    private static boolean isJsonObjectOrArray(String str) {
+        String trimmedStr = str.stripLeading();
+        return trimmedStr.startsWith("{") || trimmedStr.startsWith("[");
+    }
+
+    private static String makeSingleElementJsonArray(Object obj) {
+        return JSONArray.toJSONString(List.of(obj));
+    }
+
+    public static Geography toGeography(Object value) throws InvalidFieldInYangDataException {
+        try {
+            return new Geography((String) value);
+        } catch (ClassCastException | IOException e) {
+            throw new InvalidFieldInYangDataException(String.format("Can't create a Geography object from: %s", value), e);
+        }
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/Environment.java b/teiv/src/main/java/org/oran/smo/teiv/utils/Environment.java
new file mode 100644
index 0000000..e2cdf57
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/Environment.java
@@ -0,0 +1,72 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+/**
+ * A utility class for retrieving environment/system values.
+ *
+ * @see System#getProperty(String)
+ * @see System#getenv(String)
+ */
+public final class Environment {
+
+    private Environment() {
+
+    }
+
+    /**
+     * Returns the {@code propertyName} specified if it is set as a {@link System} property or as a
+     * {@link System}
+     * environment variable. The order of
+     * the search is property first then environment variable.
+     * <p>
+     * If neither is set then null is returned.
+     *
+     * @param propertyName
+     *     the property to search for
+     * @return the value of the searched property, otherwise {@code null}
+     */
+    public static String getEnvironmentValue(final String propertyName) {
+        return System.getProperty(propertyName, System.getenv(propertyName));
+    }
+
+    /**
+     * Returns the {@code propertyName} specified if it is set as a {@link System} property or as a
+     * {@link System}
+     * environment variable. The order of
+     * the search is property first then environment variable.
+     * <p>
+     * If neither is set then the default value provided is returned.
+     *
+     * @param propertyName
+     *     the property name to search for
+     * @param defaultValue
+     *     the default value if no property exists
+     * @return The value of the searched name, otherwise the {@code defaultValue}
+     */
+    public static String getEnvironmentValue(final String propertyName, final String defaultValue) {
+        final String envVariable = System.getenv(propertyName);
+        if (envVariable != null) {
+            return envVariable;
+        }
+        return System.getProperty(propertyName, defaultValue);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/EnvironmentVariableConstants.java b/teiv/src/main/java/org/oran/smo/teiv/utils/EnvironmentVariableConstants.java
new file mode 100644
index 0000000..b225e8a
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/EnvironmentVariableConstants.java
@@ -0,0 +1,30 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+/**
+ * Constant Environment Variables.
+ */
+public class EnvironmentVariableConstants {
+
+    private EnvironmentVariableConstants() {
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/RetryOperationUtils.java b/teiv/src/main/java/org/oran/smo/teiv/utils/RetryOperationUtils.java
new file mode 100644
index 0000000..063e9d6
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/RetryOperationUtils.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import org.springframework.retry.RetryCallback;
+import org.springframework.retry.RetryContext;
+import org.springframework.retry.RetryListener;
+import org.springframework.retry.RetryPolicy;
+import org.springframework.retry.backoff.FixedBackOffPolicy;
+import org.springframework.retry.support.RetryTemplate;
+
+import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
+
+@UtilityClass
+@Slf4j
+public class RetryOperationUtils {
+    public static RetryTemplate getRetryTemplate(String listenerName, Class<? extends Throwable> className,
+            int retryAttempts, int retryIntervalMs) {
+        return RetryTemplate.builder().maxAttempts(retryAttempts).fixedBackoff(retryIntervalMs).retryOn(className)
+                .withListener(getRetryListener(listenerName)).build();
+    }
+
+    public static RetryTemplate getRetryTemplate(RetryPolicy retryPolicy, int retryIntervalMs) {
+        RetryTemplate retryTemplate = new RetryTemplate();
+        retryTemplate.setRetryPolicy(retryPolicy);
+        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
+        fixedBackOffPolicy.setBackOffPeriod(retryIntervalMs);
+        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
+        return retryTemplate;
+    }
+
+    private static RetryListener getRetryListener(String listenerName) {
+        return new RetryListener() {
+            @Override
+            public <T, E extends Throwable> boolean open(final RetryContext retryContext,
+                    final RetryCallback<T, E> retryCallback) {
+                return true; // called before first retry
+            }
+
+            @Override
+            public <T, E extends Throwable> void close(final RetryContext retryContext,
+                    final RetryCallback<T, E> retryCallback, final Throwable throwable) {
+                if (retryContext.getRetryCount() == 0) {
+                    return;
+                }
+                log.warn("{}: Execution stopped after {} retry attempts", listenerName, retryContext.getRetryCount());
+            }
+
+            @Override
+            public <T, E extends Throwable> void onError(final RetryContext retryContext,
+                    final RetryCallback<T, E> retryCallback, final Throwable throwable) {
+                log.error("Reached the {} retry number for {}, received the following error during the execution: {}",
+                        retryContext.getRetryCount(), listenerName, throwable.getMessage());
+            }
+        };
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/TiesConstants.java b/teiv/src/main/java/org/oran/smo/teiv/utils/TiesConstants.java
new file mode 100644
index 0000000..c057c15
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/TiesConstants.java
@@ -0,0 +1,58 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class TiesConstants {
+    public static final String API_VERSION = "v1alpha11";
+    public static final String REQUEST_MAPPING = "/topology-inventory/" + API_VERSION;
+
+    public static final String TEIV_DOMAIN = "TEIV";
+    public static final String TIES_DATA_SCHEMA = "ties_data";
+    public static final String TIES_DATA = TIES_DATA_SCHEMA + ".\"%s\"";
+    public static final String TIES_MODEL = "ties_model.%s";
+    public static final String ST_TO_STRING = "ST_AsText(\"%s\")";
+    public static final String ST_TO_STRING_COLUMN_WITH_TABLE_NAME = "ST_AsText(%s)";
+    public static final String QUOTED_STRING = "\"%s\"";
+    public static final String ID_COLUMN_NAME = "id";
+    public static final String CONSUMER_DATA_PREFIX = "CD_";
+    public static final String SOURCE_IDS = "sourceIds";
+    public static final String REL_PREFIX = "REL_";
+    public static final String PROPERTY_A_SIDE = "aSide";
+    public static final String PROPERTY_B_SIDE = "bSide";
+    public static final String ITEMS = "items";
+    public static final String ATTRIBUTES = "attributes";
+    public static final String TARGET_FILTER = "targetFilter";
+    public static final String SCOPE_FILTER = "scopeFilter";
+    public static final String QUERY = "query";
+    public static final String CLOUD_EVENT_WITH_TYPE_CREATE = "create";
+    public static final String CLOUD_EVENT_WITH_TYPE_MERGE = "merge";
+    public static final String CLOUD_EVENT_WITH_TYPE_DELETE = "delete";
+    public static final String CLOUD_EVENT_WITH_TYPE_SOURCE_ENTITY_DELETE = "source-entity-delete";
+    public static final long INFINITE_MAXIMUM_CARDINALITY = 9223372036854775807L;
+    public static final String FOREIGN_KEY_VIOLATION_ERROR_CODE = "23503";
+    public static final String UNIQUE_CONSTRAINT_VIOLATION_CODE = "23505";
+
+    public static final String REL_FK = "REL_FK_";
+    public static final String IN_USAGE = "IN_USAGE";
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/YangParser.java b/teiv/src/main/java/org/oran/smo/teiv/utils/YangParser.java
new file mode 100644
index 0000000..2e4df8c
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/YangParser.java
@@ -0,0 +1,181 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.findings.ModuleAndFindingTypeAndSchemaNodePathFilterPredicate;
+import org.oran.smo.yangtools.parser.input.BufferedStreamYangInput;
+import org.oran.smo.yangtools.parser.input.ByteArrayYangInput;
+import org.oran.smo.yangtools.parser.input.YangInput;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.stereotype.Service;
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.teiv.api.model.OranTeivSchema;
+import org.oran.smo.teiv.api.model.OranTeivHref;
+
+@Service
+@Slf4j
+public class YangParser {
+
+    /**
+     * Extracting data from all yang schemas, return required information
+     *
+     * @return yangDeviceModel
+     */
+    public YangDeviceModel extractYangData() {
+        YangDeviceModel yangDeviceModel = new YangDeviceModel("r1");
+        final List<YangModel> yangModels = new ArrayList<>();
+        try {
+            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(this.getClass().getClassLoader());
+            Resource[] yangResources = resolver.getResources("classpath:models/*.yang");
+            for (Resource yangResource : yangResources) {
+                yangModels.add(new YangModel(new ByteArrayYangInput(yangResource.getContentAsByteArray(), Objects
+                        .requireNonNull(yangResource.getFilename())), ConformanceType.IMPORT));
+            }
+        } catch (final IOException ex) {
+            log.error("Unable to load schemas", ex);
+        }
+
+        final ModifyableFindingSeverityCalculator severityCalculator = new ModifyableFindingSeverityCalculator();
+        final FindingsManager findingsManager = new FindingsManager(severityCalculator);
+        final ParserExecutionContext context = new ParserExecutionContext(findingsManager);
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+        context.setFailFast(false);
+        yangDeviceModel.parseIntoYangModels(context, yangModels);
+        return yangDeviceModel;
+    }
+
+    /**
+     * Store domains and revision by schema name, return object of all schemas
+     *
+     * @param yangDeviceModel
+     *     YangDeviceModel instance
+     *
+     * @return OranTeivSchemasMetaData
+     */
+    public static List<OranTeivSchema> returnAllTiesSchemas(YangDeviceModel yangDeviceModel) {
+        List<OranTeivSchema> OranTeivSchemasMetaData = new ArrayList<>();
+        for (final YangModel yangModel : yangDeviceModel.getModuleRegistry().getAllYangModels()) {
+            OranTeivSchema schemasMetaData = new OranTeivSchema();
+            OranTeivHref href = new OranTeivHref();
+
+            schemasMetaData.setName(yangModel.getModuleIdentity().getModuleName());
+            href.setHref(String.format("/schemas/%s/content", schemasMetaData.getName()));
+            schemasMetaData.setContent(href);
+            schemasMetaData.setRevision(yangModel.getModuleIdentity().getRevision());
+
+            final AbstractStatement moduleOrSubmodule = yangModel.getYangModelRoot().getModuleOrSubmodule();
+            final AbstractStatement domainStatement = moduleOrSubmodule.getChild(new StatementModuleAndName(
+                    "o-ran-smo-teiv-common-yang-extensions", "domain"));
+            List<String> values = new ArrayList<>();
+            if (domainStatement != null && domainStatement.getDomElement() != null) {
+                values = List.of(domainStatement.getDomElement().getValue().split(","));
+            }
+            schemasMetaData.setDomain(values);
+
+            if (schemasMetaData.getDomain() != null) {
+                OranTeivSchemasMetaData.add(schemasMetaData);
+            }
+        }
+        return OranTeivSchemasMetaData;
+    }
+
+    /**
+     * Filter schemas by schema name from extracted yang model
+     *
+     * @param yangDeviceModel
+     *     YangDeviceModel instance
+     * @param schemaName
+     *     Schema to be fetched
+     */
+    public static String returnSchemaByName(YangDeviceModel yangDeviceModel, String schemaName) {
+        StringBuilder sb = new StringBuilder();
+        for (final YangModel yangModel : yangDeviceModel.getModuleRegistry().getAllYangModels()) {
+            if (yangModel.getYangModelRoot().getModuleOrSubmodule().getDomElement().getValue().equals(schemaName)) {
+                try (BufferedReader br = new BufferedReader(new InputStreamReader(yangModel.getYangInput().getInputStream(),
+                        StandardCharsets.UTF_8))) {
+                    String line;
+                    while ((line = br.readLine()) != null) {
+                        sb.append(line).append(" ");
+                    }
+                } catch (IOException ex) {
+                    log.error("Reading failed", ex);
+                }
+            }
+        }
+        if (sb.length() > 1) {
+            sb = new StringBuilder(sb.deleteCharAt(sb.length() - 1).toString().replaceAll("\\s+", " "));
+        }
+        return sb.toString();
+    }
+
+    public static YangDataDomDocumentRoot getYangDataDomDocumentRoot(final JsonNode jsonNode) throws IOException {
+        final YangDataDomDocumentRoot yangDataDomDocument = parse(jsonNode.toString());
+        if (yangDataDomDocument == null) {
+            throw new IOException("YangDataDomDocumentRoot is null");
+        }
+        final Set<Finding> findings = yangDataDomDocument.getFindings();
+        if (!findings.isEmpty()) {
+            throw new IOException("Findings when parsing yang: " + jsonNode);
+        }
+        return yangDataDomDocument;
+    }
+
+    private static YangDataDomDocumentRoot parse(final String yangTopology) throws IOException {
+
+        final ModifyableFindingSeverityCalculator severityCalculator = new ModifyableFindingSeverityCalculator();
+        final FindingsManager findingsManager = new FindingsManager(severityCalculator);
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "ietf*,iana*;*;*"));
+
+        final ParserExecutionContext context = new ParserExecutionContext(findingsManager);
+        context.setFailFast(false);
+
+        final InputStream inputStream = new ByteArrayInputStream(yangTopology.getBytes(StandardCharsets.UTF_8));
+        final YangInput yangInput = new BufferedStreamYangInput("yang-topology", inputStream,
+                YangInput.MEDIA_TYPE_YANG_DATA_JSON);
+        final YangData yangData = new YangData(yangInput);
+        yangData.parse(context);
+
+        return yangData.getYangDataDomDocumentRoot();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/StrictErrorStrategy.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/StrictErrorStrategy.java
new file mode 100644
index 0000000..c6a92d2
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/StrictErrorStrategy.java
@@ -0,0 +1,46 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path;
+
+import lombok.SneakyThrows;
+import org.antlr.v4.runtime.DefaultErrorStrategy;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+public class StrictErrorStrategy extends DefaultErrorStrategy {
+
+    ParseCancellationException exception = null;
+
+    @SneakyThrows
+    @Override
+    public Token recoverInline(Parser recognizer) {
+        Token token = recognizer.getCurrentToken();
+        String message = String.format("parse error at line %s, position %s right before %s ", token.getLine(), token
+                .getCharPositionInLine(), getTokenErrorDisplay(token));
+        exception = new ParseCancellationException(message);
+        throw exception;
+    }
+
+    @Override
+    public void sync(Parser recognizer) {
+        /* do nothing to resync */}
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathBuilder.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathBuilder.java
new file mode 100644
index 0000000..f2a16a0
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathBuilder.java
@@ -0,0 +1,183 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path;
+
+import org.oran.smo.teiv.antlr4.tiesPathBaseListener;
+import org.oran.smo.teiv.antlr4.tiesPathParser;
+import org.oran.smo.teiv.utils.path.exception.PathParsingException;
+import lombok.SneakyThrows;
+import org.antlr.v4.runtime.RuleContext;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class TiesPathBuilder extends tiesPathBaseListener {
+
+    private static final String OPEN_BRACKET = "[";
+
+    private static final String CLOSE_BRACKET = "]";
+
+    private final TiesPathQuery tiesPathQuery = new TiesPathQuery();
+
+    private final List<TiesPathQuery.DataLeaf> leavesData = new ArrayList<>();
+
+    private final StringBuilder normalizedTiesPathBuilder = new StringBuilder();
+
+    private final List<String> containerNames = new ArrayList<>();
+
+    private final List<String> booleanOperators = new ArrayList<>();
+
+    private final List<String> comparativeOperators = new ArrayList<>();
+
+    private List<String> attributeNames = new ArrayList<>();
+
+    TiesPathQuery build() {
+        tiesPathQuery.setNormalizedXpath(normalizedTiesPathBuilder.toString());
+        tiesPathQuery.setContainerNames(containerNames);
+        tiesPathQuery.setBooleanOperators(booleanOperators);
+        tiesPathQuery.setComparativeOperators(comparativeOperators);
+        tiesPathQuery.setAttributeNames(attributeNames);
+        return tiesPathQuery;
+    }
+
+    @SneakyThrows
+    @Override
+    public void exitInvalidPostFix(final tiesPathParser.InvalidPostFixContext ctx) {
+        throw new PathParsingException(ctx.getText());
+    }
+
+    @Override
+    public void exitParent(final tiesPathParser.ParentContext ctx) {
+        tiesPathQuery.setNormalizedParentPath(normalizedTiesPathBuilder.toString());
+    }
+
+    @SneakyThrows
+    @Override
+    public void exitIncorrectPrefix(final tiesPathParser.IncorrectPrefixContext ctx) {
+        throw new PathParsingException("Path can only start with one slash (/)");
+    }
+
+    @SneakyThrows
+    @Override
+    public void exitLeafCondition(final tiesPathParser.LeafConditionContext ctx) {
+        final Object comparisonValue;
+        if (ctx.IntegerLiteral() != null) {
+            comparisonValue = Integer.valueOf(ctx.IntegerLiteral().getText());
+        } else if (ctx.StringLiteral() != null) {
+            comparisonValue = unwrapQuotedString(ctx.StringLiteral().getText());
+        } else {
+            throw new PathParsingException("Unsupported comparison value encountered in expression" + ctx.getText());
+        }
+        leafContext(ctx.leafName(), comparisonValue);
+    }
+
+    @Override
+    public void exitBooleanOperators(final tiesPathParser.BooleanOperatorsContext ctx) {
+        if (ctx.getText().equals("or"))
+            throw new PathParsingException("Boolean operator 'or' is not supported, at " + ctx.getStart()
+                    .getCharPositionInLine());
+        booleanOperators.add(ctx.getText());
+    }
+
+    @Override
+    public void exitComparativeOperators(final tiesPathParser.ComparativeOperatorsContext ctx) {
+        if (!ctx.getText().equals("="))
+            throw new PathParsingException(String.format("Comparative operator '%s' is not supported, at %d", ctx.getText(),
+                    ctx.getStart().getCharPositionInLine()));
+        comparativeOperators.add(ctx.getText());
+    }
+
+    @Override
+    public void enterMultipleLeafConditions(final tiesPathParser.MultipleLeafConditionsContext ctx) {
+        normalizedTiesPathBuilder.append(OPEN_BRACKET);
+        leavesData.clear();
+        booleanOperators.clear();
+        comparativeOperators.clear();
+    }
+
+    @Override
+    public void exitMultipleLeafConditions(final tiesPathParser.MultipleLeafConditionsContext ctx) {
+        normalizedTiesPathBuilder.append(CLOSE_BRACKET);
+        tiesPathQuery.setLeavesData(leavesData);
+    }
+
+    @Override
+    public void exitContainsFunctionCondition(final tiesPathParser.ContainsFunctionConditionContext ctx) {
+        tiesPathQuery.setContainsFunctionConditionLeafName(ctx.leafName().getText());
+        tiesPathQuery.setContainsFunctionConditionValue(unwrapQuotedString(ctx.StringLiteral().getText()));
+    }
+
+    @Override
+    public void enterListElementRef(final tiesPathParser.ListElementRefContext ctx) {
+        normalizedTiesPathBuilder.append(OPEN_BRACKET);
+    }
+
+    @Override
+    public void exitListElementRef(final tiesPathParser.ListElementRefContext ctx) {
+        normalizedTiesPathBuilder.append(CLOSE_BRACKET);
+    }
+
+    @Override
+    public void exitContainerName(final tiesPathParser.ContainerNameContext ctx) {
+        final String containerName = ctx.getText();
+        normalizedTiesPathBuilder.append("/").append(containerName);
+        containerNames.add(containerName);
+    }
+
+    @Override
+    public void exitFieldLeaf(final tiesPathParser.FieldLeafContext ctx) {
+        attributeNames = ctx.leafName().stream().map(RuleContext::getText).collect(Collectors.toList());
+    }
+
+    private void leafContext(final tiesPathParser.LeafNameContext ctx, final Object comparisonValue) {
+        leavesData.add(new TiesPathQuery.DataLeaf(ctx.getText(), comparisonValue));
+        appendCondition(normalizedTiesPathBuilder, ctx.getText(), comparisonValue);
+    }
+
+    private void appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name, final Object value) {
+        final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1);
+        final boolean isStartOfExpression = lastCharacter == '[';
+        if (!isStartOfExpression) {
+            currentNormalizedPathBuilder.append(" ").append(getLastElement(booleanOperators)).append(" ");
+        }
+        currentNormalizedPathBuilder.append("@").append(name).append(getLastElement(comparativeOperators)).append("'")
+                .append(value.toString().replace("'", "''")).append("'");
+    }
+
+    private static String getLastElement(final List<String> listOfStrings) {
+        return listOfStrings.get(listOfStrings.size() - 1);
+    }
+
+    private static String unwrapQuotedString(final String wrappedString) {
+        final boolean wasWrappedInSingleQuote = wrappedString.startsWith("'");
+        final String value = stripFirstAndLastCharacter(wrappedString);
+        if (wasWrappedInSingleQuote) {
+            return value.replace("''", "'");
+        } else {
+            return value.replace("\"\"", "\"");
+        }
+    }
+
+    private static String stripFirstAndLastCharacter(final String wrappedString) {
+        return wrappedString.substring(1, wrappedString.length() - 1);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathErrorListener.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathErrorListener.java
new file mode 100644
index 0000000..63c7f2e
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathErrorListener.java
@@ -0,0 +1,37 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path;
+
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+public class TiesPathErrorListener extends BaseErrorListener {
+
+    @Override
+    public void syntaxError(Recognizer<?, ?> recognizer, Object o, int i, int i1, String s, RecognitionException e)
+            throws ParseCancellationException {
+
+        throw new ParseCancellationException(s + " at line " + i + ":" + i1);
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathLexer.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathLexer.java
new file mode 100644
index 0000000..ed49bd4
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathLexer.java
@@ -0,0 +1,39 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path;
+
+import org.oran.smo.teiv.antlr4.tiesPathLexer;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.LexerNoViableAltException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+public class TiesPathLexer extends tiesPathLexer {
+
+    public TiesPathLexer(CharStream input) {
+        super(input);
+    }
+
+    @Override
+    public void recover(LexerNoViableAltException e) {
+        String message = String.format("lex error at position %s", e.getStartIndex());
+        throw new ParseCancellationException(message);
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathParser.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathParser.java
new file mode 100644
index 0000000..8156aee
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathParser.java
@@ -0,0 +1,42 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path;
+
+import org.oran.smo.teiv.antlr4.tiesPathParser;
+import lombok.SneakyThrows;
+import org.antlr.v4.runtime.TokenStream;
+
+public class TiesPathParser extends tiesPathParser {
+    public TiesPathParser(TokenStream input) {
+        super(input);
+    }
+
+    @Override
+    @SneakyThrows
+    public void exitRule() {
+        StrictErrorStrategy handler = (StrictErrorStrategy) super.getErrorHandler();
+
+        if (handler.exception != null)
+            throw handler.exception;
+
+        super.exitRule();
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathQuery.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathQuery.java
new file mode 100644
index 0000000..8ea931d
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathQuery.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter(AccessLevel.PACKAGE)
+public class TiesPathQuery {
+    private String tiesPathPrefix;
+    private String normalizedParentPath;
+    private String normalizedXpath;
+    private List<String> containerNames;
+    private List<DataLeaf> leavesData;
+    private String ancestorSchemaNodeIdentifier = "";
+    private String textFunctionConditionLeafName;
+    private String textFunctionConditionValue;
+    private List<String> booleanOperators;
+    private List<String> comparativeOperators;
+    private String containsFunctionConditionLeafName;
+    private String containsFunctionConditionValue;
+    private List<String> attributeNames;
+
+    public boolean hasLeafConditions() {
+        return leavesData != null;
+    }
+
+    public boolean hasContainsFunctionCondition() {
+        return containsFunctionConditionLeafName != null;
+    }
+
+    @Getter
+    @EqualsAndHashCode
+    @AllArgsConstructor
+    public static class DataLeaf {
+        private final String name;
+        private final Object value;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathUtil.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathUtil.java
new file mode 100644
index 0000000..9af63f2
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/TiesPathUtil.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path;
+
+import org.oran.smo.teiv.antlr4.tiesPathParser;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class TiesPathUtil {
+
+    public static TiesPathQuery getTiesPathQuery(final String TiesPathSource) {
+        final CharStream inputStream = CharStreams.fromString(TiesPathSource);
+        final TiesPathLexer tiesPathLexer = new TiesPathLexer(inputStream);
+        final tiesPathParser tiesPathParser = new TiesPathParser(new CommonTokenStream(tiesPathLexer));
+        tiesPathParser.removeErrorListeners();
+        tiesPathParser.addErrorListener(new TiesPathErrorListener());
+        tiesPathParser.setErrorHandler(new StrictErrorStrategy());
+        final TiesPathBuilder tiesPathBuilder = new TiesPathBuilder();
+        tiesPathParser.addParseListener(tiesPathBuilder);
+        tiesPathParser.tiesPath();
+
+        return tiesPathBuilder.build();
+    }
+
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/path/exception/PathParsingException.java b/teiv/src/main/java/org/oran/smo/teiv/utils/path/exception/PathParsingException.java
new file mode 100644
index 0000000..91c3468
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/path/exception/PathParsingException.java
@@ -0,0 +1,34 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.path.exception;
+
+import lombok.Getter;
+
+public class PathParsingException extends RuntimeException {
+
+    @Getter
+    final String details;
+
+    public PathParsingException(final String details) {
+        super("Error while parsing xpath expression");
+        this.details = details;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/query/QueryElement.java b/teiv/src/main/java/org/oran/smo/teiv/utils/query/QueryElement.java
new file mode 100644
index 0000000..c389b03
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/query/QueryElement.java
@@ -0,0 +1,126 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.query;
+
+import org.oran.smo.teiv.utils.path.TiesPathQuery;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Getter
+@NoArgsConstructor
+class QueryElement {
+    private String objectType;
+    private List<String> attributes = null;
+    private Map<TokenType, List<TiesPathQuery>> filters = null;
+    private List<QueryElement> children = new ArrayList<>();
+    private boolean isIncluded = false;
+    private boolean isManyToMany = false;
+    private boolean isRelConnectingSameEntity = false;
+
+    public QueryElement(String objectType) {
+        this.objectType = objectType;
+    }
+
+    public QueryElement(String objectType, boolean isIncluded) {
+        this.objectType = objectType;
+        this.isIncluded = isIncluded;
+    }
+
+    public void addAttribute(String attribute) {
+        attributes.add(attribute);
+    }
+
+    public void setAttributes(List<String> attributes) {
+        this.attributes = attributes;
+    }
+
+    public void addFilter(TokenType type, TiesPathQuery filter) {
+        filters.putIfAbsent(type, new ArrayList<>());
+        filters.get(type).add(filter);
+
+    }
+
+    public boolean hasFilters() {
+        return filters != null;
+    }
+
+    public void setFilters(Map<TokenType, List<TiesPathQuery>> filters) {
+        this.filters = filters;
+    }
+
+    public void addChild(QueryElement child) {
+        addChild(child, true);
+    }
+
+    public void addChild(QueryElement child, boolean safeAdd) {
+        if (safeAdd && this.hasChild(child.objectType)) {
+            return;
+        }
+        children.add(child);
+    }
+
+    public void removeChild(QueryElement child) {
+        children.remove(child);
+    }
+
+    public boolean hasAttributes() {
+        return attributes != null;
+    }
+
+    public List<TiesPathQuery> getFiltersOfTypes(List<TokenType> types) {
+        return types.stream().flatMap(type -> filters.containsKey(type) ? filters.get(type).stream() : null).toList();
+    }
+
+    public boolean hasFilterOfType(TokenType type) {
+        return filters.containsKey(type);
+    }
+
+    public boolean hasChild(String child) {
+        return children.stream().anyMatch(c -> c.getObjectType().equals(child));
+    }
+
+    public QueryElement getChild(String objectType) {
+        Optional<QueryElement> result = children.stream().filter(child -> child.getObjectType().equals(objectType))
+                .findFirst();
+        return result.orElse(null);
+    }
+
+    public boolean hasChildren() {
+        return !children.isEmpty();
+    }
+
+    public void include() {
+        isIncluded = true;
+    }
+
+    public void setManyToMany() {
+        isManyToMany = true;
+    }
+
+    public void setRelConnectingSameEntity() {
+        isRelConnectingSameEntity = true;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/query/QueryMonad.java b/teiv/src/main/java/org/oran/smo/teiv/utils/query/QueryMonad.java
new file mode 100644
index 0000000..086a236
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/query/QueryMonad.java
@@ -0,0 +1,989 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.query;
+
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getDbName;
+import static org.oran.smo.teiv.schema.BidiDbNameMapper.getModelledName;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.RELATION;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.B_SIDE;
+import static org.oran.smo.teiv.utils.TiesConstants.ATTRIBUTES;
+import static org.oran.smo.teiv.utils.TiesConstants.ID_COLUMN_NAME;
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA;
+import static org.oran.smo.teiv.utils.path.TiesPathUtil.getTiesPathQuery;
+import static org.jooq.impl.DSL.asterisk;
+import static org.jooq.impl.DSL.condition;
+import static org.jooq.impl.DSL.field;
+import static org.jooq.impl.DSL.not;
+import static org.jooq.impl.DSL.one;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.oran.smo.teiv.schema.RelationshipDataLocation;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.jooq.Condition;
+import org.jooq.DSLContext;
+import org.jooq.Field;
+import org.jooq.Record;
+import org.jooq.Record1;
+import org.jooq.ResultQuery;
+import org.jooq.Select;
+import org.jooq.SelectConditionStep;
+import org.jooq.SelectJoinStep;
+import org.jooq.SelectSelectStep;
+import org.jooq.impl.DSL;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.utils.path.TiesPathQuery;
+import org.oran.smo.teiv.utils.path.exception.PathParsingException;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+
+@Builder
+public class QueryMonad {
+
+    private static final String SEMICOLON = ";";
+    private static final String BAR = "|";
+    private String managedObject;
+    private String targets;
+    private String scope;
+    private String relationships;
+    private String domain;
+
+    /**
+     * Builds a jooq query using the SchemaRegistry, based on the filters.
+     *
+     * @return the prepared jooq query
+     */
+    public Function<DSLContext, ResultQuery<Record>> withSchema(final PaginationDTO paginationDTO) {
+        return context -> buildQuery(context, paginationDTO);
+    }
+
+    public Function<DSLContext, ResultQuery<Record1<Integer>>> countWithSchema() {
+        return this::buildQueryCount;
+    }
+
+    private QueryElement constructRoot() {
+        List<PathToken> targetTokens = targets != null ? processPath(targets, true) : new ArrayList<>();
+        List<PathToken> scopeTokens = scope != null ? processPath(scope, false) : new ArrayList<>();
+
+        return buildQueryTree(managedObject, targetTokens, scopeTokens, domain);
+    }
+
+    private ResultQuery<Record> buildQuery(DSLContext context, final PaginationDTO paginationDTO) {
+        List<String> relationshipTypes = parseRelationships(relationships);
+
+        return buildJooqQuery(context, constructRoot(), relationshipTypes, paginationDTO);
+    }
+
+    private SelectConditionStep<Record1<Integer>> buildQueryCount(DSLContext context) {
+        List<String> relationshipTypes = parseRelationships(relationships);
+
+        return buildJooqQueryCount(context, constructRoot(), relationshipTypes);
+    }
+
+    private static Select<Record> buildInnerQuery(DSLContext context, QueryElement root, List<String> relationships) {
+        SelectSelectStep<Record> selectStep = buildSelectStep(context, root, root.getObjectType());
+
+        boolean[] isValidHop = { false };
+        Select<Record> query = buildFromStep(selectStep, root, relationships, isValidHop, root.getObjectType());
+        Condition joinFilter = null;
+
+        for (QueryElement child : root.getChildren()) {
+            if (root.getObjectType() != null && !SchemaRegistry.hasDirectHopBetween(root.getObjectType(), child
+                    .getObjectType(), relationships)) {
+                continue;
+            }
+
+            joinFilter = setJoinFilter(root, joinFilter, child);
+        }
+
+        for (QueryElement child : root.getChildren()) {
+            if (root.getObjectType() == null || SchemaRegistry.hasDirectHopBetween(root.getObjectType(), child
+                    .getObjectType())) {
+                query = query.union(buildUnionBody(context, root, child.getObjectType(), relationships, joinFilter,
+                        isValidHop));
+            }
+        }
+
+        buildJooqQueryCheckIfRootHasConnections(root, isValidHop[0]);
+
+        query = buildWhereStep(query, root, joinFilter, relationships);
+
+        return query;
+    }
+
+    private static SelectConditionStep<Record1<Integer>> buildJooqQueryCount(DSLContext context, QueryElement root,
+            List<String> relationships) {
+
+        Select<Record> query = buildInnerQuery(context, root, relationships);
+
+        return context.selectCount().from(query.asTable("TiesPathQuery")).where(not(field("\"TiesPathQuery\"").isNull()));
+    }
+
+    private static SelectJoinStep<Record> buildJooqQuery(DSLContext context, QueryElement root, List<String> relationships,
+            final PaginationDTO paginationDTO) {
+
+        Select<Record> query = buildInnerQuery(context, root, relationships);
+
+        return (SelectJoinStep<Record>) context.selectDistinct(asterisk()).from(query.asTable("TiesPathQuery")).orderBy(
+                one().asc()).limit(paginationDTO.getOffset(), paginationDTO.getLimit());
+    }
+
+    private static Condition setJoinFilter(QueryElement root, Condition joinFilter, QueryElement child) {
+        if (root.getObjectType() != null || child.getFilters() == null) {
+            Field<Boolean> condition = field(String.format(TIES_DATA, getDbName(child.getObjectType())) + "." + String
+                    .format(QUOTED_STRING, ID_COLUMN_NAME)).isNotNull();
+            if (joinFilter != null && root.getObjectType() != null) {
+                joinFilter = joinFilter.and(condition);
+            } else if (joinFilter != null) {
+                joinFilter = joinFilter.or(condition);
+            } else {
+                joinFilter = DSL.condition(condition);
+            }
+        }
+        return joinFilter;
+    }
+
+    private static void buildJooqQueryCheckIfRootHasConnections(QueryElement root, Boolean isValidHop) {
+        if ((root.hasChildren() && !isValidHop && root.getObjectType() != null) || (!root.hasChildren() && !root
+                .isIncluded())) {
+            throw TiesPathException.noConnectionFound(root.getObjectType());
+        } else if ((root.hasChildren() && !isValidHop) || (!root.hasChildren() && !root.isIncluded())) {
+            throw TiesPathException.noConnectionFoundWhenRootIsNull();
+        }
+    }
+
+    private static SelectSelectStep<Record> buildSelectStep(DSLContext context, QueryElement root, String returnObject) {
+        List<String> columnNames = getColumnList(root);
+        if (returnObject == null) {
+            return context.select(columnNames.stream().map(column -> field("null").cast(SchemaRegistry.getEntityTypeByName(
+                    getModelledName(column.split("\\.")[1].replaceAll("\"", ""))).getField(column, null, returnObject)
+                    .getType()).as(column)).collect(Collectors.toList()));
+        }
+        if (root.isManyToMany()) {
+            return context.select(columnNames.stream().map(DSL::field).toList());
+        } else if (root.isRelConnectingSameEntity()) {
+            return context.selectDistinct(columnNames.stream().map(DSL::field).toList());
+        } else {
+            return context.select(columnNames.stream().map(column -> column.split("\\.")[1].replaceAll("\"", "").equals(
+                    getDbName(returnObject)) ?
+                            SchemaRegistry.getEntityTypeByName(returnObject).getField(column, null, null) :
+                            field("null").cast(SchemaRegistry.getEntityTypeByName(getModelledName(column.split("\\.")[1]
+                                    .replaceAll("\"", ""))).getField(column, null, returnObject).getType()).as(column))
+                    .collect(Collectors.toList()));
+        }
+    }
+
+    private static SelectSelectStep<Record> buildSelectStepForUnion(DSLContext context, QueryElement root,
+            String returnObject) {
+        List<String> columnNames = getColumnList(root);
+        if (root.getObjectType() != null && root.getObjectType().equals(returnObject)) {
+            return context.select(columnNames.stream().map(column -> field("null").cast(SchemaRegistry.getEntityTypeByName(
+                    column.split("\\.")[1].replaceAll("\"", "")).getField(column, null, returnObject).getType()).as(column))
+                    .collect(Collectors.toList()));
+        } else {
+            return buildSelectStep(context, root, returnObject);
+        }
+    }
+
+    private static SelectJoinStep<Record> buildFromStep(SelectSelectStep<Record> selectStep, QueryElement root,
+            List<String> relationships, boolean[] isValidHop, String returnObject) {
+        if (root.getObjectType() == null) {
+            SelectJoinStep<Record> fromStep = selectStep.from("(SELECT '') as dual_table");
+
+            for (QueryElement child : root.getChildren()) {
+                if (SchemaRegistry.isEntityPartOfRelationships(child.getObjectType(), relationships)) {
+                    TableJoinConnection connection = new TableJoinConnection(B_SIDE, null, List.of(condition(field(String
+                            .format(TIES_DATA, getDbName(child.getObjectType())) + "." + ID_COLUMN_NAME).eq(field(
+                                    "(SELECT '')")))), false);
+
+                    fromStep = buildFromStepSetJoin(child, returnObject, fromStep, connection);
+
+                    isValidHop[0] = true;
+                }
+            }
+            return fromStep;
+        }
+        SelectJoinStep<Record> fromStep = selectStep.from(String.format(TIES_DATA, getDbName(root.getObjectType())));
+        for (QueryElement child : root.getChildren()) {
+            for (TableJoinConnection connection : findJoinConnections(root, child, relationships)) {
+                fromStep = getRecords(root, fromStep, child, connection);
+                isValidHop[0] = true;
+            }
+        }
+        return fromStep;
+    }
+
+    private static SelectJoinStep<Record> getRecords(QueryElement root, SelectJoinStep<Record> fromStep, QueryElement child,
+            TableJoinConnection connection) {
+        if (connection.relConnectingSameEntity) {
+            fromStep = fromStep.join(connection.getTableName()).on(connection.getConditions().get(0)).or(connection
+                    .getConditions().get(1));
+        } else {
+            if (!root.isManyToMany() && connection.getRelationshipDataLocation().equals(RELATION)) {
+                fromStep = fromStep.join(connection.getTableName()).on(connection.getConditions().get(1));
+            }
+            if (!root.isManyToMany()) {
+                fromStep = fromStep.leftJoin(String.format(TIES_DATA, getDbName(child.getObjectType()))).on(connection
+                        .getConditions().get(0));
+            } else {
+                fromStep = fromStep.join(String.format(TIES_DATA, getDbName(child.getObjectType()))).on(connection
+                        .getConditions().get(0));
+            }
+        }
+        return fromStep;
+    }
+
+    private static SelectJoinStep<Record> buildFromStepSetJoin(QueryElement child, String returnObject,
+            SelectJoinStep<Record> fromStep, TableJoinConnection connection) {
+        if (child.getObjectType().equals(returnObject)) {
+            return fromStep.rightJoin(String.format(TIES_DATA, getDbName(child.getObjectType()))).on(connection
+                    .getConditions().get(0));
+        } else {
+            return fromStep.leftJoin(String.format(TIES_DATA, getDbName(child.getObjectType()))).on(connection
+                    .getConditions().get(0));
+        }
+    }
+
+    private static List<TableJoinConnection> findJoinConnections(QueryElement qe1, QueryElement qe2,
+            List<String> relationships) {
+        List<RelationType> relationTypes;
+        if (qe1.isManyToMany() || qe1.isRelConnectingSameEntity()) {
+            relationTypes = List.of(SchemaRegistry.getRelationTypeByName(qe1.getObjectType()));
+        } else {
+            relationTypes = SchemaRegistry.getRelationTypesBetweenEntities(qe1.getObjectType(), qe2.getObjectType(),
+                    relationships);
+        }
+        return createJoinConnections(qe1, qe2, relationTypes);
+    }
+
+    private static List<TableJoinConnection> createJoinConnections(QueryElement qe1, QueryElement qe2,
+            List<RelationType> relationTypes) {
+        List<TableJoinConnection> joins = new ArrayList<>();
+        for (RelationType relationType : relationTypes) {
+            switch (relationType.getRelationshipStorageLocation()) {
+                case A_SIDE:
+                    joins.add(createASideJoin(relationType));
+                    break;
+                case B_SIDE:
+                    joins.add(createBSideJoin(relationType));
+                    break;
+                case RELATION:
+                    joins.add(createRelationJoin(qe1, qe2, relationType));
+                    break;
+            }
+        }
+        return joins;
+    }
+
+    private static TableJoinConnection createSameEntityJoin(QueryElement qe1, QueryElement qe2, RelationType relationType) {
+        String table = relationType.getTableName() + ".";
+        if (!qe1.isRelConnectingSameEntity()) {
+            return new TableJoinConnection(relationType.getRelationshipStorageLocation(), relationType.getTableName(), List
+                    .of(condition(field(table + String.format(QUOTED_STRING, relationType.bSideColumnName())).eq(field(
+                            String.format(TIES_DATA, getDbName(qe2.getObjectType())) + "." + String.format(QUOTED_STRING,
+                                    ID_COLUMN_NAME)))), condition(field(table + String.format(QUOTED_STRING, relationType
+                                            .aSideColumnName())).eq(field(String.format(TIES_DATA, qe1
+                                                    .getObjectType()) + "." + String.format(QUOTED_STRING,
+                                                            ID_COLUMN_NAME))))), true);
+        } else {
+            return new TableJoinConnection(relationType.getRelationshipStorageLocation(), String.format(TIES_DATA,
+                    getDbName(qe2.getObjectType())), List.of(condition(field(table + String.format(QUOTED_STRING,
+                            relationType.bSideColumnName())).eq(field(String.format(TIES_DATA, getDbName(qe2
+                                    .getObjectType())) + "." + String.format(QUOTED_STRING, ID_COLUMN_NAME)))), condition(
+                                            field(table + String.format(QUOTED_STRING, relationType.aSideColumnName())).eq(
+                                                    field(String.format(TIES_DATA, getDbName(qe2
+                                                            .getObjectType())) + "." + String.format(QUOTED_STRING,
+                                                                    ID_COLUMN_NAME))))), true);
+        }
+    }
+
+    private static TableJoinConnection createASideJoin(RelationType relationType) {
+        String table = relationType.getTableName() + ".";
+        return new TableJoinConnection(relationType.getRelationshipStorageLocation(), null, List.of(condition(field(
+                table + String.format(QUOTED_STRING, relationType.bSideColumnName())).eq(field(String.format(TIES_DATA,
+                        getDbName(relationType.getBSide().getName())) + "." + String.format(QUOTED_STRING,
+                                ID_COLUMN_NAME))))), false);
+    }
+
+    private static TableJoinConnection createBSideJoin(RelationType relationType) {
+        String table = relationType.getTableName() + ".";
+        return new TableJoinConnection(relationType.getRelationshipStorageLocation(), null, List.of(condition(field(
+                table + String.format(QUOTED_STRING, relationType.aSideColumnName())).eq(field(String.format(TIES_DATA,
+                        getDbName(relationType.getASide().getName())) + "." + String.format(QUOTED_STRING,
+                                ID_COLUMN_NAME))))), false);
+    }
+
+    private static TableJoinConnection createRelationJoin(QueryElement qe1, QueryElement qe2, RelationType relationType) {
+        String table = relationType.getTableName() + ".";
+        if (relationType.isConnectsSameEntity()) {
+            return createSameEntityJoin(qe1, qe2, relationType);
+        } else if (!qe1.isManyToMany()) {
+            return new TableJoinConnection(relationType.getRelationshipStorageLocation(), relationType.getTableName(), List
+                    .of(condition(field(table + String.format(QUOTED_STRING, relationType.bSideColumnName())).eq(field(
+                            String.format(TIES_DATA, getDbName(qe2.getObjectType())) + "." + String.format(QUOTED_STRING,
+                                    ID_COLUMN_NAME)))), condition(field(table + String.format(QUOTED_STRING, relationType
+                                            .aSideColumnName())).eq(field(String.format(TIES_DATA, qe1
+                                                    .getObjectType()) + "." + String.format(QUOTED_STRING,
+                                                            ID_COLUMN_NAME))))), false);
+        } else {
+            String colInManyToManyTable = relationType.getASide().getName().equals(qe2.getObjectType()) ?
+                    relationType.aSideColumnName() :
+                    relationType.bSideColumnName();
+            return new TableJoinConnection(relationType.getRelationshipStorageLocation(), relationType.getTableName(), List
+                    .of(condition(field(table + String.format(QUOTED_STRING, colInManyToManyTable)).eq(field(String.format(
+                            TIES_DATA, getDbName(qe2.getObjectType())) + "." + String.format(QUOTED_STRING,
+                                    ID_COLUMN_NAME))))), false);
+        }
+    }
+
+    private static Select<Record> buildUnionBody(DSLContext context, QueryElement root, String returnObject,
+            List<String> relationships, Condition joinFilter, boolean[] isValidHop) {
+        SelectSelectStep<Record> selectStep = buildSelectStepForUnion(context, root, returnObject);
+        SelectJoinStep<Record> fromStep = buildFromStep(selectStep, root, relationships, isValidHop, returnObject);
+        return buildWhereStep(fromStep, root, joinFilter, relationships);
+    }
+
+    private static Select<Record> buildWhereStep(Select<Record> query, QueryElement root, Condition joinFilter,
+            List<String> relationships) {
+        Condition condition = DSL.noCondition();
+        condition = buildWhereAnd(condition, root, relationships);
+        for (QueryElement child : root.getChildren()) {
+            condition = buildWhereAnd(condition, child, null);
+        }
+        if (!root.isManyToMany()) {
+            condition = buildWhereOr(condition, root);
+        }
+        for (QueryElement child : root.getChildren()) {
+            condition = buildWhereOr(condition, child);
+        }
+        if (joinFilter != null && root.getObjectType() != null) {
+            condition = condition.and(joinFilter);
+        } else if (joinFilter != null) {
+            condition = condition.or(joinFilter);
+        }
+        return query.$where(condition);
+    }
+
+    private static Condition buildWhereAnd(Condition condition, QueryElement root, List<String> relationships) {
+        if (root.hasFilters() && (root.hasFilterOfType(TokenType.AND) || root.hasFilterOfType(TokenType.NO_TYPE))) {
+            condition = condition.and(DSL.and(Stream.concat(root.getFiltersOfTypes(List.of(TokenType.AND,
+                    TokenType.NO_TYPE)).stream().flatMap(filter -> filter.hasLeafConditions() ?
+                            filter.getLeavesData().stream().map(leaf -> field(String.format(TIES_DATA, getDbName(root
+                                    .getObjectType())) + "." + String.format(QUOTED_STRING, getDbName(leaf.getName()))).eq(
+                                            leaf.getValue())) :
+                            null), root.getFiltersOfTypes(List.of(TokenType.AND, TokenType.NO_TYPE)).stream().map(
+                                    filter -> filter.hasContainsFunctionCondition() ?
+                                            field(String.format(TIES_DATA, getDbName(root.getObjectType())) + "." + String
+                                                    .format(QUOTED_STRING, getDbName(filter
+                                                            .getContainsFunctionConditionLeafName()))).contains(filter
+                                                                    .getContainsFunctionConditionValue()) :
+                                            DSL.noCondition())).toList()));
+        }
+
+        condition = getConditionsWithRelationships(condition, relationships);
+
+        return condition;
+    }
+
+    private static Condition getConditionsWithRelationships(Condition condition, List<String> relationships) {
+        if (relationships != null) {
+            List<RelationType> relationTypes = new ArrayList<>();
+
+            for (String relationship : relationships) {
+                relationTypes.add(SchemaRegistry.getRelationTypeByName(relationship));
+            }
+
+            for (RelationType relationType : relationTypes) {
+                for (Field<?> field : relationType.getBaseFieldsWithId()) {
+                    condition = condition.and(field.isNotNull());
+                }
+            }
+        }
+        return condition;
+    }
+
+    private static Condition buildWhereOr(Condition condition, QueryElement root) {
+        if (root.hasFilters() && root.hasFilterOfType(TokenType.OR)) {
+            condition = condition.or(DSL.or(root.getFiltersOfTypes(List.of(TokenType.OR)).stream().map(filter -> DSL.and(
+                    filter.hasLeafConditions() ?
+                            filter.getLeavesData().stream().map(leaf -> field(String.format(TIES_DATA, getDbName(root
+                                    .getObjectType())) + "." + String.format(QUOTED_STRING, getDbName(leaf.getName()))).eq(
+                                            leaf.getValue())).toList() :
+                            List.of(DSL.noCondition()))).toList()));
+            condition = condition.or(DSL.or(root.getFiltersOfTypes(List.of(TokenType.OR)).stream().map(filter -> filter
+                    .hasContainsFunctionCondition() ?
+                            field(String.format(TIES_DATA, getDbName(root.getObjectType())) + "." + String.format(
+                                    QUOTED_STRING, getDbName(filter.getContainsFunctionConditionLeafName()))).contains(
+                                            filter.getContainsFunctionConditionValue()) :
+                            DSL.noCondition()).toList()));
+        }
+        return condition;
+    }
+
+    private static List<String> getColumnList(QueryElement root) {
+        List<String> columns = new ArrayList<>();
+
+        if (root.isIncluded()) {
+            if (!root.hasAttributes()) {
+                columns.add(String.format(TIES_DATA, getDbName(root.getObjectType())) + "." + String.format(QUOTED_STRING,
+                        ID_COLUMN_NAME));
+            } else {
+                if (root.getAttributes().isEmpty()) {
+                    columns.addAll(SchemaRegistry.getEntityTypeByName(root.getObjectType()).getAttributeColumnsWithId());
+                } else {
+                    columns.addAll(root.getAttributes().stream().map(attribute -> String.format(TIES_DATA, getDbName(root
+                            .getObjectType())) + "." + String.format(QUOTED_STRING, getDbName(attribute))).toList());
+                    if (!columns.contains(String.format(TIES_DATA, getDbName(root.getObjectType())) + "." + String.format(
+                            QUOTED_STRING, ID_COLUMN_NAME))) {
+                        columns.add(String.format(TIES_DATA, getDbName(root.getObjectType())) + "." + String.format(
+                                QUOTED_STRING, ID_COLUMN_NAME));
+                    }
+                }
+            }
+        }
+        if (root.hasChildren()) {
+            columns.addAll(root.getChildren().stream().flatMap(child -> getColumnList(child).stream()).toList());
+        }
+
+        return columns;
+    }
+
+    private static List<PathToken> processPath(String path, boolean isSemiColonAllowed) {
+        return processPath(path, isSemiColonAllowed, null);
+    }
+
+    private static List<PathToken> processPath(String path, boolean isSemiColonAllowed, TokenType lastToken) {
+        List<PathToken> tiesPath = new ArrayList<>();
+
+        if (path.isEmpty()) {
+            return tiesPath;
+        }
+
+        if (!isSemiColonAllowed && path.indexOf(';') > -1) {
+            throw TiesPathException.grammarError(String.format("Character ';' is not allowed at %d", path.indexOf(';')));
+        }
+
+        if (path.contains(BAR) || path.contains(SEMICOLON)) {
+            String delimiter = findDelimiter(path);
+
+            String[] tokens = path.split(Pattern.quote(delimiter), 2);
+            TokenType type = delimiter.equals(BAR) ? TokenType.OR : TokenType.AND;
+            addPathSafe(tiesPath, tokens[0], type);
+            tiesPath.addAll(processPath(tokens[1], isSemiColonAllowed, type));
+        } else {
+            addPathSafe(tiesPath, path, lastToken != null ? lastToken : TokenType.NO_TYPE);
+        }
+        return tiesPath;
+    }
+
+    private static String findDelimiter(String path) {
+        if (path.contains(BAR) && path.contains(SEMICOLON)) {
+            return path.indexOf(BAR) < path.indexOf(SEMICOLON) ? SEMICOLON : BAR;
+        } else {
+            return path.contains(BAR) ? BAR : SEMICOLON;
+        }
+    }
+
+    private static void addPathSafe(List<PathToken> tiesPath, String path, TokenType type) {
+        try {
+            tiesPath.add(new PathToken(type, getTiesPathQuery(path)));
+        } catch (ParseCancellationException e) {
+            throw TiesPathException.grammarError(e.getMessage());
+        } catch (PathParsingException e) {
+            throw TiesPathException.grammarError(e.getDetails());
+        }
+    }
+
+    private static List<String> parseRelationships(final String relationships) {
+        if (relationships == null || relationships.isEmpty()) {
+            return new ArrayList<>();
+        }
+        String[] relationshipTokens = relationships.split(",");
+        List<String> relationshipsList = new ArrayList<>();
+        Arrays.stream(relationshipTokens).forEach(relationship -> {
+            String trimmed = relationship.trim();
+            if (SchemaRegistry.getRelationNames().contains(trimmed)) {
+                relationshipsList.add(trimmed);
+            } else {
+                throw TiesPathException.invalidRelationshipName(trimmed);
+            }
+        });
+        return relationshipsList;
+    }
+
+    private static QueryElement buildQueryTree(String objectType, List<PathToken> targets, List<PathToken> scopes,
+            String domain) {
+        QueryElement root = new QueryElement(objectType);
+        RelationType relationType = SchemaRegistry.getRelationTypeByName(objectType);
+        if (objectType != null && relationType != null) {
+            if (relationType.isConnectsSameEntity()) {
+                root.setRelConnectingSameEntity();
+            } else if (RELATION.equals(relationType.getRelationshipStorageLocation())) {
+                root.setManyToMany();
+            }
+        }
+
+        processTargets(root, targets, domain);
+        processScopes(root, scopes, domain);
+
+        return root;
+    }
+
+    private static void processTargets(QueryElement root, List<PathToken> targets, String domain) {
+        String prevToken = null;
+        String prevPrevToken = null;
+
+        if (targets.isEmpty()) {
+            root.include();
+        }
+
+        for (PathToken target : targets) {
+            QueryElement[] currentElement = { root };
+            boolean isValidHop = true;
+            for (int i = 0; i < target.getValue().getContainerNames().size(); ++i) {
+                String container = target.getValue().getContainerNames().get(i);
+                isValidHop = processTargetContainer(root, currentElement, container, prevToken, domain, prevPrevToken);
+                if (!isValidHop) {
+                    break;
+                }
+                prevPrevToken = prevToken;
+                prevToken = container;
+            }
+            if (isValidHop) {
+                addTargetAttributes(currentElement[0], target);
+            }
+            prevToken = null;
+        }
+
+        if (root.getObjectType() == null && root.getChildren().isEmpty()) {
+            throw TiesPathException.grammarError("No match for targetFilter condition");
+        }
+    }
+
+    private static boolean processTargetContainer(QueryElement root, QueryElement[] currentElement, String container,
+            String prevToken, String domain, String prevPrevToken) {
+        if (SchemaRegistry.isValidEntityName(container)) {
+            if (prevToken != null) {
+                throw TiesPathException.grammarError(String.format("Missing ';' or '|' before %s", container));
+            }
+            if (root.getObjectType() != null && !SchemaRegistry.hasDirectHopBetween(currentElement[0].getObjectType(),
+                    container)) {
+                return false;
+            }
+            if (root.getObjectType() == null && !SchemaRegistry.getEntityNamesByDomain(domain).contains(container)) {
+                throw TiesPathException.grammarError(String.format("%s is not part of %s domain", container, domain));
+            }
+            currentElement[0].addChild(new QueryElement(container, true));
+            currentElement[0] = currentElement[0].getChild(container);
+            prevToken = container;
+        } else if (root.getObjectType() != null && currentElement[0].getObjectType().equals(root.getObjectType()) && !root
+                .hasChildren()) {
+            root.include();
+        }
+
+        processTargetAttribute(container, prevToken, currentElement[0]);
+
+        processTargetContainerIfItIsAttributes(root, currentElement, container, prevToken, domain);
+
+        processTargetContainerIfItIsID(root, currentElement, container, prevToken, domain);
+
+        processTargetContainerPrevPrevTokenNull(root, container, prevToken, prevPrevToken);
+
+        return true;
+    }
+
+    private static void processTargetContainerPrevPrevTokenNull(QueryElement root, String container, String prevToken,
+            String prevPrevToken) {
+        if (prevPrevToken == null && prevToken != null && prevToken.equals(ATTRIBUTES) && !container.equals(
+                ID_COLUMN_NAME) && !container.equals(ATTRIBUTES)) {
+            List<QueryElement> doesNotHaveAttribute = new ArrayList<>();
+            for (QueryElement child : root.getChildren()) {
+                processTargetAttribute(container, prevToken, child);
+                if (child.getAttributes().isEmpty()) {
+                    doesNotHaveAttribute.add(child);
+                }
+            }
+            if (root.getObjectType() == null) {
+                removeChildFromRoot(doesNotHaveAttribute, root);
+            }
+        } else if (prevPrevToken == null && prevToken != null && prevToken.equals(ATTRIBUTES) && container.equals(
+                ID_COLUMN_NAME)) {
+            throw TiesPathException.idAmongAttributesError();
+        }
+    }
+
+    private static void removeChildFromRoot(List<QueryElement> childrenToRemove, QueryElement root) {
+        for (QueryElement child : childrenToRemove) {
+            root.removeChild(child);
+        }
+
+    }
+
+    private static void processTargetContainerIfItIsAttributes(QueryElement root, QueryElement[] currentElement,
+            String container, String prevToken, String domain) {
+        if (container.equals(ATTRIBUTES) && root.getObjectType() == null && prevToken == null) {
+            for (String entity : SchemaRegistry.getEntityNamesByDomain(domain)) {
+                if (currentElement[0].getChild(entity) == null) {
+                    QueryElement entityInDomain = new QueryElement(entity);
+                    addTargetContainer(entityInDomain, prevToken);
+                    currentElement[0].addChild(entityInDomain);
+                }
+            }
+        } else if (container.equals(ATTRIBUTES)) {
+            addTargetContainer(currentElement[0], prevToken);
+        }
+    }
+
+    private static void processTargetContainerIfItIsID(QueryElement root, QueryElement[] currentElement, String container,
+            String prevToken, String domain) {
+        if (container.equals(ID_COLUMN_NAME) && root.getObjectType() == null && prevToken == null) {
+            for (String entity : SchemaRegistry.getEntityNamesByDomain(domain)) {
+                if (currentElement[0].getChild(entity) == null && SchemaRegistry.doesEntityContainsAttribute(entity,
+                        container)) {
+                    QueryElement entityInDomain = new QueryElement(entity, true);
+                    currentElement[0].addChild(entityInDomain);
+                    addTargetContainer(entityInDomain, prevToken);
+                    addTargetAttribute(entityInDomain, container);
+                }
+            }
+        }
+
+    }
+
+    private static void processTargetAttribute(String container, String prevToken, QueryElement currentElement) {
+        if (SchemaRegistry.doesEntityContainsAttribute(currentElement.getObjectType(), container)) {
+            if (container.equals(ID_COLUMN_NAME) && prevToken == null) {
+                addTargetContainer(currentElement, null);
+                addTargetAttribute(currentElement, container);
+
+            } else if (container.equals(ID_COLUMN_NAME)) {
+                if (SchemaRegistry.isValidEntityName(prevToken)) {
+                    addTargetContainer(currentElement, prevToken);
+                    addTargetAttribute(currentElement, container);
+                } else {
+                    throw TiesPathException.idAmongAttributesError();
+                }
+            } else {
+                if (prevToken == null) {
+                    throw TiesPathException.grammarError(String.format("Missing 'attributes' before %s", container));
+                } else if (prevToken.equals(ATTRIBUTES)) {
+                    addTargetAttribute(currentElement, container);
+
+                } else {
+                    throw TiesPathException.grammarError(String.format("/%s/%s is not accepted", prevToken, container));
+                }
+            }
+        }
+    }
+
+    private static void addTargetContainer(QueryElement element, String prevToken) {
+        if (ATTRIBUTES.equals(prevToken)) {
+            throw TiesPathException.grammarError(String.format("Missing ';' or '|' before %s", prevToken));
+        }
+        if (!element.hasAttributes()) {
+            element.setAttributes(new ArrayList<>());
+            element.include();
+        }
+    }
+
+    private static void addTargetAttribute(QueryElement element, String container) {
+        if (!element.hasAttributes()) {
+            throw TiesPathException.grammarError(String.format("Missing 'attributes' before %s", container));
+        }
+        element.addAttribute(container);
+    }
+
+    private static void addTargetAttributes(QueryElement element, PathToken target) {
+        if (target.getValue().getNormalizedXpath().equals("/" + ID_COLUMN_NAME) && !target.getValue().getAttributeNames()
+                .isEmpty()) {
+            throw TiesPathException.grammarError("/" + ID_COLUMN_NAME + "/" + target.getValue().getAttributeNames().get(
+                    0) + " is not accepted.");
+        }
+        if (element.getObjectType() != null) {
+            addTargetAttributesIfObjectTypeIsNotNull(element, target);
+
+        } else {
+            addTargetAttributesIfObjectTypeIsNull(element, target);
+
+        }
+    }
+
+    private static void addTargetAttributesIfObjectTypeIsNotNull(QueryElement element, PathToken target) {
+        for (String attribute : target.getValue().getAttributeNames()) {
+            if (!element.isManyToMany() && attribute.equals(ID_COLUMN_NAME)) {
+                throw TiesPathException.idAmongAttributesError();
+            }
+            if (!element.isManyToMany() && !SchemaRegistry.doesEntityContainsAttribute(element.getObjectType(),
+                    attribute) && !SchemaRegistry.getRelationNamesByEntityName(element.getObjectType()).contains(attribute
+                            .replace("REL_ID_", "")) && !SchemaRegistry.getRelationNames().contains(element
+                                    .getObjectType()) && !SchemaRegistry.getAssociationNamesByEntityName(element
+                                            .getObjectType()).contains(attribute.replace("REL_FK_", ""))) {
+                throw TiesPathException.columnNameError(element.getObjectType(), attribute);
+            }
+            if (!element.hasAttributes()) {
+                throw TiesPathException.grammarError(String.format("Missing 'attributes' before (%s...", target.getValue()
+                        .getAttributeNames().get(0)));
+            }
+            element.addAttribute(attribute);
+        }
+    }
+
+    private static void addTargetAttributesIfObjectTypeIsNull(QueryElement element, PathToken target) {
+        Set<QueryElement> hasNoAttribute = new HashSet<>();
+        for (String attribute : target.getValue().getAttributeNames()) {
+            if (attribute.equals(ID_COLUMN_NAME)) {
+                throw TiesPathException.idAmongAttributesError();
+            }
+
+            for (QueryElement entity : element.getChildren()) {
+                if (SchemaRegistry.doesEntityContainsAttribute(entity.getObjectType(), attribute)) {
+                    entity.addAttribute(attribute);
+                    hasNoAttribute.remove(entity);
+                } else {
+                    hasNoAttribute.add(entity);
+                }
+            }
+        }
+        for (QueryElement child : hasNoAttribute) {
+            element.removeChild(child);
+        }
+
+    }
+
+    private static void processScopes(QueryElement root, List<PathToken> scopes, String domain) {
+        String prevToken;
+
+        for (PathToken scope : scopes) {
+            QueryElement[] currentElement = { root };
+            prevToken = null;
+            boolean isValidHop = true;
+            for (int i = 0; i < scope.getValue().getContainerNames().size(); ++i) {
+                String container = scope.getValue().getContainerNames().get(i);
+                isValidHop = processScopeContainer(currentElement, container, prevToken, domain);
+                prevToken = container;
+            }
+            if ((prevToken != null && isValidHop) && (scope.getValue().hasLeafConditions() || scope.getValue()
+                    .hasContainsFunctionCondition()) && scope.value.getNormalizedParentPath().isEmpty() && root
+                            .getObjectType() == null) {
+
+                checkIdExpressions(scope.getValue().getContainsFunctionConditionLeafName(), prevToken, scope.getValue()
+                        .getLeavesData());
+
+                processScopesIfRootsObjectTypeIsNull(currentElement[0].getChildren(), scope, prevToken);
+
+            } else if (isValidHop && (scope.getValue().hasLeafConditions() || scope.getValue()
+                    .hasContainsFunctionCondition())) {
+
+                checkConditions(currentElement[0], scope);
+
+                if (!root.isManyToMany() && !root.isRelConnectingSameEntity() && scope.getValue()
+                        .hasContainsFunctionCondition() && !SchemaRegistry.doesEntityContainsAttribute(currentElement[0]
+                                .getObjectType(), scope.getValue().getContainsFunctionConditionLeafName())) {
+                    throw TiesPathException.columnNameError(currentElement[0].getObjectType(), scope.getValue()
+                            .getContainsFunctionConditionLeafName());
+                }
+
+                checkIdAttributes(currentElement[0], prevToken);
+
+                String leafName = scope.getValue().getContainsFunctionConditionLeafName();
+
+                checkIdExpressions(leafName, prevToken, scope.getValue().getLeavesData());
+
+                currentElement[0].addFilter(scope.getType(), scope.getValue());
+            }
+        }
+    }
+
+    private static void checkIdAttributes(QueryElement currentElement, String prevToken) {
+        if (!currentElement.hasFilters() && !prevToken.equals(ID_COLUMN_NAME)) {
+            throw TiesPathException.grammarError("Missing 'attributes' before '[''");
+        }
+    }
+
+    private static void checkIdExpressions(String leafName, String prevToken, List<TiesPathQuery.DataLeaf> leavesData) {
+        if (leavesData != null) {
+            List<TiesPathQuery.DataLeaf> leavesDataWithId = leavesData.stream().filter(leaf -> leaf.getName().equals(
+                    ID_COLUMN_NAME)).toList();
+            if ((!leavesDataWithId.isEmpty() && !prevToken.equals(ID_COLUMN_NAME)) || ((leavesData
+                    .size() > 1 || leavesDataWithId.size() != 1) && prevToken.equals(ID_COLUMN_NAME))) {
+                throw TiesPathException.grammarError("Expression is not accepted");
+            }
+        }
+
+        if (leafName != null && (leafName.equals(ID_COLUMN_NAME) && !prevToken.equals(
+                ID_COLUMN_NAME)) || leafName != null && (!leafName.equals(ID_COLUMN_NAME) && prevToken.equals(
+                        ID_COLUMN_NAME))) {
+            throw TiesPathException.grammarError("Expression is not accepted");
+        }
+    }
+
+    private static boolean processScopeContainer(QueryElement[] currentElement, String container, String prevToken,
+            String domain) {
+        if (SchemaRegistry.isValidEntityName(container)) {
+            if (prevToken != null) {
+                throw TiesPathException.grammarError(String.format("Missing ';' or '|' before %s", container));
+            }
+            if (currentElement[0].getObjectType() != null && !currentElement[0].isManyToMany() && !currentElement[0]
+                    .isRelConnectingSameEntity() && !SchemaRegistry.hasDirectHopBetween(currentElement[0].getObjectType(),
+                            container)) {
+                return false;
+            }
+            if (currentElement[0].getObjectType() == null && !SchemaRegistry.getEntityNamesByDomain(domain).contains(
+                    container)) {
+                throw TiesPathException.grammarError(String.format("%s is not part of %s domain", container, domain));
+            }
+            currentElement[0].addChild(new QueryElement(container));
+            currentElement[0] = currentElement[0].getChild(container);
+        }
+        processScopeContainerIfContainerIsAttributesOrId(currentElement[0], container, prevToken);
+
+        return true;
+    }
+
+    private static void processScopeContainerIfContainerIsAttributesOrId(QueryElement currentElement, String container,
+            String prevToken) {
+        if ((container.equals(ATTRIBUTES) || container.equals(ID_COLUMN_NAME)) && prevToken == null && currentElement
+                .getObjectType() == null) {
+            for (QueryElement entity : currentElement.getChildren()) {
+                addScopeFilter(entity, container, prevToken);
+            }
+        } else if (container.equals(ATTRIBUTES) || container.equals(ID_COLUMN_NAME)) {
+            addScopeFilter(currentElement, container, prevToken);
+        }
+    }
+
+    private static void addScopeFilter(QueryElement element, String container, String prevToken) {
+        if (container.equals(prevToken)) {
+            throw TiesPathException.grammarError(String.format("Missing ';' or '|' before %s", container));
+        }
+        if (!element.hasFilters()) {
+            element.setFilters(new EnumMap<>(TokenType.class));
+        }
+    }
+
+    private static void checkConditions(QueryElement element, PathToken scope) {
+        if (element.getObjectType() != null) {
+            if (scope.getValue().hasLeafConditions()) {
+                for (TiesPathQuery.DataLeaf leaf : scope.getValue().getLeavesData()) {
+                    if (!element.isManyToMany() && !element.isRelConnectingSameEntity() && !SchemaRegistry
+                            .doesEntityContainsAttribute(element.getObjectType(), leaf.getName())) {
+                        throw TiesPathException.columnNameError(element.getObjectType(), leaf.getName());
+                    }
+                }
+            }
+            if (!element.isManyToMany() && !element.isRelConnectingSameEntity() && scope.getValue()
+                    .hasContainsFunctionCondition() && !SchemaRegistry.doesEntityContainsAttribute(element.getObjectType(),
+                            scope.getValue().getContainsFunctionConditionLeafName())) {
+                throw TiesPathException.columnNameError(element.getObjectType(), scope.getValue()
+                        .getContainsFunctionConditionLeafName());
+            }
+        }
+
+    }
+
+    private static void processScopesIfRootsObjectTypeIsNull(List<QueryElement> elements, PathToken scope,
+            String prevToken) {
+        processScopesIfRootsObjectTypeIsNullHasLeafCondition(elements, scope, prevToken);
+        processScopesIfRootsObjectTypeIsNullHasContainsCondition(elements, scope, prevToken);
+    }
+
+    private static void processScopesIfRootsObjectTypeIsNullHasLeafCondition(List<QueryElement> elements, PathToken scope,
+            String prevToken) {
+
+        if (scope.getValue().hasLeafConditions()) {
+            int counter = 0;
+            boolean anyOfElementsContainsLeaf = true;
+            for (QueryElement element : elements) {
+                for (TiesPathQuery.DataLeaf leaf : scope.getValue().getLeavesData()) {
+                    checkIdAttributes(element, prevToken);
+                    if (!SchemaRegistry.doesEntityContainsAttribute(element.getObjectType(), leaf.getName())) {
+                        anyOfElementsContainsLeaf = false;
+                        break;
+                    }
+                }
+                if (anyOfElementsContainsLeaf) {
+                    element.addFilter(TokenType.OR, scope.getValue());
+                    counter++;
+                }
+
+                anyOfElementsContainsLeaf = true;
+            }
+            if (counter == 0) {
+                throw TiesPathException.grammarError(
+                        "None of the entities in domain has the attribute that was provided in scopeFilter");
+            }
+        }
+    }
+
+    private static void processScopesIfRootsObjectTypeIsNullHasContainsCondition(List<QueryElement> elements,
+            PathToken scope, String prevToken) {
+
+        if (scope.getValue().hasContainsFunctionCondition()) {
+            boolean anyOfElementsContainsLeaf = false;
+            for (QueryElement element : elements) {
+                checkIdAttributes(element, prevToken);
+                if (SchemaRegistry.doesEntityContainsAttribute(element.getObjectType(), scope.getValue()
+                        .getContainsFunctionConditionLeafName())) {
+                    element.addFilter(TokenType.OR, scope.getValue());
+                    anyOfElementsContainsLeaf = true;
+                }
+            }
+            if (!anyOfElementsContainsLeaf) {
+                throw TiesPathException.grammarError(
+                        "None of the entities in domain has the attribute that was provided in scopeFilter");
+            }
+        }
+    }
+
+    @Getter
+    @Setter
+    @AllArgsConstructor
+    private static class PathToken {
+        private TokenType type;
+        private TiesPathQuery value;
+    }
+
+    @Getter
+    @AllArgsConstructor
+    private static class TableJoinConnection {
+        private RelationshipDataLocation relationshipDataLocation;
+        private String tableName;
+        private List<Condition> conditions;
+        private boolean relConnectingSameEntity;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/query/TokenType.java b/teiv/src/main/java/org/oran/smo/teiv/utils/query/TokenType.java
new file mode 100644
index 0000000..9a7f072
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/query/TokenType.java
@@ -0,0 +1,27 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.query;
+
+enum TokenType {
+    AND,
+    OR,
+    NO_TYPE
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/query/exception/TiesPathException.java b/teiv/src/main/java/org/oran/smo/teiv/utils/query/exception/TiesPathException.java
new file mode 100644
index 0000000..f064de5
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/query/exception/TiesPathException.java
@@ -0,0 +1,127 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.query.exception;
+
+import lombok.Getter;
+import org.springframework.http.HttpStatus;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Getter
+public class TiesPathException extends RuntimeException {
+
+    private final String message;
+    private final String details;
+    private final HttpStatus httpStatus;
+    private final transient List<Object> response;
+    private static final List<Object> defaultResponse = Collections.emptyList();
+
+    public static TiesPathException invalidRelationshipName(final String relationship) {
+        return clientException("Invalid relationship name", String.format("%s is not a known relationship", relationship));
+    }
+
+    public static TiesPathException noConnectionFound(final String object) {
+        return clientException("Objects are not related", String.format(
+                "No relationship can be found between %s and scopeFilter elements", object));
+    }
+
+    public static TiesPathException noConnectionFoundWhenRootIsNull() {
+        return clientException("Objects are not related",
+                "None of the elements in the targetFilter is part of connection provided in relationships filter");
+    }
+
+    public static TiesPathException grammarError(final String message) {
+        return clientException("Grammar error", message);
+    }
+
+    public static TiesPathException columnNameError(String entity, String column) {
+        return clientException("Grammar Error", String.format("%s is not a valid attribute of %s", column, entity));
+    }
+
+    public static TiesPathException columnNamesError(String entity, List<String> columns) {
+        if (columns.size() == 1) {
+            return columnNameError(entity, columns.get(0));
+        } else {
+            return clientException("Invalid parameter error", String.format("%s are not valid attributes of %s", String
+                    .join(", ", columns), entity));
+        }
+    }
+
+    public static TiesPathException sourceIdNameError(String entity) {
+        return clientException("Invalid parameter error", String.format("Invalid source id parameter provided for %s",
+                entity));
+    }
+
+    private static TiesPathException clientException(final String message, final String details) {
+        return new TiesPathException(message, details, HttpStatus.BAD_REQUEST, null);
+    }
+
+    public static TiesPathException idAmongAttributesError() {
+        return clientException("Grammar Error", "ID is not considered to be an attribute");
+    }
+
+    public static TiesPathException entityNameError(String entity) {
+        return clientException("Grammar Error", String.format("%s is not a valid entity", entity));
+    }
+
+    public static TiesPathException invalidTopologyObject(String topologyObject) {
+        return clientException("Invalid topology object", String.format(
+                "%s did not match any topology objects in the given domain", topologyObject));
+    }
+
+    public static TiesPathException ambiguousTopologyObject(String topologyObject) {
+        return clientException("Invalid topology object", String.format(
+                "%s is ambiguous, %s matches multiple topology object types", topologyObject, topologyObject));
+    }
+
+    public static TiesPathException invalidAssociation(String topologyObject, String associationName) {
+        return clientException("Invalid association name", String.format(
+                "%s is not a valid association name for topology object %s", associationName, topologyObject));
+    }
+
+    public static TiesPathException invalidParamsForAssociation(String associationName) {
+        return clientException("Invalid parameters for association", String.format(
+                "Invalid parameters provided for association %s", associationName));
+    }
+
+    public static TiesPathException containerValidationWithUndefinedTopologyObjectType(String topologyObject) {
+        return clientException("Container validation error", String.format(
+                "Container validation is not possible for undefined %s", topologyObject));
+    }
+
+    public static TiesPathException notMatchingScopeAndTargetFilter() {
+        return clientException("Filter Error", "TopologyObjects given in scopeFilter and targetFilter are not matching");
+    }
+
+    private static TiesPathException clientExceptionWithDefaultResponse(final String message, final String details) {
+        return new TiesPathException(message, details, HttpStatus.BAD_REQUEST, defaultResponse);
+    }
+
+    private TiesPathException(final String message, final String details, final HttpStatus httpStatus,
+            final List<Object> response) {
+        this.message = message;
+        this.details = details;
+        this.httpStatus = httpStatus;
+        this.response = response != null ? new ArrayList<>(response) : null;
+    }
+}
diff --git a/teiv/src/main/java/org/oran/smo/teiv/utils/schema/Geography.java b/teiv/src/main/java/org/oran/smo/teiv/utils/schema/Geography.java
new file mode 100644
index 0000000..6fafdcf
--- /dev/null
+++ b/teiv/src/main/java/org/oran/smo/teiv/utils/schema/Geography.java
@@ -0,0 +1,70 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.schema;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode
+@AllArgsConstructor
+public class Geography {
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+    private Double latitude;
+    private Double longitude;
+
+    /**
+     * Creates a Geography object from a standard (RFC 9179) YANG geo-location type.
+     * Only "latitude" and "longitude" fields are supported. All other fields in the json are ignored.
+     *
+     * @param json
+     *     A json that conforms to the "RFC 9179: A YANG Grouping for Geographic Location" standard.
+     * @throws IOException
+     *     when the json doesn't contain both "latitude" and "longitude" fields.
+     */
+    public Geography(String json) throws IOException {
+        JsonParser jsonParser = objectMapper.readTree(json).traverse();
+
+        while (jsonParser.nextToken() != null) {
+            if ("latitude".equals(jsonParser.currentName())) {
+                latitude = jsonParser.getDoubleValue();
+            } else if ("longitude".equals(jsonParser.currentName())) {
+                longitude = jsonParser.getDoubleValue();
+            }
+            if (latitude != null && longitude != null) {
+                return;
+            }
+        }
+        throw new IOException("Cannot find latitude and longitude fields in json: " + json);
+    }
+
+    @Override
+    public String toString() {
+        return "POINT(" + latitude + " " + longitude + ")";
+    }
+
+}
diff --git a/teiv/src/main/resources/application.yaml b/teiv/src/main/resources/application.yaml
new file mode 100644
index 0000000..a7e609c
--- /dev/null
+++ b/teiv/src/main/resources/application.yaml
@@ -0,0 +1,142 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+logging.level.root: ${ROOT_LOG_LEVEL:"INFO"}
+logging.level.org.apache.kafka: ${KAFKA_LOG_LEVEL:"WARN"}
+
+#Metrics related configurations
+management:
+  endpoint:
+    metrics:
+      enabled: "true"
+    prometheus:
+      enabled: "true"
+    health:
+      probes:
+        enabled: "true"
+      show-details: "always"
+      show-components: "always"
+      validate-group-membership: "false"
+      group:
+        readiness:
+          include: "readinessState,${HEALTH_CHECK_INDICATOR:tiesExposure}"
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  prometheus:
+    metrics:
+      export:
+        enabled: "true"
+  metrics:
+    web:
+      server:
+        request:
+          autotime:
+            enabled: "true"
+
+spring:
+  datasource:
+    read:
+      jdbc-url: ${SERVICE_DB_REPLICA_URL:jdbc:postgresql://dbpostgresql:5432/topology_exposure_db}
+      username: ${SERVICE_DB_USER:topology_exposure_user}
+      password: ${SERVICE_DB_PASSWORD:dbpassword}
+      driver-class-name: org.postgresql.Driver
+    write:
+      jdbc-url: ${SERVICE_DB_URL:jdbc:postgresql://dbpostgresql:5432/topology_exposure_db}
+      username: ${SERVICE_DB_USER:topology_exposure_user}
+      password: ${SERVICE_DB_PASSWORD:dbpassword}
+      driver-class-name: org.postgresql.Driver
+  main:
+    allow-circular-references: true
+  jooq:
+    sql-dialect: postgres
+  caching:
+    consumer-data-ttl-ms: 60000
+
+endpoints.health.sensitive: "false"
+info.app.name: '@name@'
+info.app.description: Topology Exposure and Inventory Service
+info.app.version: '@version@'
+info.app.legal: 'Copyright (C) 2024 Ericsson
+ Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ SPDX-License-Identifier: Apache-2.0'
+
+#See more details about pattern layout: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
+#See more details about logging.pattern.level : https://docs.spring.io/spring-boot/docs/2.5.2/reference/html/features.html#features.logging.custom-log-configuration
+#logging.pattern.level: "%5p [%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}][%X{userName}]"
+logging:
+  pattern:
+    dateformat: "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
+  config: ${LOGBACK_CONFIG_FILE:classpath:logback-json.xml}
+  endpoints:
+    exclude: /actuator/health, /actuator/prometheus, /ping, /metrics, /actuator/id-(.*)
+
+kafka:
+  server:
+    bootstrap-server-host: kafka
+    bootstrap-server-port: 9092
+  admin:
+    retry: 2147483647
+    retry-backoff-ms: 5000
+    reconnect-backoff-ms: 50
+    reconnect-backoff-max-ms: 30000
+    request-timeout-ms: 30000
+  availability:
+    retry-attempts: 2147483647
+    retry-interval-ms: 1000
+  topology-ingestion:
+    consumer:
+      topic:
+        name: topology-inventory-ingestion
+        partitions: 4
+        replicas: 3
+        retention-ms: 86400000
+      group-id: topology-inventory-ingestion-consumer
+      auto-offset-reset: earliest
+      max-poll-records: 500
+      max-poll-interval-ms: 300000
+      fetch-min-bytes: 1
+      fetch-max-wait-ms: 500
+      retry-attempts: 2147483647
+      retry-backoff-ms: 5000
+      concurrency: 2
+
+database:
+  retry-policies:
+    deadlock:
+      retry-attempts: 10
+      retry-backoff-ms: 200
+
+feature_flags:
+  use_alternate_delete_logic: false
\ No newline at end of file
diff --git a/teiv/src/main/resources/bootstrap.yml b/teiv/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..04c4faf
--- /dev/null
+++ b/teiv/src/main/resources/bootstrap.yml
@@ -0,0 +1,23 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+logging:
+ config: ${LOGBACK_CONFIG_FILE:classpath:logback-json.xml}
\ No newline at end of file
diff --git a/teiv/src/main/resources/logback-json.xml b/teiv/src/main/resources/logback-json.xml
new file mode 100644
index 0000000..6eba710
--- /dev/null
+++ b/teiv/src/main/resources/logback-json.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<configuration>
+    <appender name="json" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
+            <version>0.3.0</version>
+            <includeContext>false</includeContext>
+            <includeTags>false</includeTags>
+
+            <fieldNames>
+                <level>[ignore]</level>
+                <version>version</version>
+                <timestamp>timestamp</timestamp>
+                <thread>thread</thread>
+                <logger>logger</logger>
+                <levelValue>[ignore]</levelValue>
+            </fieldNames>
+
+            <!-- Add fields from MDC [user and correlation_id] -->
+            <includeMdcKeyName>user</includeMdcKeyName>
+            <provider class="net.logstash.logback.composite.loggingevent.LoggingEventPatternJsonProvider">
+                <pattern>
+                    <omitEmptyFields>true</omitEmptyFields>
+                    <pattern>
+                        {
+                        "service_id": "${SERVICE_ID:-unknown}",
+                        "correlation_id": "%mdc{X-B3-TraceId}"
+                        }
+                    </pattern>
+                </pattern>
+            </provider>
+
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="json"/>
+    </root>
+</configuration>
+
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-cloud-to-ran.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-cloud-to-ran.yang
new file mode 100644
index 0000000..8645592
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-cloud-to-ran.yang
@@ -0,0 +1,84 @@
+module o-ran-smo-teiv-cloud-to-ran {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-cloud-to-ran";
+    prefix or-teiv-cloudtoran;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import o-ran-smo-teiv-cloud {prefix or-teiv-cloud; }
+
+    import o-ran-smo-teiv-ran {prefix or-teiv-ran; }
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "RAN Cloud to RAN Logical topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the RAN Cloud to RAN Logical topology relations";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain CLOUD_TO_RAN;
+
+    or-teiv-yext:biDirectionalTopologyRelationship NFDEPLOYMENT_SERVES_GNBDUFUNCTION { // 0..n to 0..m
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-gnbduFunction {
+            description "gNodeBDU Function serviced by this NF Deployment.";
+            or-teiv-yext:aSide or-teiv-cloud:NFDeployment;
+            type instance-identifier;
+        }
+
+        leaf-list serving-nFDeployment {
+            description "NF Deployment that serves this gNodeBDU Function.";
+            or-teiv-yext:bSide or-teiv-ran:GNBDUFunction;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NFDEPLOYMENT_SERVES_GNBCUCPFUNCTION { // 0..n to 0..m
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-gnbcucpFunction {
+            description "gNodeB-CU-CP Function serviced by this NF Deployment.";
+            or-teiv-yext:aSide or-teiv-cloud:NFDeployment;
+            type instance-identifier;
+        }
+
+        leaf-list serving-nFDeployment {
+            description "NF Deployment that serves this gNodeBCUCP Function.";
+            or-teiv-yext:bSide or-teiv-ran:GNBCUCPFunction;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NFDEPLOYMENT_SERVES_GNBCUUPFUNCTION { // 0..n to 0..m
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-gnbcuupFunction {
+            description "gNodeB-CU-UP Function serviced by this NF Deployment.";
+            or-teiv-yext:aSide or-teiv-cloud:NFDeployment;
+            type instance-identifier;
+        }
+
+        leaf-list serving-nFDeployment {
+            description "NF Deployment that serves this gNodeBCUUP Function.";
+            or-teiv-yext:bSide or-teiv-ran:GNBCUUPFunction;
+            type instance-identifier;
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-cloud.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-cloud.yang
new file mode 100644
index 0000000..ef93698
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-cloud.yang
@@ -0,0 +1,188 @@
+module o-ran-smo-teiv-cloud {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-cloud";
+    prefix or-teiv-cloud;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import ietf-geo-location {
+        prefix geo;
+        reference "RFC 9179: A YANG Grouping for Geographic Locations";
+    }
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "RAN Cloud topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the topology entities and relations in the
+    RAN CLOUD domain, which comprises cloud infrastructure and
+    deployment aspects that can be used in the topology model.";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain CLOUD;
+
+    list CloudifiedNF {
+        description "A RAN Network Function software that is deployed in the O-Cloud via one or more NF Deployments.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf name {
+                description "Name of Cloudified NF";
+                type string;
+            }
+        }
+    }
+
+    list NFDeployment {
+        description "A software deployment on O-Cloud resources that realizes, all or part of, a Cloudified NF.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf name {
+                description "Name of NF Deployment";
+                type string;
+            }
+        }
+    }
+
+    list CloudNamespace {
+        description "CloudNamespace provide a mechanism for isolating
+                    groups of resources within a single cluster.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf name {
+                description "Name of Cloud Namespace";
+                type string;
+            }
+        }
+    }
+
+    list NodeCluster {
+        description "A NodeCluster manages a collection of Nodes.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf name {
+                description "Name of Node Cluster";
+                type string;
+            }
+        }
+    }
+
+    list CloudSite {
+        description "Represents the infrastructure that
+                    hosts the NF Deployment.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf name {
+                description "Name of Cloud Site";
+                type string;
+            }
+
+            uses geo:geo-location;
+        }
+    }
+
+
+    or-teiv-yext:biDirectionalTopologyRelationship CLOUDIFIEDNF_COMPRISES_NFDEPLOYMENT { // 1 to 1..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list comprised-nFDeployment {
+            description "Cloudified NF comprises of these NF Deployment.";
+            or-teiv-yext:aSide CloudifiedNF;
+            type instance-identifier;
+            min-elements 1;
+        }
+
+        leaf comprised-by-cloudifiedNF {
+            description "NF Deployment part of Cloudified NF.";
+            or-teiv-yext:bSide NFDeployment;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NFDEPLOYMENT_DEPLOYED_ON_CLOUDNAMESPACE { // 1..n to 1..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list deployed-on-cloudNamespace {
+            description "NF Deployment deployed on Cloud Namespace.";
+            or-teiv-yext:aSide NFDeployment;
+            type instance-identifier;
+            min-elements 1;
+        }
+
+        leaf-list deployed-nFDeployment {
+            description "Cloud Namespace deploys NF Deployment.";
+            or-teiv-yext:bSide CloudNamespace;
+            type instance-identifier;
+            min-elements 1;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship CLOUDNAMESPACE_DEPLOYED_ON_NODECLUSTER { // 1..n to 1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf deployed-on-nodeCluster {
+            description "Cloud Namespace deployed on Node Cluster.";
+            or-teiv-yext:aSide CloudNamespace;
+            type instance-identifier;
+            mandatory true;
+        }
+
+        leaf-list deployed-cloudNamespace {
+            description "Node Cluster deploys Cloud Namespace.";
+            or-teiv-yext:bSide NodeCluster;
+            type instance-identifier;
+            min-elements 1;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NODECLUSTER_LOCATED_AT_CLOUDSITE { // 1..n to 1..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list located-at-cloudSite {
+            description "Node Cluster located at Cloud Site.";
+            or-teiv-yext:aSide NodeCluster;
+            type instance-identifier;
+            min-elements 1;
+        }
+
+        leaf-list location-of-nodeCluster {
+            description "Cloud Site is location of Node Cluster.";
+            or-teiv-yext:bSide CloudSite;
+            type instance-identifier;
+            min-elements 1;
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-common-yang-extensions.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-common-yang-extensions.yang
new file mode 100644
index 0000000..92344b0
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-common-yang-extensions.yang
@@ -0,0 +1,129 @@
+module o-ran-smo-teiv-common-yang-extensions {
+
+  yang-version 1.1;
+  namespace "urn:o-ran:smo-teiv-common-yang-extensions";
+  prefix or-teiv-yext;
+
+  organization "ORAN";
+  contact "The Authors";
+  description
+  "Topology and Inventory YANG extensions model
+
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+  This model contains extensions to the YANG language that topology and
+  inventory models will use to define and annotate types and relationships.";
+
+  revision "2024-05-02" {
+    description "Initial revision.";
+    or-teiv-yext:label 0.3.0;
+  }
+
+  extension biDirectionalTopologyRelationship {
+
+    description
+      "Defines a bi-directional relationship in the topology.
+
+       A bi-directional-association (BDA) is a relationship comprising of an
+       A-side and a B-side. The A-side is considered the originating side of
+       the relationship; the B-side is considered the terminating side of the
+       relationship. The order of A-side and B-side is of importance and MUST
+       NOT be changed once defined.
+
+       Both A-side and B-side are defined on a type, and are given a role. A
+       type may have multiple originating and/or terminating sides of a
+       relationship, all distinguished by role name.
+
+       The statement MUST only be a substatement of the 'module' statement.
+       Multiple 'bi-directional-topology-relationship' statements are allowed
+       per parent statement.
+
+       Substatements to the 'bi-directional-topology-relationship' define the
+       A-side and the B-side, respectively, and optionally properties of the
+       relationship. Data nodes of types 'leaf' and 'leaf-list' are used for
+       this purpose. One of the data nodes MUST be annotated with the 'a-side'
+       extension; another data node MUST be annotated with the 'b-side'
+       extension. Other data nodes define properties of the relationship.
+
+       The argument is the name of the relationship. The relationship name is
+       scoped to the namespace of the declaring module and MUST be unique
+       within the scope.";
+
+    argument relationshipName;
+  }
+
+  extension aSide {
+    description
+      "Defines the A-side of a relationship.
+
+       The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+       statement, which itself must be a substatement of the
+       'uni-directional-topology-relationship' statement.
+
+       The data type of the parent 'leaf' or 'leaf-list' MUST be
+       'instance-identifier'. Constraints MAY be used as part of the parent
+       'leaf' or 'leaf-list' to enforce cardinality.
+
+       The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+       the role of the A-side of the relationship. The name of the role is
+       scoped to the type on which the A-side is defined and MUST be unique
+       within the scope.
+
+       While the parent 'leaf' or 'leaf-list' does not result in a property of
+       the relationship, it is RECOMMENDED to avoid using the name of an
+       existing type property as role name to avoid potential ambiguities
+       between properties of a type, and roles of a relationship on the type.
+
+       The argument is the name of the type on which the A-side resides. If the
+       type is declared in another module, the type must be prefixed, and a
+       corresponding 'import' statement be used to declare the prefix.";
+
+    argument aSideType;
+  }
+
+  extension bSide {
+    description "Defines the B-side of a relationship.
+
+       The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+       statement, which itself must be a substatement of the
+       'uni-directional-topology-relationship' statement.
+
+       The data type of the parent 'leaf' or 'leaf-list' MUST be
+       'instance-identifier'. Constraints MAY be used as part of the parent
+       'leaf' or 'leaf-list' to enforce cardinality.
+
+       The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+       the role of the B-side of the relationship. The name of the role is
+       scoped to the type on which the B-side is defined and MUST be unique
+       within the scope.
+
+       While the parent 'leaf' or 'leaf-list' does not result in a property of
+       the relationship, it is RECOMMENDED to avoid using the name of an
+       existing type property as role name to avoid potential ambiguities
+       between properties of a type, and roles of a relationship on the type.
+
+       The argument is the name of the type on which the B-side resides. If the
+       type is declared in another module, the type must be prefixed, and a
+       corresponding 'import' statement be used to declare the prefix.";
+
+    argument bSideType;
+  }
+
+  extension domain {
+    description "Keyword used to carry domain information.";
+    argument domainName;
+  }
+
+  extension label {
+    description "The label can be used to give modules and submodules a semantic version, in addition to their revision.
+
+      The format of the label is 'x.y.z' - expressed as pattern, it is [0-9]+\\.[0-9]+\\.[0-9]+
+
+      The statement MUST only be a substatement of the revision statement.  Zero or one revision label statements
+      per parent statement are allowed.
+
+      Revision labels MUST be unique amongst all revisions of a module or submodule.";
+      argument semversion;
+  }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-common-yang-types.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-common-yang-types.yang
new file mode 100644
index 0000000..1b15ce7
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-common-yang-types.yang
@@ -0,0 +1,90 @@
+module o-ran-smo-teiv-common-yang-types {
+
+  yang-version 1.1;
+  namespace "urn:o-ran:smo-teiv-common-yang-types";
+  prefix or-teiv-types;
+
+  import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+  import _3gpp-common-yang-types { prefix types3gpp; }
+
+  organization "ORAN";
+  contact "The Authors";
+  description
+  "Topology and Inventory common types model
+
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+  This model contains re-usable data types that topology and inventory models
+  will frequently use as part of types and relationships.";
+
+  revision "2024-05-02" {
+    description "Initial revision.";
+    or-teiv-yext:label 0.3.0;
+  }
+
+  grouping Top_Grp_Type {
+
+    description "Grouping containing the key attribute common to all types. All types
+                MUST use this grouping.";
+
+    leaf id {
+      type string;
+      description "Unique identifier of topology entities. Represents the Entity Instance Identifier.";
+    }
+  }
+
+  grouping CM_ID {
+
+    description "Grouping containing the key attributes to make
+                use of Configuration Management (CM).";
+
+    leaf cmHandle {
+      type string;
+      description "Unique identifier for network entities in CM.";
+    }
+
+    leaf resourceIdentifier {
+      type string;
+      description "The xpath expression identifying the resource in the Node model yang tree.";
+    }
+  }
+
+  typedef _3GPP_FDN_Type {
+    type types3gpp:DistinguishedName;
+  }
+
+  container consumer-data {
+    description "This container defines the consumer-data. Consumer-data may be attached to Topology Entity or
+                Topology Relation instance, outside of the declared Topology Entity or Topology Relationship's attributes.
+                This container cannot be instantiated, and it MUST NOT be augmented or deviated in any way, unless stated
+                otherwise.";
+
+    container decorators {
+      description "This container serves as extension point for applications wishing to define their own decorators.
+                  This is done via augmentations. They can only be defined in name value pair.";
+    }
+
+    leaf-list classifiers {
+      description "Consumer defined tags to topology entities and relationships.";
+      type identityref { base classifier; }
+    }
+
+    leaf-list sourceIds {
+      description "An ordered list of identities that represent the set of native source identifiers for participating
+                  entities.";
+      type string;
+      ordered-by user;
+    }
+
+    container metadata {
+      description "This container serves as extension point to define metadata. They can only be defined in name value
+                  pair.";
+    }
+  }
+
+  identity classifier{
+    description  "The classifier is used as a base to provide all classifiers with identity. ";
+  }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-equipment-to-ran.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-equipment-to-ran.yang
new file mode 100644
index 0000000..f518785
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-equipment-to-ran.yang
@@ -0,0 +1,140 @@
+module o-ran-smo-teiv-equipment-to-ran {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-equipment-to-ran";
+    prefix or-teiv-equiptoran;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import o-ran-smo-teiv-equipment {prefix or-teiv-equip; }
+
+    import o-ran-smo-teiv-ran {prefix or-teiv-ran; }
+
+
+    organization "ORAN";
+    contact "The Authors";
+    description 
+    "RAN Equipment to Logical topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the RAN Equipment to Logical topology
+    entities and relations.";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain EQUIPMENT_TO_RAN;
+
+    or-teiv-yext:biDirectionalTopologyRelationship PHYSICALNF_SERVES_GNBDUFUNCTION { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-gnbduFunction {
+            description "gNodeB-DU Function serviced by this Physical NF.";
+            or-teiv-yext:aSide or-teiv-equip:PhysicalNF;
+            type instance-identifier;
+        }
+
+        leaf serving-physicalNF {
+            description "Physical NF serves this gNodeB-DU Function.";
+            or-teiv-yext:bSide or-teiv-ran:GNBDUFunction;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship PHYSICALNF_SERVES_GNBCUCPFUNCTION { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-gnbcucpFunction {
+            description "gNodeB-CUCP Function serviced by this Physical NF.";
+            or-teiv-yext:aSide or-teiv-equip:PhysicalNF;
+            type instance-identifier;
+        }
+
+        leaf serving-physicalNF {
+            description "Physical NF serves this gNodeB-CUCP Function.";
+            or-teiv-yext:bSide or-teiv-ran:GNBCUCPFunction;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship PHYSICALNF_SERVES_GNBCUUPFUNCTION { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-gnbcuupFunction {
+            description "gNodeB-CUUP Function serviced by this Physical NF.";
+            or-teiv-yext:aSide or-teiv-equip:PhysicalNF;
+            type instance-identifier;
+        }
+
+        leaf serving-physicalNF {
+            description "Physical NF serves this gNodeB-CUUP Function.";
+            or-teiv-yext:bSide or-teiv-ran:GNBCUUPFunction;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship PHYSICALNF_SERVES_ENODEBFUNCTION { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-enodebFunction {
+            description "eNodeB Function serviced by this Physical NF.";
+            or-teiv-yext:aSide or-teiv-equip:PhysicalNF;
+            type instance-identifier;
+        }
+
+        leaf serving-physicalNF {
+            description "Physical NF serves this eNodeB Function.";
+            or-teiv-yext:bSide or-teiv-ran:ENodeBFunction;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNAMODULE_SERVES_ANTENNACAPABILITY { // 0..n to 0..m
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list serviced-antennaCapability {
+            description "Antenna Capability serviced by this Antenna Module.";
+            or-teiv-yext:aSide or-teiv-equip:AntennaModule;
+            type instance-identifier;
+        }
+
+        leaf-list serving-antennaModule {
+            description "Antenna Module serves this Antenna Capability.";
+            or-teiv-yext:bSide or-teiv-ran:AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship SECTOR_GROUPS_ANTENNAMODULE { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list grouped-antennaModule {
+            description "Sector groups Antenna Module.";
+            or-teiv-yext:aSide or-teiv-ran:Sector;
+            type instance-identifier;
+        }
+
+        leaf grouped-by-sector {
+            description "Antenna Module grouped by Sector.";
+            or-teiv-yext:bSide or-teiv-equip:AntennaModule;
+            type instance-identifier;
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-equipment.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-equipment.yang
new file mode 100644
index 0000000..9401f38
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-equipment.yang
@@ -0,0 +1,193 @@
+module o-ran-smo-teiv-equipment {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-equipment";
+    prefix or-teiv-equip;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import ietf-geo-location {
+        prefix geo;
+        reference "RFC 9179: A YANG Grouping for Geographic Locations";
+    }
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "RAN Equipment topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the topology entities and relations in the
+    RAN Equipment domain, which is modelled to understand the physical
+    location of equipment such as antennas associated with a cell/carrier
+    and their relevant properties e.g. tilt, max power etc.";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain EQUIPMENT;
+
+    list AntennaModule {
+        description "An Antenna Module represents the
+                    physical aspect of an antenna.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the AntennaSubUnit MO. It contains
+                            the full path from the Subnetwork to the
+                            AntennaSubUnit.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf antennaModelNumber {
+                description "Vendor-specific antenna model
+                            identifier. This attribute is part of
+                            AISG v3 ADB Standard and has
+                            no operational impact.";
+                type string;
+            }
+
+            leaf mechanicalAntennaBearing {
+                description "Antenna bearing on antenna subunit
+                            where antenna unit is installed.";
+                type uint32;
+            }
+
+            leaf mechanicalAntennaTilt {
+                description "The fixed antenna tilt of the installation,
+                            defined as the inclination of the antenna
+                            element respect to the vertical plane.
+                            It is a signed value. Positive indicates
+                            downtilt, and negative indicates uptilt.";
+                type uint32;
+            }
+
+            leaf positionWithinSector {
+                description "Antenna unit position within sector.
+                            This attribute is part of AISG v3 ADB
+                            Standard and has no operational impact.";
+                type string;
+            }
+
+            leaf totalTilt {
+                description "Total antenna elevation including the
+                            installed tilt and the tilt applied by
+                            the Remote Electrical Tilt (RET).";
+                type uint32;
+            }
+
+            leaf electricalAntennaTilt {
+                description "Electrically-controlled tilt of main beam maximum
+                            with respect to direction orthogonal to antenna
+                            element axis (see 3GPP TS 25.466). Value is signed;
+                            tilt down is positive, tilt up is negative.";
+                type uint32;
+            }
+
+            leaf-list antennaBeamWidth {
+                description "The angular span of the main lobe of the antenna radiation
+                              pattern in the horizontal plane. Measured in degrees.";
+                type uint32;
+            }
+
+            uses geo:geo-location;
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list Site {
+        description "A site is a physical location where an Antenna or
+                    Physical NF can be installed.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf name {
+                description "Name of Site";
+                type string;
+            }
+
+            uses geo:geo-location;
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list PhysicalNF {
+        description "Represents a Physical NF,
+                    which is used to realise Network Functions.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf name {
+                description "Name of Physical NF.";
+                type string;
+            }
+
+            leaf type {
+                description "Type of Physical NF.";
+                type string;
+            }
+
+            uses geo:geo-location;
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ANTENNAMODULE_INSTALLED_AT_SITE { // 0..n to 0..1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf installed-at-site {
+            description "Antenna Module installed at Site.";
+            or-teiv-yext:aSide AntennaModule;
+            type instance-identifier;
+        }
+
+        leaf-list installed-antennaModule {
+            description "Site where Antenna Module is installed.";
+            or-teiv-yext:bSide Site;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship PHYSICALNF_INSTALLED_AT_SITE { // 1..n to 0..1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf installed-at-site {
+            description "Physical NF installed at Site.";
+            or-teiv-yext:aSide PhysicalNF;
+            type instance-identifier;
+        }
+
+        leaf-list installed-physicalNF {
+            description "Site where Physical NF is installed.";
+            or-teiv-yext:bSide Site;
+            type instance-identifier;
+            min-elements 1;
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-oam-to-cloud.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-oam-to-cloud.yang
new file mode 100644
index 0000000..7d99b9d
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-oam-to-cloud.yang
@@ -0,0 +1,69 @@
+module o-ran-smo-teiv-oam-to-cloud {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-oam-to-cloud";
+    prefix or-teiv-oamtocloud;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import o-ran-smo-teiv-oam {prefix or-teiv-oam; }
+
+    import o-ran-smo-teiv-cloud {prefix or-teiv-cloud; }
+
+    organization "ORAN";
+    contact "The Authors";
+    description 
+    "RAN O&M to Cloud topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+    
+    This model contains the RAN O&M to Cloud topology relations";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain OAM_TO_CLOUD;
+
+    or-teiv-yext:biDirectionalTopologyRelationship MANAGEDELEMENT_DEPLOYED_AS_CLOUDIFIEDNF {  // 0..1 to 1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf deployed-as-cloudifiedNF {
+            description "Managed Element deployed as Cloudified NF.";
+            or-teiv-yext:aSide or-teiv-oam:ManagedElement;
+            type instance-identifier;
+        }
+
+        leaf deployed-managedElement {
+            description "Cloudified NF deploys Managed Element.";
+            or-teiv-yext:bSide or-teiv-cloud:CloudifiedNF;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NFDEPLOYMENT_SERVES_MANAGEDELEMENT { // 1..n to 1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf serviced-managedElement {
+            description "Managed Element serviced by this NF Deployment.";
+            or-teiv-yext:aSide or-teiv-cloud:NFDeployment;
+            type instance-identifier;
+            mandatory true;
+        }
+
+        leaf-list serving-nFDeployment {
+            description "NF Deployment that serves this Managed Element.";
+            or-teiv-yext:bSide or-teiv-oam:ManagedElement;
+            type instance-identifier;
+            min-elements 1;
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-oam-to-ran.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-oam-to-ran.yang
new file mode 100644
index 0000000..fb166ff
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-oam-to-ran.yang
@@ -0,0 +1,106 @@
+module o-ran-smo-teiv-oam-to-ran {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-oam-to-ran";
+    prefix or-teiv-oamtoran;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import o-ran-smo-teiv-oam {prefix or-teiv-oam; }
+
+    import o-ran-smo-teiv-ran {prefix or-teiv-ran; }
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "RAN O&M to Logical topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+    
+    This model contains the RAN O&M to Logical topology relations";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain OAM_TO_RAN;
+
+    or-teiv-yext:biDirectionalTopologyRelationship MANAGEDELEMENT_MANAGES_ENODEBFUNCTION {   // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list managed-enodebFunction {
+            description "Managed Element manages eNodeB Function.";
+            or-teiv-yext:aSide or-teiv-oam:ManagedElement;
+            type instance-identifier;
+        }
+
+        leaf managed-by-managedElement {
+            description "eNodeB Function managed by Managed Element.";
+            or-teiv-yext:bSide or-teiv-ran:ENodeBFunction;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship MANAGEDELEMENT_MANAGES_GNBDUFUNCTION {    // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list managed-gnbduFunction {
+            description "Managed Element manages gNodeB-DU Function.";
+            or-teiv-yext:aSide or-teiv-oam:ManagedElement;
+            type instance-identifier;
+        }
+
+        leaf managed-by-managedElement {
+            description "gNodeB-DU Function managed by Managed Element.";
+            or-teiv-yext:bSide or-teiv-ran:GNBDUFunction;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION {    // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list managed-gnbcucpFunction {
+            description "Managed Element manages gNodeB-CU-CP Function.";
+            or-teiv-yext:aSide or-teiv-oam:ManagedElement;
+            type instance-identifier;
+        }
+
+        leaf managed-by-managedElement {
+            description "gNodeB-CU-CP Function managed by Managed Element.";
+            or-teiv-yext:bSide or-teiv-ran:GNBCUCPFunction;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION {    // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list managed-gnbcuupFunction {
+            description "Managed Element manages gNodeB-CU-UP Function.";
+            or-teiv-yext:aSide or-teiv-oam:ManagedElement;
+            type instance-identifier;
+        }
+
+        leaf managed-by-managedElement {
+            description "gNodeB-CU-UP Function managed by Managed Element.";
+            or-teiv-yext:bSide or-teiv-ran:GNBCUUPFunction;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-oam.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-oam.yang
new file mode 100644
index 0000000..4d34953
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-oam.yang
@@ -0,0 +1,52 @@
+module o-ran-smo-teiv-oam {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-oam";
+    prefix or-teiv-oam;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    organization "ORAN";
+    contact "The Authors";
+    description 
+    "RAN O&M topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the topology entities and relations in the
+    RAN O&M domain, which are intended to represent management systems
+    and management interfaces.";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain OAM;
+
+    list ManagedElement {
+        description "A Managed Element (ME) is a node into a telecommunication network
+                    providing support and/or service to subscribers. An ME communicates
+                    with a manager application (directly or indirectly) over one or more
+                    interfaces for the purpose of being monitored and/or controlled.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the ManagedElement MO. It contains
+                            the full path from the Subnetwork to the
+                            ManagedElement.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/models/o-ran-smo-teiv-ran.yang b/teiv/src/main/resources/models/o-ran-smo-teiv-ran.yang
new file mode 100644
index 0000000..7ddbcb9
--- /dev/null
+++ b/teiv/src/main/resources/models/o-ran-smo-teiv-ran.yang
@@ -0,0 +1,877 @@
+module o-ran-smo-teiv-ran {
+    yang-version 1.1;
+    namespace "urn:o-ran:smo-teiv-ran";
+    prefix or-teiv-ran;
+
+    import o-ran-smo-teiv-common-yang-types {prefix or-teiv-types; }
+
+    import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-yext; }
+
+    import _3gpp-common-yang-types { prefix types3gpp; }
+
+    import ietf-geo-location {
+        prefix geo;
+        reference "RFC 9179: A YANG Grouping for Geographic Locations";
+    }
+
+    organization "ORAN";
+    contact "The Authors";
+    description
+    "RAN Logical topology model.
+
+    Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+    This model contains the topology entities and relations in the
+    RAN Logical domain, which represents the functional capability
+    of the deployed RAN that are relevant to rApps use cases.";
+
+    revision "2024-05-02" {
+        description "Initial revision.";
+        or-teiv-yext:label 0.3.0;
+    }
+
+    or-teiv-yext:domain RAN;
+
+    list GNBDUFunction {
+        description "gNodeB Distributed Unit (gNB-DU).
+
+                    A gNB may consist of a gNB-Centralized Unit
+                    (gNB-CU) and a gNB-DU. The CU processes non-real
+                    time protocols and services, and the DU processes
+                    PHY level protocol and real time services. The
+                    gNB-CU and the gNB-DU units are connected via
+                    F1 logical interface.
+
+                    The following is true for a gNB-DU:
+                    Is connected to the gNB-CU-CP through the F1-C
+                    interface.Is connected to the gNB-CU-UP through
+                    the F1-U interface. One gNB-DU is connected to only
+                    one gNB-CU-CP. One gNB-DU can be connected to
+                    multiple gNB-CU-UPs under the control of the same
+                    gNB-CU-CP.
+                    Note: A gNB may consist of a gNB-CU-CP, multiple
+                    gNB-CU-UPs and multiple gNB-DUs. gNB-DU is a concrete
+                    class that extends the NG-RAN node object. In Topology, you
+                    can create, read, update, and delete the gNB-DU object.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the GNBDUFunction MO. It contains
+                            the full path from the Subnetwork to the
+                            GNBDUFunction.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            container dUpLMNId {
+                description "PLMN identifier used as part of PM Events data";
+                uses types3gpp:PLMNId;
+            }
+
+            leaf gNBDUId {
+                description "Unique identifier for the DU within a gNodeB";
+                type uint32;
+            }
+
+            leaf gNBId {
+                description "Identity of gNodeB within a PLMN";
+                type uint32;
+            }
+
+            leaf gNBIdLength {
+                description "Length of gNBId bit string representation";
+                type uint32;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list GNBCUCPFunction {
+        description "gNodeB Centralized Unit Control Plane (gNB-CU-CP)
+
+                    This is a logical node hosting the Radio Resource
+                    Control (RRC) and the control plane part of the
+                    Packet Data Convergence Protocol (PDCP) of the
+                    gNodeB Centralized Unit (gNB-CU) for an E-UTRAN gNodeB
+                    (en-gNB) or a gNodeB (gNB). The gNB-CU-CP terminates
+                    the E1 interface connected with the gNB-CU-UP and the
+                    F1-C interface connected with the gNodeB
+                    Distributed Unit (gNB-DU).
+
+                    The following is true for a gNB-CU-CP:
+                    Is connected to the gNB-DU through the F1-C interface.
+                    Is connected to the gNB-CU-UP through the E1 interface.
+                    Only one gNB-CU-CP is connected to one gNB-DU.
+                    Only one gNB-CU-CP is connected to one gNB-CU-UP.
+                    One gNB-DU can be connected to multiple gNB-CU-UPs
+                    under the control of the same gNB-CU-CP.One gNB-CU-UP
+                    can be connected to multiple DUs under the control of
+                    the same gNB-CU-CP.
+                    Note: A gNB may consist of a gNB-CU-CP, multiple
+                    gNB-CU-UPs and multiple gNB-DUs. A gNB-CU-CP is a
+                    concrete class that extends the NG-RAN node object.
+                    In Topology, you can create, read, update, and delete
+                    the gNB-CU-CP object.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the GNBCUCPFunction MO. It contains
+                            the full path from the Subnetwork to the
+                            GNBCUCPFunction.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf gNBCUName {
+                description "Name of gNodeB-CU";
+                type string;
+            }
+
+            leaf gNBId {
+                description "Identity of gNodeB within a PLMN";
+                type uint32;
+            }
+
+            leaf gNBIdLength {
+                description "Length of gNBId bit string representation";
+                type uint32;
+            }
+
+            container pLMNId {
+                description "PLMN identifier to be used as part
+                            of global RAN node identity";
+                uses types3gpp:PLMNId;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list GNBCUUPFunction {
+        description "gNodeB Centralized Unit User Plane (gNB-CU-UP)
+
+                    A gNB-CU-UP is a logical node hosting the User
+                    Plane part of the Packet Data Convergence,
+                    Protocol (PDCP) of the gNodeB Centralized Unit
+                    (gNB-CU) for an E-UTRAN gNodeB (en-gNB), and the
+                    User Plane part of the PDCP protocol and the
+                    Service Data Adaptation Protocol (SDAP) of the
+                    gNB-CU for a gNodeB (gNB). The gNB-CU-UP terminates
+                    the E1 interface connected with the gNB-CU-CP and
+                    the F1-U interface connected with the gNodeB
+                    Distributed Unit (gNB-DU).
+
+                    The following is true for a gNB-CU-UP:
+                    Is connected to the gNB-DU through the
+                    F1-U interface. Is connected to the gNB-CU-CP through
+                    the E1 interface. One gNB-CU-UP is connected to only one
+                    gNB-CU-CP. One gNB-DU can be connected to multiple
+                    gNB-CU-UPs under the control of the same gNB-CU-CP. One
+                    gNB-CU-UP can be connected to multiple DUs under the
+                    control of the same gNB-CU-CP.
+                    Note: A gNB may consist of a gNB-CU-CP, multiple gNB-CU-UPs
+                    and multiple gNB-DUs. A gNB-CU-UP is a concrete class that
+                    extends the NG-RAN node object. In Topology, you can
+                    create, read, update, and delete the gNB-CU-UP object.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the GNBCUUPFunction MO. It contains
+                            the full path from the Subnetwork to the
+                            GNBCUUPFunction.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf gNBId {
+                description "Identity of gNodeB within a PLMN";
+                type uint32;
+            }
+
+            leaf gNBIdLength {
+                description "Length of gNBId bit string representation";
+                type uint32;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list NRCellCU {
+        description "Represents an NR Cell in gNodeB-CU.
+
+                    5G NR is a new radio access technology (RAT)
+                    developed by 3GPP for the 5G (fifth generation)
+                    mobile network. It is designed to be the global
+                    standard for the air interface of 5G networks.
+
+                    5G NR has synchronization signal that is known as
+                    Primary Synchronization signal (PSS) and Secondary
+                    Synchronization signal (SSS). These signals are
+                    specific to NR physical layer and provide the
+                    following information required by UE for downlink
+                    synchronization: PSS provides Radio Frame Boundary
+                    (Position of 1st Symbol in a Radio frame) SSS provides
+                    Subframe Boundary (Position of 1st Symbol in a Subframe)
+                    Physical Layer Cell ID (PCI) information using both
+                    PSS and SSS.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the NRCellCU MO. It contains
+                            the full path from the Subnetwork to the
+                            NRCellCU.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf cellLocalId {
+                description "Used together with gNodeB identifier to
+                            identify NR cell in PLMN. Used together
+                            with gNBId to form NCI.";
+                type uint32;
+            }
+
+            container plmnId {
+                description "PLMN ID for NR CGI. If empty,
+                            GNBCUCPFunction::pLMNId is used
+                            for PLMN ID in NR CGI";
+                uses types3gpp:PLMNId;
+            }
+
+            leaf nCI {
+                description "NR Cell Identity";
+                type uint32;
+            }
+
+            leaf nRTAC {
+                description "NR Tracking Area Code (TAC)";
+                type uint32;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list NRCellDU {
+        description "Represents an NR Cell in gNodeB-DU.
+
+                    5G NR is a new radio access technology (RAT)
+                    developed by 3GPP for the 5G (fifth generation)
+                    mobile network. It is designed to be the global
+                    standard for the air interface of 5G networks.
+
+                    5G NR has synchronization signal that is known as
+                    Primary Synchronization signal (PSS) and Secondary
+                    Synchronization signal (SSS). These signals are
+                    specific to NR physical layer and provide the
+                    following information required by UE for downlink
+                    synchronization: PSS provides Radio Frame Boundary
+                    (Position of 1st Symbol in a Radio frame) SSS provides
+                    Subframe Boundary (Position of 1st Symbol in a Subframe)
+                    Physical Layer Cell ID (PCI) information using both
+                    PSS and SSS.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the NRCellDU MO. It contains
+                            the full path from the Subnetwork to the
+                            NRCellDU.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf cellLocalId {
+                description "Used together with gNodeB identifier to identify NR
+                             cell in PLMN. Used together with gNBId to form NCI.";
+                type uint32;
+            }
+
+            leaf nCI {
+                description "NR Cell Identity.";
+                type uint32;
+            }
+
+            leaf nRPCI {
+                description "The Physical Cell Identity (PCI) of the NR cell.";
+                type uint32;
+            }
+
+            leaf nRTAC {
+                description "NR Tracking Area Code (TAC).";
+                type uint32;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list ENodeBFunction {
+        description "An Evolved Node B (eNodeB) is the only mandatory
+                    node in the radio access network (RAN) of Long-Term
+                    Evolution (LTE). The eNodeB is a complex base
+                    station that handles radio communications
+                    in the cell and carries out radio resource
+                    management and handover decisions. Unlike 2/3G
+                    wireless RAN, there is no centralized radio network
+                    controller in LTE. It is the hardware that is connected
+                    to the mobile phone network that communicates
+                    directly with mobile handsets (User Equipment), like a base
+                    transceiver station (BTS) in GSM networks. This simplifies
+                    the architecture and allows lower response times.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the ENodeBFunction MO. It contains
+                            the full path from the Subnetwork to the
+                            ENodeBFunction.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf eNBId {
+                description "The ENodeB ID that forms part of
+                            the Cell Global Identity, and is
+                            also used to identify the node over
+                            the S1 interface";
+                type uint32;
+            }
+
+            container eNodeBPlmnId {
+                description "The ENodeB Public Land Mobile Network
+                            (PLMN) ID that forms part of the ENodeB
+                            Global ID used to identify the node over
+                            the S1 interface. Note: The value (MCC=001, MNC=01)
+                            indicates that the PLMN is not initiated.
+                            The value can not be used as a valid PLMN Identity.";
+
+                leaf mcc {
+                    description "The MCC part of a PLMN identity
+                                used in the radio network.";
+                    type int32 {
+                        range 0..999;
+                    }
+                }
+                leaf mnc {
+                    description "The MNC part of a PLMN identity
+                                used in the radio network.";
+                    type int32 {
+                        range 0..999;
+                    }
+                }
+                leaf mncLength {
+                    description "The length of the MNC part of a
+                                PLMN identity used in the radio network.";
+                    type int32 {
+                        range 2..3;
+                    }
+                }
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list EUtranCell {
+        description "Represents an FDD or TDD EUtranCell and
+                    contains parameters needed by the cell.
+                    It also contains parameters for the
+                    mandatory common channels. An EUTRAN stands
+                    for Evolved Universal Mobile Telecommunications
+                    System (UMTS) Terrestrial Radio Access Network
+                    which contains an eNodeB. The eNodeB concrete
+                    class is extended from the EUTRAN Node abstract class.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of either the EUtranCellFDD MO or
+                            the EUtranCellTDD MO. It contains the full
+                            path from the Subnetwork to the EUtranCellFDD or
+                            EUtranCellTDD.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf cellId{
+                description "RBS internal ID attribute for EUtranCell.
+                            Must be unique in the RBS. Together with the
+                            Node ID and Public Land Mobile Network (PLMN)
+                            this is a universally unique cell ID";
+                type uint32;
+            }
+
+            leaf earfcndl {
+                description "The channel number for the central downlink frequency.";
+                type uint32;
+            }
+
+            leaf earfcnul {
+                description "Channel number for the central uplink frequency";
+                type uint32;
+            }
+
+            leaf dlChannelBandwidth {
+                description "The downlink channel bandwidth in the FDD cell.";
+                type uint32;
+            }
+
+            leaf earfcn {
+                description "The E-UTRA Absolute Radio Frequency Channel
+                            Number (EARFCN) for the TDD cell";
+                type uint32;
+            }
+
+            leaf channelBandwidth {
+                description "The channel bandwidth in the TDD cell.";
+                type uint32;
+            }
+
+            leaf tac {
+                description "Tracking Area Code for the EUtran Cell";
+                type uint32;
+            }
+
+            leaf duplexType {
+                description "Indicator of EUtranCell type, FDD or TDD";
+                type enumeration {
+                    enum fdd {
+                        value 0;
+                        description "FDD";
+                    }
+                    enum tdd {
+                        value 1;
+                        description "TDD";
+                    }
+                }
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list NRSectorCarrier {
+        description "The NR Sector Carrier object provides
+                    the attributes for defining the logical
+                    characteristics of a carrier (cell) in a
+                    sector. A sector is a coverage area associated
+                    with a base station having its own antennas,
+                    radio ports, and control channels. The concept
+                    of sectors was developed to improve co-channel
+                    interference in cellular systems, and most wireless
+                    systems use three sector cells.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the NRSectorCarrier MO. It contains
+                            the full path from the Subnetwork to the
+                            NRSectorCarrier.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf arfcnDL {
+                description "NR Absolute Radio Frequency Channel
+                            Number (NR-ARFCN) for downlink";
+                type uint32;
+            }
+
+            leaf arfcnUL {
+                description "NR Absolute Radio frequency Channel Number
+                            (NR-ARFCN) for uplink.";
+                type uint32;
+            }
+
+            leaf frequencyDL {
+                description "RF Reference Frequency of downlink channel";
+                type uint32;
+            }
+
+            leaf frequencyUL {
+                description "RF Reference Frequency of uplink channel";
+                type uint32;
+            }
+
+            leaf bSChannelBwDL {
+                description "BS Channel bandwidth in MHz for downlink.";
+                type uint32;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list LTESectorCarrier {
+        description "The LTE Sector Carrier object provides the
+                    attributes for defining the logical characteristics
+                    of a carrier (cell) in a sector. A sector is a coverage
+                    area associated with a base station having
+                    its own antennas, radio ports, and control channels.
+                    The concept of sectors was developed to improve co-channel
+                    interference in cellular systems, and most wireless systems
+                    use three sector cells.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the SectorCarrier MO. It contains
+                            the full path from the Subnetwork to the
+                            SectorCarrier.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf sectorCarrierType {
+                description "Indicates whether or not the sector carrier
+                            modelled by MO SectorCarrier is a digital sector.";
+                type enumeration {
+                    enum normal_sector {
+                        value 0;
+                        description "Not a digital sector";
+                    }
+                    enum left_digital_sector {
+                        value 1;
+                        description "Left digital sector for 2DS";
+                    }
+                    enum right_digital_sector {
+                        value 2;
+                        description "Right digital sector for 2DS";
+                    }
+                    enum left_digital_sector_3ds {
+                        value 3;
+                        description "Left digital sector for 3DS";
+                    }
+                    enum right_digital_sector_3ds {
+                        value 4;
+                        description "Right digital sector for 3DS";
+                    }
+                    enum middle_digital_sector {
+                        value 5;
+                        description "Middle digital sector for 3DS";
+                    }
+                }
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list AntennaCapability {
+        description "This MO serves as a mapping between the cell
+                    and the RBS equipment used to provide coverage
+                    in a certain geographical area. The MO also
+                    controls the maximum output power of the sector.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf fdn {
+                description "This Full Distinguished Name (FDN) identifies
+                            an instance of the SectorEquipmentFunction MO.
+                            It contains the full path from the Subnetwork
+                            to the SectorEquipmentFunction.";
+                type or-teiv-types:_3GPP_FDN_Type;
+            }
+
+            leaf-list eUtranFqBands {
+                description "List of LTE frequency bands
+                            that associated hardware supports";
+                type string;
+            }
+
+            leaf-list geranFqBands {
+                description "List of GERAN frequency bands
+                            that associated hardware supports";
+                type string;
+            }
+
+            leaf-list nRFqBands {
+                description "List of NR frequency bands
+                            associated hardware supports";
+                type string;
+            }
+
+            container cmId {
+                uses or-teiv-types:CM_ID;
+            }
+        }
+    }
+
+    list Sector {
+        description "A group of co-located Cells that
+                    have a shared coverage area.";
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        container attributes {
+            leaf sectorId {
+                description "Universally unique ID generated by the
+                            sector's discovery mechanism.";
+                type uint64;
+            }
+
+            uses geo:geo-location;
+
+            leaf azimuth {
+                description "Average value of the azimuths of the cells
+                            comprising the sector, determined during
+                            sector discovery.";
+                type decimal64{
+                    fraction-digits 6;
+                }
+                units "degrees";
+            }
+        }
+    }
+
+
+    or-teiv-yext:biDirectionalTopologyRelationship ENODEBFUNCTION_PROVIDES_EUTRANCELL { // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list provided-euTranCell {
+            description "eNodeB Function provides EUTRAN Cell.";
+            or-teiv-yext:aSide ENodeBFunction;
+            type instance-identifier;
+        }
+
+        leaf provided-by-enodebFunction {
+            description "EUTRAN Cell provided by eNodeB Function.";
+            or-teiv-yext:bSide EUtranCell;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER { // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list provided-lteSectorCarrier {
+            description "eNodeB Function provides LTE Sector Carrier.";
+            or-teiv-yext:aSide ENodeBFunction;
+            type instance-identifier;
+        }
+
+        leaf provided-by-enodebFunction {
+            description "LTE Sector Carrier provided by eNodeB Function.";
+            or-teiv-yext:bSide LTESectorCarrier;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship GNBDUFUNCTION_PROVIDES_NRCELLDU { // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list provided-nrCellDu {
+            description "gNodeB-DU Function provides NR Cell-DU.";
+            or-teiv-yext:aSide GNBDUFunction;
+            type instance-identifier;
+        }
+
+        leaf provided-by-gnbduFunction {
+            description "NR Cell-DU provided by gNodeB-DU Function.";
+            or-teiv-yext:bSide NRCellDU;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER { // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list provided-nrSectorCarrier {
+            description "gNodeB-DU Function provides NR Sector Carrier.";
+            or-teiv-yext:aSide GNBDUFunction;
+            type instance-identifier;
+        }
+
+        leaf provided-by-gnbduFunction {
+            description "NR Sector Carrier provided by gNodeB-DU Function.";
+            or-teiv-yext:bSide NRSectorCarrier;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship GNBCUCPFUNCTION_PROVIDES_NRCELLCU { // 1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list provided-nrCellCu {
+            description "gNodeB-CUCP Function provides NR Cell-CU.";
+            or-teiv-yext:aSide GNBCUCPFunction;
+            type instance-identifier;
+        }
+
+        leaf provided-by-gnbcucpFunction {
+            description "NR Cell-CU provided by gNodeB-CUCP Function.";
+            or-teiv-yext:bSide NRCellCU;
+            type instance-identifier;
+            mandatory true;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship EUTRANCELL_USES_LTESECTORCARRIER { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list used-lteSectorCarrier {
+            description "EUTRAN Cell uses LTE Sector Carrier.";
+            or-teiv-yext:aSide EUtranCell;
+            type instance-identifier;
+        }
+
+        leaf used-by-euTranCell {
+            description "LTE Sector Carrier used by EUTRAN Cell.";
+            or-teiv-yext:bSide LTESectorCarrier;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship LTESECTORCARRIER_USES_ANTENNACAPABILITY { // 0..n to 0..1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf used-antennaCapability {
+            description "LTE Sector Carrier uses Antenna Capability.";
+            or-teiv-yext:aSide LTESectorCarrier;
+            type instance-identifier;
+        }
+
+        leaf-list used-by-lteSectorCarrier {
+            description "Antenna Capability used by LTE Sector Carrier.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NRCELLDU_USES_NRSECTORCARRIER { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list used-nrSectorCarrier {
+            description "NR Cell-DU uses NR Sector Carrier.";
+            or-teiv-yext:aSide NRCellDU;
+            type instance-identifier;
+        }
+
+        leaf used-by-nrCellDu {
+            description "NR Sector Carrier used by NR Cell-DU.";
+            or-teiv-yext:bSide NRSectorCarrier;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship NRSECTORCARRIER_USES_ANTENNACAPABILITY { // 0..n to 0..1
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf used-antennaCapability {
+            description "NR Sector Carrier uses Antenna Capability.";
+            or-teiv-yext:aSide NRSectorCarrier;
+            type instance-identifier;
+        }
+
+        leaf-list used-by-nrSectorCarrier {
+            description "Antenna Capability used by NR Sector Carrier.";
+            or-teiv-yext:bSide AntennaCapability;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship SECTOR_GROUPS_NRCELLDU { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list grouped-nrCellDu {
+            description "Sector groups NR Cell-DU.";
+            or-teiv-yext:aSide Sector;
+            type instance-identifier;
+        }
+
+        leaf grouped-by-sector {
+            description "NR Cell-DU grouped by Sector.";
+            or-teiv-yext:bSide NRCellDU;
+            type instance-identifier;
+        }
+    }
+
+    or-teiv-yext:biDirectionalTopologyRelationship SECTOR_GROUPS_EUTRANCELL { // 0..1 to 0..n
+
+        uses or-teiv-types:Top_Grp_Type;
+        key id;
+
+        leaf-list grouped-euTranCell {
+            description "Sector groups EUTRAN Cell.";
+            or-teiv-yext:aSide Sector;
+            type instance-identifier;
+        }
+
+        leaf grouped-by-sector {
+            description "EUTRAN Cell grouped by Sector.";
+            or-teiv-yext:bSide EUtranCell;
+            type instance-identifier;
+        }
+    }
+}
\ No newline at end of file
diff --git a/teiv/src/main/resources/v1/topology-exposure-inventory-openapi.yaml b/teiv/src/main/resources/v1/topology-exposure-inventory-openapi.yaml
new file mode 100644
index 0000000..a885dcc
--- /dev/null
+++ b/teiv/src/main/resources/v1/topology-exposure-inventory-openapi.yaml
@@ -0,0 +1,1686 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+openapi: 3.0.2
+info:
+  x-api-id: 52812f69-83ac-4dfa-b83a-1a1bdf2d49b8
+  x-audience: external-public
+  description: |
+    Topology and Inventory data is the information that represents entities in a telecommunications network and the relationships between them that provide insight into a particular aspect of the network of importance to specific use cases. Topology and Inventory data can be derived from inventory, configuration, or other data.
+
+    Topology and Inventory supports several topology domains. A domain is a grouping of network topology entities which handles topology data.
+
+    Entities are enabling the modelling and storage of complex network infrastructure and relationships.
+
+    Relationships are a uni-directional connection between two entities, one of which is the originating side (A-side) and the other is the terminating side (B-side). The order of the sides matters since it defines the relationship itself which must be unique
+
+    Topology and Inventory API provides the capabilities to fetch topology data. Using the filtering options, it is possible to define more specific query requests.
+
+    ## Querying simple entities
+    EntityType is used as the root of the queries (from here referred as RootObject).  Every other object, either *targetFilter* or *scopeFilter*, has to relate to the RootObject. The queries are constructed starting from the RootObject and all other objects are joined to it. If there is no connection between the RootObject and the other object(s), the query will not get constructed. The RootObject still can be retrieved and filtered using the */attributes*.
+
+    | USE CASE                                                                                                                                                                                                                                                                                                                                                                                                       |  ENTITY TYPE    |  TARGET FILTER                                                                         | SCOPE FILTER                                                                                                    | QUERY RESULT                                                                                                      |
+    |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------|:----------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------|
+    | To return the ids for all instances of the entityType used in the query.                                                                                                                                                                                                                                                                                                                                       |&ensp;  GNBDUFunction  |                                                                                        |                                                                                                                 | All ids of every GNBDUFunction                                                                                    |
+    | To return all attributes of every instance of the entityType used in the query.                                                                                                                                                                                                                                                                                                                                |&ensp;  GNBDUFunction  |&ensp;  /attributes                                                                           |                                                                                                                 | All GNBDUFunctions with every attribute                                                                           |
+    | To return every instance of the entityType used in the query, but only the attribute that was defined in the *targetFilter* parameter. <br/> Note: The attribute must be a valid field of the object.                                                                                                                                                                                                          |&ensp;  GNBDUFunction  |&ensp;  /attributes(gNBId) <br/> &emsp;&ensp; **OR** <br/> /attributes/gNBId                      |                                                                                                             | All FDNs of every GNBDUFunction                                                                                   |
+    | To return every instance of the entityType used in the query, but only the attributes that were defined in the *targetFilter* parameter. <br/> Case 1: The attributes must be separated by a comma "," in case of using parenthesis "()". <br/> Case 2: The attributes must be separated by a semicolon ";" in case of using slash "/". <br/> Note: The attributes must be valid *targetFilter* of the object. |&ensp;  GNBDUFunction  |&ensp;  /attributes(gNBId, gNBIdLength)  <br/> &emsp;&ensp; **OR** <br/> /attributes/gNBId; /attributes/gNBIdLength |                                                                                           | All Ids and FDNs of every GNBDUFunction                                                                           |
+    | To return the ids for all instances of the entityType used in the query, that matches the given attribute in the *scopeFilter* parameter. <br/> Note: The attribute must be a valid field of the object.                                                                                                                                                                                                       |&ensp;  GNBDUFunction  |                                                                                       | /attributes[contains (@fdn, "/SubNetwork=Ireland/")]                                                             | Unique set of ids of GNBDUFunctions, where fdn contains "SubNetwork=Ireland"                                      |
+    | To return the ids for all instances of the entityType used in the query, that matches the given attributes in the *scopeFilter* parameter. <br/> Note: the entityType and the object in the *scopeFilter* parameter must match, and the attributes must be valid field or fields of the object.  The attributes must be separated by a comma ",".                                                              |&ensp;  GNBDUFunction  |                                                                                       | /attributes[@gNBIdLength=3 and @gNBId=111]                                                                | Unique set of ids of GNBDUFunctions, where the gNBIdLength equals 3 and the gNBId equals 111                      |
+    | To return the ids for all instances of the entityType used in the query, that satisfies every condition in one of the tags in the *scopeFilter* parameter. A tag is a complete unit of *scopeFilter* parameter surrounded by square brackets. <br/> Note: The attributes must be valid field or fields of the object.                                                                                          |&ensp;  GNBDUFunction  |                                                                                       | /attributes[@gNBIdLength=3 and @gNBId=111]  <br/> &emsp;&ensp; **OR** <br/> /attributes[@gNBIdLength=3 and @gNBId=112]             | Unique set of ids of GNBDUFunctions, where where the gNBIdLength equals 3 and the gNBId is either 111 or 112      |
+
+    ## Querying connected entities
+    It is possible to get information about directly connected objects as well. If entityType is present in the *targetFilter* parameter, the query provides information about that entityType itself.
+
+    | USE CASE                                                                                                                                                                                                                                                                                                                                                          | ENTITY TYPE   | TARGET FILTER                       | SCOPE FILTER                                              | QUERY RESULT                                                                                                                                      |
+    |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|-------------------------------------|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------|
+    | To return the ids for all instances of the entityType in the *targetFilter* parameter, if they are directly related to the queried entityType.                                                                                                                                                                                                                    |&ensp; GNBDUFunction |&ensp; /NRCellDU                           |                                               | Unique set of ids of NRCellDUs that relates to GNBDUFunctions directly with any relationship type                                                 |
+    | To return the ids for all instances of the entityTypes in the *targetFilter* parameter, if they are directly related to the entityType.                                                                                                                                                                                                                           |&ensp; GNBDUFunction |&ensp; /NRCellDU ;&ensp; /NRSectorCarrier        |                                         | Unique set of ids of NRCellDUs and NRSectorCarriers that relates to GNBDUFunctions directly with any relationship type                            |
+    | To return the ids for all instances of the queried entityType that has one or more direct relationships with the entityType specified in the *scopeFilter* parameter.                                                                                                                                                                                             |&ensp; GNBDUFunction |                                     | /AntennaCapability                                  | Unique set of ids of GNBDUFunctions that are directly related to AntennaCapability with any relationship type                                     |
+    | To return the ids for all instances of the queried entityType that has one or more direct relationships with at least one of the entityTypes specified in the *scopeFilter* parameter.                                                                                                                                                                            |&ensp; GNBDUFunction |                                     | /AntennaCapability <br/> &emsp;&ensp; **OR** <br/> /NRCellDU | Unique set of ids of GNBDUFunctions that are directly related to AntennaCapability or NRCellDU with any relationship type                |
+
+  version: 0.11.0
+  title: Topology and Inventory API
+  license:
+    name: Copyright (C) 2024 Ericsson, Modifications Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved.
+    url: http://www.apache.org/licenses/LICENSE-2.0
+  termsOfService: http://www.apache.org/licenses/LICENSE-2.0
+
+tags:
+  - name: Entities and relationships
+    description: "Provides the capability to retrieve topology and inventory entities and relationships."
+  - name: Schemas
+    description: "Schemas are defined in YANG modeling language. A group of Yang schemas makes the topology and inventory model, which represents topology and inventory entities, their attributes, and their relationships. For more information on YANG modelling language, see [IETF Documentation](https://datatracker.ietf.org/doc/html/rfc6020)."
+  - name: Geo-query
+    description: "Provides the capability to perform geographical queries on topology entities."
+  - name: Classifiers
+    description: "Provides the capability to update or remove user-defined keywords or tags on entities and relationships."
+  - name: Decorators
+    description: "Provides the capability to update or remove user-defined values on entities and relationships."
+  - name: Collections
+    description: "Provides the capability to group topology entities of any type, with an appropriate description and other criteria."
+
+servers:
+  - url: https://{host}/topology-inventory/v1alpha11
+    variables:
+      host:
+        default: localhost
+        description: Change this value to point to your custom host.
+
+paths:
+  /domains:
+    get:
+      description: Get all the available topology domains.
+      tags:
+        - Entities and relationships
+      summary: Get all the available topology domains.
+      operationId: "getAllDomains"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Domains'
+              examples:
+                domains:
+                  $ref: '#/components/examples/DomainsResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/entity-types:
+    get:
+      description: Get all the available topology entity types in domain name.
+      tags:
+        - Entities and relationships
+      summary: Get all the available topology entity types in domain name.
+      operationId: "getTopologyEntityTypes"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/EntityTypes'
+              examples:
+                entityTypes:
+                  $ref: '#/components/examples/EntityTypesResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/entity-types/{entityTypeName}/entities:
+    get:
+      description: Get all topology entities of a specific entity type.
+      tags:
+        - Entities and relationships
+      summary: Get all topology entities of a specific entity type.
+      operationId: "getTopologyByEntityTypeName"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/entityTypeNameInPath'
+        - $ref: '#/components/parameters/targetFilterOptionalInQuery'
+        - $ref: '#/components/parameters/scopeFilterOptionalInQuery'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/EntitiesResponseMessage'
+              examples:
+                entities:
+                  $ref: '#/components/examples/EntitiesResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/entity-types/{entityTypeName}/entities/{entityId}:
+    get:
+      description: Get topology for entity type name with specified id. Specified id represents the entity instance.
+      tags:
+        - Entities and relationships
+      summary: Get topology for entity type name with specified id. Specified id represents the entity instance.
+      operationId: "getTopologyById"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/entityTypeNameInPath'
+        - $ref: '#/components/parameters/entityIdInPath'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/yang.data+json:
+              schema:
+                type: object
+                description: "Refer to yang model for schema definition"
+              examples:
+                entity:
+                  $ref: '#/components/examples/EntityResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/entity-types/{entityTypeName}/entities/{entityId}/relationships:
+    get:
+      description: Get all relationships for entity type name with specified id. Specified id represents the entity instance.
+      tags:
+        - Entities and relationships
+      summary: Get all relationships for entity type name with specified id. Specified id represents the entity instance.
+      operationId: "getAllRelationshipsForEntityId"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/entityTypeNameInPath'
+        - $ref: '#/components/parameters/entityIdInPath'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/RelationshipsResponseMessage'
+              examples:
+                relationships:
+                  $ref: '#/components/examples/RelationshipsResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/relationship-types:
+    get:
+      description: Get all the available topology relationship types.
+      tags:
+        - Entities and relationships
+      summary: Get all the available topology relationship types.
+      operationId: "getTopologyRelationshipTypes"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/RelationshipTypes'
+              examples:
+                relationshipTypes:
+                  $ref: '#/components/examples/RelationshipTypesResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/relationship-types/{relationshipTypeName}/relationships:
+    get:
+      description: Get topology relationships of a specific relationship type name.
+      tags:
+        - Entities and relationships
+      summary: Get topology relationships of a specific relationship type name.
+      operationId: "getRelationshipsByType"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/relationshipTypeNameInPath'
+        - $ref: '#/components/parameters/targetFilterOptionalInQuery'
+        - $ref: '#/components/parameters/scopeFilterOptionalInQuery'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/RelationshipsResponseMessage'
+              examples:
+                relationships:
+                  $ref: '#/components/examples/RelationshipsResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/relationship-types/{relationshipTypeName}/relationships/{relationshipId}:
+    get:
+      description: Get relationship with specified id. Specified id represents the relationship instance.
+      tags:
+        - Entities and relationships
+      summary: Get relationship with specified id. Specified id represents the relationship instance.
+      operationId: "getRelationshipById"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/relationshipTypeNameInPath'
+        - $ref: '#/components/parameters/relationshipIdInPath'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/yang.data+json:
+              schema:
+                type: object
+                description: "Refer to yang model for schema definition"
+              examples:
+                relationship:
+                  $ref: '#/components/examples/RelationshipResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /domains/{domainName}/entities:
+    get:
+      description: Get topology entities by domain, using specified targetFilter as mandatory query parameter.
+      tags:
+        - Entities and relationships
+      summary: "Get entities by domain"
+      operationId: "getEntitiesByDomain"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainNameInPath'
+        - $ref: '#/components/parameters/targetFilterOptionalInQuery'
+        - $ref: '#/components/parameters/scopeFilterOptionalInQuery'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/EntitiesResponseMessage'
+              examples:
+                entities:
+                  $ref: '#/components/examples/EntitiesResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /schemas:
+    post:
+      description: Create a new schema.
+      tags:
+        - Schemas
+      summary: Create a new schema.
+      operationId: createSchema
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/contentTypeInHeader'
+      requestBody:
+        required: true
+        content:
+          multipart/form-data:
+            schema:
+              $ref: '#/components/schemas/MultipartFile'
+      responses:
+        '201':
+          $ref: '#/components/responses/Created'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '409':
+          $ref: '#/components/responses/Conflict'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+    get:
+      description: Get a list of all schemas.
+      tags:
+        - Schemas
+      summary: Get a list of all schemas.
+      operationId: getSchemas
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/domainOptionalInQuery'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/SchemaList'
+              examples:
+                schemas:
+                  $ref: '#/components/examples/SchemasResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+  /schemas/{schemaName}/content:
+    get:
+      description: Get the model schema by name.
+      tags:
+        - Schemas
+      summary: Get the model schema.
+      operationId: getSchemaByName
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/schemaNameInPath'
+      responses:
+        '200':
+          description: OK
+          content:
+            text/plain:
+              schema:
+                type: string
+              examples:
+                schema:
+                  $ref: '#/components/examples/SchemaResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /schemas/{schemaName}:
+    delete:
+      description: Delete a schema.
+      tags:
+        - Schemas
+      summary: Delete a schema.
+      operationId: deleteSchema
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/schemaNameInPath'
+      responses:
+        '204':
+          $ref: '#/components/responses/NoContent'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /geo-queries:
+    post:
+      description: Geo query topology entity or entities across topology domains.
+      tags:
+        - Geo-query
+      summary: Geo query topology entity or entities  across topology domains.
+      operationId: geoQueryTopologyAcrossDomains
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/contentTypeInHeader'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/QueryMessage'
+            examples:
+              geoQuery:
+                $ref: '#/components/examples/QueryMessageExample'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: object
+              examples:
+                geoQueryResponse:
+                  $ref: '#/components/examples/QueryResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '409':
+          $ref: '#/components/responses/Conflict'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /classifiers:
+    put:
+      description: Update entities and/or relationships with classifier(s).
+      tags:
+        - Classifiers
+      summary: Update entities and/or relationships with classifier(s).
+      operationId: updateClassifier
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/contentTypeInHeader'
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Classifier'
+            examples:
+              classifier:
+                $ref: '#/components/examples/ClassifierExample'
+      responses:
+        '204':
+          $ref: '#/components/responses/NoContent'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '409':
+          $ref: '#/components/responses/Conflict'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /decorators:
+    put:
+      description: Update entities and/or relationships with decorator(s).
+      tags:
+        - Decorators
+      summary: Update entities and/or relationships with decorator(s).
+      operationId: updateDecorator
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/contentTypeInHeader'
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Decorator'
+            examples:
+              decorator:
+                $ref: '#/components/examples/DecoratorExample'
+      responses:
+        '204':
+          $ref: '#/components/responses/NoContent'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '409':
+          $ref: '#/components/responses/Conflict'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /collections:
+    post:
+      description: Create a collection.
+      tags:
+        - Collections
+      summary: Create a collection.
+      operationId: createCollection
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/contentTypeInHeader'
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Collection'
+            examples:
+              dynamicCollection:
+                $ref: '#/components/examples/DynamicCollectionExample'
+              staticCollection:
+                $ref: '#/components/examples/StaticCollectionExample'
+      responses:
+        '201':
+          description: Created
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/CollectionResponse'
+              examples:
+                collection:
+                  $ref: '#/components/examples/CollectionResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '409':
+          $ref: '#/components/responses/Conflict'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+    get:
+      description: Get all collections.
+      tags:
+        - Collections
+      summary: Get all collections.
+      operationId: "getAllCollections"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/offsetParam'
+        - $ref: '#/components/parameters/limitParam'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Collections'
+              examples:
+                collections:
+                  $ref: '#/components/examples/CollectionsResponseExample'
+        '204':
+          $ref: '#/components/responses/NoContent'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+  /collections/{collectionId}:
+    get:
+      description: Get a collection with specified id.
+      tags:
+        - Collections
+      summary: Get a collection with specified id.
+      operationId: "getCollection"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/collectionIdInPath'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/CollectionResponse'
+              examples:
+                collection:
+                  $ref: '#/components/examples/CollectionResponseExample'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+    put:
+      description: Update a collection.
+      tags:
+        - Collections
+      summary: Update a collection.
+      operationId: updateCollection
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/contentTypeInHeader'
+        - $ref: '#/components/parameters/collectionIdInPath'
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Collection'
+            examples:
+              dynamicCollection:
+                $ref: '#/components/examples/DynamicCollectionExample'
+              staticCollection:
+                $ref: '#/components/examples/StaticCollectionExample'
+      responses:
+        '204':
+          $ref: '#/components/responses/NoContent'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '409':
+          $ref: '#/components/responses/Conflict'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+    delete:
+      description: Delete a collection with specified id.
+      tags:
+        - Collections
+      summary: Delete a collection with specified id.
+      operationId: "deleteCollection"
+      parameters:
+        - $ref: '#/components/parameters/acceptInHeader'
+        - $ref: '#/components/parameters/collectionIdInPath'
+      responses:
+        '204':
+          $ref: '#/components/responses/NoContent'
+        '400':
+          $ref: '#/components/responses/BadRequest'
+        '401':
+          $ref: '#/components/responses/Unauthorized'
+        '403':
+          $ref: '#/components/responses/Forbidden'
+        '404':
+          $ref: '#/components/responses/NotFound'
+        '500':
+          $ref: '#/components/responses/InternalServerError'
+
+components:
+  schemas:
+    Classifier:
+      type: object
+      title: Classifier
+      properties:
+        operation:
+          type: string
+          enum:
+          - merge
+          - delete
+        classifier:
+          type: array
+          items:
+            type: string
+        entityIds:
+          type: array
+          items:
+            type: string
+        relationshipIds:
+          type: array
+          items:
+            type: string
+    CollectionResponse:
+      type: object
+      properties:
+        id:
+          type: string
+        collectionName:
+          type: string
+        criteria:
+          oneOf:
+          -  $ref: '#/components/schemas/StaticSelection'
+          -  $ref: '#/components/schemas/DynamicSelection'
+    Collection:
+      type: object
+      properties:
+        collectionName:
+          type: string
+        criteria:
+          $ref: '#/components/schemas/TopologySelection'
+    Collections:
+      type: object
+      title: Collections
+      properties:
+        items:
+          type: array
+          items:
+            $ref: '#/components/schemas/CollectionResponse'
+        self:
+          $ref: '#/components/schemas/Href'
+        first:
+          $ref: '#/components/schemas/Href'
+        prev:
+          $ref: '#/components/schemas/Href'
+        next:
+          $ref: '#/components/schemas/Href'
+        last:
+          $ref: '#/components/schemas/Href'
+        totalCount:
+          type: integer
+    TopologySelection:
+      oneOf:
+      -  $ref: '#/components/schemas/StaticSelection'
+      -  $ref: '#/components/schemas/DynamicSelection'
+    StaticSelection:
+      type: object
+      properties:
+        resourceInstances:
+          type: array
+          minItems: 1
+          items:
+            type: string
+    DynamicSelection:
+      type: object
+      additionalProperties: false
+      properties:
+        resourceQuery:
+          type: object
+          properties:
+            url:
+              type: string
+            method:
+              type: string
+            queryParams:
+              type: object
+            requestBody:
+              type: object
+          required:
+            - url
+    Decorator:
+      type: object
+      title: Decorator
+      properties:
+        operation:
+          type: string
+          enum:
+          - merge
+          - delete
+        decorators:
+          type: object
+          additionalProperties:
+           type: string
+        entityIds:
+          type: array
+          items:
+            type: string
+        relationshipIds:
+          type: array
+          items:
+            type: string
+    Domains:
+      type: object
+      title: Domains
+      properties:
+        items:
+          type: array
+          items:
+            properties:
+              name:
+                type: string
+              entityTypes:
+                $ref: '#/components/schemas/Href'
+              relationshipTypes:
+                $ref: '#/components/schemas/Href'
+        self:
+          $ref: '#/components/schemas/Href'
+        first:
+          $ref: '#/components/schemas/Href'
+        prev:
+          $ref: '#/components/schemas/Href'
+        next:
+          $ref: '#/components/schemas/Href'
+        last:
+          $ref: '#/components/schemas/Href'
+        totalCount:
+          type: integer
+    EntityTypes:
+      type: object
+      title: EntityTypes
+      properties:
+        items:
+          type: array
+          items:
+            type: object
+            properties:
+              name:
+                type: string
+              entities:
+                $ref: '#/components/schemas/Href'
+        self:
+          $ref: '#/components/schemas/Href'
+        first:
+          $ref: '#/components/schemas/Href'
+        prev:
+          $ref: '#/components/schemas/Href'
+        next:
+          $ref: '#/components/schemas/Href'
+        last:
+          $ref: '#/components/schemas/Href'
+        totalCount:
+          type: integer
+    EntitiesResponseMessage:
+      type: object
+      title: Entities
+      properties:
+        items:
+          type: array
+          items:
+            type: object
+            description: "Refer to yang model for schema definition of topology entities"
+        self:
+          $ref: '#/components/schemas/Href'
+        first:
+          $ref: '#/components/schemas/Href'
+        prev:
+          $ref: '#/components/schemas/Href'
+        next:
+          $ref: '#/components/schemas/Href'
+        last:
+          $ref: '#/components/schemas/Href'
+        totalCount:
+          type: integer
+    RelationshipTypes:
+      type: object
+      title: RelationshipTypes
+      properties:
+        items:
+          type: array
+          items:
+            type: object
+            properties:
+              name:
+                type: string
+              relationships:
+                $ref: '#/components/schemas/Href'
+        self:
+          $ref: '#/components/schemas/Href'
+        first:
+          $ref: '#/components/schemas/Href'
+        prev:
+          $ref: '#/components/schemas/Href'
+        next:
+          $ref: '#/components/schemas/Href'
+        last:
+          $ref: '#/components/schemas/Href'
+        totalCount:
+          type: integer
+    RelationshipsResponseMessage:
+      type: object
+      title: Relationships
+      properties:
+        items:
+          type: array
+          items:
+            type: object
+            description: "Refer to yang model for schema definition of topology relationships"
+        self:
+          $ref: '#/components/schemas/Href'
+        first:
+          $ref: '#/components/schemas/Href'
+        prev:
+          $ref: '#/components/schemas/Href'
+        next:
+          $ref: '#/components/schemas/Href'
+        last:
+          $ref: '#/components/schemas/Href'
+        totalCount:
+          type: integer
+    ErrorMessage:
+      type: object
+      title: Error
+      properties:
+        status:
+          type: string
+        message:
+          type: string
+        details:
+          type: string
+    Href:
+      type: object
+      title: Href
+      properties:
+        href:
+          type: string
+          format: uri-template
+    MultipartFile:
+      type: object
+      required:
+        - file
+      properties:
+        file:
+          type: string
+          description: multipartFile
+          format: binary
+    QueryMessage:
+      type: object
+      title: Query
+      properties:
+        query:
+          type: string
+    Schema:
+      type: object
+      title: Schema
+      properties:
+        name:
+          type: string
+        domain:
+          type: array
+          items:
+            type: string
+        revision:
+          type: string
+        content:
+          $ref: '#/components/schemas/Href'
+    SchemaList:
+      type: object
+      title: Schemas
+      properties:
+        items:
+          type: array
+          items:
+            $ref: '#/components/schemas/Schema'
+        self:
+          $ref: '#/components/schemas/Href'
+        first:
+          $ref: '#/components/schemas/Href'
+        prev:
+          $ref: '#/components/schemas/Href'
+        next:
+          $ref: '#/components/schemas/Href'
+        last:
+          $ref: '#/components/schemas/Href'
+        totalCount:
+          type: integer
+
+  responses:
+    NotFound:
+      description: Not Found
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+          example:
+            status: '404'
+            title: Resource Not Found
+            details: The requested resource is not found
+    Unauthorized:
+      description: Unauthorized
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+          example:
+            status: '401'
+            title: Unauthorized request
+            details: This request is unauthorized
+    Forbidden:
+      description: Forbidden
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+          example:
+            status: '403'
+            title: Request Forbidden
+            details: This request is forbidden
+    BadRequest:
+      description: Bad Request
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+          example:
+            status: '400'
+            title: Bad Request
+            details: The provided request is not valid
+    Conflict:
+      description: Conflict
+      content:
+        application/problem+json:
+          schema:
+            $ref: '#/components/schemas/ErrorMessage'
+          example:
+            status: 409'
+            title: Conflicting request
+            details: The request cannot be processed as the resource is in use.
+    Created:
+      description: Created without response body
+    InternalServerError:
+      description: Internal Server Error
+      content:
+        application/problem+json:
+          schema:
+            $ref: "#/components/schemas/ErrorMessage"
+          example:
+            status: '500'
+            title: Internal Server Error
+            details: Internal Server Error occurred
+    NoContent:
+      description: No Content
+      content: {}
+
+  parameters:
+    acceptInHeader:
+      name: Accept
+      in: header
+      required: true
+      schema:
+        type: string
+        example: application/json
+        default: application/json
+    contentTypeInHeader:
+      name: Content-Type
+      in: header
+      required: true
+      schema:
+        type: string
+        example: application/json
+        default: application/json
+    offsetParam:
+      name: offset
+      in: query
+      description: Pagination offset.
+      required: false
+      schema:
+        type: integer
+        default: 0
+        minimum: 0
+    limitParam:
+      name: limit
+      in: query
+      description: Result limiter.
+      required: false
+      schema:
+        type: integer
+        default: 500
+        minimum: 1
+        maximum: 500
+    domainNameInPath:
+      name: domainName
+      in: path
+      description: domain name
+      required: true
+      schema:
+        type: string
+    schemaNameInPath:
+      name: schemaName
+      in: path
+      required: true
+      schema:
+        type: string
+        default: "o-ran-smo-teiv-ran"
+    collectionIdInPath:
+      name: collectionId
+      in: path
+      required: true
+      schema:
+        type: string
+    entityIdInPath:
+      name: entityId
+      in: path
+      required: true
+      schema:
+        type: string
+    relationshipIdInPath:
+      name: relationshipId
+      in: path
+      required: true
+      schema:
+        type: string
+    entityTypeNameInPath:
+      name: entityTypeName
+      in: path
+      required: true
+      schema:
+        type: string
+    relationshipTypeNameInPath:
+      name: relationshipTypeName
+      in: path
+      required: true
+      schema:
+        type: string
+        example: NRCELLDU_USES_NRSECTORCARRIER
+    domainOptionalInQuery:
+      name: domain
+      in: query
+      required: false
+      schema:
+        type: string
+      examples:
+        domain:
+          value: ran
+    targetFilterOptionalInQuery:
+      name: targetFilter
+      description: Use *targetFilter* to specify the entity type and attributes to be returned in the REST response. The value for *targetFilter* can also be a list of entity types and attributes.
+      in: query
+      required: false
+      schema:
+        type: string
+      examples:
+        targetFilter:
+          value: /attributes(nCI,nRPCI)
+    scopeFilterOptionalInQuery:
+      name: scopeFilter
+      description: Use *scopeFilter* to specify the attributes to match on. The value for *scopeFilter* can also be a list of entity types and attributes. scopeFilter returns a boolean.
+      in: query
+      required: false
+      schema:
+        type: string
+      examples:
+        scopeFilter:
+          value: /attributes[@nRTAC=310"]
+
+  examples:
+    ClassifierExample:
+      value:
+        operation: merge
+        classifiers:
+        - module-x:Outdoor
+        - module-y:Rural
+        - module-z:Weekend
+        entityIds:
+        - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+        - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+        relationshipIds:
+        - "urn:sha512:TlJDZWxsRFU6U3ViTmV0d29yaz1FdXJvcGUsU3ViTmV0d29yaz1JcmV="
+    DecoratorExample:
+      value:
+        operation: merge
+        decorators:
+          module-x:location : Stockholm
+          module-y:vendor: Ericsson
+        entityIds:
+        - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+        - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+        relationshipIds:
+        - "urn:sha512:TlJDZWxsRFU6U3ViTmV0d29yaz1FdXJvcGUsU3ViTmV0d29yaz1JcmV="
+    EntityResponseExample:
+      value:
+        o-ran-smo-teiv-ran:GNBDUFunction:
+        - id: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1"
+          attributes:
+            gNBDUId: 11
+            dUpLMNId:
+              mcc: 110
+              mnc: 210
+            gNBId: 21
+            gNBIdLength: 2
+          decorators:
+            location: Stockholm
+          classifiers:
+          - Rural
+          sourceIds:
+          - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1"
+          - "urn:cmHandle:395221E080CCF0FD1924103B15873814"
+          metadata:
+            trustLevel: RELIABLE
+    EntitiesResponseExample:
+      value:
+        items:
+        - o-ran-smo-teiv-ran:NRCellDU:
+          - id: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+            attributes:
+              cellLocalId: 4589
+              nCI: 1
+              nRPCI: 12
+              nRTAC: 310
+            decorators:
+              location: Stockholm
+            classifiers:
+            - Rural
+            sourceIds:
+            - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+            - "urn:cmHandle:395221E080CCF0FD1924103B15873814"
+            metadata:
+              trustLevel: RELIABLE
+        - o-ran-smo-teiv-ran:NRCellDU:
+          - id: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+            attributes:
+              cellLocalId: 4559
+              nRPCI: 32
+              nRTAC: 510
+            decorators:
+              location: Stockholm
+            classifiers:
+            - Rural
+            sourceIds:
+            - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+            - "urn:cmHandle:395221E080CCF0FD1924103B15873814"
+            metadata:
+              trustLevel: RELIABLE
+        self:
+          href: '/domains/RAN/entity-types/NRCellDU/entities?offset=0&limit=500&targetFilter=attributes(nCI,nRPCI)&scopeFilter=/attributes[@nRTAC=310]'
+        first:
+          href: '/domains/RAN/entity-types/NRCellDU/entities?offset=0&limit=500&targetFilter=attributes(nCI,nRPCI)&scopeFilter=/attributes[@nRTAC=310]'
+        prev:
+          href: '/domains/RAN/entity-types/NRCellDU/entities?offset=0&limit=500&targetFilter=attributes(nCI,nRPCI)&scopeFilter=/attributes[@nRTAC=310]'
+        next:
+          href: '/domains/RAN/entity-types/NRCellDU/entities?offset=500&limit=500&targetFilter=attributes(nCI,nRPCI)&scopeFilter=/attributes[@nRTAC=310]'
+        last:
+          href: '/domains/RAN/entity-types/NRCellDU/entities?offset=678&limit=500&targetFilter=attributes(nCI,nRPCI)&scopeFilter=/attributes[@nRTAC=310]'
+        totalCount: 12
+
+    RelationshipResponseExample:
+      value:
+        o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER:
+        - id: "urn:sha512:TlJDZWxsRFU6U3ViTmV0d29yaz1FdXJvcGUsU3ViTmV0d29yaz1JcmV="
+          aSide: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+          bSide: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRSectorCarrier=1"
+          decorators:
+            location: Stockholm
+          classifiers:
+          - Rural
+          sourceIds: []
+          metadata:
+            trustLevel: RELIABLE
+
+    RelationshipsResponseExample:
+      value:
+        items:
+        - o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER:
+          - id: "urn:sha512:TlJDZWxsRFU6U3ViTmV0d29yaz1FdXJvcGUsU3ViTmV0d29yaz1JcmVs="
+            aSide: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+            bSide: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRSectorCarrier=1"
+            decorators:
+              location: Stockholm
+            classifiers:
+            - Rural
+            sourceIds: []
+            metadata:
+              trustLevel: RELIABLE
+        - o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER:
+          - id: "urn:sha512:TlJDZWxsRFU6U3ViTmV0d29yaz1FdXJvcGUsU3ViTmV0d29yaz1JcmVsYW5kLE1lQ2="
+            aSide: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+            bSide: "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRSectorCarrier=2"
+            decorators:
+              location: Stockholm
+            classifiers:
+            - Rural
+            sourceIds: []
+            metadata:
+              trustLevel: RELIABLE
+        self:
+          href: '/domains/RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships?offset=0&limit=500'
+        first:
+          href: '/domains/RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships?offset=0&limit=500'
+        prev:
+          href: '/domains/RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships?offset=0&limit=500'
+        next:
+          href: '/domains/RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships?offset=500&limit=500'
+        last:
+          href: '/domains/RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships?offset=678&limit=500'
+        totalCount: 23
+
+    EntityTypesResponseExample:
+      value:
+        items:
+        - name: GNBCUUPFunction
+          entities:
+            href: '/domains/RAN/entity-types/GNBCUUPFunction/entities'
+        - name: NRCellDU
+          entities:
+            href: '/domains/RAN/entity-types/NRCellDU/entities'
+        - name: GNBDUFunction
+          entities:
+            href: '/domains/RAN/entity-types/GNBDUFunction/entities'
+        self:
+          href: '/domains/RAN/entity-types?offset=0&limit=500'
+        first:
+          href: '/domains/RAN/entity-types?offset=0&limit=500'
+        prev:
+          href: '/domains/RAN/entity-types?offset=0&limit=500'
+        next:
+          href: '/domains/RAN/entity-types?offset=500&limit=500'
+        last:
+          href: '/domains/RAN/entity-types?offset=678&limit=500'
+        totalCount: 43
+
+    RelationshipTypesResponseExample:
+      value:
+        items:
+        - name: MANAGEDELEMENT_MANAGES_GNBDUFUNCTION
+          relationships:
+            href: '/domains/RAN/relationship-types/MANAGEDELEMENT_MANAGES_GNBDUFUNCTION/relationships'
+        - name: GNBDUFUNCTION_PROVIDES_NRCELLDU
+          relationships:
+            href: '/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships'
+        - name: NRCELLDU_USES_NRSECTORCARRIER
+          relationships:
+            href: '/domains/RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships'
+        self:
+          href: '/domains/RAN/relationship-types?offset=0&limit=500'
+        first:
+          href: '/domains/RAN/relationship-types?offset=0&limit=500'
+        prev:
+          href: '/domains/RAN/relationship-types?offset=0&limit=500'
+        next:
+          href: '/domains/RAN/relationship-types?offset=500&limit=500'
+        last:
+          href: '/domains/RAN/relationship-types?offset=678&limit=500'
+        totalCount: 21
+
+    DomainsResponseExample:
+      value:
+        items:
+        - name: RAN_CLOUD
+          entityTypes:
+            href: '/domains/CLOUD/entity-types'
+          relationshipTypes:
+            href: '/domains/CLOUD/relationship-types'
+        - name: RAN_OAM
+          entityTypes:
+            href: '/domains/OAM/entity-types'
+          relationshipTypes:
+            href: '/domains/OAM/relationship-types'
+        - name: RAN_LOGICAL
+          entityTypes:
+            href: '/domains/RAN/entity-types'
+          relationshipTypes:
+            href: '/domains/RAN/relationship-types'
+        self:
+          href: '/domains?offset=0&limit=500'
+        first:
+          href: '/domains?offset=0&limit=500'
+        prev:
+          href: '/domains?offset=0&limit=500'
+        next:
+          href: '/domains?offset=500&limit=500'
+        last:
+          href: '/domains?offset=678&limit=500'
+        totalCount: 343
+
+    QueryMessageExample:
+      value:
+        query: |-
+          WITH point({longitude: 12.78232, latitude: 56.7455}) AS p1, point({latitude: 56.7134, longitude: 12.79565}) AS p2 RETURN point.distance(p1, p2) AS distance
+    QueryResponseExample:
+      value:
+        query: |-
+          WITH point({longitude: 12.78232, latitude: 56.7455}) AS p1, point({latitude: 56.7134, longitude: 12.79565}) AS p2 RETURN point.distance(p1, p2) AS distance
+        response: "distance : 2873.5"
+
+    StaticCollectionExample:
+      value:
+        collectionName: "son-cell-filter-group-1"
+        criteria:
+          resourceInstances:
+          - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+          - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+          - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=3"
+
+    DynamicCollectionExample:
+      value:
+        collectionName: "son-cell-filter-group-1"
+        criteria:
+          resourceQuery:
+            url: /domains/RAN/entity-types/NRCellDU/entities
+            method: GET
+            queryParams:
+              target:Filter: /attributes(cmId)
+              scopeFilter: /attributes[@nRTAC=310]
+            requestBody: ""
+
+    CollectionResponseExample:
+      value:
+        id: "urn:oran:collection:/JHKJ4H5JH45345TB="
+        collectionName: "son-cell-filter-group-1"
+        criteria:
+          resourceInstances:
+          - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+          - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+          - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=3"
+
+    CollectionsResponseExample:
+      value:
+        items:
+          - id: "urn:topology:collection:/JHKJ4H5JH45345TB="
+            collectionName: "son-cell-group-1"
+            criteria:
+              resourceInstances:
+              - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1"
+              - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=2"
+              - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=3"
+          - id: "urn:topology:collection:/DFJER77R6F7S9VD="
+            collectionName: "son-cell-group-2"
+            criteria:
+              resourceInstances:
+              - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=4"
+              - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=5"
+              - "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=6"
+
+        self:
+          href: '/collections?offset=0&limit=500'
+        first:
+          href: '/collections?offset=0&limit=500'
+        prev:
+          href: '/collections?offset=0&limit=500'
+        next:
+          href: '/collections?offset=500&limit=500'
+        last:
+          href: '/collections?offset=678&limit=500'
+        totalCount: 11
+
+    SchemasResponseExample:
+      value:
+        items:
+          - name: o-ran-smo-teiv-ran
+            domain:
+              - RAN_LOGICAL
+            revision: '2013-07-15'
+            content:
+              href: '/schemas/o-ran-smo-teiv-ran/content'
+          - name: o-ran-smo-teiv-cloud
+            domain:
+              - RAN_CLOUD
+            revision: '2021-05-19'
+            content:
+              href: '/schemas/o-ran-smo-teiv-cloud/content'
+          - name: o-ran-smo-teiv-oam
+            domain:
+              - RAN_OAM'
+            revision: '2021-05-19'
+            content:
+              href: '/schemas/o-ran-smo-teiv-oam/content'
+          - name: o-ran-smo-teiv-common-yang-types
+            domain:
+              []
+            revision: '2021-07-04'
+            content:
+              href: '/schemas/o-ran-smo-teiv-common-yang-types/content'
+          - name: o-ran-smo-teiv-common-yang-extensions
+            domain:
+              []
+            revision: '2021-07-04'
+            content:
+              href: '/schemas/o-ran-smo-teiv-common-yang-extensions/content'
+        self:
+          href: '/schemas?offset=0&limit=500'
+        first:
+          href: '/schemas?offset=0&limit=500'
+        prev:
+          href: '/schemas?offset=0&limit=500'
+        next:
+          href: '/schemas?offset=500&limit=500'
+        last:
+          href: '/schemas?offset=678&limit=500'
+        totalCount: 14
+
+    SchemaResponseExample:
+      value: "module stores {\
+  yang-version 1.1;\
+  namespace \"ietf-inet-types\";\
+  prefix module-references;\
+  revision \"2020-09-15\" {\
+    description\
+    \"Sample Model\";\
+    }  \
+  typedef Mcc {\
+    type string;\
+    }\
+  typedef Mnc {\
+    type string;\
+    }\
+  grouping PLMNId {\
+    leaf mcc {\
+      type Mcc;\
+        }\
+    leaf mnc {\
+      type Mnc;\
+        }\
+    }      \
+  container RAN_LOGICAL {\
+    leaf namespace {\
+      type string;\
+        }\
+    container GNBDUFunction {\
+      leaf eiid {\
+        type string;\
+            }  \
+      leaf gNBDUId {\
+        type uint16;\
+            }\
+      leaf gNBID {\
+        type uint16;\
+            }\
+      leaf gNBIdLength {\
+        type uint16;\
+            }\
+      container dUpLMNId{\
+        description \"ToDo\";\
+        uses PLMNId;\
+      }        \
+    }\
+    container GNBCUUPFunction {\
+      leaf eiid {\
+        type string;\
+      } \
+      leaf gNBID {\
+        type uint16;\
+            }\
+      leaf gNBIdLength {\
+        type uint16;\
+            }\
+        }  \
+    container GNBCUCPFunction {            \
+      leaf eiid {\
+        type string;\
+            } \
+      leaf gNBID {\
+        type uint16;\
+            }\
+      leaf gNBIdLength {\
+        type uint16;\
+            }\
+      leaf gNBCUName {\
+        type string;\
+            }\
+      container pLMNId{\
+        description \"ToDo\";\
+        uses PLMNId;\
+      }      \
+        }\
+    container NRCellCU {            \
+      leaf eiid {\
+        type string;\
+            } \
+      leaf cellLocalId {\
+        type uint16;\
+            }\
+      leaf nCI {\
+        type uint16;\
+            }\
+      leaf nRTAC {\
+        type uint16;\
+            }\
+      container plmnId{\
+        description \"ToDo\";\
+        uses PLMNId;\
+      }        \
+        }\
+    container NRCellDU {            \
+      leaf eiid {\
+        type string;\
+            } \
+      leaf cellLocalId {\
+        type uint16;\
+            }\
+      leaf nCI {\
+        type uint16;\
+            }\
+      leaf nRPCI {\
+        type uint16;\
+            }\
+      leaf nRTAC {\
+        type uint16;\
+            }\
+        }\
+    }\
+}"
diff --git a/teiv/src/test/java/org/oran/smo/teiv/CoreApplicationTest.java b/teiv/src/test/java/org/oran/smo/teiv/CoreApplicationTest.java
new file mode 100644
index 0000000..ed557f5
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/CoreApplicationTest.java
@@ -0,0 +1,139 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.Objects;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+
+import org.oran.smo.teiv.startup.SchemaHandler;
+import org.oran.smo.teiv.utils.TiesConstants;
+import jakarta.validation.ConstraintViolationException;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+@AutoConfigureMockMvc
+class CoreApplicationTest {
+    @Autowired
+    private MockMvc mvc;
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    private final String ACCEPT_TYPE = "application/json";
+
+    @Test
+    void testMetricsAvailable() throws Exception {
+        // spotless:off
+        final MvcResult result = mvc.perform(get("/actuator/prometheus")
+                .contentType(MediaType.TEXT_PLAIN))
+                .andExpect(status().isOk())
+                .andReturn();
+
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_create_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_merge_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_delete_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_not_supported_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_create_parse_success_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_create_parse_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_merge_parse_success_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_merge_parse_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_delete_parse_success_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_delete_parse_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_create_persist_success_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_create_persist_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_merge_persist_success_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_merge_persist_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_delete_persist_success_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_delete_persist_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_create_parse_seconds"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_merge_parse_seconds"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_delete_parse_seconds"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_create_persist_seconds"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_merge_persist_seconds"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_ingestion_event_topology_delete_persist_seconds"));
+
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_domain_types_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_entity_types_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_relationship_types_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_entity_by_id_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_entities_by_type_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_entities_by_domain_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_relationship_by_id_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_relationships_by_type_fail_total"));
+        Assertions.assertTrue(result.getResponse().getContentAsString().contains("ties_exposure_http_get_relationships_by_entity_id_fail_total"));
+        // spotless:on
+    }
+
+    @ParameterizedTest()
+    @CsvSource(value = { "getSchemas:/schemas", "getAllDomains:/domains",
+            "getAllRelationshipsForEntityId:/domains/RAN_LOGICAL/entity-types/GNBDUFunction/entities/1/relationships",
+            "getEntitiesByDomain:/domains/RAN_LOGICAL/entities?targetFilter=%2FNRCellDU%2Fattributes%2FnCI",
+            "getRelationshipsByType:/domains/RAN_LOGICAL/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships",
+            "getTopologyByEntityTypeName:/domains/RAN_LOGICAL/entity-types/GNBDUFunction/entities",
+            "getTopologyEntityTypes:/domains/RAN_LOGICAL/entity-types",
+            "getTopologyRelationshipTypes:/domains/RAN_LOGICAL/relationship-types" }, delimiter = ':')
+    public void testPaginationRelatedEndpoints(String method, String url) throws Exception {
+        mvc.perform(get(TiesConstants.REQUEST_MAPPING + url).param("offset", "-1").accept(ACCEPT_TYPE)).andExpect(status()
+                .isBadRequest()).andExpect(result -> assertEquals(Objects.requireNonNull(result.getResolvedException())
+                        .getMessage(), method + ".offset: must be greater than or equal to 0"));
+        mvc.perform(get(TiesConstants.REQUEST_MAPPING + url).param("limit", "0").accept(ACCEPT_TYPE)).andExpect(status()
+                .isBadRequest()).andExpect(result -> assertEquals(Objects.requireNonNull(result.getResolvedException())
+                        .getMessage(), method + ".limit: must be greater than or equal to 1"));
+        mvc.perform(get(TiesConstants.REQUEST_MAPPING + url).param("limit", "501").accept(ACCEPT_TYPE)).andExpect(status()
+                .isBadRequest()).andExpect(result -> assertEquals(Objects.requireNonNull(result.getResolvedException())
+                        .getMessage(), method + ".limit: must be less than or equal to 500"));
+
+        mvc.perform(get(TiesConstants.REQUEST_MAPPING + url).param("offset", "0").accept(ACCEPT_TYPE)).andExpect(result -> {
+            if (result.getResponse().getStatus() != HttpStatus.OK.value())
+                assertNotEquals(ConstraintViolationException.class, Objects.requireNonNull(result.getResolvedException())
+                        .getClass());
+        });
+        mvc.perform(get(TiesConstants.REQUEST_MAPPING + url).param("limit", "1").accept(ACCEPT_TYPE)).andExpect(result -> {
+            if (result.getResponse().getStatus() != HttpStatus.OK.value())
+                assertNotEquals(ConstraintViolationException.class, Objects.requireNonNull(result.getResolvedException())
+                        .getClass());
+        });
+        mvc.perform(get(TiesConstants.REQUEST_MAPPING + url).param("limit", "500").accept(ACCEPT_TYPE)).andExpect(
+                result -> {
+                    if (result.getResponse().getStatus() != HttpStatus.OK.value())
+                        assertNotEquals(ConstraintViolationException.class, Objects.requireNonNull(result
+                                .getResolvedException()).getClass());
+                });
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/availability/DependentServiceAvailabilityKafkaTest.java b/teiv/src/test/java/org/oran/smo/teiv/availability/DependentServiceAvailabilityKafkaTest.java
new file mode 100644
index 0000000..ad7f0cc
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/availability/DependentServiceAvailabilityKafkaTest.java
@@ -0,0 +1,153 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.availability;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.apache.kafka.clients.admin.AdminClient;
+import org.apache.kafka.clients.admin.ListTopicsResult;
+import org.apache.kafka.clients.admin.MockAdminClient;
+import org.apache.kafka.clients.admin.NewTopic;
+import org.apache.kafka.common.KafkaFuture;
+import org.apache.kafka.common.Node;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.system.CapturedOutput;
+import org.springframework.boot.test.system.OutputCaptureExtension;
+import org.springframework.kafka.test.EmbeddedKafkaBroker;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.MethodMode;
+import org.springframework.test.context.ActiveProfiles;
+
+import org.oran.smo.teiv.config.KafkaAdminConfig;
+import org.oran.smo.teiv.exception.UnsatisfiedExternalDependencyException;
+import org.oran.smo.teiv.service.kafka.KafkaFactory;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import lombok.Getter;
+
+@EmbeddedKafka
+@ExtendWith(OutputCaptureExtension.class)
+@SpringBootTest
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+@ActiveProfiles({ "test", "ingestion" })
+public class DependentServiceAvailabilityKafkaTest {
+    @Autowired
+    protected EmbeddedKafkaBroker embeddedKafkaBroker;
+
+    @Value("${spring.embedded.kafka.brokers}")
+    @Getter
+    private String embeddedKafkaServer;
+
+    @Autowired
+    private KafkaAdminConfig kafkaAdminConfig;
+
+    @Autowired
+    KafkaFactory factory;
+
+    @Autowired
+    private DependentServiceAvailabilityKafka dependentServiceAvailabilityKafka;
+
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @BeforeEach
+    public void setup() {
+        Supplier<String> brokers = () -> getEmbeddedKafkaServer();
+        dependentServiceAvailabilityKafka.getKafkaAdmin().setBootstrapServersSupplier(brokers);
+    }
+
+    @Test
+    @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+    @DisplayName("When checkKafkaHealth not throws exception, expect to pass, means kafka broker is up")
+    @Order(1)
+    void test_input_topic_does_exist() {
+        kafkaAdminConfig.setBootstrapServer(embeddedKafkaServer);
+        final boolean result = dependentServiceAvailabilityKafka.checkService();
+        assertTrue(result);
+    }
+
+    @Test
+    @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+    @DisplayName("When checkKafkaHealth throws exception, expect to fail, means kafka broker is down")
+    @Order(2)
+    void testKafkaNotReachable() {
+        embeddedKafkaBroker.destroy();
+        dependentServiceAvailabilityKafka.setListTopicTimeout(100);
+        final boolean result = dependentServiceAvailabilityKafka.checkService();
+        assertFalse(result);
+    }
+
+    @Test
+    @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+    @Order(3)
+    void testIsServiceAvailable_ThrowsInterruptedException(CapturedOutput output) throws Exception {
+        Node controller = new Node(0, "localhost", 8121);
+        List<Node> brokers = Arrays.asList(controller, new Node(1, "localhost", 8122), new Node(2, "localhost", 8123));
+        AdminClient mockedAdminClient = new MockAdminClient(brokers, controller);
+        AdminClient spiedAdminClient = Mockito.spy(mockedAdminClient);
+        final NewTopic newTopic = new NewTopic("test_topic", 1, (short) 1);
+        mockedAdminClient.createTopics(List.of(newTopic));
+
+        ListTopicsResult topicListresult = Mockito.spy(mockedAdminClient.listTopics());
+        KafkaFuture<Set<String>> kafkaFutures = Mockito.spy(topicListresult.names());
+        doReturn(topicListresult).when(spiedAdminClient).listTopics();
+        doReturn(kafkaFutures).when(topicListresult).names();
+        doThrow(InterruptedException.class).when(kafkaFutures).get();
+
+        MockedStatic<AdminClient> mockedStaticAdminClient = Mockito.mockStatic(AdminClient.class);
+        mockedStaticAdminClient.when(() -> AdminClient.create(ArgumentMatchers.any(Properties.class)).listTopics().names())
+                .thenReturn(spiedAdminClient);
+
+        DependentServiceAvailabilityKafka spiedDependentServiceAvailabilityKafka = Mockito.spy(
+                dependentServiceAvailabilityKafka);
+
+        assertThrows(UnsatisfiedExternalDependencyException.class,
+                spiedDependentServiceAvailabilityKafka::isServiceAvailable);
+
+        Mockito.reset(spiedAdminClient, topicListresult, kafkaFutures, spiedDependentServiceAvailabilityKafka);
+        mockedStaticAdminClient.close();
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/controller/health/TiesExposureHealthIndicatorTest.java b/teiv/src/test/java/org/oran/smo/teiv/controller/health/TiesExposureHealthIndicatorTest.java
new file mode 100644
index 0000000..4a3a5db
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/controller/health/TiesExposureHealthIndicatorTest.java
@@ -0,0 +1,104 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.controller.health;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import org.oran.smo.teiv.schema.PostgresSchemaLoader;
+import org.oran.smo.teiv.startup.SchemaHandler;
+
+@AutoConfigureMockMvc
+@SpringBootTest(properties = { "spring.profiles.active=test", "management.endpoint.health.probes.enabled=true",
+        "management.endpoint.health.group.readiness.include=readinessState,tiesExposure" })
+class TiesExposureHealthIndicatorTest {
+    private final String readinessProbePath = "/actuator/health/readiness";
+    private final String livenessProbePath = "/actuator/health/liveness";
+    private final String tiesExposureProbePath = "/actuator/health/tiesExposure";
+
+    @Autowired
+    private MockMvc mvc;
+    @Autowired
+    private HealthStatus healthStatus;
+    private static final String SERVICE_NAME = "topology-exposure-inventory";
+
+    @MockBean
+    private PostgresSchemaLoader postgresSchemaLoader;
+
+    @AfterEach
+    protected void tearDown() {
+        healthStatus.setSchemaInitialized(false);
+    }
+
+    @Test
+    void upAndHealthy() throws Exception {
+        mvc.perform(get(readinessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(livenessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(tiesExposureProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+                .andExpect(content().json(String.format("{'status':'UP','details':{'UP': '%s is UP and Healthy.'}}",
+                        SERVICE_NAME)));
+    }
+
+    @Test
+    void upSchemaServiceLoaded() throws Exception {
+        SchemaHandler schemaHandlerSpy = Mockito.spy(new SchemaHandler(postgresSchemaLoader, healthStatus));
+        schemaHandlerSpy.initializeSchema();
+        Assertions.assertTrue(healthStatus.isSchemaInitialized());
+        mvc.perform(get(readinessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(livenessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(tiesExposureProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+                .andExpect(content().json(String.format("{'status':'UP','details':{'UP': '%s is UP and Healthy.'}}",
+                        SERVICE_NAME)));
+    }
+
+    @Test
+    void downSchemaServiceNotLoaded() throws Exception {
+        healthStatus.setSchemaInitialized(false);
+        performReadinessGroupProbesDownWithMessage(" Schema is yet to be initialized.");
+    }
+
+    private void performReadinessGroupProbesDownWithMessage(String message) throws Exception {
+        mvc.perform(get(livenessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(readinessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().is5xxServerError())
+                .andExpect(content().json("{'status' : 'DOWN'}"));
+        mvc.perform(get(tiesExposureProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status()
+                .is5xxServerError()).andExpect(content().json(String.format(
+                        "{'status' : 'DOWN', 'details':{'Error':'%s is DOWN because:%s'}}", SERVICE_NAME, message)))
+                .andReturn();
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/controller/health/TiesIngestionHealthIndicatorTest.java b/teiv/src/test/java/org/oran/smo/teiv/controller/health/TiesIngestionHealthIndicatorTest.java
new file mode 100644
index 0000000..75fbed1
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/controller/health/TiesIngestionHealthIndicatorTest.java
@@ -0,0 +1,111 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.controller.health;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import org.oran.smo.teiv.availability.DependentServiceAvailabilityKafka;
+import org.oran.smo.teiv.schema.PostgresSchemaLoader;
+import org.oran.smo.teiv.startup.SchemaHandler;
+
+@AutoConfigureMockMvc
+@SpringBootTest(properties = { "spring.profiles.active=test,ingestion", "management.endpoint.health.probes.enabled=true",
+        "management.endpoint.health.group.readiness.include=readinessState,tiesIngestion" })
+public class TiesIngestionHealthIndicatorTest {
+    private final String readinessProbePath = "/actuator/health/readiness";
+    private final String livenessProbePath = "/actuator/health/liveness";
+    private final String tiesIngestionProbePath = "/actuator/health/tiesIngestion";
+
+    @Autowired
+    private MockMvc mvc;
+
+    @Autowired
+    private HealthStatus healthStatus;
+
+    @SpyBean
+    private DependentServiceAvailabilityKafka spiedDependentServiceAvailabilityKafka;
+
+    private static final String SERVICE_NAME = "top-exp-inv-ingestion";
+
+    @MockBean
+    PostgresSchemaLoader postgresSchemaLoader;
+
+    @AfterEach
+    protected void tearDown() {
+        healthStatus.setSchemaInitialized(false);
+        doReturn(false).when(spiedDependentServiceAvailabilityKafka).checkService();
+    }
+
+    @Test
+    void upAndHealthy() throws Exception {
+        doReturn(true).when(spiedDependentServiceAvailabilityKafka).checkService();
+        healthStatus.setSchemaInitialized(true);
+        mvc.perform(get(readinessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(livenessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(tiesIngestionProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+                .andExpect(content().json(String.format("{'status':'UP','details':{'UP': '%s is UP and Healthy.'}}",
+                        SERVICE_NAME)));
+    }
+
+    @Test
+    void downSchemaNotInitialized() throws Exception {
+        healthStatus.setSchemaInitialized(false);
+        doReturn(true).when(spiedDependentServiceAvailabilityKafka).checkService();
+        performReadinessGroupProbesDownWithMessage(" Schema is yet to be initialized.");
+    }
+
+    @Test
+    void downKafkaUnavailable() throws Exception {
+        SchemaHandler schemaHandlerSpy = Mockito.spy(new SchemaHandler(postgresSchemaLoader, healthStatus));
+        schemaHandlerSpy.initializeSchema();
+        assertTrue(healthStatus.isSchemaInitialized());
+        doReturn(false).when(spiedDependentServiceAvailabilityKafka).checkService();
+        performReadinessGroupProbesDownWithMessage(" Kafka is unavailable.");
+    }
+
+    private void performReadinessGroupProbesDownWithMessage(String message) throws Exception {
+        mvc.perform(get(livenessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(
+                content().json("{'status' : 'UP'}"));
+        mvc.perform(get(readinessProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status().is5xxServerError())
+                .andExpect(content().json("{'status' : 'DOWN'}"));
+        mvc.perform(get(tiesIngestionProbePath).contentType(MediaType.APPLICATION_JSON)).andExpect(status()
+                .is5xxServerError()).andExpect(content().json(String.format(
+                        "{'status' : 'DOWN', 'details':{'Error':'%s is DOWN because:%s'}}", SERVICE_NAME, message)))
+                .andReturn();
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/db/RyukImageNameSubstitutor.java b/teiv/src/test/java/org/oran/smo/teiv/db/RyukImageNameSubstitutor.java
new file mode 100644
index 0000000..6f8e317
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/db/RyukImageNameSubstitutor.java
@@ -0,0 +1,55 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.db;
+
+import org.testcontainers.utility.DockerImageName;
+import org.testcontainers.utility.ImageNameSubstitutor;
+import org.testcontainers.utility.TestcontainersConfiguration;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class RyukImageNameSubstitutor extends ImageNameSubstitutor {
+
+    private final TestcontainersConfiguration configuration = TestcontainersConfiguration.getInstance();
+
+    @Override
+    public DockerImageName apply(DockerImageName original) {
+        final String configuredRyukImage = configuration.getEnvVarOrProperty("substitutor.ryuk.container.image", "");
+
+        if ("testcontainers/ryuk".equals(original.getRepository()) && "".equals(original.getRegistry())) {
+            if (configuredRyukImage.isEmpty()) {
+                // if you have configured the RyukImageNameSubstitutor class you probably want also a substitute configured
+                log.info("No ryuk substitute is configured");
+                return original;
+            }
+
+            log.debug("Substituting testcontainers/ryuk with {}", configuredRyukImage);
+            return DockerImageName.parse(configuredRyukImage);
+        }
+        return original;
+    }
+
+    @Override
+    protected String getDescription() {
+        return getClass().getSimpleName();
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/db/TestPostgresqlContainer.java b/teiv/src/test/java/org/oran/smo/teiv/db/TestPostgresqlContainer.java
new file mode 100644
index 0000000..db7f18a
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/db/TestPostgresqlContainer.java
@@ -0,0 +1,69 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.db;
+
+import java.io.IOException;
+
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.utility.DockerImageName;
+import org.testcontainers.utility.MountableFile;
+
+public class TestPostgresqlContainer extends PostgreSQLContainer<TestPostgresqlContainer> {
+
+    private static TestPostgresqlContainer container;
+
+    private TestPostgresqlContainer(DockerImageName image) {
+        super(image);
+    }
+
+    public static TestPostgresqlContainer getInstance() {
+        if (container == null) {
+            container = new TestPostgresqlContainer(DockerImageName.parse("postgis/postgis:13-3.4-alpine")
+                    .asCompatibleSubstituteFor("postgres"));
+
+            container.withCopyFileToContainer(MountableFile.forClasspathResource(
+                    "pgsqlschema/00_init-oran-smo-teiv-data.sql"), "/pgsqlschema/00_init-oran-smo-teiv-data.sql");
+            container.withCopyFileToContainer(MountableFile.forClasspathResource(
+                    "pgsqlschema/01_init-oran-smo-teiv-model.sql"), "/pgsqlschema/01_init-oran-smo-teiv-model.sql");
+            container.withCopyFileToContainer(MountableFile.forClasspathResource("data/data.sql"), "/02_data.sql");
+            container.setCommand("postgres", "-c", "max_connections=2000");
+
+            container.start();
+            try {
+                container.execInContainer("psql", "-U", "test", "-w", "-f", "/pgsqlschema/00_init-oran-smo-teiv-data.sql",
+                        "--set=pguser=\"test\";");
+                container.execInContainer("psql", "-U", "test", "-w", "-f", "/pgsqlschema/01_init-oran-smo-teiv-model.sql",
+                        "--set=pguser=\"test\";");
+            } catch (UnsupportedOperationException | IOException | InterruptedException e) {
+                throw new RuntimeException(e.getMessage());
+            }
+        }
+        return container;
+    }
+
+    public static void loadSampleData() {
+        try {
+            container.execInContainer("psql", "-U", "test", "-w", "-f", "/02_data.sql", "--set=pguser=\"test\";");
+        } catch (UnsupportedOperationException | IOException | InterruptedException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/e2e/DataControllerE2EContainerizedNonXPathTest.java b/teiv/src/test/java/org/oran/smo/teiv/e2e/DataControllerE2EContainerizedNonXPathTest.java
new file mode 100644
index 0000000..705faea
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/e2e/DataControllerE2EContainerizedNonXPathTest.java
@@ -0,0 +1,317 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.e2e;
+
+import org.oran.smo.teiv.api.model.OranTeivDomains;
+import org.oran.smo.teiv.api.model.OranTeivDomainsItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypes;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.exposure.data.rest.controller.DataRestController;
+import org.oran.smo.teiv.schema.PostgresSchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.jooq.DSLContext;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import javax.sql.DataSource;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import static org.oran.smo.teiv.utils.TiesConstants.TEIV_DOMAIN;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+
+@Slf4j
+@ActiveProfiles({ "test", "exposure" })
+@SpringBootTest
+public class DataControllerE2EContainerizedNonXPathTest {
+
+    public static final String ACCEPT_TYPE = "application/yang+json";
+
+    @Autowired
+    public DataRestController underTest;
+    public static TestPostgresqlContainer postgreSQLContainer = TestPostgresqlContainer.getInstance();
+
+    @Autowired
+    DSLContext writeDataDslContext;
+
+    @DynamicPropertySource
+    static void setProperties(DynamicPropertyRegistry registry) {
+        registry.add("spring.datasource.read.jdbc-url", () -> postgreSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.read.username", () -> postgreSQLContainer.getUsername());
+        registry.add("spring.datasource.read.password", () -> postgreSQLContainer.getPassword());
+
+        registry.add("spring.datasource.write.jdbc-url", () -> postgreSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.write.username", () -> postgreSQLContainer.getUsername());
+        registry.add("spring.datasource.write.password", () -> postgreSQLContainer.getPassword());
+    }
+
+    @BeforeAll
+    public static void beforeAll() throws UnsupportedOperationException, SchemaLoaderException {
+        String url = postgreSQLContainer.getJdbcUrl();
+        DataSource ds = DataSourceBuilder.create().url(url).username("test").password("test").build();
+        DSLContext dslContext = DSL.using(ds, SQLDialect.POSTGRES);
+        PostgresSchemaLoader postgresSchemaLoader = new PostgresSchemaLoader(dslContext, new ObjectMapper());
+        postgresSchemaLoader.loadSchemaRegistry();
+    }
+
+    @BeforeEach
+    public void deleteAll() {
+        writeDataDslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(
+                t -> writeDataDslContext.truncate(t).cascade().execute());
+        TestPostgresqlContainer.loadSampleData();
+    }
+
+    @Test
+    public void testGetAllDomains() {
+        final OranTeivDomains responseMessage = underTest.getAllDomains(ACCEPT_TYPE, 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage);
+        Assertions.assertEquals(9, responseMessage.getItems().size());
+
+        Map<String, String> expectedData = new HashMap<>();
+        expectedData.put("name", TEIV_DOMAIN);
+        expectedData.put("entityTypes", "/domains/" + TEIV_DOMAIN + "/entity-types");
+        expectedData.put("relationshipTypes", "/domains/" + TEIV_DOMAIN + "/relationship-types");
+
+        OranTeivDomainsItemsInner actualItem = responseMessage.getItems().get(8);
+
+        Assertions.assertEquals(expectedData.get("name"), actualItem.getName());
+        Assertions.assertEquals(expectedData.get("entityTypes"), actualItem.getEntityTypes().getHref());
+        Assertions.assertEquals(expectedData.get("relationshipTypes"), actualItem.getRelationshipTypes().getHref());
+
+        Map<String, String> expectedDataCloud = new HashMap<>();
+        expectedDataCloud.put("name", "CLOUD");
+        expectedDataCloud.put("entityTypes", "/domains/CLOUD/entity-types");
+        expectedDataCloud.put("relationshipTypes", "/domains/CLOUD/relationship-types");
+
+        OranTeivDomainsItemsInner actualItemCloud = responseMessage.getItems().get(0);
+
+        Assertions.assertEquals(expectedDataCloud.get("name"), actualItemCloud.getName());
+        Assertions.assertEquals(expectedDataCloud.get("entityTypes"), actualItemCloud.getEntityTypes().getHref());
+        Assertions.assertEquals(expectedDataCloud.get("relationshipTypes"), actualItemCloud.getRelationshipTypes()
+                .getHref());
+
+        Map<String, String> expectedDataLogicalToEquipment = new HashMap<>();
+        expectedDataLogicalToEquipment.put("name", "EQUIPMENT_TO_RAN");
+        expectedDataLogicalToEquipment.put("entityTypes", "/domains/EQUIPMENT_TO_RAN/entity-types");
+        expectedDataLogicalToEquipment.put("relationshipTypes", "/domains/EQUIPMENT_TO_RAN/relationship-types");
+
+        OranTeivDomainsItemsInner actualItemLogicalToEquipment = responseMessage.getItems().get(3);
+
+        Assertions.assertEquals(expectedDataLogicalToEquipment.get("name"), actualItemLogicalToEquipment.getName());
+        Assertions.assertEquals(expectedDataLogicalToEquipment.get("entityTypes"), actualItemLogicalToEquipment
+                .getEntityTypes().getHref());
+        Assertions.assertEquals(expectedDataLogicalToEquipment.get("relationshipTypes"), actualItemLogicalToEquipment
+                .getRelationshipTypes().getHref());
+    }
+
+    @Test
+    public void testGetTopologyEntityTypes() {
+        final OranTeivEntityTypes responseMessage = underTest.getTopologyEntityTypes(ACCEPT_TYPE, "EQUIPMENT_TO_RAN", 0, 20)
+                .getBody();
+
+        Assertions.assertNotNull(responseMessage);
+        Assertions.assertEquals(20, responseMessage.getItems().size());
+
+        Map<String, String> expectedSite = new HashMap<>();
+        expectedSite.put("name", "Site");
+        expectedSite.put("entities", "/domains/EQUIPMENT_TO_RAN/entity-types/Site/entities");
+
+        OranTeivEntityTypesItemsInner item1 = responseMessage.getItems().stream().filter(items -> {
+            return "Site".equals(items.getName());
+        }).findFirst().get();
+        Assertions.assertEquals(expectedSite.get("name"), item1.getName());
+        Assertions.assertEquals(expectedSite.get("entities"), item1.getEntities().getHref());
+
+        Map<String, String> expectedNRCellCu = new HashMap<>();
+        expectedNRCellCu.put("name", "NRCellCU");
+        expectedNRCellCu.put("entities", "/domains/EQUIPMENT_TO_RAN/entity-types/NRCellCU/entities");
+
+        OranTeivEntityTypesItemsInner item2 = responseMessage.getItems().stream().filter(items -> {
+            return "NRCellCU".equals(items.getName());
+        }).findFirst().get();
+        Assertions.assertEquals(expectedNRCellCu.get("name"), item2.getName());
+        Assertions.assertEquals(expectedNRCellCu.get("entities"), item2.getEntities().getHref());
+
+        Map<String, String> expectedGNBCUUFunction = new HashMap<>();
+        expectedGNBCUUFunction.put("name", "GNBCUUPFunction");
+        expectedGNBCUUFunction.put("entities", "/domains/EQUIPMENT_TO_RAN/entity-types/GNBCUUPFunction/entities");
+
+        OranTeivEntityTypesItemsInner item3 = responseMessage.getItems().stream().filter(items -> {
+            return "GNBCUUPFunction".equals(items.getName());
+        }).findFirst().get();
+        Assertions.assertEquals(expectedGNBCUUFunction.get("name"), item3.getName());
+        Assertions.assertEquals(expectedGNBCUUFunction.get("entities"), item3.getEntities().getHref());
+    }
+
+    @Test
+    public void testGetTopologyRelationshipTypes() {
+        final OranTeivRelationshipTypes responseMessage = underTest.getTopologyRelationshipTypes(ACCEPT_TYPE,
+                "EQUIPMENT_TO_RAN", 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage);
+        Assertions.assertEquals(20, responseMessage.getItems().size());
+
+        Map<String, String> expectedData1 = new HashMap<>();
+        expectedData1.put("name", "NRCELLDU_USES_NRSECTORCARRIER");
+        expectedData1.put("relationships",
+                "/domains/EQUIPMENT_TO_RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships");
+
+        OranTeivRelationshipTypesItemsInner item1 = responseMessage.getItems().get(14);
+        Assertions.assertEquals(expectedData1.get("name"), item1.getName());
+        Assertions.assertEquals(expectedData1.get("relationships"), item1.getRelationships().getHref());
+
+        Map<String, String> expectedData2 = new HashMap<>();
+        expectedData2.put("name", "ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE");
+        expectedData2.put("relationships",
+                "/domains/EQUIPMENT_TO_RAN/relationship-types/ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE/relationships");
+
+        OranTeivRelationshipTypesItemsInner item2 = responseMessage.getItems().get(1);
+        Assertions.assertEquals(expectedData2.get("name"), item2.getName());
+        Assertions.assertEquals(expectedData2.get("relationships"), item2.getRelationships().getHref());
+
+        Map<String, String> expectedData3 = new HashMap<>();
+        expectedData3.put("name", "SECTOR_GROUPS_ANTENNAMODULE");
+        expectedData3.put("relationships",
+                "/domains/EQUIPMENT_TO_RAN/relationship-types/SECTOR_GROUPS_ANTENNAMODULE/relationships");
+
+        OranTeivRelationshipTypesItemsInner item3 = responseMessage.getItems().get(17);
+        Assertions.assertEquals(expectedData3.get("name"), item3.getName());
+        Assertions.assertEquals(expectedData3.get("relationships"), item3.getRelationships().getHref());
+    }
+
+    @Test
+    public void testGetTopologyById() {
+        final Object responseMessage = underTest.getTopologyById(ACCEPT_TYPE, "RAN", "Sector",
+                "2F445AA5744FA3D230FD6838531F1407").getBody();
+
+        Assertions.assertNotNull(responseMessage);
+
+        Map<String, Object> expectedResponse = new HashMap<>();
+        Map<String, Object> innerMap = new HashMap<>();
+        Map<String, Object> attributes = new HashMap<>();
+
+        attributes.put("sectorId", 1);
+        attributes.put("geo-location", "POINT(59.4019881 17.9419888)");
+        attributes.put("sectorId", 1);
+        attributes.put("azimuth", 1);
+
+        innerMap.put("attributes", attributes);
+        innerMap.put("id", "2F445AA5744FA3D230FD6838531F1407");
+        innerMap.put("sourceIds", Collections.EMPTY_LIST);
+
+        expectedResponse.put("o-ran-smo-teiv-ran:Sector", Collections.singletonList(innerMap));
+
+        Map<String, Object> actualResponse = (Map<String, Object>) responseMessage;
+
+        Assertions.assertEquals(expectedResponse.size(), actualResponse.size());
+        for (Map.Entry<String, Object> entry : expectedResponse.entrySet()) {
+            String key = entry.getKey();
+            Object expectedValue = entry.getValue();
+            Object actualValue = actualResponse.get(key);
+            if (expectedValue instanceof List && actualValue instanceof List) {
+                List<?> expectedList = (List<?>) expectedValue;
+                List<?> actualList = (List<?>) actualValue;
+                Assertions.assertEquals(expectedList.size(), actualList.size());
+                for (int i = 0; i < expectedList.size(); i++) {
+                    Object expectedMap = expectedList.get(i);
+                    Object actualMap = actualList.get(i);
+                    Assertions.assertTrue(expectedMap instanceof Map);
+                    Assertions.assertTrue(actualMap instanceof Map);
+                    String expectedAttributesString = ((Map<String, Object>) expectedMap).get("attributes").toString();
+                    String actualAttributesString = ((Map<String, Object>) actualMap).get("attributes").toString();
+                    Assertions.assertEquals(expectedAttributesString, actualAttributesString);
+                }
+            } else {
+                Assertions.assertEquals(expectedValue, actualValue);
+            }
+        }
+    }
+
+    @Test
+    public void testGetAllRelationshipsForEntityId() {
+        final OranTeivRelationshipsResponseMessage responseMessage = underTest.getAllRelationshipsForEntityId(ACCEPT_TYPE,
+                "RAN", "Sector", "2F445AA5744FA3D230FD6838531F1407", 0, 10).getBody();
+
+        Assertions.assertNotNull(responseMessage);
+        Assertions.assertEquals(0, responseMessage.getTotalCount());
+        Assertions.assertTrue(responseMessage.getItems().isEmpty());
+
+        final OranTeivRelationshipsResponseMessage responseMessage2 = underTest.getAllRelationshipsForEntityId(ACCEPT_TYPE,
+                "RAN", "GNBDUFunction", "1050570EBB1315E1AE7A9FD5E1400A00", 0, 10).getBody();
+
+        Assertions.assertNotNull(responseMessage2);
+        Assertions.assertEquals(1, responseMessage2.getTotalCount());
+
+        Map<String, Object> innerResponse = new HashMap<>();
+        innerResponse.put("bSide", "1050570EBB1315E1AE7A9FD5E1400A00");
+        innerResponse.put("aSide", "6F02817AFE4D53237DB235EBE5378613");
+        innerResponse.put("id",
+                "urn:base64:TWFuYWdlZEVsZW1lbnQ6NkYwMjgxN0FGRTRENTMyMzdEQjIzNUVCRTUzNzg2MTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjEwNTA1NzBFQkIxMzE1RTFBRTdBOUZENUUxNDAwQTAw");
+        Map<String, Object> response = new HashMap<>();
+        response.put("o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBDUFUNCTION", List.of(innerResponse));
+        Assertions.assertEquals(response, responseMessage2.getItems().get(0));
+    }
+
+    @Test
+    public void testGetRelationshipById() {
+        final Object responseMessage = underTest.getRelationshipById(ACCEPT_TYPE, "CLOUD",
+                "NODECLUSTER_LOCATED_AT_CLOUDSITE",
+                "urn:base64:Tm9kZUNsdXN0ZXI6MDE1QzJEREJEN0FDNzIyQjM0RUQ2QTIwRURFRUI5QzM6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=")
+                .getBody();
+
+        Assertions.assertNotNull(responseMessage);
+        Assertions.assertTrue(responseMessage instanceof Map);
+
+        Map<String, List<Map<String, Object>>> responseMap = (Map<String, List<Map<String, Object>>>) responseMessage;
+
+        Assertions.assertTrue(responseMap.containsKey("o-ran-smo-teiv-cloud:NODECLUSTER_LOCATED_AT_CLOUDSITE"));
+        List<Map<String, Object>> relationshipList = responseMap.get(
+                "o-ran-smo-teiv-cloud:NODECLUSTER_LOCATED_AT_CLOUDSITE");
+
+        Assertions.assertNotNull(relationshipList);
+        Assertions.assertFalse(relationshipList.isEmpty());
+
+        for (Map<String, Object> relationship : relationshipList) {
+            Assertions.assertTrue(relationship.containsKey("bSide"));
+            Assertions.assertTrue(relationship.containsKey("aSide"));
+            Assertions.assertTrue(relationship.containsKey("id"));
+            Assertions.assertTrue(relationship.containsKey("sourceIds"));
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/e2e/DataControllerE2EContainerizedTest.java b/teiv/src/test/java/org/oran/smo/teiv/e2e/DataControllerE2EContainerizedTest.java
new file mode 100644
index 0000000..8a6cf1f
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/e2e/DataControllerE2EContainerizedTest.java
@@ -0,0 +1,249 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.e2e;
+
+import org.oran.smo.teiv.api.model.OranTeivEntitiesResponseMessage;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.exposure.data.rest.controller.DataRestController;
+import org.oran.smo.teiv.schema.PostgresSchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.jooq.DSLContext;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+
+import javax.sql.DataSource;
+
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+
+import java.util.*;
+
+@Slf4j
+@ActiveProfiles({ "test", "exposure" })
+@SpringBootTest
+public class DataControllerE2EContainerizedTest {
+
+    public static final String ACCEPT_TYPE = "application/yang+json";
+
+    @Autowired
+    public DataRestController underTest;
+    public static TestPostgresqlContainer postgresSQLContainer = TestPostgresqlContainer.getInstance();
+
+    @Autowired
+    DSLContext writeDataDslContext;
+
+    @DynamicPropertySource
+    static void setProperties(DynamicPropertyRegistry registry) {
+        registry.add("spring.datasource.read.jdbc-url", () -> postgresSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.read.username", () -> postgresSQLContainer.getUsername());
+        registry.add("spring.datasource.read.password", () -> postgresSQLContainer.getPassword());
+
+        registry.add("spring.datasource.write.jdbc-url", () -> postgresSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.write.username", () -> postgresSQLContainer.getUsername());
+        registry.add("spring.datasource.write.password", () -> postgresSQLContainer.getPassword());
+    }
+
+    @BeforeAll
+    public static void beforeAll() throws UnsupportedOperationException, SchemaLoaderException {
+        String url = postgresSQLContainer.getJdbcUrl();
+        DataSource ds = DataSourceBuilder.create().url(url).username("test").password("test").build();
+        DSLContext dslContext = DSL.using(ds, SQLDialect.POSTGRES);
+        PostgresSchemaLoader postgresSchemaLoader = new PostgresSchemaLoader(dslContext, new ObjectMapper());
+        postgresSchemaLoader.loadSchemaRegistry();
+    }
+
+    @BeforeEach
+    public void deleteAll() {
+        writeDataDslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(
+                t -> writeDataDslContext.truncate(t).cascade().execute());
+        TestPostgresqlContainer.loadSampleData();
+    }
+
+    @Test
+    public void getRelationshipsByTypeWithoutScopeFilterTest() {
+        final OranTeivRelationshipsResponseMessage responseMessage1 = underTest.getRelationshipsByType(ACCEPT_TYPE, "RAN",
+                "NRCELLDU_USES_NRSECTORCARRIER", null, "", 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage1);
+        Assertions.assertEquals(1, responseMessage1.getItems().size());
+        Map<String, Object> innerResponse = new HashMap<>();
+        innerResponse.put("bSide", "E49D942C16E0364E1E0788138916D70C");
+        innerResponse.put("aSide", "B480427E8A0C0B8D994E437784BB382F");
+        innerResponse.put("id",
+                "urn:base64:TlJDZWxsRFU6QjQ4MDQyN0U4QTBDMEI4RDk5NEU0Mzc3ODRCQjM4MkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM=");
+        Map<String, Object> response = new HashMap<>();
+        response.put("o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER", List.of(innerResponse));
+        Assertions.assertEquals(response, responseMessage1.getItems().get(0));
+    }
+
+    @Test
+    public void getRelationshipsByTypeWithScopeFilterTest() {
+        final OranTeivRelationshipsResponseMessage responseMessage1 = underTest.getRelationshipsByType(ACCEPT_TYPE, "RAN",
+                "SECTOR_GROUPS_NRCELLDU", null, "/NRCellDU/attributes[@cellLocalId=1]", 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage1);
+        Assertions.assertEquals(1, responseMessage1.getItems().size());
+        Map<String, Object> innerResponse = new HashMap<>();
+        innerResponse.put("bSide", "98C3A4591A37718E1330F0294E23B62A");
+        innerResponse.put("aSide", "F5128C172A70C4FCD4739650B06DE9E2");
+        innerResponse.put("id",
+                "urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==");
+        Map<String, Object> response = new HashMap<>();
+        response.put("o-ran-smo-teiv-ran:SECTOR_GROUPS_NRCELLDU", List.of(innerResponse));
+        Assertions.assertEquals(response, responseMessage1.getItems().get(0));
+    }
+
+    @Test
+    public void getTopologyByEntityTypeNameWithScopeFilterTest() {
+        final OranTeivEntitiesResponseMessage responseMessage1 = underTest.getTopologyByEntityTypeName(
+
+                ACCEPT_TYPE, "RAN", "NRCellDU", null, "/NRCellDU/attributes[@cellLocalId=1]", 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage1);
+        Assertions.assertEquals(1, responseMessage1.getItems().size());
+        Map<String, Object> innerResponse = new HashMap<>();
+        innerResponse.put("id", "98C3A4591A37718E1330F0294E23B62A");
+
+        Map<String, Object> response = new HashMap<>();
+        response.put("o-ran-smo-teiv-ran:NRCellDU", List.of(innerResponse));
+        Assertions.assertEquals(response, responseMessage1.getItems().get(0));
+    }
+
+    @Test
+    public void getTopologyByEntityTypeWithoutScopeFilterTest() {
+        final OranTeivEntitiesResponseMessage responseMessage1 = underTest.getTopologyByEntityTypeName(
+
+                ACCEPT_TYPE, "RAN", "NRCellDU", null, "", 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage1);
+        Assertions.assertEquals(1, responseMessage1.getItems().size());
+
+        List<String> ids = new ArrayList<>();
+        ids.add("67A1BDA10B5AF43028D07C7BE5CB1AE2");
+        ids.add("76E9F605D4F37330BF0B505E94F64F11");
+        ids.add("98C3A4591A37718E1330F0294E23B62A");
+        ids.add("B3B0A1939EFCA654A37005B6A7F24BD7");
+        ids.add("B480427E8A0C0B8D994E437784BB382F");
+        ids.add("F9546E82313AC1D5E690DCD7BE55606F");
+
+        List<Map<String, String>> idList = new ArrayList<>();
+        for (String id : ids) {
+            Map<String, String> idMap = new HashMap<>();
+            idMap.put("id", id);
+            idList.add(idMap);
+        }
+
+        Map<String, Object> response = new HashMap<>();
+        response.put("o-ran-smo-teiv-ran:NRCellDU", idList);
+        Assertions.assertEquals(response, responseMessage1.getItems().get(0));
+    }
+
+    @Test
+    public void getEntitiesByDomainWithoutScopeFilter() {
+        final OranTeivEntitiesResponseMessage responseMessage1 = underTest.getEntitiesByDomain(ACCEPT_TYPE, "RAN",
+                "/NRCellDU/attributes/nCI", "", 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage1);
+        Assertions.assertEquals(1, responseMessage1.getItems().size());
+
+        @SuppressWarnings("unchecked") List<Map<String, Object>> actualList = (List<Map<String, Object>>) ((Map<String, Object>) responseMessage1
+                .getItems().get(0)).get("o-ran-smo-teiv-ran:NRCellDU");
+
+        List<Map<String, Object>> expectedList = new ArrayList<>();
+        Map<String, Object> entity = new HashMap<>();
+
+        entity.put("attributes", Map.of("nCI", 1));
+        entity.put("id", "98C3A4591A37718E1330F0294E23B62A");
+        expectedList.add(entity);
+
+        entity = new HashMap<>();
+        entity.put("attributes", Map.of("nCI", 2));
+        entity.put("id", "F9546E82313AC1D5E690DCD7BE55606F");
+        expectedList.add(entity);
+
+        entity = new HashMap<>();
+        entity.put("attributes", Map.of("nCI", 3));
+        entity.put("id", "B480427E8A0C0B8D994E437784BB382F");
+        expectedList.add(entity);
+
+        entity = new HashMap<>();
+        entity.put("attributes", Map.of("nCI", 91));
+        entity.put("id", "76E9F605D4F37330BF0B505E94F64F11");
+        expectedList.add(entity);
+
+        entity = new HashMap<>();
+        entity.put("attributes", Map.of("nCI", 92));
+        entity.put("id", "67A1BDA10B5AF43028D07C7BE5CB1AE2");
+        expectedList.add(entity);
+
+        entity = new HashMap<>();
+        entity.put("attributes", Map.of("nCI", 93));
+        entity.put("id", "B3B0A1939EFCA654A37005B6A7F24BD7");
+        expectedList.add(entity);
+
+        Assertions.assertEquals(expectedList.size(), actualList.size());
+        for (int i = 0; i < expectedList.size(); i++) {
+            Map<String, Object> actualEntity = actualList.get(i);
+            Map<String, Object> expectedEntity = expectedList.get(i);
+
+            Map<String, Object> actualAttributes = (Map<String, Object>) actualEntity.get("attributes");
+            Map<String, Object> expectedAttributes = (Map<String, Object>) expectedEntity.get("attributes");
+
+            Assertions.assertEquals(((Number) expectedAttributes.get("nCI")).intValue(), ((Number) actualAttributes.get(
+                    "nCI")).intValue());
+
+        }
+    }
+
+    @Test
+    public void getEntitiesByDomainWithScopeFilter() {
+        final String relationships = "GNBDUFUNCTION_PROVIDES_NRCELLDU";
+        final OranTeivEntitiesResponseMessage responseMessage1 = underTest.getEntitiesByDomain(ACCEPT_TYPE, "RAN",
+                "/NRCellDU/attributes/nCI", "/NRCellDU/attributes[@cellLocalId=1]", 0, 20).getBody();
+
+        Assertions.assertNotNull(responseMessage1);
+        Assertions.assertEquals(1, responseMessage1.getItems().size());
+
+        Map<String, Object> actualResponseMap = new HashMap<>((Map<String, Object>) responseMessage1.getItems().get(0));
+
+        Map<String, Object> expectedResponse = new HashMap<>();
+        Map<String, Object> innerMap = new HashMap<>();
+        Map<String, Object> attributes = new HashMap<>();
+        attributes.put("nCI", 1);
+        innerMap.put("id", "98C3A4591A37718E1330F0294E23B62A");
+        innerMap.put("attributes", attributes);
+        expectedResponse.put("o-ran-smo-teiv-ran:NRCellDU", List.of(innerMap));
+
+        Assertions.assertEquals(expectedResponse.toString(), actualResponseMap.toString());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/TopologyExposureApiBase.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/TopologyExposureApiBase.java
new file mode 100644
index 0000000..29d38ce
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/TopologyExposureApiBase.java
@@ -0,0 +1,167 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.api.contract;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.exposure.utils.RequestValidator;
+import java.util.List;
+
+import org.oran.smo.teiv.api.model.OranTeivSchema;
+import org.oran.smo.teiv.api.model.OranTeivHref;
+import org.oran.smo.teiv.api.model.OranTeivSchemaList;
+import org.oran.smo.teiv.exposure.api.contract.utils.RelationshipTestUtility;
+import org.oran.smo.teiv.exposure.api.contract.utils.TopologyObjectTestUtility;
+import org.oran.smo.teiv.exposure.data.api.impl.DataServiceImpl;
+import org.oran.smo.teiv.exposure.data.rest.controller.DataRestController;
+import org.oran.smo.teiv.exposure.exception.ApplicationExceptionHandler;
+import org.oran.smo.teiv.exposure.model.api.impl.ModelSchemaServiceImpl;
+import org.oran.smo.teiv.exposure.model.rest.controller.ModelSchemaRestController;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder;
+import io.restassured.module.mockmvc.RestAssuredMockMvc;
+
+@ExtendWith(MockitoExtension.class)
+public abstract class TopologyExposureApiBase {
+
+    private static final ModelSchemaServiceImpl modelSchemaService = Mockito.mock(ModelSchemaServiceImpl.class);
+
+    private static final DataServiceImpl dataService = Mockito.mock(DataServiceImpl.class);
+    private static final CustomMetrics customMetrics = Mockito.mock(CustomMetrics.class);
+    private static final RequestValidator requestValidator = Mockito.mock(RequestValidator.class);
+
+    @InjectMocks
+    private ModelSchemaRestController modelSchemaRestController;
+
+    @InjectMocks
+    private DataRestController dataRestController;
+
+    @BeforeEach
+    public void setup() {
+        mockData();
+        final StandaloneMockMvcBuilder standaloneMockMvcBuilder = MockMvcBuilders.standaloneSetup(modelSchemaRestController,
+                dataRestController).setControllerAdvice(new ApplicationExceptionHandler());
+        RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
+    }
+
+    public void mockData() {
+        RelationshipTestUtility.getMockForAllRelationshipsForObjectId(dataService);
+        TopologyObjectTestUtility.getMockForAllTopologyObjectById(dataService);
+    }
+
+    @BeforeAll
+    public static void mockModelSchemaData() {
+
+        OranTeivSchema schemasMetaData = new OranTeivSchema();
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/schemas/o-ran-smo-teiv-cloud-to-ran/content");
+        schemasMetaData.setName("o-ran-smo-teiv-cloud-to-ran");
+        schemasMetaData.setDomain(List.of("RAN", "CLOUD"));
+        schemasMetaData.setRevision("2023-06-26");
+        schemasMetaData.setContent(href);
+
+        List<OranTeivSchema> schemaList = List.of(schemasMetaData);
+
+        OranTeivSchemaList schemas = new OranTeivSchemaList();
+        schemas.setItems(schemaList);
+        OranTeivHref hrefFirst = new OranTeivHref();
+        hrefFirst.setHref("/schemas?offset=0&limit=100");
+        schemas.setFirst(hrefFirst);
+        OranTeivHref hrefNext = new OranTeivHref();
+        hrefNext.setHref("/schemas?offset=0&limit=100");
+        schemas.setNext(hrefNext);
+        OranTeivHref hrefPrev = new OranTeivHref();
+        hrefPrev.setHref("/schemas?offset=0&limit=100");
+        schemas.setPrev(hrefPrev);
+        OranTeivHref hrefSelf = new OranTeivHref();
+        hrefSelf.setHref("/schemas?offset=0&limit=100");
+        schemas.setSelf(hrefSelf);
+        OranTeivHref hrefLast = new OranTeivHref();
+        hrefLast.setHref("/schemas?offset=0&limit=100");
+        schemas.setLast(hrefLast);
+
+        OranTeivSchemaList schemaQuery = new OranTeivSchemaList();
+        schemaQuery.setItems(schemaList);
+        OranTeivHref hrefFirst1 = new OranTeivHref();
+        hrefFirst1.setHref("/schemas?domain=RAN&offset=0&limit=8");
+        schemaQuery.setFirst(hrefFirst1);
+        OranTeivHref hrefNext1 = new OranTeivHref();
+        hrefNext1.setHref("/schemas?domain=RAN&offset=0&limit=8");
+        schemaQuery.setNext(hrefNext1);
+        OranTeivHref hrefPrev1 = new OranTeivHref();
+        hrefPrev1.setHref("/schemas?domain=RAN&offset=0&limit=8");
+        schemaQuery.setPrev(hrefPrev1);
+        OranTeivHref hrefSelf1 = new OranTeivHref();
+        hrefSelf1.setHref("/schemas?domain=RAN&offset=0&limit=8");
+        schemaQuery.setSelf(hrefSelf1);
+        OranTeivHref hrefLast1 = new OranTeivHref();
+        hrefLast1.setHref("/schemas?domain=RAN&offset=0&limit=8");
+        schemaQuery.setLast(hrefLast1);
+
+        OranTeivSchemaList emptyResponse = new OranTeivSchemaList();
+        emptyResponse.setItems(List.of());
+        OranTeivHref hrefFirst2 = new OranTeivHref();
+        hrefFirst2.setHref("/schemas?domain=LOGICAL&offset=0&limit=500");
+        emptyResponse.setFirst(hrefFirst2);
+        OranTeivHref hrefNext2 = new OranTeivHref();
+        hrefNext2.setHref("/schemas?domain=LOGICAL&offset=0&limit=500");
+        emptyResponse.setNext(hrefNext2);
+        OranTeivHref hrefPrev2 = new OranTeivHref();
+        hrefPrev2.setHref("/schemas?domain=LOGICAL&offset=0&limit=500");
+        emptyResponse.setPrev(hrefPrev2);
+        OranTeivHref hrefSelf2 = new OranTeivHref();
+        hrefSelf2.setHref("/schemas?domain=LOGICAL&offset=0&limit=500");
+        emptyResponse.setSelf(hrefSelf2);
+        OranTeivHref hrefLast2 = new OranTeivHref();
+        hrefLast2.setHref("/schemas?domain=LOGICAL&offset=0&limit=500");
+        emptyResponse.setLast(hrefLast2);
+
+        String modelSchema = "module o-ran-smo-teiv-cloud-to-ran { yang-version 1.1; }";
+
+        Mockito.when(modelSchemaService.getSchemas(PaginationDTO.builder().offset(0).limit(100).basePath("/schemas")
+                .build())).thenReturn(schemas).thenThrow(new RuntimeException());
+
+        Mockito.when(modelSchemaService.getSchemaByName("o-ran-smo-teiv-cloud-to-ran")).thenReturn(modelSchema).thenThrow(
+                new RuntimeException());
+
+        Mockito.when(modelSchemaService.getSchemasInDomain("RAN", PaginationDTO.builder().offset(0).limit(8).basePath(
+                "/schemas").addPathParameters("domain", "RAN").build())).thenReturn(schemaQuery).thenThrow(
+                        new RuntimeException());
+
+        Mockito.when(modelSchemaService.getSchemasInDomain("LOGICAL", PaginationDTO.builder().offset(0).limit(500).basePath(
+                "/schemas").addPathParameters("domain", "LOGICAL").build())).thenReturn(emptyResponse).thenThrow(
+                        new RuntimeException());
+    }
+
+    @AfterAll
+    public static void teardown() {
+        Mockito.reset(modelSchemaService);
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/utils/RelationshipTestUtility.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/utils/RelationshipTestUtility.java
new file mode 100644
index 0000000..e80ac4e
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/utils/RelationshipTestUtility.java
@@ -0,0 +1,86 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.api.contract.utils;
+
+import org.oran.smo.teiv.api.model.OranTeivHref;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.data.api.DataService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+
+import static org.mockito.Mockito.when;
+
+public class RelationshipTestUtility {
+
+    private static final Map<String, Object> ITEMS = Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(
+            Map.of("id", "urn:sha512:R05CRFVGdW5jdGlvbjpTdWJOZXR3b3JrPUV1cm9wZSxTdWJOZXR3", "aSide",
+                    "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1", "bSide",
+                    "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1", "decorators", Map.of("location",
+                            "Stockholm"), "classifiers", List.of("Rural"), "sourceIds", new ArrayList<>(), "metadata", Map
+                                    .of("trustLevel", "RELIABLE"))));
+    private static DataService dataService;
+
+    public static void getMockForAllRelationshipsForObjectId(DataService dataService) {
+        RelationshipTestUtility.dataService = dataService;
+        mockRanGNBDUFunctionRelationships();
+    }
+
+    private static void mockRanGNBDUFunctionRelationships() {
+        OranTeivRelationshipsResponseMessage gnbduMap = new OranTeivRelationshipsResponseMessage();
+
+        OranTeivHref hrefFirst = new OranTeivHref();
+        hrefFirst.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100");
+        gnbduMap.setFirst(hrefFirst);
+        OranTeivHref hrefNext = new OranTeivHref();
+        hrefNext.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100");
+        gnbduMap.setNext(hrefNext);
+        OranTeivHref hrefPrev = new OranTeivHref();
+        hrefPrev.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100");
+        gnbduMap.setPrev(hrefPrev);
+        OranTeivHref hrefSelf = new OranTeivHref();
+        hrefSelf.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100");
+        gnbduMap.setSelf(hrefSelf);
+        OranTeivHref hrefLast = new OranTeivHref();
+        hrefLast.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100");
+        gnbduMap.setLast(hrefLast);
+
+        gnbduMap.setItems(List.of(ITEMS));
+
+        when(dataService.getAllRelationshipsForObjectId(eq("GNBDUFunction"), eq(
+                "urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D1"),
+                any())).thenReturn(gnbduMap);
+
+        when(dataService.getAllRelationshipsForObjectId(eq("5GCell"), eq("R05CRFVGdW5jdGlvbg"), any())).thenThrow(
+                TiesException.unknownEntityType("5GCell", Collections.emptyList()));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/utils/TopologyObjectTestUtility.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/utils/TopologyObjectTestUtility.java
new file mode 100644
index 0000000..c367dfb
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/api/contract/utils/TopologyObjectTestUtility.java
@@ -0,0 +1,164 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.api.contract.utils;
+
+import org.oran.smo.teiv.api.model.OranTeivEntitiesResponseMessage;
+import org.oran.smo.teiv.api.model.OranTeivHref;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.data.api.DataService;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.endsWith;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+public class TopologyObjectTestUtility {
+
+    private static final Map<String, Object> ITEMS =
+
+            Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of("id",
+                    "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1", "attributes", Map.of(
+                            "gNBDUId", 1), "metadata", Map.of("trustLevel", "RELIABLE"))
+
+            ));
+
+    private static DataService dataService;
+
+    public static void getMockForAllTopologyObjectById(DataService dataService) {
+        TopologyObjectTestUtility.dataService = dataService;
+        mockRanGNBDUFunctionTopologyObject();
+        mockRanNRCellDUTopologyObject();
+    }
+
+    private static void mockRanGNBDUFunctionTopologyObject() {
+
+        OranTeivEntitiesResponseMessage gnbduMap = new OranTeivEntitiesResponseMessage();
+        OranTeivEntitiesResponseMessage gnbduQueryMap = new OranTeivEntitiesResponseMessage();
+        OranTeivHref hrefFirst = new OranTeivHref();
+        hrefFirst.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50");
+        gnbduMap.setFirst(hrefFirst);
+        OranTeivHref hrefNext = new OranTeivHref();
+        hrefNext.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50");
+        gnbduMap.setNext(hrefNext);
+        OranTeivHref hrefPrev = new OranTeivHref();
+        hrefPrev.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50");
+        gnbduMap.setPrev(hrefPrev);
+        OranTeivHref hrefSelf = new OranTeivHref();
+        hrefSelf.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50");
+        gnbduMap.setSelf(hrefSelf);
+        OranTeivHref hrefLast = new OranTeivHref();
+        hrefLast.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50");
+        gnbduMap.setLast(hrefLast);
+
+        gnbduMap.setItems(List.of(ITEMS));
+
+        OranTeivHref hrefFirstQuery = new OranTeivHref();
+        hrefFirstQuery.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100");
+        gnbduQueryMap.setFirst(hrefFirstQuery);
+        OranTeivHref hrefNextQuery = new OranTeivHref();
+        hrefNextQuery.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100");
+        gnbduQueryMap.setNext(hrefNextQuery);
+        OranTeivHref hrefPrevQuery = new OranTeivHref();
+        hrefPrevQuery.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100");
+        gnbduQueryMap.setPrev(hrefPrevQuery);
+        OranTeivHref hrefSelfQuery = new OranTeivHref();
+        hrefSelfQuery.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100");
+        gnbduQueryMap.setSelf(hrefSelfQuery);
+        OranTeivHref hrefLastQuery = new OranTeivHref();
+        hrefLastQuery.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100");
+        gnbduQueryMap.setLast(hrefLastQuery);
+
+        gnbduQueryMap.setItems(List.of(ITEMS));
+
+        when(dataService.getTopologyById(eq("GNBDUFunction"), eq(
+                "urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D1")))
+                        .thenReturn(
+
+                                Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of("id",
+                                        "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1",
+                                        "attributes", Map.of("gNBId", 1, "gNBDUId", 1, "gNBIdLength", 2, "dUpLMNId", Map.of(
+                                                "mcc", "110", "mnc", "210")), "decorators", Map.of("location", "Stockholm"),
+                                        "classifiers", List.of("Rural"), "sourceIds", List.of(
+                                                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1"),
+                                        "metadata", Map.of("trustLevel", "RELIABLE")))));
+
+        when(dataService.getTopologyById(eq("GNBDUFunction"), eq(
+                "urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D2")))
+                        .thenReturn(Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of("id",
+                                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=2", "attributes",
+                                Map.of("gNBId", 2, "gNBDUId", 2, "gNBIdLength", 2, "dUpLMNId", Map.of("mcc", "110", "mnc",
+                                        "210")), "decorators", Map.of("location", "Stockholm"), "classifiers", List.of(
+                                                "Rural"), "sourceIds", List.of(
+                                                        "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=2"),
+                                "metadata", Map.of("trustLevel", "RELIABLE")))));
+
+        when(dataService.getTopologyById(eq("GBFunction"), eq(
+                "urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D1")))
+                        .thenThrow(TiesException.unknownEntityType("GBFunction", Collections.emptyList()));
+
+        when(dataService.getTopologyById(eq("NRDU"), eq(
+                "urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio%2FGNBDUFunction%3D1%2FNRCellDU%3D1")))
+                        .thenThrow(TiesException.unknownEntityType("NRDU", Collections.emptyList()));
+
+        when(dataService.getTopologyByType(eq("GNBDUFunction"), endsWith("%2Fattributes(gNBDUId)"), any(), any()))
+                .thenReturn(gnbduMap);
+
+        when(dataService.getTopologyByType(eq("GNBDUFunction"), endsWith("%2Fattributes(gNBDUId)"), endsWith(
+                "%2Fattributes[@gNBDUId=1]"), any())).thenReturn(gnbduQueryMap);
+
+        when(dataService.getTopologyByType(eq("GNBBUFunction"), any(), any(), any())).thenThrow(TiesException
+                .unknownEntityType("GNBBUFunction", Collections.emptyList()));
+    }
+
+    private static void mockRanNRCellDUTopologyObject() {
+        when(dataService.getTopologyById(eq("NRCellDU"), eq(
+                "urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio%2FGNBDUFunction%3D1%2FNRCellDU%3D1")))
+                        .thenReturn(Map.of("o-ran-smo-teiv-ran:NRCellDU", List.of(Map.of("id",
+                                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=1",
+                                "attributes", Map.of("nCI", 1, "nRPCI", 35, "nRTAC", 50, "cellLocalId", 91), "decorators",
+                                Map.of("location", "Stockholm"), "classifiers", List.of("Rural"), "sourceIds", List.of(
+                                        "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=1"),
+                                "metadata", Map.of("trustLevel", "RELIABLE")))));
+
+        when(dataService.getTopologyById(eq("NRCellDU"), eq(
+                "urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio%2FGNBDUFunction%3D1%2FNRCellDU%3D2")))
+                        .thenReturn(Map.of("o-ran-smo-teiv-ran:NRCellDU", List.of(Map.of("id",
+                                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=2",
+                                "attributes", Map.of("nCI", 5, "nRPCI", 35, "nRTAC", 50, "cellLocalId", 95), "decorators",
+                                Map.of("location", "Stockholm"), "classifiers", List.of("Rural"), "sourceIds", List.of(
+                                        "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=2"),
+                                "metadata", Map.of("trustLevel", "RELIABLE")))));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/data/api/impl/DataServiceImplTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/data/api/impl/DataServiceImplTest.java
new file mode 100644
index 0000000..709c121
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/data/api/impl/DataServiceImplTest.java
@@ -0,0 +1,654 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.data.api.impl;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.spi.DataPersistanceService;
+import org.oran.smo.teiv.exposure.spi.mapper.MapperUtility;
+import org.oran.smo.teiv.exposure.spi.mapper.PaginationMetaData;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+
+import org.oran.smo.teiv.api.model.OranTeivDomains;
+import org.oran.smo.teiv.api.model.OranTeivDomainsItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivEntitiesResponseMessage;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypes;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivHref;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import static org.oran.smo.teiv.schema.SchemaRegistry.*;
+import static org.oran.smo.teiv.utils.ResponseGenerator.generateResponse;
+import static org.oran.smo.teiv.utils.TiesConstants.ITEMS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class DataServiceImplTest {
+
+    private static DataPersistanceService mockedDataPersistanceService;
+    private static DataServiceImpl underTest;
+    private static final String REL_ID_PREFIX = "urn:base64:";
+    private static MockHttpServletRequest request = new MockHttpServletRequest();
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+
+        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
+        mockedDataPersistanceService = mock(DataPersistanceService.class);
+        SchemaLoader mockedSchemaLoader = new MockSchemaLoader();
+        mockedSchemaLoader.loadSchemaRegistry();
+        underTest = new DataServiceImpl(mockedDataPersistanceService, new MapperUtility());
+        mockGetTopologyById();
+        mockGetRelationshipById();
+        mockGetRelationshipByType();
+        mockGetAllRelationships();
+        mockGetTopologyByType();
+        MockGetTopologyByTargetFilter();
+    }
+
+    @Test
+    void testGetTopologyById() {
+        Assertions.assertEquals(generateResponse("GNBDUFunction", "5A548EA9D166341776CA0695837E55D8"), underTest
+                .getTopologyById("GNBDUFunction", "5A548EA9D166341776CA0695837E55D8"));
+        Assertions.assertEquals(generateResponse("NRCellDU", "98C3A4591A37718E1330F0294E23B62A"), underTest.getTopologyById(
+                "NRCellDU", "98C3A4591A37718E1330F0294E23B62A"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getTopologyById("NRCellDU", "NOT_EXISTING"));
+    }
+
+    @Test
+    void testGetTopologyByType() {
+        OranTeivEntitiesResponseMessage expectedResponse1 = new OranTeivEntitiesResponseMessage();
+
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().basePath("/domains/RAN/entity-types/GNBDUFunction/entities")
+                .offset(0).limit(2).addQueryParameters("scopeFilter",
+                        "/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]")
+                .addQueryParameters("targetFilter", "/attributes/fdn;/attributes/id").build();
+        paginationDTO1.setTotalSize(2);
+
+        expectedResponse1.setItems(List.of(Map.of("fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=111", "id",
+                "5BAE4346C241237AA8C74AE1259EF203"), Map.of("fdn",
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=112",
+                        "id", "6B55F987ED838C0FA58DC11AB19CD1D3")));
+
+        OranTeivHref hrefFirst1 = new OranTeivHref();
+        hrefFirst1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?offset=0&limit=2&scopeFilter=/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]&targetFilter=/attributes/fdn;/attributes/id");
+        expectedResponse1.setFirst(hrefFirst1);
+        OranTeivHref hrefNext1 = new OranTeivHref();
+        hrefNext1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?offset=0&limit=2&scopeFilter=/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]&targetFilter=/attributes/fdn;/attributes/id");
+        expectedResponse1.setNext(hrefNext1);
+        OranTeivHref hrefPrev1 = new OranTeivHref();
+        hrefPrev1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?offset=0&limit=2&scopeFilter=/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]&targetFilter=/attributes/fdn;/attributes/id");
+        expectedResponse1.setPrev(hrefPrev1);
+        OranTeivHref hrefSelf1 = new OranTeivHref();
+        hrefSelf1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?offset=0&limit=2&scopeFilter=/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]&targetFilter=/attributes/fdn;/attributes/id");
+        expectedResponse1.setSelf(hrefSelf1);
+        OranTeivHref hrefLast1 = new OranTeivHref();
+        hrefLast1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/entities?offset=0&limit=2&scopeFilter=/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]&targetFilter=/attributes/fdn;/attributes/id");
+        expectedResponse1.setLast(hrefLast1);
+        expectedResponse1.setTotalCount(2);
+
+        Assertions.assertEquals(expectedResponse1, underTest.getTopologyByType("GNBDUFunction",
+                "/attributes/fdn;/attributes/id",
+                "/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]", paginationDTO1));
+    }
+
+    @Test
+    void testGetEntitiesByDomain() {
+        OranTeivEntitiesResponseMessage expectedResult = new OranTeivEntitiesResponseMessage();
+
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains/RAN/entities").offset(0).limit(1)
+                .addQueryParameters("targetFilter", "/GNBDUFunction/id").build();
+        paginationDTO.setTotalSize(1);
+
+        expectedResult.setItems(List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of("id",
+                "1050570EBB1315E1AE7A9FD5E1400A00")))));
+
+        OranTeivHref hrefFirst1 = new OranTeivHref();
+        hrefFirst1.setHref("/domains/RAN/entities?offset=0&limit=1&targetFilter=/GNBDUFunction/id");
+        expectedResult.setFirst(hrefFirst1);
+        OranTeivHref hrefNext1 = new OranTeivHref();
+        hrefNext1.setHref("/domains/RAN/entities?offset=0&limit=1&targetFilter=/GNBDUFunction/id");
+        expectedResult.setNext(hrefNext1);
+        OranTeivHref hrefPrev1 = new OranTeivHref();
+        hrefPrev1.setHref("/domains/RAN/entities?offset=0&limit=1&targetFilter=/GNBDUFunction/id");
+        expectedResult.setPrev(hrefPrev1);
+        OranTeivHref hrefSelf1 = new OranTeivHref();
+        hrefSelf1.setHref("/domains/RAN/entities?offset=0&limit=1&targetFilter=/GNBDUFunction/id");
+        expectedResult.setSelf(hrefSelf1);
+        OranTeivHref hrefLast1 = new OranTeivHref();
+        hrefLast1.setHref("/domains/RAN/entities?offset=0&limit=1&targetFilter=/GNBDUFunction/id");
+        expectedResult.setLast(hrefLast1);
+        expectedResult.setTotalCount(1);
+
+        Assertions.assertEquals(expectedResult, underTest.getEntitiesByDomain("RAN", "/GNBDUFunction/id", null,
+                paginationDTO));
+
+    }
+
+    @Test
+    void testGetRelationshipById() {
+        String id = REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==";
+        String notExistingId = "NOT_EXISTING";
+        Map<String, Object> response = Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(
+                generateResponse("D3215E08570BE58339C7463626B50E37", "98C3A4591A37718E1330F0294E23B62A", id,
+                        Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(response, underTest.getRelationshipById("GNBDUFUNCTION_PROVIDES_NRCELLDU", id));
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getRelationshipById(
+                "GNBDUFUNCTION_PROVIDES_NRCELLDU", notExistingId));
+    }
+
+    @Test
+    void testGetRelationshipsByType() {
+        OranTeivRelationshipsResponseMessage response = new OranTeivRelationshipsResponseMessage();
+        OranTeivRelationshipsResponseMessage response2 = new OranTeivRelationshipsResponseMessage();
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath(
+                "/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships").offset(0).limit(5).build();
+
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().basePath(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships").offset(0)
+                .limit(5).build();
+
+        response.setItems(List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "0525930249302B9649FC8F201EC4F7FC", "BCA882C87D49687E731F9B3872EFDBD3",
+                REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpHTkJEVUZ1bmN0aW9uLzkxOlBST1ZJREVTOk5SQ2VsbERVOk5SQ2VsbERVLzE=",
+                Collections.EMPTY_LIST)))));
+
+        response2.setItems(List.of(Map.of("o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", List.of(
+                generateResponse("A05C67D47D117C2DC5BDF5E00AE70", "2256120E73ADD4026A43A971DCE5C151",
+                        REL_ID_PREFIX + "R05CQ1VVUEZ1bmN0aW9uOkJGRUVBQzJDRTYwMjczQ0IwQTc4MzE5Q0MyMDFBN0ZFOlJE=",
+                        Collections.EMPTY_LIST)))));
+
+        OranTeivHref hrefFirst = new OranTeivHref();
+        hrefFirst.setHref("/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships?offset=0&limit=5");
+        response.setFirst(hrefFirst);
+        OranTeivHref hrefFirst2 = new OranTeivHref();
+        hrefFirst2.setHref(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships?offset=0&limit=5");
+        response2.setFirst(hrefFirst2);
+        OranTeivHref hrefNext = new OranTeivHref();
+        hrefNext.setHref("/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships?offset=0&limit=5");
+        response.setNext(hrefNext);
+        OranTeivHref hrefNext2 = new OranTeivHref();
+        hrefNext2.setHref(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships?offset=0&limit=5");
+        response2.setNext(hrefNext2);
+        OranTeivHref hrefPrev = new OranTeivHref();
+        hrefPrev.setHref("/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships?offset=0&limit=5");
+        response.setPrev(hrefPrev);
+        OranTeivHref hrefPrev2 = new OranTeivHref();
+        hrefPrev2.setHref(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships?offset=0&limit=5");
+        response2.setPrev(hrefPrev2);
+        OranTeivHref hrefSelf = new OranTeivHref();
+        hrefSelf.setHref("/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships?offset=0&limit=5");
+        response.setSelf(hrefSelf);
+        OranTeivHref hrefSelf2 = new OranTeivHref();
+        hrefSelf2.setHref(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships?offset=0&limit=5");
+        response2.setSelf(hrefSelf2);
+        OranTeivHref hrefLast = new OranTeivHref();
+        hrefLast.setHref("/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships?offset=0&limit=5");
+        response.setLast(hrefLast);
+        OranTeivHref hrefLast2 = new OranTeivHref();
+        hrefLast2.setHref(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships?offset=0&limit=5");
+        response2.setLast(hrefLast2);
+
+        response.setTotalCount(1);
+        response2.setTotalCount(1);
+
+        Assertions.assertEquals(response, underTest.getRelationshipsByType("GNBDUFUNCTION_PROVIDES_NRCELLDU", null,
+                paginationDTO));
+
+        Assertions.assertEquals(response2, underTest.getRelationshipsByType("ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", null,
+                paginationDTO2));
+    }
+
+    @Test
+    void testAllRelationshipsForObjectId() {
+        OranTeivRelationshipsResponseMessage response1 = new OranTeivRelationshipsResponseMessage();
+        OranTeivRelationshipsResponseMessage response2 = new OranTeivRelationshipsResponseMessage();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().basePath(
+                "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships").offset(0).limit(
+                        100).build();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().basePath(
+                "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships").offset(0).limit(
+                        100).build();
+
+        List<Object> mapList = new ArrayList<>();
+        List<Object> items1 = new ArrayList<>();
+        List<Object> items2 = new ArrayList<>();
+        mapList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "0525930249302B9649FC8F201EC4F7FC", "BCA882C87D49687E731F9B3872EFDBD3",
+                REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6RVV0cmFuQ2VsbDpCQ0E4ODJDODdENDk2ODdFNzMxRjlCMzg3MkVGREJEMw==",
+                Collections.EMPTY_LIST))));
+        mapList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", List.of(generateResponse(
+                "0525930249302B9649FC8F201EC4F7FC", "3256120E73ADD4026A43A971DCE5C151",
+                REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozMjU2MTIwRTczQURENDAyNkE0M0E5NzFEQ0U1QzE1MQ==",
+                Collections.EMPTY_LIST))));
+        mapList.add(Map.of("o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVESYSTEM", List.of(
+                generateResponse("0525930249302B9649FC8F201EC4F7FC", "2256120E73ADD4026A43A971DCE5C151",
+                        REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozMjU2MTIwRTczQURENDAyNkE0M0E5NzFEQ0U1QzE1MR==",
+                        Collections.EMPTY_LIST))));
+        mapList.add(Map.of("o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY", List.of(generateResponse(
+                "3256120E73ADD4026A43A971DCE5C151", "3223120E73ADD4026A43A971DCE5C151",
+                REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozMjU2MTIwRTczQURENDAyNkE0M0E5NzFEQ0U1QzE1MS==",
+                Collections.EMPTY_LIST))));
+
+        items1.add(mapList.get(0));
+        items1.add(mapList.get(1));
+        items1.add(mapList.get(2));
+
+        items2.add(mapList.get(1));
+        items2.add(mapList.get(3));
+
+        response1.setItems(items1);
+        response2.setItems(items2);
+
+        OranTeivHref hrefFirst1 = new OranTeivHref();
+        hrefFirst1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships?offset=0&limit=100");
+        response1.setFirst(hrefFirst1);
+        OranTeivHref hrefNext1 = new OranTeivHref();
+        hrefNext1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships?offset=0&limit=100");
+        response1.setNext(hrefNext1);
+        OranTeivHref hrefPrev1 = new OranTeivHref();
+        hrefPrev1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships?offset=0&limit=100");
+        response1.setPrev(hrefPrev1);
+        OranTeivHref hrefSelf1 = new OranTeivHref();
+        hrefSelf1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships?offset=0&limit=100");
+        response1.setSelf(hrefSelf1);
+        OranTeivHref hrefLast1 = new OranTeivHref();
+        hrefLast1.setHref(
+                "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships?offset=0&limit=100");
+        response1.setLast(hrefLast1);
+        response1.setTotalCount(3);
+
+        OranTeivHref hrefFirst2 = new OranTeivHref();
+        hrefFirst2.setHref(
+                "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships?offset=0&limit=100");
+        response2.setFirst(hrefFirst2);
+        OranTeivHref hrefNext2 = new OranTeivHref();
+        hrefNext2.setHref(
+                "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships?offset=0&limit=100");
+        response2.setNext(hrefNext2);
+        OranTeivHref hrefPrev2 = new OranTeivHref();
+        hrefPrev2.setHref(
+                "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships?offset=0&limit=100");
+        response2.setPrev(hrefPrev2);
+        OranTeivHref hrefSelf2 = new OranTeivHref();
+        hrefSelf2.setHref(
+                "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships?offset=0&limit=100");
+        response2.setSelf(hrefSelf2);
+        OranTeivHref hrefLast2 = new OranTeivHref();
+        hrefLast2.setHref(
+                "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships?offset=0&limit=100");
+        response2.setLast(hrefLast2);
+        response2.setTotalCount(1);
+
+        Assertions.assertEquals(response1, underTest.getAllRelationshipsForObjectId("GNBDUFunction",
+                "0525930249302B9649FC8F201EC4F7FC", paginationDTO1));
+        Assertions.assertEquals(response2, underTest.getAllRelationshipsForObjectId("NRSectorCarrier",
+                "3256120E73ADD4026A43A971DCE5C151", paginationDTO2));
+    }
+
+    @Test
+    void testGetTopologyRelationshipTypes() {
+        OranTeivRelationshipTypes expectedResponse = new OranTeivRelationshipTypes();
+        List<OranTeivRelationshipTypesItemsInner> items = new ArrayList<>();
+        OranTeivRelationshipTypesItemsInner item1 = new OranTeivRelationshipTypesItemsInner();
+        OranTeivRelationshipTypesItemsInner item2 = new OranTeivRelationshipTypesItemsInner();
+        OranTeivRelationshipTypesItemsInner item3 = new OranTeivRelationshipTypesItemsInner();
+        OranTeivRelationshipTypesItemsInner item4 = new OranTeivRelationshipTypesItemsInner();
+        OranTeivHref relationships1 = new OranTeivHref();
+        OranTeivHref relationships2 = new OranTeivHref();
+        OranTeivHref relationships3 = new OranTeivHref();
+        OranTeivHref relationships4 = new OranTeivHref();
+
+        item1.setName("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        relationships1.setHref("/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships");
+        item1.setRelationships(relationships1);
+
+        item2.setName("GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER");
+        relationships2.setHref("/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER/relationships");
+
+        item2.setRelationships(relationships2);
+
+        item3.setName("NRCELLDU_USES_NRSECTORCARRIER");
+        relationships3.setHref("/domains/RAN/relationship-types/NRCELLDU_USES_NRSECTORCARRIER/relationships");
+        item3.setRelationships(relationships3);
+
+        item4.setName("NRSECTORCARRIER_USES_ANTENNACAPABILITY");
+        relationships4.setHref("/domains/RAN/relationship-types/NRSECTORCARRIER_USES_ANTENNACAPABILITY/relationships");
+        item4.setRelationships(relationships4);
+
+        items.add(item1);
+        items.add(item2);
+        items.add(item3);
+        items.add(item4);
+
+        expectedResponse.setItems(items);
+        OranTeivHref hrefFirst = new OranTeivHref();
+        hrefFirst.setHref("/domains/RAN/relationship-types?offset=0&limit=5");
+        expectedResponse.setFirst(hrefFirst);
+        OranTeivHref hrefNext = new OranTeivHref();
+        hrefNext.setHref("/domains/RAN/relationship-types?offset=0&limit=5");
+        expectedResponse.setNext(hrefNext);
+        OranTeivHref hrefPrev = new OranTeivHref();
+        hrefPrev.setHref("/domains/RAN/relationship-types?offset=0&limit=5");
+        expectedResponse.setPrev(hrefPrev);
+        OranTeivHref hrefSelf = new OranTeivHref();
+        hrefSelf.setHref("/domains/RAN/relationship-types?offset=0&limit=5");
+        expectedResponse.setSelf(hrefSelf);
+        OranTeivHref hrefLast = new OranTeivHref();
+        hrefLast.setHref("/domains/RAN/relationship-types?offset=0&limit=5");
+        expectedResponse.setLast(hrefLast);
+        expectedResponse.setTotalCount(4);
+
+        PaginationDTO paginationDTO3 = PaginationDTO.builder().basePath("/domains/RAN/relationship-types").offset(0).limit(
+                5).build();
+
+        Assertions.assertEquals(expectedResponse, underTest.getTopologyRelationshipTypes("RAN", paginationDTO3));
+    }
+
+    @Test
+    void testGetTopologyEntityTypes() {
+        OranTeivEntityTypes expectedResponse = new OranTeivEntityTypes();
+        List<OranTeivEntityTypesItemsInner> items = new ArrayList<>();
+
+        OranTeivEntityTypesItemsInner item1 = new OranTeivEntityTypesItemsInner();
+        OranTeivEntityTypesItemsInner item2 = new OranTeivEntityTypesItemsInner();
+
+        item1.setName("AntennaCapability");
+        OranTeivHref entities1 = new OranTeivHref();
+        entities1.setHref("/domains/EQUIPMENT_TO_RAN/entity-types/AntennaCapability/entities");
+        item1.setEntities(entities1);
+
+        item2.setName("AntennaModule");
+        OranTeivHref entities2 = new OranTeivHref();
+        entities2.setHref("/domains/EQUIPMENT_TO_RAN/entity-types/AntennaModule/entities");
+        item2.setEntities(entities2);
+
+        items.add(item1);
+        items.add(item2);
+        expectedResponse.setItems(items);
+        OranTeivHref hrefFirst = new OranTeivHref();
+        hrefFirst.setHref("/domains/EQUIPMENT_TO_RAN/entity-types?offset=0&limit=2");
+        expectedResponse.setFirst(hrefFirst);
+        OranTeivHref hrefNext = new OranTeivHref();
+        hrefNext.setHref("/domains/EQUIPMENT_TO_RAN/entity-types?offset=2&limit=2");
+        expectedResponse.setNext(hrefNext);
+        OranTeivHref hrefPrev = new OranTeivHref();
+        hrefPrev.setHref("/domains/EQUIPMENT_TO_RAN/entity-types?offset=0&limit=2");
+        expectedResponse.setPrev(hrefPrev);
+        OranTeivHref hrefSelf = new OranTeivHref();
+        hrefSelf.setHref("/domains/EQUIPMENT_TO_RAN/entity-types?offset=0&limit=2");
+        expectedResponse.setSelf(hrefSelf);
+        OranTeivHref hrefLast = new OranTeivHref();
+        hrefLast.setHref("/domains/EQUIPMENT_TO_RAN/entity-types?offset=6&limit=2");
+        expectedResponse.setLast(hrefLast);
+        expectedResponse.setTotalCount(8);
+
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains/EQUIPMENT_TO_RAN/entity-types").offset(0)
+                .limit(2).build();
+
+        Assertions.assertEquals(expectedResponse, underTest.getTopologyEntityTypes("EQUIPMENT_TO_RAN", paginationDTO));
+    }
+
+    @Test
+    void testGetDomainTypes() {
+        OranTeivDomains expectedResponse = new OranTeivDomains();
+        OranTeivDomainsItemsInner item1 = new OranTeivDomainsItemsInner();
+        OranTeivDomainsItemsInner item2 = new OranTeivDomainsItemsInner();
+
+        item1.setName("CLOUD");
+        OranTeivHref entityType1 = new OranTeivHref();
+        OranTeivHref relationshipType1 = new OranTeivHref();
+        entityType1.setHref("/domains/CLOUD/entity-types");
+        relationshipType1.setHref("/domains/CLOUD/relationship-types");
+        item1.setEntityTypes(entityType1);
+        item1.setRelationshipTypes(relationshipType1);
+
+        item2.setName("CLOUD_TO_RAN");
+        OranTeivHref entityType2 = new OranTeivHref();
+        OranTeivHref relationshipType2 = new OranTeivHref();
+        entityType2.setHref("/domains/CLOUD_TO_RAN/entity-types");
+        relationshipType2.setHref("/domains/CLOUD_TO_RAN/relationship-types");
+        item2.setEntityTypes(entityType2);
+        item2.setRelationshipTypes(relationshipType2);
+
+        List<OranTeivDomainsItemsInner> items = new ArrayList<>();
+        items.add(item1);
+        items.add(item2);
+        expectedResponse.setItems(items);
+
+        OranTeivHref hrefFirst = new OranTeivHref();
+        hrefFirst.setHref("/domains?offset=0&limit=2");
+        expectedResponse.setFirst(hrefFirst);
+        OranTeivHref hrefNext = new OranTeivHref();
+        hrefNext.setHref("/domains?offset=2&limit=2");
+        expectedResponse.setNext(hrefNext);
+        OranTeivHref hrefPrev = new OranTeivHref();
+        hrefPrev.setHref("/domains?offset=0&limit=2");
+        expectedResponse.setPrev(hrefPrev);
+        OranTeivHref hrefSelf = new OranTeivHref();
+        hrefSelf.setHref("/domains?offset=0&limit=2");
+        expectedResponse.setSelf(hrefSelf);
+        OranTeivHref hrefLast = new OranTeivHref();
+        hrefLast.setHref("/domains?offset=6&limit=2");
+        expectedResponse.setLast(hrefLast);
+        expectedResponse.setTotalCount(2);
+
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains").offset(0).limit(2).build();
+        paginationDTO.setTotalSize(8);
+
+        Assertions.assertEquals(expectedResponse, underTest.getDomainTypes(paginationDTO));
+    }
+
+    private static void mockGetTopologyById() {
+        EntityType entity1 = getEntityTypeByName("GNBDUFunction");
+        EntityType entity2 = getEntityTypeByName("NRCellDU");
+
+        when(mockedDataPersistanceService.getTopology(entity1, "5A548EA9D166341776CA0695837E55D8")).thenReturn(
+                generateResponse("GNBDUFunction", "5A548EA9D166341776CA0695837E55D8"));
+        when(mockedDataPersistanceService.getTopology(entity2, "98C3A4591A37718E1330F0294E23B62A")).thenReturn(
+                generateResponse("NRCellDU", "98C3A4591A37718E1330F0294E23B62A"));
+        when(mockedDataPersistanceService.getTopology(entity2, "NOT_EXISTING")).thenThrow(TiesException.class);
+    }
+
+    private static void mockGetTopologyByType() {
+        Map<String, Object> mockedResponse1 = new HashMap<>();
+        PaginationMetaData pmd1 = new PaginationMetaData();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().basePath("/domains/RAN/entity-types/GNBDUFunction/entities")
+                .offset(0).limit(2).addQueryParameters("targetFilter", "/attributes/fdn;/attributes/id").addQueryParameters(
+                        "scopeFilter",
+                        "/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]").build();
+        paginationDTO1.setTotalSize(2);
+        mockedResponse1.putAll(pmd1.getObjectList(paginationDTO1));
+
+        mockedResponse1.put("items", List.of(Map.of("fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=111", "id",
+                "5BAE4346C241237AA8C74AE1259EF203"), Map.of("fdn",
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=112",
+                        "id", "6B55F987ED838C0FA58DC11AB19CD1D3")));
+        mockedResponse1.putAll(pmd1.getObjectList(paginationDTO1));
+
+        when(mockedDataPersistanceService.getTopologyByType("GNBDUFunction", "/attributes/fdn;/attributes/id",
+                "/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]", paginationDTO1))
+                        .thenReturn(mockedResponse1);
+    }
+
+    private static void MockGetTopologyByTargetFilter() {
+        Map<String, Object> mockedResponse = new HashMap<>();
+        Map<String, Object> query = new HashMap<>();
+
+        query.put("targetFilter", "/GNBDUFunction/id");
+
+        PaginationMetaData pmd1 = new PaginationMetaData();
+
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains/RAN/entities").offset(0).limit(1)
+                .addQueryParameters("targetFilter", "/GNBDUFunction/id").build();
+
+        paginationDTO.setTotalSize(1);
+        mockedResponse.putAll(pmd1.getObjectList(paginationDTO));
+        mockedResponse.put("query", query);
+
+        mockedResponse.put("items", List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of("id",
+                "1050570EBB1315E1AE7A9FD5E1400A00")))));
+
+        when(mockedDataPersistanceService.getEntitiesByDomain("RAN", "/GNBDUFunction/id", null, paginationDTO)).thenReturn(
+                mockedResponse);
+
+    }
+
+    private static void mockGetRelationshipById() {
+        String id = REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==";
+        String wrongId = "NOT_EXISTING";
+        String relationshipName = "GNBDUFUNCTION_PROVIDES_NRCELLDU";
+        Map<String, Object> response = Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(
+                generateResponse("D3215E08570BE58339C7463626B50E37", "98C3A4591A37718E1330F0294E23B62A", id,
+                        Collections.EMPTY_LIST)));
+
+        when(mockedDataPersistanceService.getRelationshipWithSpecifiedId(id, SchemaRegistry.getRelationTypeByName(
+                relationshipName))).thenReturn(response);
+        when(mockedDataPersistanceService.getRelationshipWithSpecifiedId(wrongId, SchemaRegistry.getRelationTypeByName(
+                relationshipName))).thenThrow(TiesException.class);
+    }
+
+    private static void mockGetRelationshipByType() {
+        Map<String, Object> mockedResponse = new HashMap<>();
+        Map<String, Object> items = Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "0525930249302B9649FC8F201EC4F7FC", "BCA882C87D49687E731F9B3872EFDBD3",
+                REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpHTkJEVUZ1bmN0aW9uLzkxOlBST1ZJREVTOk5SQ2VsbERVOk5SQ2VsbERVLzE=",
+                Collections.EMPTY_LIST)));
+        RelationType relationType = getRelationTypeByName("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+
+        PaginationMetaData pmd1 = new PaginationMetaData();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().basePath(
+                "/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships").offset(0).limit(5).build();
+        paginationDTO1.setTotalSize(1);
+        mockedResponse.putAll(pmd1.getObjectList(paginationDTO1));
+        mockedResponse.put(ITEMS, List.of(items));
+
+        when(mockedDataPersistanceService.getRelationshipsByType(relationType, null, PaginationDTO.builder().basePath(
+                "/domains/RAN/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships").offset(0).limit(5)
+                .build())).thenReturn(mockedResponse);
+
+        Map<String, Object> mockedResponse2 = new HashMap<>();
+        Map<String, Object> items2 = Map.of("o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", List.of(
+                generateResponse("A05C67D47D117C2DC5BDF5E00AE70", "2256120E73ADD4026A43A971DCE5C151",
+                        REL_ID_PREFIX + "R05CQ1VVUEZ1bmN0aW9uOkJGRUVBQzJDRTYwMjczQ0IwQTc4MzE5Q0MyMDFBN0ZFOlJE=",
+                        Collections.EMPTY_LIST)));
+        RelationType relationType2 = getRelationTypeByName("ANTENNAMODULE_REALISED_BY_ANTENNAMODULE");
+
+        PaginationMetaData pmd2 = new PaginationMetaData();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().basePath(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships").offset(0)
+                .limit(5).build();
+        paginationDTO2.setTotalSize(1);
+        mockedResponse2.putAll(pmd2.getObjectList(paginationDTO2));
+        mockedResponse2.put(ITEMS, List.of(items2));
+
+        when(mockedDataPersistanceService.getRelationshipsByType(relationType2, null, PaginationDTO.builder().basePath(
+                "/domains/EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships").offset(0)
+                .limit(5).build())).thenReturn(mockedResponse2);
+    }
+
+    private static void mockGetAllRelationships() {
+        final EntityType gnbduFunction = getEntityTypeByName("GNBDUFunction");
+        final EntityType nrSectorCarrier = getEntityTypeByName("NRSectorCarrier");
+        Map<String, Object> mockedResponse1 = new HashMap<>();
+        Map<String, Object> mockedResponse2 = new HashMap<>();
+        List<Object> mapList = new ArrayList<>();
+        mapList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "0525930249302B9649FC8F201EC4F7FC", "BCA882C87D49687E731F9B3872EFDBD3",
+                REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6RVV0cmFuQ2VsbDpCQ0E4ODJDODdENDk2ODdFNzMxRjlCMzg3MkVGREJEMw==",
+                Collections.EMPTY_LIST))));
+        mapList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", List.of(generateResponse(
+                "0525930249302B9649FC8F201EC4F7FC", "3256120E73ADD4026A43A971DCE5C151",
+                REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozMjU2MTIwRTczQURENDAyNkE0M0E5NzFEQ0U1QzE1MQ==",
+                Collections.EMPTY_LIST))));
+        mapList.add(Map.of("o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVESYSTEM", List.of(
+                generateResponse("0525930249302B9649FC8F201EC4F7FC", "2256120E73ADD4026A43A971DCE5C151",
+                        REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozMjU2MTIwRTczQURENDAyNkE0M0E5NzFEQ0U1QzE1MR==",
+                        Collections.EMPTY_LIST))));
+        mapList.add(Map.of("o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY", List.of(generateResponse(
+                "3256120E73ADD4026A43A971DCE5C151", "3223120E73ADD4026A43A971DCE5C151",
+                REL_ID_PREFIX + "RU5vZGVCRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozMjU2MTIwRTczQURENDAyNkE0M0E5NzFEQ0U1QzE1MS==",
+                Collections.EMPTY_LIST))));
+
+        PaginationMetaData pmd1 = new PaginationMetaData();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().basePath(
+                "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships").offset(0).limit(
+                        100).build();
+        paginationDTO1.setTotalSize(3);
+        mockedResponse1.putAll(pmd1.getObjectList(paginationDTO1));
+        mockedResponse1.put(ITEMS, List.of(mapList.get(0), mapList.get(1), mapList.get(2)));
+
+        PaginationMetaData pmd2 = new PaginationMetaData();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().basePath(
+                "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships").offset(0).limit(
+                        100).build();
+        paginationDTO2.setTotalSize(1);
+        mockedResponse2.putAll(pmd2.getObjectList(paginationDTO2));
+        mockedResponse2.put(ITEMS, List.of(mapList.get(1), mapList.get(3)));
+
+        when(mockedDataPersistanceService.getAllRelationships(gnbduFunction, getRelationTypesByEntityName("GNBDUFunction"),
+                "0525930249302B9649FC8F201EC4F7FC", PaginationDTO.builder().basePath(
+                        "/domains/RAN/entity-types/GNBDUFunction/0525930249302B9649FC8F201EC4F7FC/relationships").offset(0)
+                        .limit(100).build())).thenReturn(mockedResponse1);
+        when(mockedDataPersistanceService.getAllRelationships(nrSectorCarrier, getRelationTypesByEntityName(
+                "NRSectorCarrier"), "3256120E73ADD4026A43A971DCE5C151", PaginationDTO.builder().basePath(
+                        "/domains/RAN/entity-types/NRSectorCarrier/3256120E73ADD4026A43A971DCE5C151/relationships").offset(
+                                0).limit(100).build())).thenReturn(mockedResponse2);
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/data/api/impl/ExposureMetricsTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/data/api/impl/ExposureMetricsTest.java
new file mode 100644
index 0000000..7abf88c
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/data/api/impl/ExposureMetricsTest.java
@@ -0,0 +1,141 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.data.api.impl;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.data.rest.controller.DataRestController;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.exposure.utils.RequestValidator;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.function.Supplier;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ExposureMetricsTest {
+
+    private DataServiceImpl mockedDataService;
+    private RequestValidator mockedRequestValidator;
+    private CustomMetrics underTest;
+    private DataRestController dataRestController;
+
+    private final static String ACCEPT_TYPE = "application/json";
+    private final static String DOMAIN_NAME = "RAN_LOGICAL";
+    private final static String ENTITY_ID = "5A548EA9D166341776CA0695837E55D8";
+    private final static String ENTITY_NAME = "GNBDUFunction";
+    private final static String RELATION_TYPE = "GNBDUFUNCTION_PROVIDES_NRCELLDU";
+    private final static PaginationDTO paginationDto = PaginationDTO.builder().basePath("").offset(0).limit(1).build();
+
+    @BeforeEach
+    void setUp() throws SchemaLoaderException {
+        SchemaLoader mockedSchemaLoader = new MockSchemaLoader();
+        mockedSchemaLoader.loadSchemaRegistry();
+        mockedRequestValidator = mock(RequestValidator.class);
+        mockedDataService = mock(DataServiceImpl.class);
+        underTest = new CustomMetrics(new SimpleMeterRegistry());
+        dataRestController = new DataRestController(mockedRequestValidator, mockedDataService, underTest);
+    }
+
+    @Test
+    void testGetRelationshipsByEntityIdFailMetrics() {
+        when(mockedDataService.getAllRelationshipsForObjectId(eq(ENTITY_NAME), eq(ENTITY_ID), any(PaginationDTO.class)))
+                .thenThrow(TiesException.class);
+        assertMetrics(() -> dataRestController.getAllRelationshipsForEntityId(ACCEPT_TYPE, DOMAIN_NAME, ENTITY_NAME,
+                ENTITY_ID, 0, 1), underTest.getNumUnsuccessfullyExposedRelationshipsByEntityId()::count);
+    }
+
+    @Test
+    void testGetEntityByIdFailMetrics() {
+        when(mockedDataService.getTopologyById(ENTITY_NAME, ENTITY_ID)).thenThrow(TiesException.class);
+        assertMetrics(() -> dataRestController.getTopologyById(ACCEPT_TYPE, DOMAIN_NAME, ENTITY_NAME, ENTITY_ID), underTest
+                .getNumUnsuccessfullyExposedEntityById()::count);
+    }
+
+    @Test
+    void testGetEntitiesByTypeFailMetrics() {
+        when(mockedDataService.getTopologyByType(eq(ENTITY_NAME), anyString(), anyString(), any(PaginationDTO.class)))
+                .thenThrow(TiesException.class);
+        assertMetrics(() -> dataRestController.getTopologyByEntityTypeName(ACCEPT_TYPE, DOMAIN_NAME, ENTITY_NAME, "", "", 0,
+                1), underTest.getNumUnsuccessfullyExposedEntitiesByType()::count);
+    }
+
+    @Test
+    void testGetEntitiesByDomainFailMetrics() {
+        when(mockedDataService.getEntitiesByDomain(eq(DOMAIN_NAME), anyString(), anyString(), any(PaginationDTO.class)))
+                .thenThrow(TiesException.class);
+        assertMetrics(() -> dataRestController.getEntitiesByDomain(ACCEPT_TYPE, DOMAIN_NAME, "", "", 0, 1), underTest
+                .getNumUnsuccessfullyExposedEntitiesByDomain()::count);
+    }
+
+    @Test
+    void testGetRelationshipByIdFailMetrics() {
+        when(mockedDataService.getRelationshipById(RELATION_TYPE, ENTITY_ID)).thenThrow(TiesException.class);
+        assertMetrics(() -> dataRestController.getRelationshipById(ACCEPT_TYPE, DOMAIN_NAME, RELATION_TYPE, ENTITY_ID),
+                underTest.getNumUnsuccessfullyExposedRelationshipById()::count);
+    }
+
+    @Test
+    void testGetRelationshipsByTypeFailMetrics() {
+        when(mockedDataService.getRelationshipsByType(eq(RELATION_TYPE), anyString(), any(PaginationDTO.class))).thenThrow(
+                TiesException.class);
+        assertMetrics(() -> dataRestController.getRelationshipsByType(ACCEPT_TYPE, DOMAIN_NAME, RELATION_TYPE, "", "", 0,
+                1), underTest.getNumUnsuccessfullyExposedRelationshipsByType()::count);
+    }
+
+    @Test
+    void testGetRelationshipTypesFailMetrics() {
+        when(mockedDataService.getTopologyRelationshipTypes(eq(DOMAIN_NAME), any(PaginationDTO.class))).thenThrow(
+                TiesException.class);
+        assertMetrics(() -> dataRestController.getTopologyRelationshipTypes(ACCEPT_TYPE, DOMAIN_NAME, 0, 1), underTest
+                .getNumUnsuccessfullyExposedRelationshipTypes()::count);
+    }
+
+    @Test
+    void testGetDomainTypesFailMetrics() {
+        when(mockedDataService.getDomainTypes(any(PaginationDTO.class))).thenThrow(TiesException.class);
+        assertMetrics(() -> dataRestController.getAllDomains(ACCEPT_TYPE, 0, 1), underTest
+                .getNumUnsuccessfullyExposedDomainTypes()::count);
+    }
+
+    @Test
+    void testGetEntityTypesFailMetrics() {
+        when(mockedDataService.getTopologyEntityTypes(eq(DOMAIN_NAME), any(PaginationDTO.class))).thenThrow(
+                TiesException.class);
+        assertMetrics(() -> dataRestController.getTopologyEntityTypes(ACCEPT_TYPE, DOMAIN_NAME, 0, 1), underTest
+                .getNumUnsuccessfullyExposedEntityTypes()::count);
+    }
+
+    private <T> void assertMetrics(Supplier<T> dataServiceMethod, Supplier<T> failerSupplier) {
+        Assertions.assertThrowsExactly(TiesException.class, dataServiceMethod::get);
+        Assertions.assertEquals(1.0, failerSupplier.get());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/data/rest/controller/DataRestControllerTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/data/rest/controller/DataRestControllerTest.java
new file mode 100644
index 0000000..313568e
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/data/rest/controller/DataRestControllerTest.java
@@ -0,0 +1,573 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.data.rest.controller;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.api.model.OranTeivDomains;
+import org.oran.smo.teiv.api.model.OranTeivHref;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivEntityTypes;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypesItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipsResponseMessage;
+import org.oran.smo.teiv.api.model.OranTeivRelationshipTypes;
+import org.oran.smo.teiv.api.model.OranTeivDomainsItemsInner;
+import org.oran.smo.teiv.api.model.OranTeivEntitiesResponseMessage;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.data.api.impl.DataServiceImpl;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.exposure.utils.RequestValidator;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.http.ResponseEntity;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.oran.smo.teiv.utils.ResponseGenerator.generateResponse;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class DataRestControllerTest {
+    private static DataServiceImpl dataService;
+    private static DataRestController underTest;
+    private static RequestValidator requestValidator;
+    private static CustomMetrics customMetrics;
+    private final String ACCEPT_TYPE = "application/json";
+    private static final String EIID_PREFIX = "urn:base64:";
+
+    @BeforeAll
+    static void setUp() {
+        dataService = mock(DataServiceImpl.class);
+        requestValidator = mock(RequestValidator.class);
+        customMetrics = mock(CustomMetrics.class);
+        underTest = new DataRestController(requestValidator, dataService, customMetrics);
+        mockTopologyById();
+        mockGetTopologyRelationshipTypes();
+        mockTopologyEntityTypes();
+        mockGetRelationshipById();
+        mockGetRelationshipByType();
+        mockGetAllRelationshipsForEntityId();
+        mockGetDomainTypes();
+        mockGetTopologyEntityTypes();
+        mockTopologyByType();
+    }
+
+    @BeforeEach
+    void clearInvocations() {
+        Mockito.clearInvocations(requestValidator);
+    }
+
+    @Test
+    void testGetTopologyById() {
+        assertEquals(ResponseEntity.ok(generateResponse("GNBDUFunction", "5A548EA9D166341776CA0695837E55D8")), underTest
+                .getTopologyById(ACCEPT_TYPE, "RAN_LOGICAL", "GNBDUFunction", "5A548EA9D166341776CA0695837E55D8"));
+        assertEquals(ResponseEntity.ok(generateResponse("NRCellDU", "98C3A4591A37718E1330F0294E23B62A")), underTest
+                .getTopologyById(ACCEPT_TYPE, "RAN_LOGICAL", "NRCellDU", "98C3A4591A37718E1330F0294E23B62A"));
+        assertThrows(TiesException.class, () -> underTest.getTopologyById(ACCEPT_TYPE, "RAN_LOGICAL", "NRCellDU",
+                "NOT_EXISTING"));
+
+        verify(requestValidator, Mockito.times(3)).validateDomain("RAN_LOGICAL");
+        verify(requestValidator, Mockito.times(1)).validateEntityType("GNBDUFunction");
+        verify(requestValidator, Mockito.times(2)).validateEntityType("NRCellDU");
+        verify(requestValidator, Mockito.times(1)).validateEntityTypeInDomain("GNBDUFunction", "RAN_LOGICAL");
+        verify(requestValidator, Mockito.times(2)).validateEntityTypeInDomain("NRCellDU", "RAN_LOGICAL");
+    }
+
+    @Test
+    void testGetTopologyEntityTypes() {
+        OranTeivEntityTypesItemsInner element1 = new OranTeivEntityTypesItemsInner();
+        element1.setName("Site");
+        OranTeivEntityTypesItemsInner element2 = new OranTeivEntityTypesItemsInner();
+        element1.setName("AntennaModule");
+        OranTeivEntityTypesItemsInner element3 = new OranTeivEntityTypesItemsInner();
+        element1.setName("PhysicalNetworkAppliance");
+
+        List<OranTeivEntityTypesItemsInner> entityTypes = new ArrayList<>();
+        entityTypes.add(element1);
+        entityTypes.add(element2);
+        entityTypes.add(element3);
+        OranTeivEntityTypes response = new OranTeivEntityTypes();
+        response.setItems(entityTypes);
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/domains/RAN_EQUIPMENT/entity-types?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getTopologyEntityTypes(ACCEPT_TYPE, "RAN_EQUIPMENT",
+                0, 5));
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getTopologyEntityTypes("*/*", "RAN_EQUIPMENT", 0,
+                5));
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getTopologyEntityTypes(
+                "application/json, application/problem+json", "RAN_EQUIPMENT", 0, 5));
+
+        verify(requestValidator, Mockito.times(3)).validateDomain("RAN_EQUIPMENT");
+    }
+
+    @Test
+    void testGetTopologyRelationshipTypes() {
+        OranTeivRelationshipTypesItemsInner element1 = new OranTeivRelationshipTypesItemsInner();
+        element1.setName("NRSECTORCARRIER_USES_ANTENNACAPABILITY");
+        OranTeivRelationshipTypesItemsInner element2 = new OranTeivRelationshipTypesItemsInner();
+        element2.setName("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        OranTeivRelationshipTypesItemsInner element3 = new OranTeivRelationshipTypesItemsInner();
+        element3.setName("GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        OranTeivRelationshipTypesItemsInner element4 = new OranTeivRelationshipTypesItemsInner();
+        element4.setName("EUTRANCELL_USES_LTESECTORCARRIER");
+        OranTeivRelationshipTypesItemsInner element5 = new OranTeivRelationshipTypesItemsInner();
+        element5.setName("MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION");
+
+        List<OranTeivRelationshipTypesItemsInner> relationshipTypes = new ArrayList<>();
+        relationshipTypes.add(element1);
+        relationshipTypes.add(element2);
+        relationshipTypes.add(element3);
+        relationshipTypes.add(element4);
+        relationshipTypes.add(element5);
+
+        OranTeivRelationshipTypes response = new OranTeivRelationshipTypes();
+        response.setItems(relationshipTypes);
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/domains/RAN_LOGICAL/relationship-types?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getTopologyRelationshipTypes(ACCEPT_TYPE,
+                "RAN_LOGICAL", 0, 5));
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getTopologyRelationshipTypes("*/*", "RAN_LOGICAL", 0,
+                5));
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getTopologyRelationshipTypes(
+                "application/json, application/problem+json", "RAN_LOGICAL", 0, 5));
+    }
+
+    @Test
+    void testGetDomainTypes() {
+        OranTeivDomainsItemsInner element1 = new OranTeivDomainsItemsInner();
+        element1.setName("RAN_LOGICAL_TO_EQUIPMENT");
+        OranTeivDomainsItemsInner element2 = new OranTeivDomainsItemsInner();
+        element2.setName("RAN_LOGICAL");
+        OranTeivDomainsItemsInner element3 = new OranTeivDomainsItemsInner();
+        element3.setName("RAN_EQUIPMENT");
+
+        List<OranTeivDomainsItemsInner> domains = new ArrayList<>();
+        domains.add(element1);
+        domains.add(element2);
+        domains.add(element3);
+
+        OranTeivDomains response = new OranTeivDomains();
+        response.setItems(domains);
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/domains?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getAllDomains(ACCEPT_TYPE, 0, 3));
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getAllDomains("*/*", 0, 3));
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getAllDomains(
+                "application/json, application/problem+json", 0, 3));
+
+    }
+
+    @Test
+    void testGetRelationshipById() {
+        Map<String, Object> response = Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(
+                generateResponse("D3215E08570BE58339C7463626B50E37", "98C3A4591A37718E1330F0294E23B62A",
+                        EIID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==",
+                        Collections.emptyList())));
+
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getRelationshipById(ACCEPT_TYPE, "RAN_LOGICAL",
+                "GNBDUFUNCTION_PROVIDES_NRCELLDU",
+                EIID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ=="));
+
+        verify(requestValidator, Mockito.times(1)).validateDomain("RAN_LOGICAL");
+        verify(requestValidator, Mockito.times(1)).validateRelationshipType("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        verify(requestValidator, Mockito.times(1)).validateRelationshipTypeInDomain("GNBDUFUNCTION_PROVIDES_NRCELLDU",
+                "RAN_LOGICAL");
+    }
+
+    @Test
+    void testGetAllRelationshipsForEntityId() {
+        List<Object> mapList = new ArrayList<>();
+        mapList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "D3215E08570BE58339C7463626B50E37", "B480427E8A0C0B8D994E437784BB382F",
+                EIID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                Collections.emptyList()))));
+        mapList.add(Map.of("o-ran-smo-teiv-equipment-to-ran:SECTOR_GROUPS_NRCELLDU", List.of(generateResponse(
+                "F5128C172A70C4FCD4739650B06DE9E2", "B480427E8A0C0B8D994E437784BB382F",
+                EIID_PREFIX + "U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                Collections.emptyList()))));
+        mapList.add(Map.of("o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER", List.of(generateResponse(
+                "B480427E8A0C0B8D994E437784BB382F", "E49D942C16E0364E1E0788138916D70C",
+                EIID_PREFIX + "TlJDZWxsRFU6QjQ4MDQyN0U4QTBDMEI4RDk5NEU0Mzc3ODRCQjM4MkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM=",
+                Collections.emptyList()))));
+
+        OranTeivRelationshipsResponseMessage response = new OranTeivRelationshipsResponseMessage();
+
+        response.setItems(mapList);
+        OranTeivHref href = new OranTeivHref();
+        href.setHref(
+                "/domains/RAN_LOGICAL/entity-types/NRCellDU/entities/B480427E8A0C0B8D994E437784BB382F/relationships?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getAllRelationshipsForEntityId(ACCEPT_TYPE,
+                "RAN_LOGICAL", "NRCellDU", "B480427E8A0C0B8D994E437784BB382F", 0, 5));
+
+        verify(requestValidator, Mockito.times(1)).validateDomain("RAN_LOGICAL");
+        verify(requestValidator, Mockito.times(1)).validateEntityType("NRCellDU");
+        verify(requestValidator, Mockito.times(1)).validateEntityTypeInDomain("NRCellDU", "RAN_LOGICAL");
+    }
+
+    @Test
+    void testGetRelationshipsByType() {
+        underTest.getRelationshipsByType(ACCEPT_TYPE, "RAN_LOGICAL", "GNBDUFUNCTION_PROVIDES_NRCELLDU", null, null, 0, 5);
+
+        verify(requestValidator, Mockito.times(1)).validateDomain("RAN_LOGICAL");
+        verify(requestValidator, Mockito.times(1)).validateRelationshipType("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        verify(requestValidator, Mockito.times(1)).validateRelationshipTypeInDomain("GNBDUFUNCTION_PROVIDES_NRCELLDU",
+                "RAN_LOGICAL");
+
+        OranTeivRelationshipsResponseMessage response = new OranTeivRelationshipsResponseMessage();
+
+        response.setItems(List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "91", "1", EIID_PREFIX + "R05CRFVGdW5jdGlvbjpHTkJEVUZ1bmN0aW9uLzkxOlBST1ZJREVTOk5SQ2VsbERVOk5SQ2VsbERVLzE=",
+                Collections.emptyList()), generateResponse("92", "2",
+                        EIID_PREFIX + "R05CRFVGdW5jdGlvbjpHTkJEVUZ1bmN0aW9uLzkyOlBST1ZJREVTOk5SQ2VsbERVOk5SQ2VsbERVLzI=",
+                        Collections.emptyList())))));
+        OranTeivHref href = new OranTeivHref();
+        href.setHref(
+                "/domains/RAN_LOGICAL/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getRelationshipsByType(ACCEPT_TYPE, "RAN_LOGICAL",
+                "GNBDUFUNCTION_PROVIDES_NRCELLDU", null, null, 0, 5));
+    }
+
+    @Test
+    void testGetTopologyByTargetFilter() {
+        underTest.getEntitiesByDomain(ACCEPT_TYPE, "RAN_LOGICAL", null, null, 0, 2);
+
+        verify(requestValidator, Mockito.times(1)).validateDomain("RAN_LOGICAL");
+    }
+
+    @Test
+    void testGetTopologyByType() {
+
+        OranTeivEntitiesResponseMessage response = new OranTeivEntitiesResponseMessage();
+        Map<String, Object> query = new HashMap<>();
+
+        query.put("scopeFilter", "/attributes[contains (@fnd, \"/SubNetwork=Ireland/\")]");
+
+        response.setItems(List.of(Map.of("GNBDUFunction", List.of(Map.of("id", "5FE67725576EDA7937752E7965164C2E"), Map.of(
+                "id", "9BCD297B8258F67908477D895636ED65"), Map.of("id", "8E249BCFAEC86C03D9ADD27FA9748254")))));
+        OranTeivHref href = new OranTeivHref();
+        href.setHref(
+                "/domains/RAN_LOGICAL/entity-types/GNBDUFunction/entities?scopeFilter=/attributes[contains (@fdn, \"/SubNetwork=Ireland/\")]&offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        Assertions.assertEquals(ResponseEntity.ok(response), underTest.getTopologyByEntityTypeName(ACCEPT_TYPE,
+                "RAN_LOGICAL", "GNBDUFunction", "", "/attributes[contains (@fdn, \"/SubNetwork=Ireland/\")]", 0, 3));
+
+        verify(requestValidator, Mockito.times(1)).validateDomain("RAN_LOGICAL");
+        verify(requestValidator, Mockito.times(1)).validateEntityType("GNBDUFunction");
+        verify(requestValidator, Mockito.times(1)).validateEntityTypeInDomain("GNBDUFunction", "RAN_LOGICAL");
+
+        assertThrows(TiesException.class, () -> underTest.getTopologyByEntityTypeName(ACCEPT_TYPE, "RAN_LOGICAL",
+                "CloudSite", "", "/attributes[contains (@fdn, \"/SubNetwork Ireland/\")]", 0, 3));
+        assertThrows(TiesException.class, () -> underTest.getTopologyByEntityTypeName(ACCEPT_TYPE, "RAN_LOGICAL",
+                "GNBDUFunction2", "", "/attributes[contains (@fdn, \"/SubNetwork Ireland/\")]", 0, 3));
+        assertThrows(TiesPathException.class, () -> underTest.getTopologyByEntityTypeName(ACCEPT_TYPE, "RAN_LOGICAL",
+                "GNBDUFunction", "", "/attributes[contains ( fdn, \"/SubNetwork Ireland/\")]", 0, 3));
+
+    }
+
+    private static void mockTopologyById() {
+        when(dataService.getTopologyById("GNBDUFunction", "5A548EA9D166341776CA0695837E55D8")).thenReturn(generateResponse(
+                "GNBDUFunction", "5A548EA9D166341776CA0695837E55D8"));
+        when(dataService.getTopologyById("NRCellDU", "98C3A4591A37718E1330F0294E23B62A")).thenReturn(generateResponse(
+                "NRCellDU", "98C3A4591A37718E1330F0294E23B62A"));
+        when(dataService.getTopologyById("NRCellDU", "NOT_EXISTING")).thenThrow(TiesException.class);
+    }
+
+    private static void mockTopologyEntityTypes() {
+        OranTeivEntityTypesItemsInner element1 = new OranTeivEntityTypesItemsInner();
+        element1.setName("Site");
+        OranTeivEntityTypesItemsInner element2 = new OranTeivEntityTypesItemsInner();
+        element1.setName("AntennaModule");
+        OranTeivEntityTypesItemsInner element3 = new OranTeivEntityTypesItemsInner();
+        element1.setName("PhysicalNetworkAppliance");
+
+        List<OranTeivEntityTypesItemsInner> entityTypes = new ArrayList<>();
+        entityTypes.add(element1);
+        entityTypes.add(element2);
+        entityTypes.add(element3);
+        OranTeivEntityTypes response = new OranTeivEntityTypes();
+        response.setItems(entityTypes);
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/domains/RAN_EQUIPMENT/entity-types?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        when(dataService.getTopologyEntityTypes("RAN_EQUIPMENT", PaginationDTO.builder().offset(0).limit(5).build()))
+                .thenReturn(response);
+    }
+
+    private static void mockGetRelationshipById() {
+        Map<String, Object> response = Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(
+                generateResponse("D3215E08570BE58339C7463626B50E37", "98C3A4591A37718E1330F0294E23B62A",
+                        EIID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==",
+                        Collections.emptyList())));
+
+        when(dataService.getRelationshipById("GNBDUFUNCTION_PROVIDES_NRCELLDU",
+                EIID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ=="))
+                        .thenReturn(response);
+    }
+
+    private static void mockGetRelationshipByType() {
+        PaginationDTO paginationDTO = PaginationDTO.builder().offset(0).limit(5).addPathParameters("relationshipType",
+                "GNBDUFUNCTION_PROVIDES_NRCELLDU").addPathParameters("domain", "RAN_LOGICAL").addQueryParameters(
+                        "scopeFilter", null).basePath(
+                                "/domains/RAN_LOGICAL/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships")
+                .build();
+
+        OranTeivRelationshipsResponseMessage response = new OranTeivRelationshipsResponseMessage();
+        response.setItems(List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "91", "1", EIID_PREFIX + "R05CRFVGdW5jdGlvbjpHTkJEVUZ1bmN0aW9uLzkxOlBST1ZJREVTOk5SQ2VsbERVOk5SQ2VsbERVLzE=",
+                Collections.emptyList()), generateResponse("92", "2",
+                        EIID_PREFIX + "R05CRFVGdW5jdGlvbjpHTkJEVUZ1bmN0aW9uLzkyOlBST1ZJREVTOk5SQ2VsbERVOk5SQ2VsbERVLzI=",
+                        Collections.emptyList())))));
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref(
+                "/domains/RAN_LOGICAL/relationship-types/GNBDUFUNCTION_PROVIDES_NRCELLDU/relationships?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        when(dataService.getRelationshipsByType("GNBDUFUNCTION_PROVIDES_NRCELLDU", null, paginationDTO)).thenReturn(
+                response);
+    }
+
+    private static void mockGetAllRelationshipsForEntityId() {
+        OranTeivRelationshipsResponseMessage response = new OranTeivRelationshipsResponseMessage();
+
+        List<Object> mapList = new ArrayList<>();
+        mapList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "D3215E08570BE58339C7463626B50E37", "B480427E8A0C0B8D994E437784BB382F",
+                EIID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                Collections.emptyList()))));
+        mapList.add(Map.of("o-ran-smo-teiv-equipment-to-ran:SECTOR_GROUPS_NRCELLDU", List.of(generateResponse(
+                "F5128C172A70C4FCD4739650B06DE9E2", "B480427E8A0C0B8D994E437784BB382F",
+                EIID_PREFIX + "U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                Collections.emptyList()))));
+        mapList.add(Map.of("o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER", List.of(generateResponse(
+                "B480427E8A0C0B8D994E437784BB382F", "E49D942C16E0364E1E0788138916D70C",
+                EIID_PREFIX + "TlJDZWxsRFU6QjQ4MDQyN0U4QTBDMEI4RDk5NEU0Mzc3ODRCQjM4MkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM=",
+                Collections.emptyList()))));
+
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().addPathParameters("domain", "RAN_LOGICAL").addPathParameters(
+                "entityType", "NRCellDU").addPathParameters("id", "B480427E8A0C0B8D994E437784BB382F").basePath(String
+                        .format("/domains/%s/entity-types/%s/entities/%s/relationships", "RAN_LOGICAL", "NRCellDU",
+                                "B480427E8A0C0B8D994E437784BB382F")).offset(0).limit(5).build();
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref(
+                "/domains/RAN_LOGICAL/entity-types/NRCellDU/entities/B480427E8A0C0B8D994E437784BB382F/relationships?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        response.setItems(mapList);
+        when(dataService.getAllRelationshipsForObjectId("NRCellDU", "B480427E8A0C0B8D994E437784BB382F", paginationDTO1))
+                .thenReturn(response);
+    }
+
+    private static void mockGetDomainTypes() {
+        OranTeivDomainsItemsInner element1 = new OranTeivDomainsItemsInner();
+        element1.setName("RAN_LOGICAL_TO_EQUIPMENT");
+        OranTeivDomainsItemsInner element2 = new OranTeivDomainsItemsInner();
+        element2.setName("RAN_LOGICAL");
+        OranTeivDomainsItemsInner element3 = new OranTeivDomainsItemsInner();
+        element3.setName("RAN_EQUIPMENT");
+
+        List<OranTeivDomainsItemsInner> domains = new ArrayList<>();
+        domains.add(element1);
+        domains.add(element2);
+        domains.add(element3);
+
+        OranTeivDomains response = new OranTeivDomains();
+        response.setItems(domains);
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/domains?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        when(dataService.getDomainTypes(PaginationDTO.builder().offset(0).basePath("/domains").limit(3).build()))
+                .thenReturn(response);
+    }
+
+    private static void mockGetTopologyEntityTypes() {
+        OranTeivEntityTypesItemsInner element1 = new OranTeivEntityTypesItemsInner();
+        element1.setName("Site");
+        OranTeivEntityTypesItemsInner element2 = new OranTeivEntityTypesItemsInner();
+        element1.setName("AntennaModule");
+        OranTeivEntityTypesItemsInner element3 = new OranTeivEntityTypesItemsInner();
+        element1.setName("PhysicalNetworkAppliance");
+
+        List<OranTeivEntityTypesItemsInner> entityTypes = new ArrayList<>();
+        entityTypes.add(element1);
+        entityTypes.add(element2);
+        entityTypes.add(element3);
+        OranTeivEntityTypes response = new OranTeivEntityTypes();
+        response.setItems(entityTypes);
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/domains/RAN_EQUIPMENT/entity-types?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().basePath("/domains/RAN_EQUIPMENT/entity-types")
+                .addPathParameters("domain", "RAN_EQUIPMENT").offset(0).limit(5).build();
+
+        when(dataService.getTopologyEntityTypes("RAN_EQUIPMENT", paginationDTO1)).thenReturn(response);
+    }
+
+    private static void mockGetTopologyRelationshipTypes() {
+        OranTeivRelationshipTypesItemsInner element1 = new OranTeivRelationshipTypesItemsInner();
+        element1.setName("NRSECTORCARRIER_USES_ANTENNACAPABILITY");
+        OranTeivRelationshipTypesItemsInner element2 = new OranTeivRelationshipTypesItemsInner();
+        element2.setName("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        OranTeivRelationshipTypesItemsInner element3 = new OranTeivRelationshipTypesItemsInner();
+        element3.setName("GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        OranTeivRelationshipTypesItemsInner element4 = new OranTeivRelationshipTypesItemsInner();
+        element4.setName("EUTRANCELL_USES_LTESECTORCARRIER");
+        OranTeivRelationshipTypesItemsInner element5 = new OranTeivRelationshipTypesItemsInner();
+        element5.setName("MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION");
+
+        List<OranTeivRelationshipTypesItemsInner> relationshipTypes = new ArrayList<>();
+        relationshipTypes.add(element1);
+        relationshipTypes.add(element2);
+        relationshipTypes.add(element3);
+        relationshipTypes.add(element4);
+        relationshipTypes.add(element5);
+
+        OranTeivRelationshipTypes response = new OranTeivRelationshipTypes();
+        response.setItems(relationshipTypes);
+
+        OranTeivHref href = new OranTeivHref();
+        href.setHref("/domains/RAN_LOGICAL/relationship-types?offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().basePath("/domains/RAN_LOGICAL/relationship-types").offset(0)
+                .limit(5).addPathParameters("domain", "RAN_LOGICAL").build();
+
+        when(dataService.getTopologyRelationshipTypes("RAN_LOGICAL", paginationDTO1)).thenReturn(response);
+    }
+
+    private static void mockTopologyByType() {
+        OranTeivEntitiesResponseMessage response = new OranTeivEntitiesResponseMessage();
+        Map<String, Object> query = new HashMap<>();
+
+        query.put("scopeFilter", "/attributes[contains (@fnd, \"/SubNetwork=Ireland/\")]");
+
+        PaginationDTO paginationDTO = PaginationDTO.builder().offset(0).limit(3).addPathParameters("domain", "RAN_LOGICAL")
+                .addQueryParameters("targetFilter", "").addQueryParameters("scopeFilter",
+                        "/attributes[contains (@fdn, \"/SubNetwork=Ireland/\")]").basePath(
+                                "/domains/RAN_LOGICAL/entity-types/GNBDUFunction/entities").build();
+
+        response.setItems(List.of(Map.of("GNBDUFunction", List.of(Map.of("id", "5FE67725576EDA7937752E7965164C2E"), Map.of(
+                "id", "9BCD297B8258F67908477D895636ED65"), Map.of("id", "8E249BCFAEC86C03D9ADD27FA9748254")))));
+        OranTeivHref href = new OranTeivHref();
+        href.setHref(
+                "/domains/RAN_LOGICAL/entity-types/GNBDUFunction/entities?scopeFilter=/attributes[contains (@fdn, \"/SubNetwork=Ireland/\")]&offset=0&limit=5");
+        response.setSelf(href);
+        response.setFirst(href);
+        response.setPrev(href);
+        response.setNext(href);
+        response.setLast(href);
+
+        when(dataService.getTopologyByType("GNBDUFunction", "", "/attributes[contains (@fdn, \"/SubNetwork=Ireland/\")]",
+                paginationDTO)).thenReturn(response);
+
+        doThrow(TiesException.class).when(requestValidator).validateEntityTypeInDomain(eq("CloudSite"), eq("RAN_LOGICAL"));
+        doThrow(TiesException.class).when(requestValidator).validateEntityTypeInDomain(eq("GNBDUFunction2"), eq(
+                "RAN_LOGICAL"));
+
+        when(dataService.getTopologyByType("GNBDUFunction", "", "/attributes[contains ( fdn, \"/SubNetwork Ireland/\")]",
+                PaginationDTO.builder().offset(0).limit(3).addQueryParameters("targetFilter", "").addQueryParameters(
+                        "scopeFilter", "/attributes[contains ( fdn, \"/SubNetwork Ireland/\")]").basePath(
+                                "/domains/RAN_LOGICAL/entity-types/GNBDUFunction/entities").addPathParameters("domain",
+                                        "RAN_LOGICAL").build())).thenThrow(TiesPathException.grammarError("'@' missing"));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/impl/DataPersistenceServiceImplGETRequestsContainerizedTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/impl/DataPersistenceServiceImplGETRequestsContainerizedTest.java
new file mode 100644
index 0000000..504974d
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/impl/DataPersistenceServiceImplGETRequestsContainerizedTest.java
@@ -0,0 +1,1190 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.impl;
+
+import static org.oran.smo.teiv.utils.ResponseGenerator.generateResponse;
+import static org.oran.smo.teiv.utils.TiesConstants.ATTRIBUTES;
+import static org.oran.smo.teiv.utils.TiesConstants.ITEMS;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.oran.smo.teiv.utils.exposure.PaginationVerifierTestUtil.verifyResponse;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.sql.DataSource;
+
+import org.oran.smo.teiv.schema.DataType;
+import org.jooq.DSLContext;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Configuration;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.spi.mapper.MapperUtility;
+import org.oran.smo.teiv.exposure.spi.mapper.PaginationMetaData;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.PostgresSchemaLoader;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+import java.util.HashSet;
+
+@Configuration
+@SpringBootTest
+class DataPersistenceServiceImplGETRequestsContainerizedTest {
+    public static TestPostgresqlContainer postgreSQLContainer = TestPostgresqlContainer.getInstance();
+    private static DataPersistanceServiceImpl underTest;
+    private static MapperUtility mapperUtility;
+    private static DSLContext dslContext;
+    private static DSLContext writeDataDslContext;
+    private static final String REL_ID_PREFIX = "urn:base64:";
+
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @BeforeAll
+    public static void beforeAll() throws UnsupportedOperationException, SchemaLoaderException {
+        String url = postgreSQLContainer.getJdbcUrl();
+        DataSource ds = DataSourceBuilder.create().url(url).username("test").password("test").build();
+        dslContext = DSL.using(ds, SQLDialect.POSTGRES);
+        writeDataDslContext = DSL.using(ds, SQLDialect.POSTGRES);
+        mapperUtility = new MapperUtility();
+        underTest = new DataPersistanceServiceImpl(dslContext, writeDataDslContext, mapperUtility);
+        PostgresSchemaLoader postgresSchemaLoader = new PostgresSchemaLoader(dslContext, new ObjectMapper());
+        postgresSchemaLoader.loadSchemaRegistry();
+        TestPostgresqlContainer.loadSampleData();
+    }
+
+    @BeforeEach
+    public void deleteAll() {
+        writeDataDslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(
+                t -> writeDataDslContext.truncate(t).cascade().execute());
+        TestPostgresqlContainer.loadSampleData();
+    }
+
+    @Test
+    void testGetTopology() {
+        Map<String, List<Object>> response = new HashMap<>();
+        Map<String, Object> responseData = new HashMap<>();
+        Map<String, Object> attributesMap = new HashMap<>();
+        response.put("o-ran-smo-teiv-ran:GNBDUFunction", List.of(responseData));
+        attributesMap.put("gNBDUId", null);
+        attributesMap.put("fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=16");
+        attributesMap.put("dUpLMNId", Map.of("mcc", "456", "mnc", "82"));
+        attributesMap.put("gNBId", 16L);
+        attributesMap.put("gNBIdLength", 2L);
+        attributesMap.put("cmId", null);
+        responseData.put("attributes", attributesMap);
+        responseData.put("id", "5A548EA9D166341776CA0695837E55D8");
+        responseData.put("sourceIds", List.of(
+                "urn:3gpp:dn:/SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary" + "/GNBDUFunction=16",
+                "urn:cmHandle:/395221E080CCF0FD1924103B15873814"));
+
+        Assertions.assertEquals(response, underTest.getTopology(SchemaRegistry.getEntityTypeByName("GNBDUFunction"),
+                "5A548EA9D166341776CA0695837E55D8"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getTopology(SchemaRegistry.getEntityTypeByName(
+                "GNBDUFunction"), "-1"));
+
+        response.clear();
+        responseData.clear();
+        attributesMap.clear();
+
+        response.put("o-ran-smo-teiv-ran:AntennaCapability", List.of(responseData));
+        attributesMap.put("fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=1");
+        attributesMap.put("eUtranFqBands", List.of("123", "4564", "789"));
+        attributesMap.put("geranFqBands", List.of("123", "456", "789"));
+        attributesMap.put("nRFqBands", List.of("123", "456", "789"));
+        attributesMap.put("cmId", null);
+        responseData.put("attributes", attributesMap);
+        responseData.put("id", "5835F77BE9D4E102316BD59195F6370B");
+        responseData.put("sourceIds", Collections.EMPTY_LIST);
+
+        Assertions.assertEquals(response, underTest.getTopology(SchemaRegistry.getEntityTypeByName("AntennaCapability"),
+                "5835F77BE9D4E102316BD59195F6370B"));
+    }
+
+    @Test
+    void testGetAllRelationships_manyToOneAndOneToMany() {
+        List<Map<String, List<Object>>> mapsList = new ArrayList<>();
+        Map<String, Object> response = new HashMap<>();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/NRCellDU/B480427E8A0C0B8D994E437784BB382F/relationships").addPathParameters("eiid",
+                        "B480427E8A0C0B8D994E437784BB382F").addPathParameters("domain", "RAN").addPathParameters(
+                                "entityType", "NRCellDU").build();
+
+        paginationDTO1.setTotalSize(3);
+        response.putAll(new PaginationMetaData().getObjectList(paginationDTO1));
+
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/NRCellDU/NON_EXISTING/relationships").addPathParameters("eiid", "NON_EXISTING")
+                .addPathParameters("domain", "RAN").addPathParameters("entityType", "NRCellDU").build();
+
+        mapsList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "D3215E08570BE58339C7463626B50E37", "B480427E8A0C0B8D994E437784BB382F",
+                REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg=="))));
+
+        mapsList.add(Map.of("o-ran-smo-teiv-ran:SECTOR_GROUPS_NRCELLDU", List.of(generateResponse(
+                "F5128C172A70C4FCD4739650B06DE9E2", "B480427E8A0C0B8D994E437784BB382F",
+                REL_ID_PREFIX + "U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg=="))));
+
+        mapsList.add(Map.of("o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER", List.of(generateResponse(
+                "B480427E8A0C0B8D994E437784BB382F", "E49D942C16E0364E1E0788138916D70C",
+                REL_ID_PREFIX + "TlJDZWxsRFU6QjQ4MDQyN0U4QTBDMEI4RDk5NEU0Mzc3ODRCQjM4MkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM="))));
+
+        response.put(ITEMS, mapsList);
+
+        verifyResponse(response, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName("NRCellDU"),
+                SchemaRegistry.getRelationTypesByEntityName("NRCellDU"), "B480427E8A0C0B8D994E437784BB382F",
+                paginationDTO1));
+
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getAllRelationships(SchemaRegistry
+                .getEntityTypeByName("NRCellDU"), SchemaRegistry.getRelationTypesByEntityName("NRCellDU"), "NON_EXISTING",
+                paginationDTO2));
+    }
+
+    @Test
+    void testGetAllRelationships_manyToMany() {
+        Map<String, Object> response = new HashMap<>();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/GNBCUUPFunction/BFEEAC2CE60273CB0A78319CC201A7FE/relationships").addPathParameters(
+                        "eiid", "BFEEAC2CE60273CB0A78319CC201A7FE").addPathParameters("domain", "RAN").addPathParameters(
+                                "entityType", "GNBCUUPFunction").build();
+        paginationDTO1.setTotalSize(2);
+        response.putAll(new PaginationMetaData().getObjectList(paginationDTO1));
+
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/NRCellDU/NON_EXISTING/relationships").addPathParameters("eiid", "NON_EXISTING")
+                .addPathParameters("domain", "RAN").addPathParameters("entityType", "NRCellDU").build();
+
+        List<Map<String, List<Object>>> mapsList = new ArrayList<>();
+
+        mapsList.add(Map.of("o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", List.of(
+                generateResponse("BFEEAC2CE60273CB0A78319CC201A7FE", "AD42D90497E93D276215DF6D3B899E17",
+                        REL_ID_PREFIX + "R05CQ1VVUEZ1bmN0aW9uOkJGRUVBQzJDRTYwMjczQ0IwQTc4MzE5Q0MyMDFBN0ZFOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246QUQ0MkQ5MDQ5N0U5M0QyNzYyMTVERjZEM0I4OTlFMTc="))));
+
+        mapsList.add(Map.of("o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION", List.of(generateResponse(
+                "E64371CD4D12ED0CED200DD3A7591784", "BFEEAC2CE60273CB0A78319CC201A7FE",
+                REL_ID_PREFIX + "TWFuYWdlZEVsZW1lbnQ6RTY0MzcxQ0Q0RDEyRUQwQ0VEMjAwREQzQTc1OTE3ODQ6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246QkZFRUFDMkNFNjAyNzNDQjBBNzgzMTlDQzIwMUE3RkU="))));
+
+        response.put(ITEMS, mapsList);
+
+        verifyResponse(response, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName("GNBCUUPFunction"),
+                SchemaRegistry.getRelationTypesByEntityName("GNBCUUPFunction"), "BFEEAC2CE60273CB0A78319CC201A7FE",
+                paginationDTO1));
+
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getAllRelationships(SchemaRegistry
+                .getEntityTypeByName("GNBCUUPFunction"), SchemaRegistry.getRelationTypesByEntityName("GNBCUUPFunction"),
+                "NON_EXISTING", paginationDTO2));
+    }
+
+    @Test
+    void testGetAllRelationshipsManyToMany_filteredByRelationship() {
+        List<Map<String, List<Object>>> mapsList = new ArrayList<>();
+        Map<String, Object> response = new HashMap<>();
+
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/GNBCUUPFunction/BFEEAC2CE60273CB0A78319CC201A7FE/relationships").addPathParameters(
+                        "eiid", "BFEEAC2CE60273CB0A78319CC201A7FE").addPathParameters("domain", "RAN").addPathParameters(
+                                "entityType", "GNBCUUPFunction").build();
+        paginationDTO1.setTotalSize(1);
+        paginationDTO1.setQueryParameters(Map.of("relationshipType", "MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION"));
+
+        response.putAll(new PaginationMetaData().getObjectList(paginationDTO1));
+        mapsList.add(Map.of("o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION", List.of(generateResponse(
+                "E64371CD4D12ED0CED200DD3A7591784", "BFEEAC2CE60273CB0A78319CC201A7FE",
+                REL_ID_PREFIX + "TWFuYWdlZEVsZW1lbnQ6RTY0MzcxQ0Q0RDEyRUQwQ0VEMjAwREQzQTc1OTE3ODQ6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246QkZFRUFDMkNFNjAyNzNDQjBBNzgzMTlDQzIwMUE3RkU="))));
+        mapsList.add(Map.of("o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", List.of(
+                generateResponse("BFEEAC2CE60273CB0A78319CC201A7FE", "AD42D90497E93D276215DF6D3B899E17",
+                        REL_ID_PREFIX + "R05CQ1VVUEZ1bmN0aW9uOkJGRUVBQzJDRTYwMjczQ0IwQTc4MzE5Q0MyMDFBN0ZFOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246QUQ0MkQ5MDQ5N0U5M0QyNzYyMTVERjZEM0I4OTlFMTc="))));
+
+        response.put(ITEMS, List.of(mapsList.get(0)));
+        verifyResponse(response, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName("GNBCUUPFunction"), List
+                .of(SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION")),
+                "BFEEAC2CE60273CB0A78319CC201A7FE", paginationDTO1));
+
+        response.replace(ITEMS, List.of(mapsList.get(0)), List.of(mapsList.get(1)));
+        paginationDTO1.setQueryParameters(Map.of("relationshipType", "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION"));
+        response.putAll(new PaginationMetaData().getObjectList(paginationDTO1));
+        verifyResponse(response, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName("GNBCUUPFunction"), List
+                .of(SchemaRegistry.getRelationTypeByName("GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION")),
+                "BFEEAC2CE60273CB0A78319CC201A7FE", paginationDTO1));
+
+        paginationDTO1.setQueryParameters(Map.of("relationshipType", "NON_EXISTING"));
+        response.putAll(new PaginationMetaData().getObjectList(paginationDTO1));
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getAllRelationships(SchemaRegistry
+                .getEntityTypeByName("GNBCUUPFunction"), List.of(SchemaRegistry.getRelationTypeByName(
+                        "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION")), "NON_EXISTING", paginationDTO1));
+    }
+
+    @Test
+    void testGetAllRelationshipsConnectingSameEntity_filteredByRelationship() {
+        String idConnectingSameEntity = REL_ID_PREFIX + "QW50ZW5uYU1vZHVsZToyNzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpSRUFMSVNFRF9CWTpBbnRlbm5hTW9kdWxlOjI3OEEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==";
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN_EQUIPMENT/entities/AntennaModule/278A05C67D47D117C2DC5BDF5E00AE70/relationships")
+                .addPathParameters("eiid", "278A05C67D47D117C2DC5BDF5E00AE70").addPathParameters("domain", "RAN_EQUIPMENT")
+                .addPathParameters("entityType", "AntennaModule").build();
+        paginationDTO1.setTotalSize(1);
+        paginationDTO1.setQueryParameters(Map.of("relationshipType", "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE"));
+
+        Map<String, Object> response = new HashMap<>(new PaginationMetaData().getObjectList(paginationDTO1));
+        Map<String, List<Object>> mapsList = Map.of("o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", List
+                .of(generateResponse("278A05C67D47D117C2DC5BDF5E00AE70", "279A05C67D47D117C2DC5BDF5E00AE70",
+                        idConnectingSameEntity)));
+        response.put(ITEMS, List.of(mapsList));
+
+        RelationType relSameEntity = SchemaRegistry.getRelationTypeByName("ANTENNAMODULE_REALISED_BY_ANTENNAMODULE");
+        EntityType entity = SchemaRegistry.getEntityTypeByName("AntennaModule");
+
+        Assertions.assertNotNull(relSameEntity);
+        Assertions.assertNotNull(entity);
+
+        verifyResponse(response, underTest.getAllRelationships(entity, List.of(relSameEntity),
+                "278A05C67D47D117C2DC5BDF5E00AE70", paginationDTO1));
+
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getAllRelationships(entity, List.of(
+                relSameEntity), "NON_EXISTING", paginationDTO1));
+    }
+
+    @Test
+    void testGetRelationshipWithSpecifiedId() {
+        String idOneToMany = REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==";
+        Map<String, List<Object>> relationshipOneToMany = Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List
+                .of(generateResponse("D3215E08570BE58339C7463626B50E37", "98C3A4591A37718E1330F0294E23B62A", idOneToMany,
+                        Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipOneToMany, underTest.getRelationshipWithSpecifiedId(idOneToMany, SchemaRegistry
+                .getRelationTypeByName("GNBDUFUNCTION_PROVIDES_NRCELLDU")));
+
+        String idManyToOne = REL_ID_PREFIX + "Tm9kZUNsdXN0ZXI6MDE1QzJEREJEN0FDNzIyQjM0RUQ2QTIwRURFRUI5QzM6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=";
+        Map<String, List<Object>> relationshipManyToOne = Map.of("o-ran-smo-teiv-cloud:NODECLUSTER_LOCATED_AT_CLOUDSITE",
+                List.of(generateResponse("015C2DDBD7AC722B34ED6A20EDEEB9C3", "16EE17AE89DF11B69E94B3F6827C2C0E",
+                        idManyToOne, Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipManyToOne, underTest.getRelationshipWithSpecifiedId(idManyToOne, SchemaRegistry
+                .getRelationTypeByName("NODECLUSTER_LOCATED_AT_CLOUDSITE")));
+
+        String idManyToMany = REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE";
+        Map<String, List<Object>> relationshipManyToMany = Map.of(
+                "o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", List.of(generateResponse(
+                        "4CFF136200A2DE36205A13559C55DB2A", "C549905CF3CC890CE5746C5E10ACF00D", idManyToMany,
+                        Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipManyToMany, underTest.getRelationshipWithSpecifiedId(idManyToMany,
+                SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION")));
+
+        String idConnectingSameEntity = REL_ID_PREFIX + "QW50ZW5uYU1vZHVsZToyNzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpSRUFMSVNFRF9CWTpBbnRlbm5hTW9kdWxlOjI3OEEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==";
+        Map<String, List<Object>> relationshipConnectingSameEntity = Map.of(
+                "o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", List.of(generateResponse(
+                        "278A05C67D47D117C2DC5BDF5E00AE70", "279A05C67D47D117C2DC5BDF5E00AE70", idConnectingSameEntity,
+                        Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipConnectingSameEntity, underTest.getRelationshipWithSpecifiedId(
+                idConnectingSameEntity, SchemaRegistry.getRelationTypeByName("ANTENNAMODULE_REALISED_BY_ANTENNAMODULE")));
+
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getRelationshipWithSpecifiedId("NOT_EXISTING",
+                SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_PROVIDES_NRCELLDU")));
+    }
+
+    @Test
+    void testGetRelationshipsByType() {
+        Map<String, Object> oneToManyResult = new HashMap<>();
+        Map<String, Object> manyToOneResult = new HashMap<>();
+        Map<String, Object> manyToManyResult = new HashMap<>();
+
+        Map<String, Object> oneToManyQueryMap = new HashMap<>();
+        oneToManyQueryMap.put("query", Map.of("scopeFilter", "/attributes[@cellLocalId=2]"));
+        oneToManyResult.putAll(oneToManyQueryMap);
+
+        oneToManyResult.put("items", List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(
+                generateResponse("D3215E08570BE58339C7463626B50E37", "F9546E82313AC1D5E690DCD7BE55606F",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpGOTU0NkU4MjMxM0FDMUQ1RTY5MERDRDdCRTU1NjA2Rg==")))));
+
+        PaginationMetaData metadataOneToMany = new PaginationMetaData();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/attributes[@cellLocalId=2]").build();
+        paginationDTO1.setTotalSize(1);
+        oneToManyResult.putAll(metadataOneToMany.getObjectList(paginationDTO1));
+
+        Map<String, Object> manyToOneQueryMap = new HashMap<>();
+        manyToOneQueryMap.put("query", Map.of("scopeFilter", "/id[@id=\"719BD5C7CD8A939D76A83DA95DA45C01\"]"));
+        manyToOneResult.putAll(manyToOneQueryMap);
+
+        manyToOneResult.put("items", List.of(Map.of("o-ran-smo-teiv-cloud:CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE",
+                List.of(generateResponse("719BD5C7CD8A939D76A83DA95DA45C01", "1C02E96B2AAE036C7AE404BC38C308E0",
+                        REL_ID_PREFIX + "Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6MUMwMkU5NkIyQUFFMDM2QzdBRTQwNEJDMzhDMzA4RTA=")))));
+
+        PaginationMetaData metadataManyToOne = new PaginationMetaData();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/id[@id=\"719BD5C7CD8A939D76A83DA95DA45C01\"]").build();
+        paginationDTO2.setTotalSize(1);
+        manyToOneResult.putAll(metadataManyToOne.getObjectList(paginationDTO2));
+
+        Map<String, Object> manyToManyQueryMap = new HashMap<>();
+        manyToManyQueryMap.put("query", Map.of("scopeFilter",
+                "/CloudNativeApplication/id[@id=\"C549905CF3CC890CE5746C5E10ACF00D\"]"));
+        manyToManyResult.putAll(manyToManyQueryMap);
+
+        manyToManyResult.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", List.of(generateResponse(
+                        "4CFF136200A2DE36205A13559C55DB2A", "C549905CF3CC890CE5746C5E10ACF00D",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE")))));
+
+        PaginationMetaData metadataManyToMany = new PaginationMetaData();
+        PaginationDTO paginationDTO3 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/CloudNativeApplication/id[@id=\"C549905CF3CC890CE5746C5E10ACF00D\"]").build();
+        paginationDTO3.setTotalSize(1);
+        manyToManyResult.putAll(metadataManyToMany.getObjectList(paginationDTO3));
+
+        RelationType oneToMany = SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        RelationType manyToOne = SchemaRegistry.getRelationTypeByName("CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE");
+        RelationType manyToMany = SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+
+        verifyResponse(oneToManyResult, underTest.getRelationshipsByType(oneToMany, "/attributes[@cellLocalId=2]",
+                PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter", "/attributes[@cellLocalId=2]")
+                        .build()));
+
+        verifyResponse(manyToOneResult, underTest.getRelationshipsByType(manyToOne,
+                "/id[@id=\"719BD5C7CD8A939D76A83DA95DA45C01\"]", PaginationDTO.builder().offset(0).limit(5)
+                        .addQueryParameters("scopeFilter", "/id[@id=\"719BD5C7CD8A939D76A83DA95DA45C01\"]").build()));
+
+        verifyResponse(manyToManyResult, underTest.getRelationshipsByType(manyToMany,
+                "/CloudNativeApplication/id[@id=\"C549905CF3CC890CE5746C5E10ACF00D\"]", PaginationDTO.builder().offset(0)
+                        .limit(5).addQueryParameters("scopeFilter",
+                                "/CloudNativeApplication/id[@id=\"C549905CF3CC890CE5746C5E10ACF00D\"]").build()));
+
+        assertThatThrownBy(() -> underTest.getRelationshipsByType(oneToMany, "/attributes[@celllocalid=2]", PaginationDTO
+                .builder().offset(0).limit(5).build())).isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+        Assertions.assertDoesNotThrow(() -> underTest.getRelationshipsByType(oneToMany, null, PaginationDTO.builder()
+                .offset(0).limit(5).build()));
+        Assertions.assertDoesNotThrow(() -> underTest.getRelationshipsByType(oneToMany,
+                "/GNBDUFunction/attributes[contains (@fdn, \"GNBDUFunction=16\")]", PaginationDTO.builder().offset(0).limit(
+                        5).build()));
+        Assertions.assertDoesNotThrow(() -> underTest.getRelationshipsByType(manyToMany,
+                "/CloudNativeApplication/attributes[@name=\"Example Cloud App/10\"] | /GNBDUFunction/id[@id=\"5A548EA9D166341776CA0695837E55D8\"]",
+                PaginationDTO.builder().offset(0).limit(5).build()));
+    }
+
+    @Test
+    void testGetRelationshipsByType_relConnectingSameEntity() {
+
+        Map<String, Object> resultOneScopeFilter = new HashMap<>();
+        Map<String, Object> resultTwoScopeFilter = new HashMap<>();
+        RelationType relationshipConnectingSameEntity = SchemaRegistry.getRelationTypeByName(
+                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE");
+        String idConnectingSameEntity = REL_ID_PREFIX + "QW50ZW5uYU1vZHVsZToyNzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpSRUFMSVNFRF9CWTpBbnRlbm5hTW9kdWxlOjI3OEEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==";
+        PaginationMetaData metadataRelConnectingSameEntity = new PaginationMetaData();
+
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]").build();
+        paginationDTO1.setTotalSize(1);
+        resultOneScopeFilter.putAll(metadataRelConnectingSameEntity.getObjectList(paginationDTO1));
+
+        Map<String, Object> queryMapOneScope = new HashMap<>();
+        queryMapOneScope.put("query", Map.of("scopeFilter", "/AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]"));
+        resultOneScopeFilter.putAll(queryMapOneScope);
+
+        resultOneScopeFilter.put("items", List.of(Map.of("o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE",
+                List.of(generateResponse("278A05C67D47D117C2DC5BDF5E00AE70", "279A05C67D47D117C2DC5BDF5E00AE70",
+                        idConnectingSameEntity)))));
+
+        verifyResponse(resultOneScopeFilter, underTest.getRelationshipsByType(relationshipConnectingSameEntity,
+                "/AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]", PaginationDTO.builder().offset(0).limit(5)
+                        .addQueryParameters("scopeFilter", "/AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]")
+                        .build()));
+
+        Map<String, Object> queryMapTwoScopes = new HashMap<>();
+        queryMapTwoScopes.put("query", Map.of("scopeFilter",
+                "/AntennaModule/id[@id=\"278A05C67D47D117C2DC5BDF5E00AE70\"] | /AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]"));
+        resultTwoScopeFilter.putAll(queryMapTwoScopes);
+
+        resultTwoScopeFilter.put("items", List.of(Map.of("o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE",
+                List.of(generateResponse("278A05C67D47D117C2DC5BDF5E00AE70", "279A05C67D47D117C2DC5BDF5E00AE70",
+                        idConnectingSameEntity)))));
+
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/AntennaModule/id[@id=\"278A05C67D47D117C2DC5BDF5E00AE70\"] | /AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]")
+                .build();
+        paginationDTO2.setTotalSize(1);
+        resultTwoScopeFilter.putAll(metadataRelConnectingSameEntity.getObjectList(paginationDTO2));
+
+        verifyResponse(resultTwoScopeFilter, underTest.getRelationshipsByType(relationshipConnectingSameEntity,
+                "/AntennaModule/id[@id=\"278A05C67D47D117C2DC5BDF5E00AE70\"]| /AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]",
+                PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                        "/AntennaModule/id[@id=\"278A05C67D47D117C2DC5BDF5E00AE70\"] | /AntennaModule/id[@id=\"279A05C67D47D117C2DC5BDF5E00AE70\"]")
+                        .build()));
+
+    }
+
+    @Test
+    void testGetTopologyByType() {
+        Map<String, Object> result = new HashMap<>();
+        Map<String, Object> queryMap = new HashMap<>();
+
+        queryMap.put("query", Map.of("targetFilter", "/attributes(fdn)", "scopeFilter",
+                "/attributes[contains(@fdn, \"13\")] | /id[@id='5A3085C3400C3096E2ED2321452766B1']"));
+
+        result.putAll(queryMap);
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains/RAN/entities/GNBDUFunction").offset(0)
+                .limit(2).addQueryParameters("targetFilter", "/attributes(fdn)").addQueryParameters("scopeFilter",
+                        "/attributes[contains(@fdn, \"13\")] | /id[@id='5A3085C3400C3096E2ED2321452766B1']").build();
+        paginationDTO.setTotalSize(2);
+        result.putAll(new PaginationMetaData().getObjectList(paginationDTO));
+
+        result.put("items", List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of(ATTRIBUTES, Map.of("fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=13"), "id",
+                "25E690E22BDA90B9C4FEE1F083CBA597"), Map.of(ATTRIBUTES, Map.of("fdn",
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=14"),
+                        "id", "5A3085C3400C3096E2ED2321452766B1")))));
+
+        verifyResponse(result, underTest.getTopologyByType("GNBDUFunction", "/attributes(fdn)",
+                "/attributes[contains(@fdn, \"13\")] | /id[@id='5A3085C3400C3096E2ED2321452766B1']", PaginationDTO.builder()
+                        .offset(0).limit(2).basePath("/domains/RAN/entities/GNBDUFunction").addQueryParameters(
+                                "targetFilter", "/attributes(fdn)").addQueryParameters("scopeFilter",
+                                        "/attributes[contains(@fdn, \"13\")] | /id[@id='5A3085C3400C3096E2ED2321452766B1']")
+                        .build()));
+
+        Assertions.assertThrows(TiesPathException.class, () -> underTest.getTopologyByType("GNBDUFunction",
+                "/attributes(fdn)", "/attributes[contains(@fdn, \"1000493\")] ; /attributes[@gNBId=4000259]", PaginationDTO
+                        .builder().offset(0).limit(2).build()));
+    }
+
+    @Test
+    void testGetEntitiesByDomain() {
+        Map<String, Object> reference1 = new HashMap<>();
+        Map<String, Object> query = new HashMap<>();
+
+        query.put("targetFilter", "/attributes(azimuth)");
+        query.put("scopeFilter", "/attributes[@azimuth=3]");
+
+        PaginationMetaData pmd1 = new PaginationMetaData();
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains/RAN").offset(0).limit(5)
+                .addQueryParameters("targetFilter", "/attributes(azimuth)").addQueryParameters("scopeFilter",
+                        "/attributes[@azimuth=3]").build();
+        paginationDTO.setTotalSize(1);
+        reference1.putAll(pmd1.getObjectList(paginationDTO));
+        reference1.put("query", query);
+
+        BigDecimal azimuth = new BigDecimal(3);
+        reference1.put("items", List.of(Map.of("o-ran-smo-teiv-ran:Sector", List.of(Map.of("id",
+                "ADB1BAAC878C0BEEFE3175C60F44BB1D", ATTRIBUTES, Map.of("azimuth", azimuth))))));
+        verifyResponse(reference1, underTest.getEntitiesByDomain("RAN", "/attributes(azimuth)", "/attributes[@azimuth=3]",
+                paginationDTO));
+
+        Map<String, Object> reference2 = new HashMap<>();
+        Map<String, Object> query2 = new HashMap<>();
+
+        query2.put("targetFilter", "/id");
+        query2.put("scopeFilter", "/id[contains(@id,\"F1407\")]");
+
+        PaginationMetaData pmd2 = new PaginationMetaData();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().basePath("/domains/RAN").offset(0).limit(5)
+                .addQueryParameters("targetFilter", "/id").addQueryParameters("scopeFilter", "/id[contains(@id,\"F1407\")]")
+                .build();
+        paginationDTO2.setTotalSize(1);
+        pmd2.getObjectList(paginationDTO2);
+
+        reference2.put("query", query2);
+        PaginationDTO paginationDTO3 = PaginationDTO.builder().basePath("/domains/RAN").offset(0).limit(5)
+                .addQueryParameters("targetFilter", "/id").addQueryParameters("scopeFilter", "/id[contains(@id,\"F1407\")]")
+                .build();
+        paginationDTO3.setTotalSize(1);
+        reference2.putAll(pmd2.getObjectList(paginationDTO3));
+
+        reference2.put("items", List.of(Map.of("o-ran-smo-teiv-ran:Sector", List.of(Map.of("id",
+                "2F445AA5744FA3D230FD6838531F1407")))));
+
+        verifyResponse(reference2, underTest.getEntitiesByDomain("RAN", "/id", "/id[contains(@id,\"F1407\")]",
+                paginationDTO2));
+
+        Map<String, Object> reference3 = new HashMap<>();
+        Map<String, Object> query3 = new HashMap<>();
+
+        query3.put("targetFilter", "/GNBDUFunction/attributes/fdn");
+        query3.put("scopeFilter", "/GNBDUFunction/attributes[contains(@fdn,\"GNBDUFunction=10\")]");
+
+        PaginationMetaData pmd3 = new PaginationMetaData();
+
+        reference3.put("query", query3);
+        PaginationDTO paginationDTO4 = PaginationDTO.builder().basePath("/domains/RAN").offset(0).limit(5)
+                .addQueryParameters("targetFilter", "/GNBDUFunction/attributes/fdn").addQueryParameters("scopeFilter",
+                        "/GNBDUFunction/attributes[contains(@fdn,\"GNBDUFunction=10\")]").build();
+        paginationDTO4.setTotalSize(1);
+        reference3.putAll(pmd3.getObjectList(paginationDTO4));
+
+        reference3.put("items", List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of("id",
+                "1050570EBB1315E1AE7A9FD5E1400A00", ATTRIBUTES, Map.of("fdn",
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=10"))))));
+
+        verifyResponse(reference3, underTest.getEntitiesByDomain("RAN", "/GNBDUFunction/attributes/fdn",
+                "/GNBDUFunction/attributes[contains(@fdn,\"GNBDUFunction=10\")]", paginationDTO4));
+
+        Object result = underTest.getEntitiesByDomain("OAM_TO_RAN", "/id", "", PaginationDTO.builder().offset(0).limit(500)
+                .build());
+        Assertions.assertEquals(10, ((Map) ((List) ((HashMap) result).get("items")).get(0)).size());
+        Assertions.assertTrue(((Map) ((List) ((HashMap) result).get("items")).get(0)).containsKey(
+                "o-ran-smo-teiv-oam:ManagedElement"));
+
+        Assertions.assertTrue(((Map) ((List) ((HashMap) result).get("items")).get(0)).containsKey(
+                "o-ran-smo-teiv-ran:GNBDUFunction"));
+    }
+
+    @Test
+    void testGetTopologyWithLongNames() {
+        Map<String, List<Object>> response = new HashMap<>();
+        Map<String, Object> responseData = new HashMap<>();
+        Map<String, Object> attributesMap = new HashMap<>();
+        response.put("o-ran-smo-teiv-ran:GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", List.of(
+                responseData));
+        attributesMap.put("gNBDUId", null);
+        attributesMap.put("fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=16");
+        attributesMap.put("dUpLMNId", Map.of("mcc", "456", "mnc", "82"));
+        attributesMap.put("gNBId", 16L);
+        attributesMap.put("gNBIdLength", 2L);
+        attributesMap.put("cmId", null);
+        responseData.put("attributes", attributesMap);
+        responseData.put("id", "5A548EA9D166341776CA0695837E55D8");
+        responseData.put("sourceIds", Collections.EMPTY_LIST);
+
+        Assertions.assertEquals(response, underTest.getTopology(SchemaRegistry.getEntityTypeByName(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"), "5A548EA9D166341776CA0695837E55D8"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getTopology(SchemaRegistry.getEntityTypeByName(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"), "-1"));
+    }
+
+    @Test
+    void testGetAllRelationshipsWithLongNames_manyToOne_oneToMany_manyToMany() {
+        Map<String, Object> response = new HashMap<>();
+        List<Map<String, List<Object>>> mapsList = new ArrayList<>();
+
+        PaginationDTO paginationDTO = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/4CFF136200A2DE36205A13559C55DB2A/relationships")
+                .addPathParameters("eiid", "4CFF136200A2DE36205A13559C55DB2A").addPathParameters("domain", "RAN")
+                .addPathParameters("entityType", "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn")
+                .build();
+        paginationDTO.setTotalSize(6);
+        response.putAll(new PaginationMetaData().getObjectList(paginationDTO));
+
+        mapsList.add(Map.of("o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN",
+                List.of(generateResponse("8D51EFC759166044DACBCA63C4EDFC51", "4CFF136200A2DE36205A13559C55DB2A",
+                        REL_ID_PREFIX + "TWFuYWdlZEVsZW1lbnQ6OEQ1MUVGQzc1OTE2NjA0NERBQ0JDQTYzQzRFREZDNTE6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjRDRkYxMzYyMDBBMkRFMzYyMDVBMTM1NTlDNTVEQjJB"))));
+
+        mapsList.add(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU", List.of(
+                generateResponse("4CFF136200A2DE36205A13559C55DB2A", "76E9F605D4F37330BF0B505E94F64F11",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo3NkU5RjYwNUQ0RjM3MzMwQkYwQjUwNUU5NEY2NEYxMQ=="),
+                generateResponse("4CFF136200A2DE36205A13559C55DB2A", "67A1BDA10B5AF43028D07C7BE5CB1AE2",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo2N0ExQkRBMTBCNUFGNDMwMjhEMDdDN0JFNUNCMUFFMg=="),
+                generateResponse("4CFF136200A2DE36205A13559C55DB2A", "B3B0A1939EFCA654A37005B6A7F24BD7",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpCM0IwQTE5MzlFRkNBNjU0QTM3MDA1QjZBN0YyNEJENw=="),
+                generateResponse("4CFF136200A2DE36205A13559C55DB2A", "F26F279E91D0941DB4F646E707EA403A",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpGMjZGMjc5RTkxRDA5NDFEQjRGNjQ2RTcwN0VBNDAzQQ=="))));
+
+        mapsList.add(Map.of("o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN",
+                List.of(generateResponse("4CFF136200A2DE36205A13559C55DB2A", "C549905CF3CC890CE5746C5E10ACF00D",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE"))));
+
+        response.put(ITEMS, mapsList);
+
+        verifyResponse(response, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"), SchemaRegistry
+                        .getRelationTypesByEntityName("GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"),
+                "4CFF136200A2DE36205A13559C55DB2A", paginationDTO));
+
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getAllRelationships(SchemaRegistry
+                .getEntityTypeByName("GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"), SchemaRegistry
+                        .getRelationTypesByEntityName("GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"),
+                "NON_EXISTING", paginationDTO));
+    }
+
+    @Test
+    void testGetAllRelationshipsWithLongNames_filteredByRelationship() {
+        List<Map<String, List<Object>>> mapsList = new ArrayList<>();
+
+        //One_To_One
+        Map<String, Object> expectedResponse1 = new HashMap<>();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN_OAM/entities/ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt/45EF31D8A1FD624D7276390A1215BFC3/relationships")
+                .addPathParameters("eiid", "45EF31D8A1FD624D7276390A1215BFC3").addPathParameters("domain", "RAN")
+                .addPathParameters("entityType", "ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt")
+                .build();
+        paginationDTO1.setTotalSize(1);
+        paginationDTO1.setQueryParameters(Map.of("relationshipType",
+                "MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM"));
+        expectedResponse1.putAll(new PaginationMetaData().getObjectList(paginationDTO1));
+        mapsList.add(Map.of("o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM",
+                List.of(generateResponse("45EF31D8A1FD624D7276390A1215BFC3", "C4E311A55666726FD9FE25CA572AFAF9",
+                        REL_ID_PREFIX + "TWFuYWdlZEVsZW1lbnQ6NDVFRjMxRDhBMUZENjI0RDcyNzYzOTBBMTIxNUJGQzM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06QzRFMzExQTU1NjY2NzI2RkQ5RkUyNUNBNTcyQUZBRjk="))));
+        expectedResponse1.put(ITEMS, List.of(mapsList.get(0)));
+        verifyResponse(expectedResponse1, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName(
+                "ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt"), List.of(SchemaRegistry
+                        .getRelationTypeByName("MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM")),
+                "45EF31D8A1FD624D7276390A1215BFC3", paginationDTO1));
+
+        //One_To_Many
+        Map<String, Object> expectedResponse2 = new HashMap<>();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/45EF31D8A1FD624D7276390A1215BFC3/relationships")
+                .addPathParameters("eiid", "45EF31D8A1FD624D7276390A1215BFC3").addPathParameters("domain", "RAN")
+                .addPathParameters("entityType", "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn")
+                .build();
+        paginationDTO2.setTotalSize(1);
+        paginationDTO2.setQueryParameters(Map.of("relationshipType",
+                "MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN"));
+        expectedResponse2.putAll(new PaginationMetaData().getObjectList(paginationDTO2));
+        mapsList.add(Map.of("o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN",
+                List.of(generateResponse("8D51EFC759166044DACBCA63C4EDFC51", "4CFF136200A2DE36205A13559C55DB2A",
+                        REL_ID_PREFIX + "TWFuYWdlZEVsZW1lbnQ6OEQ1MUVGQzc1OTE2NjA0NERBQ0JDQTYzQzRFREZDNTE6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjRDRkYxMzYyMDBBMkRFMzYyMDVBMTM1NTlDNTVEQjJB"))));
+        expectedResponse2.put(ITEMS, List.of(mapsList.get(1)));
+        verifyResponse(expectedResponse2, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"), List.of(SchemaRegistry
+                        .getRelationTypeByName("MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN")),
+                "4CFF136200A2DE36205A13559C55DB2A", paginationDTO2));
+
+        //Many_To_One
+        Map<String, Object> expectedResponse3 = new HashMap<>();
+        PaginationDTO paginationDTO3 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN_CLOUD/entities/Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/719BD5C7CD8A939D76A83DA95DA45C01/relationships")
+                .addPathParameters("eiid", "719BD5C7CD8A939D76A83DA95DA45C01").addPathParameters("domain", "RAN_CLOUD")
+                .addPathParameters("entityType", "Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
+                .build();
+        paginationDTO3.setTotalSize(1);
+        paginationDTO3.setQueryParameters(Map.of("relationshipType",
+                "CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE"));
+        expectedResponse3.putAll(new PaginationMetaData().getObjectList(paginationDTO3));
+        mapsList.add(Map.of("o-ran-smo-teiv-cloud:CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE", List
+                .of(generateResponse("719BD5C7CD8A939D76A83DA95DA45C01", "1C02E96B2AAE036C7AE404BC38C308E0",
+                        REL_ID_PREFIX + "Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6MUMwMkU5NkIyQUFFMDM2QzdBRTQwNEJDMzhDMzA4RTA="))));
+        expectedResponse3.put(ITEMS, List.of(mapsList.get(2)));
+        verifyResponse(expectedResponse3, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName(
+                "Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), List.of(SchemaRegistry
+                        .getRelationTypeByName("CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE")),
+                "1C02E96B2AAE036C7AE404BC38C308E0", paginationDTO3));
+
+        //Many_To_Many
+        Map<String, Object> expectedResponse4 = new HashMap<>();
+        PaginationDTO paginationDTO4 = PaginationDTO.builder().offset(0).limit(100).basePath(
+                "/domains/RAN/entities/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/4CFF136200A2DE36205A13559C55DB2A/relationships")
+                .addPathParameters("eiid", "4CFF136200A2DE36205A13559C55DB2A").addPathParameters("domain", "CLOUD_TO_RAN")
+                .addPathParameters("entityType", "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn")
+                .build();
+        paginationDTO4.setTotalSize(1);
+        paginationDTO4.setQueryParameters(Map.of("relationshipType",
+                "GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN"));
+        expectedResponse4.putAll(new PaginationMetaData().getObjectList(paginationDTO4));
+        mapsList.add(Map.of("o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN",
+                List.of(generateResponse("4CFF136200A2DE36205A13559C55DB2A", "C549905CF3CC890CE5746C5E10ACF00D",
+                        REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE"))));
+        expectedResponse4.put(ITEMS, List.of(mapsList.get(3)));
+        verifyResponse(expectedResponse4, underTest.getAllRelationships(SchemaRegistry.getEntityTypeByName(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"), List.of(SchemaRegistry
+                        .getRelationTypeByName("GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN")),
+                "4CFF136200A2DE36205A13559C55DB2A", paginationDTO4));
+
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getAllRelationships(SchemaRegistry
+                .getEntityTypeByName("GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"), List.of(
+                        SchemaRegistry.getRelationTypeByName(
+                                "GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN")), "NON_EXISTING",
+                paginationDTO4));
+    }
+
+    @Test
+    void testGetRelationshipWithSpecifiedIdWithLongNames() {
+        String idOneToOne = REL_ID_PREFIX + "TWFuYWdlZEVsZW1lbnQ6NDVFRjMxRDhBMUZENjI0RDcyNzYzOTBBMTIxNUJGQzM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06QzRFMzExQTU1NjY2NzI2RkQ5RkUyNUNBNTcyQUZBRjk=";
+        Map<String, List<Object>> relationshipOneToOne = Map.of(
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM", List.of(
+                        generateResponse("45EF31D8A1FD624D7276390A1215BFC3", "C4E311A55666726FD9FE25CA572AFAF9", idOneToOne,
+                                Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipOneToOne, underTest.getRelationshipWithSpecifiedId(idOneToOne, SchemaRegistry
+                .getRelationTypeByName("MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM")));
+
+        String idOneToMany = REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==";
+        Map<String, List<Object>> relationshipOneToMany = Map.of(
+                "o-ran-smo-teiv-ran:GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU", List.of(
+                        generateResponse("D3215E08570BE58339C7463626B50E37", "98C3A4591A37718E1330F0294E23B62A",
+                                idOneToMany, Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipOneToMany, underTest.getRelationshipWithSpecifiedId(idOneToMany, SchemaRegistry
+                .getRelationTypeByName("GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU")));
+
+        String idManyToOne = REL_ID_PREFIX + "Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6MUMwMkU5NkIyQUFFMDM2QzdBRTQwNEJDMzhDMzA4RTA=";
+        Map<String, List<Object>> relationshipManyToOne = Map.of(
+                "o-ran-smo-teiv-cloud:CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE", List.of(
+                        generateResponse("719BD5C7CD8A939D76A83DA95DA45C01", "1C02E96B2AAE036C7AE404BC38C308E0",
+                                idManyToOne, Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipManyToOne, underTest.getRelationshipWithSpecifiedId(idManyToOne, SchemaRegistry
+                .getRelationTypeByName("CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE")));
+
+        String idManyToMany = REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE";
+        Map<String, List<Object>> relationshipManyToMany = Map.of(
+                "o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN", List.of(
+                        generateResponse("4CFF136200A2DE36205A13559C55DB2A", "C549905CF3CC890CE5746C5E10ACF00D",
+                                idManyToMany, Collections.EMPTY_LIST)));
+
+        Assertions.assertEquals(relationshipManyToMany, underTest.getRelationshipWithSpecifiedId(idManyToMany,
+                SchemaRegistry.getRelationTypeByName("GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN")));
+
+        Assertions.assertThrowsExactly(TiesException.class, () -> underTest.getRelationshipWithSpecifiedId("NOT_EXISTING",
+                SchemaRegistry.getRelationTypeByName("GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU")));
+    }
+
+    @Test
+    void testGetRelationshipsByTypeWithLongNames() {
+        Map<String, Object> oneToOneResult = new HashMap<>();
+        Map<String, Object> oneToManyResult = new HashMap<>();
+        Map<String, Object> manyToOneResult = new HashMap<>();
+        Map<String, Object> manyToManyResult = new HashMap<>();
+
+        oneToOneResult.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM", List.of(
+                        generateResponse("45EF31D8A1FD624D7276390A1215BFC3", "C4E311A55666726FD9FE25CA572AFAF9",
+                                REL_ID_PREFIX + "TWFuYWdlZEVsZW1lbnQ6NDVFRjMxRDhBMUZENjI0RDcyNzYzOTBBMTIxNUJGQzM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06QzRFMzExQTU1NjY2NzI2RkQ5RkUyNUNBNTcyQUZBRjk=")))));
+        PaginationMetaData metadataOneToOne = new PaginationMetaData();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(5).build();
+        paginationDTO1.setTotalSize(1);
+        oneToOneResult.putAll(metadataOneToOne.getObjectList(paginationDTO1));
+
+        oneToManyResult.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-ran:GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU", List.of(
+                        generateResponse("D3215E08570BE58339C7463626B50E37", "F9546E82313AC1D5E690DCD7BE55606F",
+                                REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpGOTU0NkU4MjMxM0FDMUQ1RTY5MERDRDdCRTU1NjA2Rg==")))));
+        PaginationMetaData metadataOneToMany = new PaginationMetaData();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/attributes[@cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd=2]").build();
+        paginationDTO2.setTotalSize(1);
+        oneToManyResult.putAll(metadataOneToMany.getObjectList(paginationDTO2));
+
+        manyToOneResult.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-cloud:CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE", List.of(
+                        generateResponse("719BD5C7CD8A939D76A83DA95DA45C01", "1C02E96B2AAE036C7AE404BC38C308E0",
+                                REL_ID_PREFIX + "Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6MUMwMkU5NkIyQUFFMDM2QzdBRTQwNEJDMzhDMzA4RTA=")))));
+        PaginationMetaData metadataManyToOne = new PaginationMetaData();
+        PaginationDTO paginationDTO3 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/id[@id=\"719BD5C7CD8A939D76A83DA95DA45C01\"]").build();
+        paginationDTO3.setTotalSize(1);
+        manyToOneResult.putAll(metadataManyToOne.getObjectList(paginationDTO3));
+
+        manyToManyResult.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN", List.of(
+                        generateResponse("4CFF136200A2DE36205A13559C55DB2A", "C549905CF3CC890CE5746C5E10ACF00D",
+                                REL_ID_PREFIX + "R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE")))));
+        PaginationMetaData metadataManyToMany = new PaginationMetaData();
+        PaginationDTO paginationDTO4 = PaginationDTO.builder().offset(0).limit(5).addQueryParameters("scopeFilter",
+                "/CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/id[@id=\"C549905CF3CC890CE5746C5E10ACF00D\"] | /GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/id[@id=\"4CFF136200A2DE36205A13559C55DB2A\"]")
+                .build();
+        paginationDTO4.setTotalSize(1);
+        manyToManyResult.putAll(metadataManyToMany.getObjectList(paginationDTO4));
+
+        RelationType oneToOne = SchemaRegistry.getRelationTypeByName(
+                "MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM");
+        RelationType oneToMany = SchemaRegistry.getRelationTypeByName(
+                "GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU");
+        RelationType manyToOne = SchemaRegistry.getRelationTypeByName(
+                "CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE");
+        RelationType manyToMany = SchemaRegistry.getRelationTypeByName(
+                "GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN");
+
+        verifyResponse(oneToOneResult, underTest.getRelationshipsByType(oneToOne, null, paginationDTO1));
+        verifyResponse(oneToManyResult, underTest.getRelationshipsByType(oneToMany,
+                "/attributes[@cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd=2]", paginationDTO2));
+        verifyResponse(manyToOneResult, underTest.getRelationshipsByType(manyToOne,
+                "/id[@id=\"719BD5C7CD8A939D76A83DA95DA45C01\"]", paginationDTO3));
+        verifyResponse(manyToManyResult, underTest.getRelationshipsByType(manyToMany,
+                "/CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/id[@id=\"C549905CF3CC890CE5746C5E10ACF00D\"] | /GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/id[@id=\"4CFF136200A2DE36205A13559C55DB2A\"]",
+                paginationDTO4));
+
+        assertThatThrownBy(() -> underTest.getRelationshipsByType(oneToMany, "/attributes[@celllocalid=2]", PaginationDTO
+                .builder().offset(0).limit(5).build())).isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+        Assertions.assertDoesNotThrow(() -> underTest.getRelationshipsByType(oneToMany, null, PaginationDTO.builder()
+                .offset(0).limit(5).build()));
+        Assertions.assertDoesNotThrow(() -> underTest.getRelationshipsByType(oneToMany,
+                "/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn, \"GNBDUFunction=16\")]",
+                PaginationDTO.builder().offset(0).limit(5).build()));
+        Assertions.assertDoesNotThrow(() -> underTest.getRelationshipsByType(manyToMany,
+                "/CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes[@name=\"Example Cloud App/10\"] | /GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/id[@id=\"5A548EA9D166341776CA0695837E55D8\"]",
+                PaginationDTO.builder().offset(0).limit(5).build()));
+    }
+
+    @Test
+    void testGetRelationshipsByTypeWithLongNames_relConnectingSameEntity() {
+        Map<String, Object> sameEntityOneToOneResult = new HashMap<>();
+        Map<String, Object> sameEntityOneToManyResult = new HashMap<>();
+
+        // Rel connectingSameEntity ONE_TO_ONE
+        RelationType relSameEntityOneToOne = SchemaRegistry.getRelationTypeByName(
+                "ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE");
+        sameEntityOneToOneResult.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE", List.of(
+                        generateResponse("478A05C67D47D117C2DC5BDF5E00AE70", "479A05C67D47D117C2DC5BDF5E00AE70",
+                                REL_ID_PREFIX + "QW50ZW5uYU1vZHVsZTo0NzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpERVBMT1lFRF9CWTpBbnRlbm5hTW9kdWxlOjQ3OUEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==")))));
+        PaginationMetaData metadataOneToMany = new PaginationMetaData();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().offset(0).limit(5).build();
+        paginationDTO2.setTotalSize(1);
+        sameEntityOneToOneResult.putAll(metadataOneToMany.getObjectList(paginationDTO2));
+
+        verifyResponse(sameEntityOneToOneResult, underTest.getRelationshipsByType(relSameEntityOneToOne, null, PaginationDTO
+                .builder().offset(0).limit(5).build()));
+
+        // Rel connectingSameEntity ONE_TO_MANY
+        RelationType relSameEntityOneToMany = SchemaRegistry.getRelationTypeByName(
+                "ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE");
+        sameEntityOneToManyResult.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE", List.of(
+                        generateResponse("378A05C67D47D117C2DC5BDF5E00AE70", "379A05C67D47D117C2DC5BDF5E00AE70",
+                                REL_ID_PREFIX + "QW50ZW5uYU1vZHVsZTozNzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpSRUFMSVNFRF9CWTpBbnRlbm5hTW9kdWxlOjM3OUEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==")))));
+        PaginationMetaData metadataOneToOne = new PaginationMetaData();
+        PaginationDTO paginationDTO1 = PaginationDTO.builder().offset(0).limit(5).build();
+        paginationDTO1.setTotalSize(1);
+        sameEntityOneToManyResult.putAll(metadataOneToOne.getObjectList(paginationDTO1));
+
+        verifyResponse(sameEntityOneToManyResult, underTest.getRelationshipsByType(relSameEntityOneToMany, null,
+                PaginationDTO.builder().offset(0).limit(5).build()));
+    }
+
+    @Test
+    void testGetTopologyByTypeWithLongNames() {
+        Map<String, Object> result = new HashMap<>();
+        Map<String, Object> queryMap = new HashMap<>();
+
+        queryMap.put("query", Map.of("targetFilter",
+                "/attributes(fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn)", "scopeFilter",
+                "/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn, \"13\")] | /id[@id='5A3085C3400C3096E2ED2321452766B1']"));
+
+        result.putAll(queryMap);
+
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains/RAN/entities/GNBDUFunction").offset(0)
+                .limit(2).addQueryParameters("targetFilter",
+                        "/attributes(fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn)").addQueryParameters(
+                                "scopeFilter",
+                                "/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn, \"13\")] | /id[@id='5A3085C3400C3096E2ED2321452766B1']")
+                .build();
+        paginationDTO.setTotalSize(2);
+        result.putAll(new PaginationMetaData().getObjectList(paginationDTO));
+
+        result.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-ran:GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", List.of(Map.of(
+                        ATTRIBUTES, Map.of("fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=13"),
+                        "id", "25E690E22BDA90B9C4FEE1F083CBA597"), Map.of(ATTRIBUTES, Map.of(
+                                "fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=14"),
+                                "id", "5A3085C3400C3096E2ED2321452766B1")))));
+
+        verifyResponse(result, underTest.getTopologyByType(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                "/attributes(fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn)",
+                "/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn, \"13\")] | /id[@id='5A3085C3400C3096E2ED2321452766B1']",
+                paginationDTO));
+        Assertions.assertThrows(TiesPathException.class, () -> underTest.getTopologyByType(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                "/attributes(fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn)",
+                "/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn, \"1000493\")] ; /attributes[@gNBId=4000259]",
+                PaginationDTO.builder().offset(0).limit(2).build()));
+    }
+
+    @Test
+    void testGetEntitiesByDomainWithLongNames() {
+        Map<String, Object> reference1 = new HashMap<>();
+        Map<String, String> query = new LinkedHashMap<>();
+
+        query.put("scopeFilter", "/attributes[@cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd=3]");
+        query.put("targetFilter", "/attributes(cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd)");
+
+        PaginationMetaData pmd1 = new PaginationMetaData();
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/domains/EQUIPMENT_TO_RAN").offset(0).limit(5)
+                .build();
+        paginationDTO.setQueryParameters(query);
+        paginationDTO.setTotalSize(1);
+        reference1.putAll(pmd1.getObjectList(paginationDTO));
+
+        reference1.put("query", query);
+
+        reference1.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-ran:NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU", List.of(Map.of("id",
+                        "B480427E8A0C0B8D994E437784BB382F", ATTRIBUTES, Map.of(
+                                "cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd", "3"))))));
+
+        Map<String, Object> reference2 = new HashMap<>();
+        Map<String, Object> query2 = new HashMap<>();
+
+        query2.put("targetFilter", "/id");
+        query2.put("scopeFilter", "/id[contains(@id,\"EA403A\")]");
+
+        PaginationMetaData pmd2 = new PaginationMetaData();
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().basePath("/domains/EQUIPMENT_TO_RAN").offset(0).limit(5)
+                .addQueryParameters("targetFilter", "/id").addQueryParameters("scopeFilter",
+                        "/id[contains(@id,\"EA403A\")]").build();
+        paginationDTO2.setTotalSize(1);
+        reference1.putAll(pmd2.getObjectList(paginationDTO2));
+
+        reference2.put("query", query2);
+
+        reference2.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-ran:NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU", List.of(Map.of("id",
+                        "F26F279E91D0941DB4F646E707EA403A")))));
+
+        verifyResponse(reference2, underTest.getEntitiesByDomain("EQUIPMENT_TO_RAN", "/id", "/id[contains(@id,\"EA403A\")]",
+                paginationDTO2));
+
+        Map<String, Object> reference3 = new HashMap<>();
+        Map<String, Object> query3 = new HashMap<>();
+
+        query3.put("targetFilter",
+                "/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes/fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn");
+        query3.put("scopeFilter",
+                "/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,\"GNBDUFunction=10\")]");
+
+        PaginationMetaData pmd3 = new PaginationMetaData();
+        PaginationDTO paginationDTO3 = PaginationDTO.builder().basePath("/domains/EQUIPMENT_TO_RAN").offset(0).limit(5)
+                .addQueryParameters("targetFilter",
+                        "/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes/fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn")
+                .addQueryParameters("scopeFilter",
+                        "/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,\"GNBDUFunction=10\")]")
+                .build();
+        paginationDTO3.setTotalSize(1);
+        reference1.putAll(pmd3.getObjectList(paginationDTO3));
+
+        reference3.put("query", query3);
+
+        reference3.put("items", List.of(Map.of(
+                "o-ran-smo-teiv-ran:GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn", List.of(Map.of("id",
+                        "1050570EBB1315E1AE7A9FD5E1400A00", ATTRIBUTES, Map.of(
+                                "fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=10"))))));
+
+        verifyResponse(reference3, underTest.getEntitiesByDomain("RAN",
+                "/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes/fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                "/GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn/attributes[contains(@fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,\"GNBDUFunction=10\")]",
+                paginationDTO3));
+
+        Object result = underTest.getEntitiesByDomain("OAM_TO_RAN", "/id", "", PaginationDTO.builder().offset(0).limit(500)
+                .build());
+        Assertions.assertEquals(10, ((Map) ((List) ((HashMap) result).get("items")).get(0)).size());
+        Assertions.assertTrue(((Map) ((List) ((HashMap) result).get("items")).get(0)).containsKey(
+                "o-ran-smo-teiv-oam:ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt"));
+
+        Assertions.assertTrue(((Map) ((List) ((HashMap) result).get("items")).get(0)).containsKey(
+                "o-ran-smo-teiv-ran:GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"));
+    }
+
+    @Test
+    void testAvailableClassifiers() {
+        Assertions.assertEquals(Set.of("gnbdu-function-model:Rural", "gnbcucp-gnbcuup-model:Weekend"), underTest
+                .loadClassifiers());
+    }
+
+    @Test
+    void testAvailableDecorators() {
+        Assertions.assertEquals(Map.of("gnbdu-function-model:location", DataType.PRIMITIVE,
+                "gnbcucp-gnbcuup-model:metadata", DataType.CONTAINER), underTest.loadDecorators());
+    }
+
+    @Test
+    void testGetSchemasByDomain() {
+        Set<Map<String, Object>> expected = new HashSet<>();
+        for (StoredSchema schema : getSchemasList()) {
+            if (schema.getDomain() == null || !schema.getDomain().equals("RAN_OAM_TO_CLOUD")) {
+                continue;
+            }
+            Map<String, Object> exp = new HashMap<>();
+            exp.put("domain", Collections.singletonList(schema.getDomain()));
+            exp.put("name", schema.getName());
+            exp.put("revision", schema.getRevision());
+            exp.put("content", Collections.singletonMap("href", "/schemas/" + schema.getName() + "/content"));
+            expected.add(exp);
+        }
+
+        Assertions.assertEquals(expected, new HashSet<>((List) underTest.getSchemas("RAN_OAM_TO_CLOUD", PaginationDTO
+                .builder().offset(0).limit(15).build()).get("items")));
+    }
+
+    @Test
+    void testGetSchemasWithPartialDomain() {
+        Set<Map<String, Object>> expected = new HashSet<>();
+        for (StoredSchema schema : getSchemasList()) {
+            if (schema.getDomain() == null || !schema.getDomain().matches("RAN_.*O.*")) {
+                continue;
+            }
+            Map<String, Object> exp = new HashMap<>();
+            exp.put("domain", Collections.singletonList(schema.getDomain()));
+            exp.put("name", schema.getName());
+            exp.put("revision", schema.getRevision());
+            exp.put("content", Collections.singletonMap("href", "/schemas/" + schema.getName() + "/content"));
+            expected.add(exp);
+        }
+
+        Assertions.assertEquals(expected, new HashSet<>((List) underTest.getSchemas("RAN_.*O.*", PaginationDTO.builder()
+                .offset(0).limit(15).build()).get("items")));
+    }
+
+    @Test
+    void testGetSchema() {
+        StoredSchema expected = null;
+        for (StoredSchema schema : getSchemasList()) {
+            if (schema.getName().equals("o-ran-smo-teiv-oam")) {
+                expected = schema;
+                break;
+            }
+        }
+
+        StoredSchema actual = underTest.getSchema("o-ran-smo-teiv-oam");
+        Assertions.assertTrue(actual.getContent().contains("o-ran-smo-teiv-oam"));
+
+        actual.setContent("yang model o-ran-smo-teiv-oam {}");
+        Assertions.assertEquals(expected, actual);
+
+        Assertions.assertNull(underTest.getSchema("o-ran-smo-teiv-invalid"));
+    }
+
+    @Test
+    void testSchemaCRUD() {
+        Assertions.assertNull(underTest.getSchema("newSchema"));
+
+        StoredSchema expected = new StoredSchema();
+        expected.setName("newSchema");
+        expected.setNamespace("new-namespace");
+        expected.setDomain("NEW_DOMAIN");
+        expected.setIncludedModules(new ArrayList<>());
+        expected.setContent("yang content {} \n\n \t\t\t;");
+        expected.setOwnerAppId("additional");
+        expected.setStatus("IN_USAGE");
+
+        underTest.postSchema("newSchema", "new-namespace", "NEW_DOMAIN", new ArrayList<>(), "yang content {} \n\n \t\t\t;",
+                "additional");
+
+        Assertions.assertEquals(expected, underTest.getSchema("newSchema"));
+
+        underTest.setSchemaToDeleting("newSchema");
+
+        expected.setStatus("DELETING");
+        Assertions.assertEquals(expected, underTest.getSchema("newSchema"));
+
+        underTest.deleteSchema("newSchema");
+
+        Assertions.assertNull(underTest.getSchema("newSchema"));
+    }
+
+    private List<StoredSchema> getSchemasList() {
+        final List<StoredSchema> schemas = new ArrayList<>();
+
+        StoredSchema ranLogicalToCloud = new StoredSchema();
+        ranLogicalToCloud.setName("o-ran-smo-teiv-cloud-to-ran");
+        ranLogicalToCloud.setNamespace("urn:o-ran:smo-teiv-cloud-to-ran");
+        ranLogicalToCloud.setDomain("CLOUD_TO_RAN");
+        ranLogicalToCloud.setRevision("2023-10-24");
+
+        StoredSchema ranEquipment = new StoredSchema();
+        ranEquipment.setName("o-ran-smo-teiv-equipment");
+        ranEquipment.setNamespace("urn:o-ran:smo-teiv-equipment");
+        ranEquipment.setDomain("EQUIPMENT");
+        ranEquipment.setRevision("2023-06-26");
+
+        StoredSchema ranOamToCloud = new StoredSchema();
+        ranOamToCloud.setName("o-ran-smo-teiv-oam-to-cloud");
+        ranOamToCloud.setNamespace("urn:o-ran:smo-teiv-oam-to-cloud");
+        ranOamToCloud.setDomain("OAM_TO_CLOUD");
+        ranOamToCloud.setRevision("2023-10-24");
+
+        StoredSchema ranOamToLogical = new StoredSchema();
+        ranOamToLogical.setName("o-ran-smo-teiv-oam-to-ran");
+        ranOamToLogical.setNamespace("urn:o-ran:smo-teiv-oam-to-ran");
+        ranOamToLogical.setDomain("OAM_TO_RAN");
+        ranOamToLogical.setRevision("2023-10-24");
+
+        StoredSchema ranCloud = new StoredSchema();
+        ranCloud.setName("o-ran-smo-teiv-cloud");
+        ranCloud.setNamespace("urn:o-ran:smo-teiv-cloud");
+        ranCloud.setDomain("CLOUD");
+        ranCloud.setRevision("2023-06-26");
+
+        StoredSchema ranOam = new StoredSchema();
+        ranOam.setName("o-ran-smo-teiv-oam");
+        ranOam.setNamespace("urn:o-ran:smo-teiv-oam");
+        ranOam.setDomain("OAM");
+        ranOam.setRevision("2024-05-02");
+        ranOam.setIncludedModules(new ArrayList<>());
+        ranOam.setOwnerAppId("BUILT_IN_MODULE");
+        ranOam.setStatus("IN_USAGE");
+        ranOam.setContent("yang model o-ran-smo-teiv-oam {}");
+
+        StoredSchema yangTypes = new StoredSchema();
+        yangTypes.setName("o-ran-smo-teiv-common-yang-types");
+        yangTypes.setRevision("2023-07-04");
+
+        StoredSchema ranLogicalToEquipment = new StoredSchema();
+        ranLogicalToEquipment.setName("o-ran-smo-teiv-equipment-to-ran");
+        ranLogicalToEquipment.setDomain("EQUIPMENT_TO_RAN");
+        ranLogicalToEquipment.setRevision("2023-10-24");
+
+        StoredSchema gnbcucpGnbcuupModel = new StoredSchema();
+        gnbcucpGnbcuupModel.setName("gnbcucp-gnbcuup-model");
+
+        StoredSchema yangExtensions = new StoredSchema();
+        yangExtensions.setName("o-ran-smo-teiv-common-yang-extensions");
+        yangExtensions.setRevision("2023-07-04");
+
+        StoredSchema ranLogical = new StoredSchema();
+        ranLogical.setName("o-ran-smo-teiv-ran");
+        ranLogical.setDomain("RAN");
+        ranLogical.setRevision("2023-11-03");
+
+        StoredSchema gnbduFunctionModel = new StoredSchema();
+        gnbduFunctionModel.setName("gnbdu-function-model");
+
+        schemas.add(ranLogicalToCloud);
+        schemas.add(ranEquipment);
+        schemas.add(ranOamToCloud);
+        schemas.add(ranOamToLogical);
+        schemas.add(ranCloud);
+        schemas.add(ranOam);
+        schemas.add(yangTypes);
+        schemas.add(ranLogicalToEquipment);
+        schemas.add(gnbcucpGnbcuupModel);
+        schemas.add(yangExtensions);
+        schemas.add(ranLogical);
+        schemas.add(gnbduFunctionModel);
+
+        return schemas;
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/ComplexMapperTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/ComplexMapperTest.java
new file mode 100644
index 0000000..5b63746
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/ComplexMapperTest.java
@@ -0,0 +1,77 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.oran.smo.teiv.utils.TiesConstants.ATTRIBUTES;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA;
+import static org.jooq.impl.DSL.field;
+
+class ComplexMapperTest {
+    private static ComplexMapper complexMapper;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        MockSchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+        complexMapper = new ComplexMapper();
+    }
+
+    @Test
+    void testMap() {
+        final Result<Record> records = DSL.using(SQLDialect.POSTGRES).newResult();
+
+        final String gNBDUName = String.format(TIES_DATA, "GNBDUFunction");
+        final String nRCellDUName = String.format(TIES_DATA, "NRCellDU");
+
+        records.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(gNBDUName + ".id"), field(gNBDUName + ".fdn"), field(
+                nRCellDUName + ".id")).values("9BCD297B8258F67908477D895636ED65",
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=91",
+                        null));
+        records.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(gNBDUName + ".id"), field(gNBDUName + ".fdn"), field(
+                nRCellDUName + ".id")).values(null, null, "98C3A4591A37718E1330F0294E23B62A"));
+
+        Map<String, Object> result = new HashMap<>();
+
+        result.put("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of(ATTRIBUTES, Map.of("fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=91"), "id",
+                "9BCD297B8258F67908477D895636ED65")));
+
+        result.put("o-ran-smo-teiv-ran:NRCellDU", List.of(Map.of("id", "98C3A4591A37718E1330F0294E23B62A")));
+
+        Assertions.assertEquals(result, complexMapper.map(records));
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/EntityMapperTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/EntityMapperTest.java
new file mode 100644
index 0000000..1971be4
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/EntityMapperTest.java
@@ -0,0 +1,77 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import org.oran.smo.teiv.schema.Module;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import static org.oran.smo.teiv.utils.TiesConstants.ATTRIBUTES;
+import static org.jooq.impl.DSL.field;
+
+class EntityMapperTest {
+    private static EntityMapper entityMapper;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        EntityType entityType = EntityType.builder().name("GNBDUFunction").module(Module.builder().name(
+                "o-ran-smo-teiv-ran").build()).build();
+        entityMapper = new EntityMapper(entityType);
+        SchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+    }
+
+    @Test
+    void testMap() {
+        final Result<Record> record = DSL.using(SQLDialect.POSTGRES).newResult();
+        Map<String, Object> result = new HashMap<>();
+
+        record.add(DSL.using(SQLDialect.POSTGRES).newRecord(field("dUpLMNId"), field("fdn"), field("gNBDUId"), field(
+                "gNBId"), field("cmId"), field("gNBIdLength"), field("id"), field("CD_sourceIds")).values(Map.of("mcc",
+                        "456", "mnc", "82"),
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=95", 95,
+                        95, "null", 2, "5970A12E0AF8B0FBE0B49290FE847F9B", List.of(
+                                "urn:3gpp:dn:/SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=95",
+                                "urn:cmHandle:/395221E080CCF0FD1924103B15873814")));
+
+        result.put("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of(ATTRIBUTES, Map.of("dUpLMNId", Map.of("mcc", "456",
+                "mnc", "82"), "fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=95", "gNBDUId",
+                95, "gNBId", 95, "cmId", "null", "gNBIdLength", 2), "id", "5970A12E0AF8B0FBE0B49290FE847F9B", "sourceIds",
+                List.of("urn:3gpp:dn:/SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=95",
+                        "urn:cmHandle:/395221E080CCF0FD1924103B15873814"))));
+
+        Assertions.assertEquals(result, entityMapper.map(record));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/MapperUtilityTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/MapperUtilityTest.java
new file mode 100644
index 0000000..26b908b
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/MapperUtilityTest.java
@@ -0,0 +1,178 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import static org.oran.smo.teiv.utils.ResponseGenerator.generateResponse;
+import static org.oran.smo.teiv.utils.TiesConstants.ATTRIBUTES;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA;
+import static org.jooq.impl.DSL.field;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import static org.oran.smo.teiv.utils.ResponseGenerator.generateResponse;
+import static org.oran.smo.teiv.utils.exposure.PaginationVerifierTestUtil.verifyResponse;
+import static org.jooq.impl.DSL.field;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+
+class MapperUtilityTest {
+    private MapperUtility underTest;
+    private static PaginationMetaData paginationMetaData;
+
+    @BeforeEach
+    void setUp() throws SchemaLoaderException {
+        underTest = new MapperUtility();
+        SchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+        paginationMetaData = new PaginationMetaData();
+    }
+
+    @Test
+    void testMapEntity() {
+        final Result<Record> result = DSL.using(SQLDialect.POSTGRES).newResult();
+        result.add(DSL.using(SQLDialect.POSTGRES).newRecord(field("gNBDUId"), field("fdn"), field("dUpLMNId"), field(
+                "gNBId"), field("id"), field("gNBIdLength")).values(null, "GNBDUFunction/6653097A7B47B082BA96245354BB5BE7",
+                        Map.of("mcc", 456, "mnc", 82), "6653097A7B47B082BA96245354BB5BE7",
+                        "GNBDUFunction:6653097A7B47B082BA96245354BB5BE7", 2));
+        Assertions.assertEquals(generateResponse("GNBDUFunction", "6653097A7B47B082BA96245354BB5BE7"), underTest.mapEntity(
+                SchemaRegistry.getEntityTypeByName("GNBDUFunction"), result));
+    }
+
+    @Test
+    void testMapAllRelationships() {
+        final Result<Record> result = DSL.using(SQLDialect.POSTGRES).newResult();
+        result.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(
+                "ties_data.\"NRCellDU\".\"REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU\""), field(
+                        "ties_data.\"NRCellDU\".\"REL_FK_provided-by-gnbduFunction\""), field(
+                                "ties_data.\"NRCellDU\".\"id\""), field(
+                                        "ties_data.\"NRCellDU\".\"REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU\""))
+                .values("urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                        "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F", Collections.EMPTY_LIST));
+
+        Assertions.assertEquals(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F",
+                "urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                Collections.EMPTY_LIST))), underTest.mapRelationships(result, SchemaRegistry.getRelationTypeByName(
+                        "GNBDUFUNCTION_PROVIDES_NRCELLDU")));
+    }
+
+    @Test
+    void testMapRelationship() {
+        final Record record = DSL.using(SQLDialect.POSTGRES).newRecord(field(
+                "ties_data.\"NRCellDU\".\"REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU\""), field(
+                        "ties_data.\"NRCellDU\".\"REL_FK_provided-by-gnbduFunction\""), field(
+                                "ties_data.\"NRCellDU\".\"id\""), field(
+                                        "ties_data.\"NRCellDU\".\"REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU\""))
+                .values("urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                        "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F", Collections.EMPTY_LIST);
+
+        final Result result = DSL.using(SQLDialect.POSTGRES).newResult();
+        result.add(record);
+
+        Assertions.assertEquals(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F",
+                "urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                Collections.EMPTY_LIST))), underTest.mapRelationship(result, SchemaRegistry.getRelationTypeByName(
+                        "GNBDUFUNCTION_PROVIDES_NRCELLDU")));
+    }
+
+    @Test
+    void testMapComplexQuery() {
+        final Result<Record> records = DSL.using(SQLDialect.POSTGRES).newResult();
+
+        final String gNBDUName = String.format(TIES_DATA, "GNBDUFunction");
+        final String nRCellDUName = String.format(TIES_DATA, "NRCellDU");
+
+        records.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(gNBDUName + ".id"), field(gNBDUName + ".fdn"), field(
+                nRCellDUName + ".id")).values("9BCD297B8258F67908477D895636ED65",
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=91",
+                        null));
+        records.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(gNBDUName + ".id"), field(gNBDUName + ".fdn"), field(
+                nRCellDUName + ".id")).values(null, null, "98C3A4591A37718E1330F0294E23B62A"));
+
+        Map<String, Object> result = new HashMap<>();
+
+        result.put("items", List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of(ATTRIBUTES, Map.of("fdn",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=91"), "id",
+                "9BCD297B8258F67908477D895636ED65")), "o-ran-smo-teiv-ran:NRCellDU", List.of(Map.of("id",
+                        "98C3A4591A37718E1330F0294E23B62A")))));
+
+        try (MockedStatic<RequestContextHolder> requestContextHolderMockedStatic = Mockito.mockStatic(
+                RequestContextHolder.class)) {
+            requestContextHolderMockedStatic.when(RequestContextHolder::currentRequestAttributes).thenReturn(
+                    new ServletRequestAttributes(new MockHttpServletRequest()));
+            PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/pathTo/endPoint").offset(0).limit(5).build();
+            paginationDTO.setTotalSize(2);
+            result.putAll(paginationMetaData.getObjectList(paginationDTO));
+            verifyResponse(result, underTest.mapComplexQuery(records, paginationDTO));
+        }
+    }
+
+    @Test
+    void testMapComplexQuery_SingleEntity() {
+        final Result<Record> records = DSL.using(SQLDialect.POSTGRES).newResult();
+
+        final String gNBDUName = String.format(TIES_DATA, "GNBDUFunction");
+
+        records.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(gNBDUName + ".id"), field(gNBDUName + ".fdn")).values(
+                "9BCD297B8258F67908477D895636ED65",
+                "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=91"));
+
+        Map<String, Object> reference = new HashMap<>();
+
+        reference.put("items", List.of(Map.of("o-ran-smo-teiv-ran:GNBDUFunction", List.of(Map.of("id",
+                "9BCD297B8258F67908477D895636ED65", ATTRIBUTES, Map.of("fdn",
+                        "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=91"))))));
+
+        try (MockedStatic<RequestContextHolder> requestContextHolderMockedStatic = Mockito.mockStatic(
+                RequestContextHolder.class)) {
+            requestContextHolderMockedStatic.when(RequestContextHolder::currentRequestAttributes).thenReturn(
+                    new ServletRequestAttributes(new MockHttpServletRequest()));
+            PageMetaData pageMetaDataSelf = new PageMetaData(PaginationDTO.builder().offset(0).limit(5).build());
+            reference.put("self", pageMetaDataSelf);
+            PaginationMetaData pmd = new PaginationMetaData();
+            PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/pathTo/endPoint").offset(0).limit(5).build();
+            paginationDTO.setTotalSize(0);
+            reference.putAll(pmd.getObjectList(paginationDTO));
+            verifyResponse(reference, underTest.mapComplexQuery(records, paginationDTO));
+
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/PaginationMetaDataTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/PaginationMetaDataTest.java
new file mode 100644
index 0000000..3dccacc
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/PaginationMetaDataTest.java
@@ -0,0 +1,139 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.oran.smo.teiv.utils.exposure.PaginationVerifierTestUtil.verifyResponse;
+
+public class PaginationMetaDataTest {
+
+    @Test
+    void testIsItFirst() {
+
+        Map<String, Object> result = new HashMap<>();
+        try (MockedStatic<RequestContextHolder> requestContextHolderMockedStatic = Mockito.mockStatic(
+                RequestContextHolder.class)) {
+            requestContextHolderMockedStatic.when(RequestContextHolder::currentRequestAttributes).thenReturn(
+                    new ServletRequestAttributes(new MockHttpServletRequest()));
+
+            PaginationMetaData paginationMetaData1 = new PaginationMetaData();
+            PageMetaData pageMetaDataSelf = new PageMetaData(0, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataNext = new PageMetaData(5, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataLast = new PageMetaData(50, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataPrev = new PageMetaData(0, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataFirst = new PageMetaData(0, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+
+            result.put("self", pageMetaDataSelf);
+            result.put("first", pageMetaDataFirst);
+            result.put("prev", pageMetaDataPrev);
+            result.put("next", pageMetaDataNext);
+            result.put("last", pageMetaDataLast);
+
+            final PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/pathTo/endPoint").offset(0).limit(5)
+                    .build();
+            paginationDTO.setTotalSize(55);
+            verifyResponse(result, paginationMetaData1.getObjectList(paginationDTO));
+        }
+    }
+
+    @Test
+    void testIsItLast() {
+
+        Map<String, Object> result = new HashMap<>();
+        try (MockedStatic<RequestContextHolder> requestContextHolderMockedStatic = Mockito.mockStatic(
+                RequestContextHolder.class)) {
+            requestContextHolderMockedStatic.when(RequestContextHolder::currentRequestAttributes).thenReturn(
+                    new ServletRequestAttributes(new MockHttpServletRequest()));
+
+            PaginationMetaData paginationMetaData1 = new PaginationMetaData();
+            PageMetaData pageMetaDataSelf = new PageMetaData(60, 10, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataNext = new PageMetaData(60, 10, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataLast = new PageMetaData(60, 10, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataPrev = new PageMetaData(50, 10, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataFirst = new PageMetaData(0, 10, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+
+            result.put("self", pageMetaDataSelf);
+            result.put("next", pageMetaDataNext);
+            result.put("last", pageMetaDataLast);
+            result.put("prev", pageMetaDataPrev);
+            result.put("first", pageMetaDataFirst);
+
+            final PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/pathTo/endPoint").offset(60).limit(10)
+                    .build();
+            paginationDTO.setTotalSize(70);
+            verifyResponse(result, paginationMetaData1.getObjectList(paginationDTO));
+        }
+    }
+
+    @Test
+    void testMiddleTable() {
+
+        Map<String, Object> result = new HashMap<>();
+        try (MockedStatic<RequestContextHolder> requestContextHolderMockedStatic = Mockito.mockStatic(
+                RequestContextHolder.class)) {
+            requestContextHolderMockedStatic.when(RequestContextHolder::currentRequestAttributes).thenReturn(
+                    new ServletRequestAttributes(new MockHttpServletRequest()));
+
+            PaginationMetaData paginationMetaData1 = new PaginationMetaData();
+            PageMetaData pageMetaDataSelf = new PageMetaData(10, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataPrev = new PageMetaData(5, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataNext = new PageMetaData(15, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataFirst = new PageMetaData(0, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+            PageMetaData pageMetaDataLast = new PageMetaData(65, 5, PaginationDTO.builder().basePath("/pathTo/endPoint")
+                    .build());
+
+            result.put("self", pageMetaDataSelf);
+            result.put("prev", pageMetaDataPrev);
+            result.put("next", pageMetaDataNext);
+            result.put("first", pageMetaDataFirst);
+            result.put("last", pageMetaDataLast);
+
+            final PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/pathTo/endPoint").offset(10).limit(5)
+                    .build();
+            paginationDTO.setTotalSize(70);
+            verifyResponse(result, paginationMetaData1.getObjectList(paginationDTO));
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipMapperTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipMapperTest.java
new file mode 100644
index 0000000..e8424f3
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipMapperTest.java
@@ -0,0 +1,95 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.schema.Association;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.Module;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.B_SIDE;
+
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.oran.smo.teiv.utils.ResponseGenerator.generateResponse;
+import static org.jooq.impl.DSL.field;
+
+class RelationshipMapperTest {
+    private static RelationshipMapper relationshipMapper;
+    private static RelationType relationType;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        MockSchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+        relationType = RelationType.builder().name("GNBDUFUNCTION_PROVIDES_NRCELLDU").aSideAssociation(Association.builder()
+                .name("provided-nrCellDu").build()).aSide(EntityType.builder().name("GNBDUFUNCTION").build())
+                .bSideAssociation(Association.builder().name("provided-by-gnbduFunction").build()).bSide(EntityType
+                        .builder().name("NRCellDU").build()).relationshipStorageLocation(B_SIDE).module(Module.builder()
+                                .name("o-ran-smo-teiv-ran").build()).build();
+        relationshipMapper = new RelationshipMapper(relationType);
+    }
+
+    @Test
+    void testMap() {
+        final Result<Record> record = DSL.using(SQLDialect.POSTGRES).newResult();
+        record.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(
+                "ties_data.\"NRCellDU\".\"REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU\""), field(
+                        "ties_data.\"NRCellDU\".\"REL_FK_provided-by-gnbduFunction\""), field(
+                                "ties_data.\"NRCellDU\".\"id\""), field(
+                                        "ties_data.\"NRCellDU\".\"REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU\""))
+                .values("urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                        "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F", List.of("sid1", "sid2")));
+
+        Assertions.assertEquals(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F",
+                "urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                List.of("sid1", "sid2")))), relationshipMapper.map(record));
+    }
+
+    @Test
+    void testCreateProperties() {
+        Record record = DSL.using(SQLDialect.POSTGRES).newRecord(field(
+                "ties_data.\"NRCellDU\".\"REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU\""), field(
+                        "ties_data.\"NRCellDU\".\"REL_FK_provided-by-gnbduFunction\""), field(
+                                "ties_data.\"NRCellDU\".\"id\""), field(
+                                        "ties_data.\"NRCellDU\".\"REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU\""))
+                .values("urn:base64:R05CRFVGdW5jdGlvbjo2QTBENUFBMjhGNzcwQzk5NDFCNzRFQkU1NzYxMUFFMTpQUk9WSURFUzpOUkNlbGxEVTowMDAxNjFCMDE0QzMyMDEwNkE5RDZCMTQxN0Y4RUIwQQ==",
+                        "6A0D5AA28F770C9941B74EBE57611AE1", "000161B014C320106A9D6B1417F8EB0A", List.of("sid1", "sid2"));
+
+        Map<String, Object> result = Map.of("id",
+                "urn:base64:R05CRFVGdW5jdGlvbjo2QTBENUFBMjhGNzcwQzk5NDFCNzRFQkU1NzYxMUFFMTpQUk9WSURFUzpOUkNlbGxEVTowMDAxNjFCMDE0QzMyMDEwNkE5RDZCMTQxN0Y4RUIwQQ==",
+                "aSide", "6A0D5AA28F770C9941B74EBE57611AE1", "bSide", "000161B014C320106A9D6B1417F8EB0A", "sourceIds", List
+                        .of("sid1", "sid2"));
+
+        Assertions.assertEquals(result, relationshipMapper.createProperties(record, relationType));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipsMapperTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipsMapperTest.java
new file mode 100644
index 0000000..f13100a
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/spi/mapper/RelationshipsMapperTest.java
@@ -0,0 +1,75 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.spi.mapper;
+
+import org.oran.smo.teiv.schema.Association;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.Module;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.B_SIDE;
+
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.oran.smo.teiv.utils.ResponseGenerator.generateResponse;
+import static org.jooq.impl.DSL.field;
+
+class RelationshipsMapperTest {
+    private static RelationshipsMapper relationshipsMapper;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        MockSchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+        RelationType relationType = RelationType.builder().name("GNBDUFUNCTION_PROVIDES_NRCELLDU").aSideAssociation(
+                Association.builder().name("provided-nrCellDu").build()).aSide(EntityType.builder().name("GNBDUFUNCTION")
+                        .build()).bSideAssociation(Association.builder().name("provided-by-gnbduFunction").build()).bSide(
+                                EntityType.builder().name("NRCellDU").build()).relationshipStorageLocation(B_SIDE).module(
+                                        Module.builder().name("o-ran-smo-teiv-ran").build()).build();
+        relationshipsMapper = new RelationshipsMapper(relationType);
+    }
+
+    @Test
+    void testMap() {
+        final Result<Record> record = DSL.using(SQLDialect.POSTGRES).newResult();
+        record.add(DSL.using(SQLDialect.POSTGRES).newRecord(field(
+                "ties_data.\"NRCellDU\".\"REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU\""), field(
+                        "ties_data.\"NRCellDU\".\"REL_FK_provided-by-gnbduFunction\""), field(
+                                "ties_data.\"NRCellDU\".\"id\"")).values(
+                                        "urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==",
+                                        "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F"));
+
+        Assertions.assertEquals(Map.of("o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU", List.of(generateResponse(
+                "9BCD297B8258F67908477D895636ED65", "B480427E8A0C0B8D994E437784BB382F",
+                "urn:base64:R05CRFVGdW5jdGlvbjo5QkNEMjk3QjgyNThGNjc5MDg0NzdEODk1NjM2RUQ2NTpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg=="))),
+                relationshipsMapper.map(record));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/FilterCriteriaTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/FilterCriteriaTest.java
new file mode 100644
index 0000000..ba35f10
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/FilterCriteriaTest.java
@@ -0,0 +1,96 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.jooq.SelectField;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import org.oran.smo.teiv.schema.DataType;
+
+class FilterCriteriaTest {
+    @Test
+    void testFilterCriteria() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        TargetObject targetObject = TargetObject.builder("GNBDUFunction").container(ContainerType.ATTRIBUTES).params(List
+                .of("gNBId")).build();
+        filterCriteria.setTargets(List.of(targetObject));
+        ScopeObject scopeObject = new ScopeObject("GNDBUFunction", ContainerType.ATTRIBUTES, "gNBIDLength",
+                QueryFunction.EQ, "1", DataType.BIGINT);
+        ScopeLogicalBlock logicalBlock = new ScopeLogicalBlock(scopeObject);
+        filterCriteria.setScope(logicalBlock);
+
+        Assertions.assertEquals(1, filterCriteria.getTargets().size());
+        Assertions.assertEquals("RAN_LOGICAL", filterCriteria.getDomain());
+        Assertions.assertEquals(QueryFunction.EQ, ((ScopeLogicalBlock) filterCriteria.getScope()).getScopeObject()
+                .getQueryFunction());
+    }
+
+    @Test
+    void testGetTables() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        TargetObject targetObject = TargetObject.builder("GNBDUFunction").container(ContainerType.ATTRIBUTES).params(List
+                .of("gNBId", "gNBIdLength")).build();
+        filterCriteria.setTargets(Arrays.asList(targetObject));
+        OrLogicalBlock orLogicalBlock = new OrLogicalBlock();
+        ScopeObject scopeObject1 = new ScopeObject("GNBDUFunction", ContainerType.ATTRIBUTES, "gNBIdLength",
+                QueryFunction.EQ, "1", DataType.BIGINT);
+        ScopeObject scopeObject2 = new ScopeObject("GNBDUFunction", ContainerType.ATTRIBUTES, "gNBId", QueryFunction.EQ,
+                "8", DataType.BIGINT);
+        ScopeLogicalBlock scopeLogicalBlock1 = new ScopeLogicalBlock(scopeObject1);
+        ScopeLogicalBlock scopeLogicalBlock2 = new ScopeLogicalBlock(scopeObject2);
+        orLogicalBlock.setChildren(Arrays.asList(scopeLogicalBlock1, scopeLogicalBlock2));
+        filterCriteria.setScope(orLogicalBlock);
+
+        Set<SelectField> expected = new HashSet<>();
+        expected.add(null);
+        Assertions.assertEquals(expected, filterCriteria.getTables());
+    }
+
+    @Test
+    void testGetSelects() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+
+        TargetObject targetObject = TargetObject.builder("GNBDUFunction").container(ContainerType.ATTRIBUTES).params(List
+                .of("gNBId", "gNBIdLength")).build();
+        filterCriteria.setTargets(Arrays.asList(targetObject));
+
+        Set<SelectField> expected = new HashSet<>();
+        expected.add(null);
+        Assertions.assertEquals(expected, filterCriteria.getSelects());
+    }
+
+    @Test
+    void testGetCondition() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        ScopeObject scopeObject = new ScopeObject("GNBDUFunction", ContainerType.ATTRIBUTES, QueryFunction.EQ, "1",
+                DataType.BIGINT);
+        ScopeLogicalBlock scopeLogicalBlock = new ScopeLogicalBlock(scopeObject);
+        filterCriteria.setScope(scopeLogicalBlock);
+
+        Assertions.assertEquals(null, filterCriteria.getCondition());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/PathObjectTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/PathObjectTest.java
new file mode 100644
index 0000000..a5e87cb
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/innerlanguage/PathObjectTest.java
@@ -0,0 +1,36 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.innerlanguage;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class PathObjectTest {
+    @Test
+    void PathObjectTest() {
+        PathObject pathObject = new PathObject("GNBDUFunction");
+        Assertions.assertEquals("GNBDUFunction", pathObject.getId());
+        Assertions.assertEquals("GNBDUFunction", pathObject.getTopologyObject());
+
+        pathObject.setTopologyObjectType(TopologyObjectType.ENTITY);
+        Assertions.assertEquals(TopologyObjectType.ENTITY, pathObject.getTopologyObjectType());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/BasePathRefinementTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/BasePathRefinementTest.java
new file mode 100644
index 0000000..ca044db
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/BasePathRefinementTest.java
@@ -0,0 +1,376 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.refiner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang3.NotImplementedException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ContainerType;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.EmptyLogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.FilterCriteria;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.LogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.OrLogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.QueryFunction;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ScopeLogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ScopeObject;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.TargetObject;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.TopologyObjectType;
+import org.oran.smo.teiv.schema.DataType;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+
+import org.junit.jupiter.api.BeforeAll;
+
+import static org.oran.smo.teiv.utils.TiesConstants.ITEMS;
+
+class BasePathRefinementTest {
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        SchemaLoader mockedSchemaLoader = new MockSchemaLoader();
+        mockedSchemaLoader.loadSchemaRegistry();
+    }
+
+    @Test
+    void testResolveWildCardObjectsInScopeAndTarget() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        Assertions.assertThrows(NotImplementedException.class, () -> BasePathRefinement
+                .resolveWildCardObjectsInScopeAndTarget(filterCriteria));
+    }
+
+    @Test
+    void testResolveUndefinedTopologyObjects_Entity() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        TargetObject targetObject = TargetObject.builder("GNBDUFunction").build();
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject)));
+        ScopeObject scopeObject = new ScopeObject("GNBDUFunction", ContainerType.ATTRIBUTES, "gNBId", QueryFunction.EQ, "1",
+                DataType.BIGINT);
+        LogicalBlock scope = new ScopeLogicalBlock(scopeObject);
+        filterCriteria.setScope(scope);
+
+        try (MockedStatic<SchemaRegistry> utilities = Mockito.mockStatic(SchemaRegistry.class)) {
+            utilities.when(() -> SchemaRegistry.getEntityNamesByDomain("RAN_LOGICAL")).thenReturn(Arrays.asList(
+                    "GNBDUFunction", "NRCellDU"));
+            utilities.when(() -> SchemaRegistry.getRelationNamesByDomain("RAN_LOGICAL")).thenReturn(Arrays.asList(
+                    "GNBDUFUNCTION_PROVIDES_NRCELLDU"));
+
+            BasePathRefinement.resolveUndefinedTopologyObjectTypes(filterCriteria);
+
+            Assertions.assertEquals(TopologyObjectType.ENTITY, filterCriteria.getTargets().get(0).getTopologyObjectType());
+            Assertions.assertEquals(TopologyObjectType.ENTITY, ((ScopeLogicalBlock) filterCriteria.getScope())
+                    .getScopeObject().getTopologyObjectType());
+
+            filterCriteria.setScope(EmptyLogicalBlock.getInstance());
+            targetObject.setTopologyObjectType(TopologyObjectType.UNDEFINED);
+
+            BasePathRefinement.resolveUndefinedTopologyObjectTypes(filterCriteria);
+
+            Assertions.assertEquals(TopologyObjectType.ENTITY, filterCriteria.getTargets().get(0).getTopologyObjectType());
+        }
+    }
+
+    @Test
+    void testResolveUndefinedTopologyObjects_Relation() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        TargetObject targetObject = TargetObject.builder("GNBDUFUNCTION_PROVIDES_NRCELLDU").build();
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject)));
+        ScopeObject scopeObject = new ScopeObject("GNBDUFUNCTION_PROVIDES_NRCELLDU", ContainerType.ID, QueryFunction.EQ,
+                "1", DataType.PRIMITIVE);
+        LogicalBlock scope = new ScopeLogicalBlock(scopeObject);
+        filterCriteria.setScope(scope);
+
+        try (MockedStatic<SchemaRegistry> utilities = Mockito.mockStatic(SchemaRegistry.class)) {
+            utilities.when(() -> SchemaRegistry.getEntityNamesByDomain("RAN_LOGICAL")).thenReturn(Arrays.asList(
+                    "GNBDUFunction", "NRCellDU"));
+            utilities.when(() -> SchemaRegistry.getRelationNamesByDomain("RAN_LOGICAL")).thenReturn(Arrays.asList(
+                    "GNBDUFUNCTION_PROVIDES_NRCELLDU"));
+
+            BasePathRefinement.resolveUndefinedTopologyObjectTypes(filterCriteria);
+
+            Assertions.assertEquals(TopologyObjectType.RELATION, filterCriteria.getTargets().get(0)
+                    .getTopologyObjectType());
+            Assertions.assertEquals(TopologyObjectType.RELATION, ((ScopeLogicalBlock) filterCriteria.getScope())
+                    .getScopeObject().getTopologyObjectType());
+        }
+    }
+
+    @Test
+    void testResolveUndefinedTopologyObjects_InvalidTargetAndScope() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        TargetObject targetObject = TargetObject.builder("InvalidObject").build();
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject)));
+        ScopeObject scopeObject = new ScopeObject("InvalidObject", ContainerType.ATTRIBUTES, "gNBId", QueryFunction.EQ, "1",
+                DataType.BIGINT);
+        LogicalBlock scope = new ScopeLogicalBlock(scopeObject);
+        filterCriteria.setScope(scope);
+
+        try (MockedStatic<SchemaRegistry> utilities = Mockito.mockStatic(SchemaRegistry.class)) {
+            utilities.when(() -> SchemaRegistry.getEntityNamesByDomain("RAN_LOGICAL")).thenReturn(Arrays.asList(
+                    "GNBDUFunction", "NRCellDU", "EntityAndRelation"));
+            utilities.when(() -> SchemaRegistry.getRelationNamesByDomain("RAN_LOGICAL")).thenReturn(Arrays.asList(
+                    "GNBDUFUNCTION_PROVIDES_NRCELLDU", "EntityAndRelation"));
+            // Error thrown because of invalid topology object in targetFilter
+            Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.resolveUndefinedTopologyObjectTypes(
+                    filterCriteria));
+
+            targetObject.setTopologyObject("GNBDUFunction");
+
+            // Error thrown because of invalid topology object in scopeFilter
+            Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.resolveUndefinedTopologyObjectTypes(
+                    filterCriteria));
+
+            scopeObject.setTopologyObject("EntityAndRelation");
+
+            // Error thrown because of topology object type is ambiguous
+            Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.resolveUndefinedTopologyObjectTypes(
+                    filterCriteria));
+
+            targetObject.setTopologyObjectType(TopologyObjectType.UNDEFINED);
+            targetObject.setTopologyObject("EntityAndRelation");
+
+            // Error thrown because of topology object type is ambiguous
+            Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.resolveUndefinedTopologyObjectTypes(
+                    filterCriteria));
+        }
+    }
+
+    @Test
+    void testValidateContainers() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+
+        TargetObject targetObject0 = TargetObject.builder("GNBDUFunction").container(ContainerType.ID).params(
+                new ArrayList<>(Arrays.asList("gNBId"))).build();
+        targetObject0.setTopologyObjectType(TopologyObjectType.ENTITY);
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject0)));
+
+        // Reason: container:ID, params is not empty
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        TargetObject targetObject1 = TargetObject.builder("GNBDUFunction").container(ContainerType.ATTRIBUTES).params(
+                new ArrayList<>(Arrays.asList("gNBId", "gNBIdLength", "notValidAttribute1", "notValidAttribute2"))).build();
+        targetObject1.setTopologyObjectType(TopologyObjectType.ENTITY);
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject1)));
+
+        ScopeObject scopeObject = new ScopeObject("GNBDUFunction", ContainerType.ATTRIBUTES, "gNBId", QueryFunction.EQ, "1",
+                DataType.BIGINT);
+        scopeObject.setTopologyObjectType(TopologyObjectType.ENTITY);
+        LogicalBlock scopeLogicalBlock = new ScopeLogicalBlock(scopeObject);
+        filterCriteria.setScope(scopeLogicalBlock);
+
+        // Reason: invalid attributes in ENTITY type targetObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        TargetObject targetObject2 = TargetObject.builder("GNBDUFUNCTION_PROVIDES_NRCELLDU").container(
+                ContainerType.ATTRIBUTES).topologyObjectType(TopologyObjectType.RELATION).params(new ArrayList<>(Arrays
+                        .asList("notValidAttribute1", "notValidAttribute2"))).build();
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject2)));
+
+        // Reason: invalid attributes in RELATION type targetObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setLeaf("notValidAttribute");
+
+        TargetObject targetObject3 = TargetObject.builder("GNBDUFunction").container(ContainerType.ATTRIBUTES)
+                .topologyObjectType(TopologyObjectType.ENTITY).params(new ArrayList<>(Arrays.asList("gNBId",
+                        "gNBIdLength"))).build();
+        targetObject3.setTopologyObjectType(TopologyObjectType.ENTITY);
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject3)));
+
+        // Reason: invalid attributes in ENTITY type scopeObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setLeaf("gNBId");
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.validateContainers(filterCriteria));
+
+        TargetObject targetObject4 = TargetObject.builder("GNBDUFunction").container(ContainerType.SOURCE_IDS)
+                .topologyObjectType(TopologyObjectType.ENTITY).params(new ArrayList<>(Arrays.asList("gNBId"))).build();
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject4)));
+
+        // Reason: invalid source id param for ENTITY type targetObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        targetObject4.setParams(Collections.emptyList());
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.validateContainers(filterCriteria));
+
+        TargetObject targetObject5 = TargetObject.builder("GNBDUFUNCTION_PROVIDES_NRCELLDU").container(
+                ContainerType.SOURCE_IDS).topologyObjectType(TopologyObjectType.RELATION).params(new ArrayList<>(Arrays
+                        .asList("InvalidSourceIdParam"))).build();
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject5)));
+
+        // Reason: invalid source id param for RELATION type targetObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        targetObject5.setParams(new ArrayList<>(Arrays.asList(ITEMS)));
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.validateContainers(filterCriteria));
+    }
+
+    @Test
+    void testValidateContainers_Associations() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        ScopeObject scopeObject = new ScopeObject("GNBDUFunction", ContainerType.ASSOCIATION, "nCI", QueryFunction.EQ, "1",
+                DataType.BIGINT);
+        scopeObject.setInnerContainer(Arrays.asList("provided-by-gnbduFunction"));
+        scopeObject.setTopologyObjectType(TopologyObjectType.ENTITY);
+        LogicalBlock scopeLogicalBlock = new ScopeLogicalBlock(scopeObject);
+        filterCriteria.setScope(scopeLogicalBlock);
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setLeaf(null);
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setLeaf("invalid");
+
+        // Reason: invalid leaf for scopeObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setLeaf("nCI");
+        scopeObject.setInnerContainer(Arrays.asList("invalid-association"));
+
+        // Reason: invalid association added in innerContainer list for ENTITY type scopeObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setInnerContainer(Collections.emptyList());
+
+        // Reason: no association name added in innerContainer list for scopeObject in case of association containerType
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setTopologyObject("GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        scopeObject.setTopologyObjectType(TopologyObjectType.RELATION);
+        scopeObject.setInnerContainer(Arrays.asList("provided-by-gnbduFunction"));
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setTopologyObjectType(TopologyObjectType.UNDEFINED);
+
+        // Reason: cannot validate container for UNDEFINED type topologyObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+        scopeObject.setTopologyObjectType(TopologyObjectType.RELATION);
+        scopeObject.setInnerContainer(Arrays.asList("invalid-association"));
+
+        // Reason: invalid association added in innerContainer list for RELATION type scopeObject
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.validateContainers(filterCriteria));
+
+    }
+
+    @Test
+    void testValidateScopeParametersDataType() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        Assertions.assertThrows(NotImplementedException.class, () -> BasePathRefinement.validateScopeParametersDataType(
+                filterCriteria));
+    }
+
+    @Test
+    void testCheckIfTargetMatchesWithScope() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        TargetObject targetObject1 = TargetObject.builder("GNBDUFunction").container(ContainerType.ATTRIBUTES).params(List
+                .of("gNBId", "gNBIdLength")).build();
+        TargetObject targetObject2 = TargetObject.builder("NRCellDU").container(ContainerType.ATTRIBUTES).params(List.of(
+                "nCI")).build();
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject1, targetObject2)));
+
+        OrLogicalBlock orLogicalBlock1 = new OrLogicalBlock();
+        ScopeObject scopeObject1 = new ScopeObject("GNBDUFunction", ContainerType.ATTRIBUTES, "gNBIdLength",
+                QueryFunction.EQ, "1", DataType.BIGINT);
+        ScopeObject scopeObject2 = new ScopeObject("GNBDUFunction", ContainerType.ATTRIBUTES, "gNBId", QueryFunction.EQ,
+                "8", DataType.BIGINT);
+
+        ScopeLogicalBlock scopeLogicalBlock1 = new ScopeLogicalBlock(scopeObject1);
+        ScopeLogicalBlock scopeLogicalBlock2 = new ScopeLogicalBlock(scopeObject2);
+        orLogicalBlock1.setChildren(new ArrayList<>(Arrays.asList(scopeLogicalBlock1, scopeLogicalBlock2)));
+        filterCriteria.setScope(orLogicalBlock1);
+
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.checkIfTargetMatchesWithScope(
+                filterCriteria));
+
+        filterCriteria.setTargets(new ArrayList<>(Arrays.asList(targetObject1)));
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.checkIfTargetMatchesWithScope(filterCriteria));
+
+        ScopeObject scopeObject3 = new ScopeObject("NRSectorCarrier", ContainerType.ATTRIBUTES, "arfcnUL", QueryFunction.EQ,
+                "8", DataType.BIGINT);
+        ScopeLogicalBlock scopeLogicalBlock3 = new ScopeLogicalBlock(scopeObject3);
+        filterCriteria.setScope(scopeLogicalBlock3);
+
+        Assertions.assertThrows(TiesPathException.class, () -> BasePathRefinement.checkIfTargetMatchesWithScope(
+                filterCriteria));
+
+        filterCriteria.setTargets(Collections.emptyList());
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.checkIfTargetMatchesWithScope(filterCriteria));
+
+        filterCriteria.setScope(EmptyLogicalBlock.getInstance());
+
+        Assertions.assertDoesNotThrow(() -> BasePathRefinement.checkIfTargetMatchesWithScope(filterCriteria));
+
+    }
+
+    @Test
+    void testValidateQuery() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        Assertions.assertThrows(NotImplementedException.class, () -> BasePathRefinement.validateQuery(filterCriteria));
+    }
+
+    @Test
+    void testRunOnTree() {
+        FilterCriteria filterCriteria = new FilterCriteria("RAN_LOGICAL");
+        OrLogicalBlock orLogicalBlock = new OrLogicalBlock();
+        filterCriteria.setScope(orLogicalBlock);
+        OrLogicalBlock orLogicalBlockChild1 = new OrLogicalBlock();
+        OrLogicalBlock orLogicalBlockChild2 = new OrLogicalBlock();
+
+        LogicalBlock scopeLogicalBlock1 = new ScopeLogicalBlock(new ScopeObject("GNDBUFunction", ContainerType.ATTRIBUTES,
+                "gNBIdLength", QueryFunction.EQ, "1", DataType.BIGINT));
+        LogicalBlock scopeLogicalBlock2 = new ScopeLogicalBlock(new ScopeObject("GNDBUFunction", ContainerType.ATTRIBUTES,
+                "gNBIdLength", QueryFunction.EQ, "2", DataType.BIGINT));
+        LogicalBlock scopeLogicalBlock3 = new ScopeLogicalBlock(new ScopeObject("GNDBUFunction", ContainerType.ATTRIBUTES,
+                "gNBIdLength", QueryFunction.EQ, "3", DataType.BIGINT));
+        LogicalBlock scopeLogicalBlock4 = new ScopeLogicalBlock(new ScopeObject("GNDBUFunction", ContainerType.ATTRIBUTES,
+                "gNBIdLength", QueryFunction.EQ, "4", DataType.BIGINT));
+
+        orLogicalBlockChild1.setChildren(Arrays.asList(scopeLogicalBlock1, scopeLogicalBlock2));
+        orLogicalBlockChild2.setChildren(Arrays.asList(scopeLogicalBlock3, scopeLogicalBlock4));
+        orLogicalBlock.setChildren(Arrays.asList(orLogicalBlockChild1, orLogicalBlockChild2));
+
+        BasePathRefinement.runOnTree(orLogicalBlock, filterCriteria.getDomain(), (ScopeLogicalBlock lb, String domain) -> lb
+                .getScopeObject().setParameter("0"));
+
+        Assertions.assertEquals("0", ((ScopeLogicalBlock) scopeLogicalBlock1).getScopeObject().getParameter());
+        Assertions.assertEquals("0", ((ScopeLogicalBlock) scopeLogicalBlock2).getScopeObject().getParameter());
+        Assertions.assertEquals("0", ((ScopeLogicalBlock) scopeLogicalBlock3).getScopeObject().getParameter());
+        Assertions.assertEquals("0", ((ScopeLogicalBlock) scopeLogicalBlock4).getScopeObject().getParameter());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/PathToJooqRefinementTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/PathToJooqRefinementTest.java
new file mode 100644
index 0000000..95eaecf
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/PathToJooqRefinementTest.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.refiner;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ContainerType;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.QueryFunction;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ScopeLogicalBlock;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.FilterCriteria;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ScopeObject;
+import org.oran.smo.teiv.schema.DataType;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.apache.commons.lang3.NotImplementedException;
+
+public class PathToJooqRefinementTest {
+    @Test
+    void toJooqTest() {
+        Assertions.assertThrows(NotImplementedException.class, () -> PathToJooqRefinement.toJooq(new FilterCriteria(
+                "RAN_LOGICAL")));
+    }
+
+    @Test
+    void logicalBlockToJooqTest() {
+        ScopeObject scopeObject = new ScopeObject("GNDBUFunction", ContainerType.ATTRIBUTES, "gNBIdLength",
+                QueryFunction.EQ, "1", DataType.BIGINT);
+        Assertions.assertThrows(NotImplementedException.class, () -> PathToJooqRefinement.logicalBlockToJooq(
+                new ScopeLogicalBlock(scopeObject)));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/TiesPathQueryRefinementTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/TiesPathQueryRefinementTest.java
new file mode 100644
index 0000000..0a3d46f
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/refiner/TiesPathQueryRefinementTest.java
@@ -0,0 +1,34 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.refiner;
+
+import org.oran.smo.teiv.utils.path.TiesPathQuery;
+import org.apache.commons.lang3.NotImplementedException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TiesPathQueryRefinementTest {
+    @Test
+    void parseTiesPathQueryTest() {
+        Assertions.assertThrows(NotImplementedException.class, () -> TiesPathQueryRefinement.parseTiesPathQuery(
+                new TiesPathQuery()));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/resolver/TargetResolverTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/resolver/TargetResolverTest.java
new file mode 100644
index 0000000..6807f32
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/tiespath/resolver/TargetResolverTest.java
@@ -0,0 +1,171 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.tiespath.resolver;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Assertions;
+
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.ContainerType;
+import org.oran.smo.teiv.exposure.tiespath.innerlanguage.TargetObject;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+
+class TargetResolverTest {
+
+    private TargetResolver targetResolver = new TargetResolver();
+
+    @Test
+    void testIdOnlyWhenTopologyObjectInRootObjectType() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("GNBDUFunction").build());
+
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("GNBDUFunction", ""));
+    }
+
+    @Test
+    void testIdOnlyWhenTopologyObjectAndContainerInTargetOnlyTest() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("ENodeBFunction").build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("", "/ENodeBFunction/id"));
+    }
+
+    @Test
+    void testIdOnlyWhenSameTopologyObjectInTargetAndRootObjectType() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("GNBDUFunction").build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("GNBDUFunction", "/GNBDUFunction"));
+    }
+
+    @Test
+    void testExceptionNonMatchingContainerType() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("GNBDUFunction",
+                "/bla"));
+        assertEquals("Invalid Container name or Root Object name does not match to the path parameter", thrown
+                .getDetails());
+    }
+
+    @Test
+    void testExceptionWhenTopologyObjectInTargetWithParamButNoMatchingContainer() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("",
+                "/GNBDUFunction(fdn, enbId)"));
+        assertEquals("Attributes cannot be associated at this level", thrown.getDetails());
+    }
+
+    @Test
+    void testEmptyTargetAndRootObjectType() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("*" + "").build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("", ""));
+    }
+
+    @Test
+    void testAllAttributes() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("GNBDUFunction").container(
+                ContainerType.ATTRIBUTES).build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("GNBDUFunction", "/attributes"));
+    }
+
+    @Test
+    void testAllAttributesWithEmptyRootObject() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("*").container(ContainerType.ATTRIBUTES).build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("", "/attributes"));
+    }
+
+    @Test
+    void testSelectedAttributes() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("GNBDUFunction").container(
+                ContainerType.ATTRIBUTES).params(List.of("fdn", "enbId")).build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("GNBDUFunction",
+                "/GNBDUFunction/attributes(fdn, enbId)"));
+
+    }
+
+    @Test
+    void testLogicalANDWithTwoDifferentContainersTypes() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("GNBDUFunction").container(
+                ContainerType.ATTRIBUTES).params(List.of("fdn", "enbId")).build(), TargetObject.builder("GNBDUFunction")
+                        .container(ContainerType.SOURCE_IDS).build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("GNBDUFunction",
+                "/GNBDUFunction/attributes(fdn, enbId);/sourceIds"));
+    }
+
+    @Test
+    void testLogicalANDWithTwoDifferentContainersTypesWithAttributes() {
+        List<TargetObject> expectedObject = List.of(TargetObject.builder("GNBDUFunction").container(
+                ContainerType.ATTRIBUTES).params(List.of("fdn", "enbId")).build(), TargetObject.builder("GNBDUFunction")
+                        .container(ContainerType.DECORATORS).params(List.of("module-x:location", "module-y:vendor"))
+                        .build());
+        Assertions.assertEquals(expectedObject, targetResolver.resolve("",
+                "/GNBDUFunction/attributes(fdn, enbId);" + "/GNBDUFunction/decorators(module-x:location,module-y:vendor)"));
+    }
+
+    @Test
+    void testExceptionWithMoreThanTwoLevel() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("",
+                "/GNBDUFunction/NRCellDU/attributes"));
+        assertEquals("More than two level deep path is not allowed", thrown.getDetails());
+    }
+
+    @Test
+    void testExceptionWithPipeInTargetFilter() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("",
+                "/GNBDUFunction/attributes(fdn, enbId)|/GNBDUFunction/classifiers"));
+        assertEquals("OR (|) is not supported for target filter", thrown.getDetails());
+    }
+
+    /* ToDo Below test will be activated when scopeFilter work is done
+       @Test
+    void testExceptionWithScopeFilterInTargetFilter() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("GNBDUFunction",
+                "/GNBDUFunction/attributes[@gNBIdLength=3]"));
+        assertEquals("Condition of parameter(s) is not supported for target filter", thrown.getDetails());
+    }*/
+
+    @Test
+    void testTargetWithoutSlash() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("GNBDUFunction",
+                "attributes"));
+        assertEquals("no viable alternative at input 'attributes' at line 1:0", thrown.getDetails());
+    }
+
+    @Test
+    void testDifferentTopologyObjectInTargetFilterAndRootObjectType() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("GNBDUFunction",
+                "/ENodeBFunction"));
+        assertEquals("Invalid Container name or Root Object name does not match to the path parameter", thrown
+                .getDetails());
+    }
+
+    @Test
+    void testDifferentTopologyObjectInTargetFilterWithAttributesAndRootObjectType() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("GNBDUFunction",
+                "/ENodeBFunction/attributes"));
+        assertEquals("Target filter can only contain Root Object types mentioned in the path parameter", thrown
+                .getDetails());
+    }
+
+    @Test
+    void testEmptyRootObjectTypeWithOneOfTheWrongTargetToken() {
+        TiesPathException thrown = assertThrows(TiesPathException.class, () -> targetResolver.resolve("",
+                "/GNBDUFunction/attributes(fdn, enbId);/GNBDUFunction/NRCellDU/attributes"));
+        assertEquals("More than two level deep path is not allowed", thrown.getDetails());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/exposure/utils/RequestValidatorTest.java b/teiv/src/test/java/org/oran/smo/teiv/exposure/utils/RequestValidatorTest.java
new file mode 100644
index 0000000..2acc630
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/exposure/utils/RequestValidatorTest.java
@@ -0,0 +1,88 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.exposure.utils;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+
+class RequestValidatorTest {
+
+    private static RequestValidator requestValidator;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        SchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+        requestValidator = new RequestValidator();
+    }
+
+    @Test
+    void testValidateDomain() {
+        Assertions.assertDoesNotThrow(() -> requestValidator.validateDomain("RAN"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> requestValidator.validateDomain("RAN_WRONG"));
+    }
+
+    @Test
+    void testValidateEntityType() {
+        Assertions.assertDoesNotThrow(() -> requestValidator.validateEntityType("GNBDUFunction"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> requestValidator.validateEntityType("InvalidEntity"));
+    }
+
+    @Test
+    void testValidateEntityTypeInDomain() {
+        Assertions.assertDoesNotThrow(() -> requestValidator.validateEntityTypeInDomain("GNBCUUPFunction", "RAN"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> requestValidator.validateEntityTypeInDomain(
+                "GNBDU_FUNCTION", "EQUIPMENT"));
+    }
+
+    @Test
+    void testValidateRelationshipType() {
+        Assertions.assertDoesNotThrow(() -> requestValidator.validateRelationshipType("ANTENNAMODULE_INSTALLED_AT_SITE"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> requestValidator.validateRelationshipType(
+                "ANTENNAMODULE_INSTALLED_ON_SITE"));
+    }
+
+    @Test
+    void testValidateRelationshipTypeInDomain() {
+        Assertions.assertDoesNotThrow(() -> requestValidator.validateRelationshipTypeInDomain(
+                "ANTENNAMODULE_INSTALLED_AT_SITE", "EQUIPMENT"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> requestValidator.validateRelationshipTypeInDomain(
+                "ANTENNAMODULE_INSTALLED_AT_SITE", "RAN"));
+    }
+
+    @Test
+    void testValidateFiltersForRelationships() {
+        Assertions.assertDoesNotThrow(() -> requestValidator.validateFiltersForRelationships(null, null));
+        Assertions.assertDoesNotThrow(() -> requestValidator.validateFiltersForRelationships(null,
+                "/GNBDUFunction/attributes[contains (@fdn, \"Hungary\")]"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> requestValidator.validateFiltersForRelationships(
+                "/attributes", "/GNBDUFunction/attributes[contains (@fdn, \"Hungary\")]"));
+        Assertions.assertThrowsExactly(TiesException.class, () -> requestValidator.validateFiltersForRelationships(null,
+                "/attributes[contains (@fdn, \"Hungary\")]"));
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidatorTest.java b/teiv/src/test/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidatorTest.java
new file mode 100644
index 0000000..f97d05f
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/ingestion/validation/IngestionOperationValidatorTest.java
@@ -0,0 +1,364 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.ingestion.validation;
+
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.jooq.impl.DSL.table;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.jooq.DSLContext;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.exception.InvalidFieldInYangDataException;
+import org.oran.smo.teiv.ingestion.validation.IngestionOperationValidator.MAXIMUM_CARDINALITY_CASE;
+import org.oran.smo.teiv.schema.Association;
+import org.oran.smo.teiv.schema.PostgresSchemaLoader;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.RelationshipDataLocation;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.TiesDbOperations;
+import org.oran.smo.teiv.service.cloudevent.data.Entity;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import jakarta.annotation.PostConstruct;
+
+@Configuration
+@SpringBootTest
+@ActiveProfiles({ "test", "ingestion" })
+public class IngestionOperationValidatorTest {
+    public static TestPostgresqlContainer postgresqlContainer = TestPostgresqlContainer.getInstance();
+
+    @Autowired
+    private TiesDbOperations tiesDbOperations;
+
+    @SpyBean
+    private IngestionOperationValidatorFactory validatorFactory;
+
+    @Autowired
+    private DSLContext writeDataDslContext;
+
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @DynamicPropertySource
+    static void setProperties(DynamicPropertyRegistry registry) {
+        registry.add("spring.datasource.read.jdbc-url", () -> postgresqlContainer.getJdbcUrl());
+        registry.add("spring.datasource.read.username", () -> postgresqlContainer.getUsername());
+        registry.add("spring.datasource.read.password", () -> postgresqlContainer.getPassword());
+
+        registry.add("spring.datasource.write.jdbc-url", () -> postgresqlContainer.getJdbcUrl());
+        registry.add("spring.datasource.write.username", () -> postgresqlContainer.getUsername());
+        registry.add("spring.datasource.write.password", () -> postgresqlContainer.getPassword());
+    }
+
+    private TiesDbServiceForValidation spiedDbServiceForValidation;
+
+    @PostConstruct
+    public void beforeAll() throws UnsupportedOperationException, SchemaLoaderException {
+        PostgresSchemaLoader postgresSchemaLoader = new PostgresSchemaLoader(writeDataDslContext, new ObjectMapper());
+        postgresSchemaLoader.loadSchemaRegistry();
+        when(validatorFactory.createValidator(any())).thenAnswer(i -> {
+            spiedDbServiceForValidation = spy(new TiesDbServiceForValidation((DSLContext) i.getArguments()[0]));
+            return new IngestionOperationValidator(spiedDbServiceForValidation);
+        });
+    }
+
+    @BeforeEach
+    public void deleteAll() {
+        writeDataDslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(
+                t -> writeDataDslContext.truncate(t).cascade().execute());
+        if (spiedDbServiceForValidation != null) {
+            reset(spiedDbServiceForValidation);
+        }
+    }
+
+    @Test
+    void maximumCardinalityViolationOneToOne_aSideMax() throws InvalidFieldInYangDataException {
+        //MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM is a 0..1 to 1 relationship
+        List<Entity> entities = generateEntities(MAXIMUM_CARDINALITY_CASE.ONE_ONE);
+        List<Relationship> relationships = new ArrayList<>();
+        relationships.add(new Relationship("o-ran-smo-teiv-oam-to-cloud", "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM",
+                "rel_1", "ManagedElement_1", "CloudNativeSystem_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-oam-to-cloud", "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM",
+                "rel_2", "ManagedElement_2", "CloudNativeSystem_1", List.of()));
+        ParsedCloudEventData parsedCloudEventData = new ParsedCloudEventData(entities, relationships);
+        //It's expected to fail, because the CloudNativeSystem_1 entity would be connected to 2 ManagedElement instances
+        assertThrows(MaximumCardinalityViolationException.class, () -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData));
+
+        //The whole transaction is rolled back. Neither the entities nor the relationships are persisted.
+        assertEmptyTable("ties_data.\"ManagedElement\"");
+        assertEmptyTable("ties_data.\"CloudNativeSystem\"");
+
+        //Remove the extra relationship that caused the cardinality violation. Successfully insert the others.
+        Relationship redundantRelationship = relationships.remove(1);
+        ParsedCloudEventData parsedCloudEventData2 = new ParsedCloudEventData(entities, relationships);
+        assertEquals(entities.size() + relationships.size(), tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData2).size());
+        verify(spiedDbServiceForValidation).acquireEntityInstanceExclusiveLock("ties_data.\"CloudNativeSystem\"",
+                "CloudNativeSystem_1");
+
+        //Try to insert an extra relationship. It's expected to fail, because the CloudNativeSystem_1 entity already has the maximum number of relationships.
+        ParsedCloudEventData parsedCloudEventData3 = new ParsedCloudEventData(List.of(), List.of(redundantRelationship));
+        assertThrows(MaximumCardinalityViolationException.class, () -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData3));
+    }
+
+    @Test
+    void maximumCardinalityViolationOneToConstRelationship() throws InvalidFieldInYangDataException {
+        // TESTENTITYA_USES_TESTENTITYB is a 0..1 to 0..2 relationship
+        List<Entity> entities = generateEntities(MAXIMUM_CARDINALITY_CASE.ONE_CONST);
+        List<Relationship> relationships = new ArrayList<>();
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_USES_TESTENTITYB", "rel_1", "TestEntityA_1",
+                "TestEntityB_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_USES_TESTENTITYB", "rel_2", "TestEntityA_1",
+                "TestEntityB_2", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_USES_TESTENTITYB", "rel_3", "TestEntityA_1",
+                "TestEntityB_3", List.of()));
+        ParsedCloudEventData parsedCloudEventData = new ParsedCloudEventData(entities, relationships);
+        //It's expected to fail, because the TestEntityA_1 entity would be connected to 3 TestEntityB instances
+        assertThrows(MaximumCardinalityViolationException.class, () -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData));
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityA\"",
+                "TestEntityA_1");
+
+        //The whole transaction is rolled back. Neither the entities nor the relationships are persisted.
+        assertEmptyTable("ties_data.\"TestEntityA\"");
+        assertEmptyTable("ties_data.\"TestEntityB\"");
+
+        //Remove the extra relationship that caused the cardinality violation. Successfully insert the others.
+        Relationship redundantRelationship = relationships.remove(2);
+        ParsedCloudEventData parsedCloudEventData2 = new ParsedCloudEventData(entities, relationships);
+        assertEquals(entities.size() + relationships.size(), tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData2).size());
+        verify(spiedDbServiceForValidation, times(2)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityA\"",
+                "TestEntityA_1");
+        verify(spiedDbServiceForValidation, times(2)).executeValidationQuery(any(), any(), any(), any(Long.class));
+        verifyNoMoreInteractions(spiedDbServiceForValidation);
+
+        //Try to insert an extra relationship. It's expected to fail, because the CloudNativeSystem_1 entity already has the maximum number of relationships.
+        ParsedCloudEventData parsedCloudEventData3 = new ParsedCloudEventData(List.of(), List.of(redundantRelationship));
+        assertThrows(MaximumCardinalityViolationException.class, () -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData3));
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityA\"",
+                "TestEntityA_1");
+    }
+
+    @Test
+    void maximumCardinalityViolationConstToConstRelationship() throws InvalidFieldInYangDataException {
+        // TESTENTITYA_PROVIDES_TESTENTITYB is a 0..2 to 0..3 relationship
+        List<Entity> entities = generateEntities(MAXIMUM_CARDINALITY_CASE.CONST_CONST);
+        List<Relationship> relationships = new ArrayList<>();
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_PROVIDES_TESTENTITYB", "rel_1",
+                "TestEntityA_1", "TestEntityB_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_PROVIDES_TESTENTITYB", "rel_2",
+                "TestEntityA_1", "TestEntityB_2", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_PROVIDES_TESTENTITYB", "rel_3",
+                "TestEntityA_1", "TestEntityB_3", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_PROVIDES_TESTENTITYB", "rel_4",
+                "TestEntityA_1", "TestEntityB_4", List.of()));
+        ParsedCloudEventData parsedCloudEventData = new ParsedCloudEventData(entities, relationships);
+        //It's expected to fail, because the TestEntityA_1 entity would be connected to 4 TestEntityB instances
+        assertThrows(MaximumCardinalityViolationException.class, () -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData));
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityB\"",
+                "TestEntityB_1");
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityA\"",
+                "TestEntityA_1");
+
+        //The whole transaction is rolled back. Neither the entities nor the relationships are persisted.
+        assertEmptyTable("ties_data.\"TestEntityA\"");
+        assertEmptyTable("ties_data.\"TestEntityB\"");
+        assertEmptyTable("ties_data.\"TESTENTITYA_PROVIDES_TESTENTITYB\"");
+
+        //Test the other side's cardinality as well
+        relationships = new ArrayList<>();
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_PROVIDES_TESTENTITYB", "rel_1",
+                "TestEntityA_1", "TestEntityB_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_PROVIDES_TESTENTITYB", "rel_2",
+                "TestEntityA_2", "TestEntityB_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_PROVIDES_TESTENTITYB", "rel_3",
+                "TestEntityA_3", "TestEntityB_1", List.of()));
+
+        ParsedCloudEventData parsedCloudEventData2 = new ParsedCloudEventData(entities, relationships);
+        //It's expected to fail, because the TestEntityB_1 entity would be connected to 3 TestEntityA instances
+        assertThrows(MaximumCardinalityViolationException.class, () -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData2));
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityB\"",
+                "TestEntityB_1");
+        assertEmptyTable("ties_data.\"TestEntityA\"");
+        assertEmptyTable("ties_data.\"TestEntityB\"");
+        assertEmptyTable("ties_data.\"TESTENTITYA_PROVIDES_TESTENTITYB\"");
+    }
+
+    @Test
+    void maximumCardinalityViolationConstToInfiniteRelationship() throws InvalidFieldInYangDataException {
+        // TESTENTITYA_GROUPS_TESTENTITYB is a 0..2 to 0..n relationship
+        List<Entity> entities = generateEntities(MAXIMUM_CARDINALITY_CASE.CONST_INFINITE);
+        List<Relationship> relationships = new ArrayList<>();
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_GROUPS_TESTENTITYB", "rel_1", "TestEntityA_1",
+                "TestEntityB_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_GROUPS_TESTENTITYB", "rel_2", "TestEntityA_2",
+                "TestEntityB_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_GROUPS_TESTENTITYB", "rel_3", "TestEntityA_3",
+                "TestEntityB_1", List.of()));
+        ParsedCloudEventData parsedCloudEventData = new ParsedCloudEventData(entities, relationships);
+        //It's expected to fail, because the TestEntityB_1 entity would be connected to 3 TestEntityB instances
+        assertThrows(MaximumCardinalityViolationException.class, () -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData));
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityB\"",
+                "TestEntityB_1");
+
+        //The whole transaction is rolled back. Neither the entities nor the relationships are persisted.
+        assertEmptyTable("ties_data.\"TestEntityA\"");
+        assertEmptyTable("ties_data.\"TestEntityB\"");
+        assertEmptyTable("ties_data.\"TESTENTITYA_GROUPS_TESTENTITYB\"");
+
+        //Test the other side's cardinality
+        entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityB", "TestEntityB_2", Map.of(), List.of()));
+        entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityB", "TestEntityB_3", Map.of(), List.of()));
+        relationships = new ArrayList<>();
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_GROUPS_TESTENTITYB", "rel_1", "TestEntityA_1",
+                "TestEntityB_1", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_GROUPS_TESTENTITYB", "rel_2", "TestEntityA_1",
+                "TestEntityB_2", List.of()));
+        relationships.add(new Relationship("o-ran-smo-teiv-ran", "TESTENTITYA_GROUPS_TESTENTITYB", "rel_3", "TestEntityA_1",
+                "TestEntityB_3", List.of()));
+        ParsedCloudEventData parsedCloudEventData2 = new ParsedCloudEventData(entities, relationships);
+        assertEquals(entities.size() + relationships.size(), tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData2).size());
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityB\"",
+                "TestEntityB_1");
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityB\"",
+                "TestEntityB_2");
+        verify(spiedDbServiceForValidation, times(1)).acquireEntityInstanceExclusiveLock("ties_data.\"TestEntityB\"",
+                "TestEntityB_3");
+        verify(spiedDbServiceForValidation, times(3)).executeValidationQuery(any(), any(), any(), any(Long.class));
+        verifyNoMoreInteractions(spiedDbServiceForValidation);
+    }
+
+    @ParameterizedTest
+    @CsvSource({ "5, 5, A_SIDE", "3, 3, B_SIDE" })
+    void unsupportedStorageLocation(int aSideMax, int bSideMax, RelationshipDataLocation location)
+            throws InvalidFieldInYangDataException {
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            Relationship relationship = new Relationship("", "relation_type", "id", "a", "b", List.of());
+            RelationType relationType = RelationType.builder().aSideAssociation(Association.builder().maxCardinality(
+                    aSideMax).build()).bSideAssociation(Association.builder().maxCardinality(bSideMax).build())
+                    .relationshipStorageLocation(location).build();
+            mockedSchemaRegistry.when(() -> SchemaRegistry.getRelationTypeByName("relation_type")).thenReturn(relationType);
+            ParsedCloudEventData parsedCloudEventData = new ParsedCloudEventData(List.of(), List.of(relationship));
+            assertThrows(UnsupportedOperationException.class, () -> validatorFactory.createValidator(writeDataDslContext)
+                    .validate(parsedCloudEventData));
+        }
+    }
+
+    @Test
+    void determineMaxCardinalityCase() throws InvalidFieldInYangDataException {
+        assertThrows(IllegalArgumentException.class, () -> IngestionOperationValidator.determineMaxCardinalityCase(0, 0));
+        assertThrows(IllegalArgumentException.class, () -> IngestionOperationValidator.determineMaxCardinalityCase(-1, 0));
+        assertThrows(IllegalArgumentException.class, () -> IngestionOperationValidator.determineMaxCardinalityCase(0, -1));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.ONE_ONE, IngestionOperationValidator.determineMaxCardinalityCase(1, 1));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.ONE_CONST, IngestionOperationValidator.determineMaxCardinalityCase(1, 2));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.ONE_INFINITE, IngestionOperationValidator.determineMaxCardinalityCase(1,
+                Long.MAX_VALUE));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.CONST_ONE, IngestionOperationValidator.determineMaxCardinalityCase(5, 1));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.CONST_CONST, IngestionOperationValidator.determineMaxCardinalityCase(3, 4));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.CONST_INFINITE, IngestionOperationValidator.determineMaxCardinalityCase(4,
+                Long.MAX_VALUE));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.INFINITE_ONE, IngestionOperationValidator.determineMaxCardinalityCase(
+                Long.MAX_VALUE, 1));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.INFINITE_CONST, IngestionOperationValidator.determineMaxCardinalityCase(
+                Long.MAX_VALUE, 2));
+        assertEquals(MAXIMUM_CARDINALITY_CASE.INFINITE_INFINITE, IngestionOperationValidator.determineMaxCardinalityCase(
+                Long.MAX_VALUE, Long.MAX_VALUE));
+    }
+
+    @Test
+    void testMaxCardinalityIsLong() {
+        assertFalse(new TiesDbServiceForValidation(null).executeValidationQuery("", "", "", Long.MAX_VALUE));
+    }
+
+    void assertEmptyTable(String tableName) {
+        Result<Record> rows = writeDataDslContext.selectFrom(table(tableName)).fetch();
+        assertEquals(0, rows.size());
+    }
+
+    private List<Entity> generateEntities(MAXIMUM_CARDINALITY_CASE cardinalityCase) {
+        List<Entity> entities = new ArrayList<>();
+        switch (cardinalityCase) {
+            case ONE_ONE:
+                entities.add(new Entity("o-ran-smo-teiv-oam", "ManagedElement", "ManagedElement_1", Map.of("fdn", "fdn1"),
+                        List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-oam", "ManagedElement", "ManagedElement_2", Map.of("fdn", "fdn2"),
+                        List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-cloud", "CloudNativeSystem", "CloudNativeSystem_1", Map.of("name",
+                        "name1"), List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-cloud", "CloudNativeSystem", "CloudNativeSystem_2", Map.of("name",
+                        "name2"), List.of()));
+                break;
+            default:
+                entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityA", "TestEntityA_1", Map.of(), List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityA", "TestEntityA_2", Map.of(), List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityA", "TestEntityA_3", Map.of(), List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityB", "TestEntityB_1", Map.of(), List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityB", "TestEntityB_2", Map.of(), List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityB", "TestEntityB_3", Map.of(), List.of()));
+                entities.add(new Entity("o-ran-smo-teiv-ran", "TestEntityB", "TestEntityB_4", Map.of(), List.of()));
+                break;
+        }
+        return entities;
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/listener/CreateTopologyProcessorTest.java b/teiv/src/test/java/org/oran/smo/teiv/listener/CreateTopologyProcessorTest.java
new file mode 100644
index 0000000..df5cc07
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/listener/CreateTopologyProcessorTest.java
@@ -0,0 +1,167 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.service.TiesDbService;
+import org.oran.smo.teiv.service.cloudevent.CloudEventParser;
+import org.oran.smo.teiv.service.cloudevent.data.Entity;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import org.oran.smo.teiv.utils.CloudEventTestUtil;
+
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import io.cloudevents.CloudEvent;
+
+@SpringBootTest
+@ActiveProfiles({ "test", "ingestion" })
+class CreateTopologyProcessorTest {
+    @Autowired
+    private CreateTopologyProcessor createTopologyProcessor;
+
+    @MockBean
+    private CloudEventParser cloudEventParser;
+    @MockBean
+    private TiesDbService tiesDbService;
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @Autowired
+    private CustomMetrics metrics;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        SchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+    }
+
+    @Test
+    void testCreateCloudNativeApplicationEntity1() {
+        CloudEvent event = CloudEventTestUtil.getCloudEvent("create", "{}");
+        String entityType = "CloudNativeApplication";
+        Map<String, Object> yangParserOutputMapBSide = new HashMap<>();
+        Entity entity = new Entity("", entityType, "cloud_id_1", yangParserOutputMapBSide, List.of());
+
+        ParsedCloudEventData parsedData = new ParsedCloudEventData(List.of(entity), List.of());
+        when(cloudEventParser.getCloudEventData(any())).thenReturn(parsedData);
+
+        doThrow(new RuntimeException("test error")).when(tiesDbService).execute(anyList());
+        Assertions.assertDoesNotThrow(() -> createTopologyProcessor.process(event, anyString()));
+
+        Mockito.verify(tiesDbService, times(1)).execute(anyList());
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testInvalidAttribute() {
+        CloudEvent event = CloudEventTestUtil.getCloudEvent("create", "{}");
+        String entityType = "CloudNativeApplication";
+        Map<String, Object> yangParserOutputMap = new HashMap<>();
+        yangParserOutputMap.put("invalidfield", "value1");
+        Entity entity = new Entity("", entityType, "id1", yangParserOutputMap, List.of());
+        ParsedCloudEventData parsedData = new ParsedCloudEventData(List.of(entity), List.of());
+        when(cloudEventParser.getCloudEventData(ArgumentMatchers.any())).thenReturn(parsedData);
+
+        createTopologyProcessor.process(event, anyString());
+        verifyNoInteractions(tiesDbService);
+
+        assertEquals(1, metrics.getNumSuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getCloudEventCreatePersistTime().count());
+        assertEquals(0, metrics.getCloudEventMergePersistTime().count());
+        assertEquals(0, metrics.getCloudEventDeletePersistTime().count());
+        assertEquals(1, metrics.getCloudEventCreateParseTime().count());
+        assertEquals(0, metrics.getCloudEventMergeParseTime().count());
+        assertEquals(0, metrics.getCloudEventDeleteParseTime().count());
+
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(1, metrics.getNumUnsuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedDeleteCloudEvents().count());
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testInvalidGeoLocationAttribute() {
+        CloudEvent event = CloudEventTestUtil.getCloudEvent("create", "{}");
+        String entityType = "PhysicalNetworkAppliance";
+        Map<String, Object> yangParserOutputMap = new HashMap<>();
+        yangParserOutputMap.put("geo-location", 0);
+        Entity entity = new Entity("", entityType, "id1", yangParserOutputMap, List.of());
+        ParsedCloudEventData parsedData = new ParsedCloudEventData(List.of(entity), List.of());
+        when(cloudEventParser.getCloudEventData(ArgumentMatchers.any())).thenReturn(parsedData);
+
+        createTopologyProcessor.process(event, anyString());
+        verifyNoInteractions(tiesDbService);
+
+        assertEquals(1, metrics.getNumSuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getCloudEventCreatePersistTime().count());
+        assertEquals(0, metrics.getCloudEventMergePersistTime().count());
+        assertEquals(0, metrics.getCloudEventDeletePersistTime().count());
+        assertEquals(1, metrics.getCloudEventCreateParseTime().count());
+        assertEquals(0, metrics.getCloudEventMergeParseTime().count());
+        assertEquals(0, metrics.getCloudEventDeleteParseTime().count());
+
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(1, metrics.getNumUnsuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedDeleteCloudEvents().count());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/listener/DeleteTopologyProcessorTest.java b/teiv/src/test/java/org/oran/smo/teiv/listener/DeleteTopologyProcessorTest.java
new file mode 100644
index 0000000..5ecdd44
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/listener/DeleteTopologyProcessorTest.java
@@ -0,0 +1,85 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.service.TiesDbService;
+import org.oran.smo.teiv.service.cloudevent.CloudEventParser;
+import org.oran.smo.teiv.service.cloudevent.data.Entity;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import org.oran.smo.teiv.utils.CloudEventTestUtil;
+import io.cloudevents.CloudEvent;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+@SpringBootTest
+@ActiveProfiles({ "test", "ingestion" })
+class DeleteTopologyProcessorTest {
+
+    @Autowired
+    private DeleteTopologyProcessor deleteTopologyProcessor;
+
+    @MockBean
+    private CloudEventParser cloudEventParser;
+    @MockBean
+    private TiesDbService tiesDbService;
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        SchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+    }
+
+    @Test
+    void testDeleteCloudNativeApplicationEntity1() {
+        CloudEvent event = CloudEventTestUtil.getCloudEvent("delete", "{}");
+        String entityType = "CloudNativeApplication";
+        Map<String, Object> yangParserOutputMapBSide = new HashMap<>();
+        Entity entity = new Entity("", entityType, "cloud_id_1", yangParserOutputMapBSide, List.of());
+
+        ParsedCloudEventData parsedData = new ParsedCloudEventData(List.of(entity), List.of());
+        when(cloudEventParser.getCloudEventData(any())).thenReturn(parsedData);
+
+        doThrow(new RuntimeException("test error")).when(tiesDbService).execute(anyList());
+        Assertions.assertDoesNotThrow(() -> deleteTopologyProcessor.process(event, anyString()));
+
+        Mockito.verify(tiesDbService, times(1)).execute(anyList());
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/listener/MergeTopologyProcessorTest.java b/teiv/src/test/java/org/oran/smo/teiv/listener/MergeTopologyProcessorTest.java
new file mode 100644
index 0000000..28151ad
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/listener/MergeTopologyProcessorTest.java
@@ -0,0 +1,169 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.teiv.CustomMetrics;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import org.oran.smo.teiv.schema.SchemaLoader;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import io.cloudevents.CloudEvent;
+
+import org.oran.smo.teiv.service.TiesDbService;
+import org.oran.smo.teiv.service.cloudevent.CloudEventParser;
+import org.oran.smo.teiv.service.cloudevent.data.Entity;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.utils.CloudEventTestUtil;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+
+@SpringBootTest
+@ActiveProfiles({ "test", "ingestion" })
+class MergeTopologyProcessorTest {
+
+    @Autowired
+    private MergeTopologyProcessor mergeTopologyProcessor;
+
+    @MockBean
+    private CloudEventParser cloudEventParser;
+    @MockBean
+    private TiesDbService tiesDbService;
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @Autowired
+    private CustomMetrics metrics;
+
+    @BeforeAll
+    static void setUp() throws SchemaLoaderException {
+        SchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+    }
+
+    @Test
+    void testMergeCloudNativeApplicationEntity1() {
+        CloudEvent event = CloudEventTestUtil.getCloudEvent("merge", "{}");
+        String entityType = "CloudNativeApplication";
+        Map<String, Object> yangParserOutputMapBSide = new HashMap<>();
+        Entity entity = new Entity("", entityType, "cloud_id_1", yangParserOutputMapBSide, List.of());
+
+        ParsedCloudEventData parsedData = new ParsedCloudEventData(List.of(entity), List.of());
+        when(cloudEventParser.getCloudEventData(any())).thenReturn(parsedData);
+
+        doThrow(new RuntimeException("test error")).when(tiesDbService).execute(anyList());
+        Assertions.assertDoesNotThrow(() -> mergeTopologyProcessor.process(event, anyString()));
+
+        Mockito.verify(tiesDbService, times(1)).execute(anyList());
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testInvalidAttribute() {
+        CloudEvent event = CloudEventTestUtil.getCloudEvent("merge", "{}");
+        String entityType = "CloudNativeApplication";
+        Map<String, Object> yangParserOutputMap = new HashMap<>();
+        yangParserOutputMap.put("invalidfield", "value1");
+        Entity entity = new Entity("", entityType, "id1", yangParserOutputMap, List.of());
+        ParsedCloudEventData parsedData = new ParsedCloudEventData(List.of(entity), List.of());
+        when(cloudEventParser.getCloudEventData(ArgumentMatchers.any())).thenReturn(parsedData);
+
+        mergeTopologyProcessor.process(event, anyString());
+        verifyNoInteractions(tiesDbService);
+
+        assertEquals(0, metrics.getNumSuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(1, metrics.getNumSuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getCloudEventCreatePersistTime().count());
+        assertEquals(0, metrics.getCloudEventMergePersistTime().count());
+        assertEquals(0, metrics.getCloudEventDeletePersistTime().count());
+        assertEquals(0, metrics.getCloudEventCreateParseTime().count());
+        assertEquals(1, metrics.getCloudEventMergeParseTime().count());
+        assertEquals(0, metrics.getCloudEventDeleteParseTime().count());
+
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(1, metrics.getNumUnsuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedDeleteCloudEvents().count());
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testInvalidGeoLocationAttribute() {
+        CloudEvent event = CloudEventTestUtil.getCloudEvent("merge", "{}");
+        String entityType = "PhysicalNetworkAppliance";
+        Map<String, Object> yangParserOutputMap = new HashMap<>();
+        yangParserOutputMap.put("geo-location", 0);
+        Entity entity = new Entity("", entityType, "id1", yangParserOutputMap, List.of());
+        ParsedCloudEventData parsedData = new ParsedCloudEventData(List.of(entity), List.of());
+        when(cloudEventParser.getCloudEventData(ArgumentMatchers.any())).thenReturn(parsedData);
+
+        mergeTopologyProcessor.process(event, anyString());
+        verifyNoInteractions(tiesDbService);
+
+        assertEquals(0, metrics.getNumSuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(1, metrics.getNumSuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumSuccessfullyPersistedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getCloudEventCreatePersistTime().count());
+        assertEquals(0, metrics.getCloudEventMergePersistTime().count());
+        assertEquals(0, metrics.getCloudEventDeletePersistTime().count());
+        assertEquals(0, metrics.getCloudEventCreateParseTime().count());
+        assertEquals(1, metrics.getCloudEventMergeParseTime().count());
+        assertEquals(0, metrics.getCloudEventDeleteParseTime().count());
+
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedCreateCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyParsedDeleteCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedCreateCloudEvents().count());
+        assertEquals(1, metrics.getNumUnsuccessfullyPersistedMergeCloudEvents().count());
+        assertEquals(0, metrics.getNumUnsuccessfullyPersistedDeleteCloudEvents().count());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorTest.java b/teiv/src/test/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorTest.java
new file mode 100644
index 0000000..1d285ae
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorTest.java
@@ -0,0 +1,136 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.TiesDbService;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+@SpringBootTest
+@AutoConfigureJson
+@ActiveProfiles({ "test", "ingestion" })
+class SourceEntityDeleteTopologyProcessorTest {
+    @Autowired
+    private SourceEntityDeleteTopologyProcessor sourceEntityDeleteTopologyProcessor;
+
+    @Autowired
+    CustomMetrics metrics;
+    @MockBean
+    private TiesDbService tiesDbService;
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testSourceEntityDeleteWithInvalidEventData() {
+        //given
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            CloudEvent event = CloudEventBuilder.v1().withId("test-id").withType("ran-logical.source-entity-delete")
+                    .withSource(URI.create("http://localhost:8080/test-source")).withDataContentType("application/json")
+                    .withDataSchema(URI.create("http://localhost:8080/schema/v1/source-entity-delete")).withData(
+                            "{\"type\":\"cmHandle\",\"invalid\":\"abc\"}".getBytes(StandardCharsets.UTF_8)).build();
+            //when
+            assertDoesNotThrow(() -> sourceEntityDeleteTopologyProcessor.process(event, "messageKey"));
+            //then
+            mockedSchemaRegistry.verifyNoInteractions();
+            verifyNoInteractions(tiesDbService);
+
+            assertEquals(0, metrics.getNumSuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumSuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getCloudEventSourceEntityDeleteParseTime().count());
+            assertEquals(0, metrics.getCloudEventSourceEntityDeletePersistTime().count());
+        }
+    }
+
+    @Test
+    void testSourceEntityDeleteWithUnsupportedEntityType() {
+        //given
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            CloudEvent event = CloudEventBuilder.v1().withId("test-id").withType("ran-logical.source-entity-delete")
+                    .withSource(URI.create("http://localhost:8080/test-source")).withDataContentType("application/json")
+                    .withDataSchema(URI.create("http://localhost:8080/schema/v1/source-entity-delete")).withData(
+                            "{\"type\":\"unsupported-type\",\"value\":\"abc\"}".getBytes(StandardCharsets.UTF_8)).build();
+            //when
+            assertDoesNotThrow(() -> sourceEntityDeleteTopologyProcessor.process(event, "messageKey"));
+            //then
+            mockedSchemaRegistry.verifyNoInteractions();
+            verifyNoInteractions(tiesDbService);
+        }
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testSourceEntityDeleteUponRuntimeExceptionDuringDeletion() {
+        //given
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            EntityType entityType = Mockito.mock(EntityType.class);
+            CloudEvent event = CloudEventBuilder.v1().withId("test-id").withType("ran-logical.source-entity-delete")
+                    .withSource(URI.create("http://localhost:8080/test-source")).withDataContentType("application/json")
+                    .withDataSchema(URI.create("http://localhost:8080/schema/v1/source-entity-delete")).withData(
+                            "{\"type\":\"cmHandle\",\"value\":\"abc\"}".getBytes(StandardCharsets.UTF_8)).build();
+            mockedSchemaRegistry.when(SchemaRegistry::getEntityTypesWithCmId).thenReturn(List.of(entityType));
+            doThrow(new RuntimeException()).when(tiesDbService).execute(anyList());
+            //when
+            assertDoesNotThrow(() -> sourceEntityDeleteTopologyProcessor.process(event, "messageKey"));
+            //then
+            mockedSchemaRegistry.verify(SchemaRegistry::getEntityTypesWithCmId, times(1));
+            verify(tiesDbService, times(1)).execute(anyList());
+
+            assertEquals(1, metrics.getNumSuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumSuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getCloudEventSourceEntityDeleteParseTime().count());
+            assertTrue(metrics.getCloudEventSourceEntityDeleteParseTime().totalTime(TimeUnit.NANOSECONDS) > 0);
+            assertEquals(0, metrics.getCloudEventSourceEntityDeletePersistTime().count());
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorV1Test.java b/teiv/src/test/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorV1Test.java
new file mode 100644
index 0000000..08818dc
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/listener/SourceEntityDeleteTopologyProcessorV1Test.java
@@ -0,0 +1,196 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.listener;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.Field;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import org.jooq.DSLContext;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.service.models.OperationResult;
+import org.oran.smo.teiv.schema.BidiDbNameMapper;
+import org.oran.smo.teiv.schema.EntityType;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.TiesDbOperations;
+import org.oran.smo.teiv.service.TiesDbService;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+@SpringBootTest(properties = "feature_flags.use_alternate_delete_logic=true")
+@AutoConfigureJson
+@ActiveProfiles({ "test", "ingestion" })
+class SourceEntityDeleteTopologyProcessorV1Test {
+
+    @Autowired
+    private SourceEntityDeleteTopologyProcessorV1 sourceEntityDeleteTopologyProcessor;
+    @Autowired
+    CustomMetrics metrics;
+    @MockBean
+    private TiesDbService tiesDbService;
+    @MockBean
+    private TiesDbOperations tiesDbOperations;
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testSourceEntityDeleteWithInvalidEventData() {
+        //given
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            CloudEvent event = CloudEventBuilder.v1().withId("test-id").withType("ran-logical.source-entity-delete")
+                    .withSource(URI.create("http://localhost:8080/test-source")).withDataContentType("application/json")
+                    .withDataSchema(URI.create("http://localhost:8080/schema/v1/source-entity-delete")).withData(
+                            "{\"type\":\"cmHandle\",\"invalid\":\"abc\"}".getBytes(StandardCharsets.UTF_8)).build();
+            //when
+            assertDoesNotThrow(() -> sourceEntityDeleteTopologyProcessor.process(event, "messageKey"));
+            //then
+            mockedSchemaRegistry.verifyNoInteractions();
+            verifyNoInteractions(tiesDbService);
+
+            assertEquals(0, metrics.getNumSuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumSuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getCloudEventSourceEntityDeleteParseTime().count());
+            assertEquals(0, metrics.getCloudEventSourceEntityDeletePersistTime().count());
+        }
+    }
+
+    @Test
+    void testSourceEntityDeleteWithUnsupportedEntityType() {
+        //given
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            CloudEvent event = CloudEventBuilder.v1().withId("test-id").withType("ran-logical.source-entity-delete")
+                    .withSource(URI.create("http://localhost:8080/test-source")).withDataContentType("application/json")
+                    .withDataSchema(URI.create("http://localhost:8080/schema/v1/source-entity-delete")).withData(
+                            "{\"type\":\"unsupported-type\",\"value\":\"abc\"}".getBytes(StandardCharsets.UTF_8)).build();
+            //when
+            assertDoesNotThrow(() -> sourceEntityDeleteTopologyProcessor.process(event, "messageKey"));
+            //then
+            mockedSchemaRegistry.verifyNoInteractions();
+            verifyNoInteractions(tiesDbService);
+        }
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testSourceEntityDeleteUponRuntimeExceptionDuringDeletion() {
+        //given
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            EntityType entityType = Mockito.mock(EntityType.class);
+            CloudEvent event = CloudEventBuilder.v1().withId("test-id").withType("ran-logical.source-entity-delete")
+                    .withSource(URI.create("http://localhost:8080/test-source")).withDataContentType("application/json")
+                    .withDataSchema(URI.create("http://localhost:8080/schema/v1/source-entity-delete")).withData(
+                            "{\"type\":\"cmHandle\",\"value\":\"abc\"}".getBytes(StandardCharsets.UTF_8)).build();
+            mockedSchemaRegistry.when(SchemaRegistry::getEntityTypes).thenReturn(List.of(entityType));
+            doThrow(new RuntimeException()).when(tiesDbService).execute(anyList());
+            //when
+            assertDoesNotThrow(() -> sourceEntityDeleteTopologyProcessor.process(event, "messageKey"));
+            //then
+            mockedSchemaRegistry.verify(SchemaRegistry::getEntityTypes, times(1));
+            verify(tiesDbService, times(1)).execute(anyList());
+
+            assertEquals(1, metrics.getNumSuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumSuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getCloudEventSourceEntityDeleteParseTime().count());
+            assertTrue(metrics.getCloudEventSourceEntityDeleteParseTime().totalTime(TimeUnit.NANOSECONDS) > 0);
+            assertEquals(0, metrics.getCloudEventSourceEntityDeletePersistTime().count());
+        }
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testSourceEntityDelete() throws NoSuchFieldException {
+        //given
+        try (MockedStatic<SchemaRegistry> mockedSchemaRegistry = Mockito.mockStatic(SchemaRegistry.class)) {
+            DSLContext stream = mock(DSLContext.class);
+            CloudEvent event = CloudEventBuilder.v1().withId("test-id").withType("ran-logical.source-entity-delete")
+                    .withSource(URI.create("http://localhost:8080/test-source")).withDataContentType("application/json")
+                    .withDataSchema(URI.create("http://localhost:8080/schema/v1/source-entity-delete")).withData(
+                            "{\"type\":\"cmHandle\",\"value\":\"395221E080CCF0FD1924103B15873814\"}".getBytes(
+                                    StandardCharsets.UTF_8)).build();
+
+            Map<String, String> mockNameMap = new HashMap<>();
+            mockNameMap.put("GNBDUFunction", "GNBDUFunction");
+            Field nameMapField = BidiDbNameMapper.class.getDeclaredField("nameMap");
+            nameMapField.setAccessible(true);
+            nameMapField.set(null, mockNameMap);
+
+            OperationResult mockOperationResult = mock(OperationResult.class);
+            EntityType gnbduFunction = EntityType.builder().name("GNBDUFunction").build();
+            when(SchemaRegistry.getEntityTypes()).thenReturn(List.of(gnbduFunction));
+            when(tiesDbOperations.selectByCmHandleFormSourceIds(any(), anyString(), anyString())).thenReturn(List.of(
+                    "result1"));
+            when(tiesDbOperations.deleteEntity(any(), any(), anyString())).thenReturn(List.of(mockOperationResult));
+            doAnswer(new Answer<Void>() {
+                @Override
+                public Void answer(InvocationOnMock invocation) throws Throwable {
+                    List<Consumer<DSLContext>> consumers = invocation.getArgument(0);
+                    consumers.forEach(consumer -> {
+                        consumer.accept(stream);
+                    });
+                    return null;
+                }
+            }).when(tiesDbService).execute(anyList());
+            //when
+            assertDoesNotThrow(() -> sourceEntityDeleteTopologyProcessor.process(event, "messageKey"));
+            //then
+            mockedSchemaRegistry.verify(SchemaRegistry::getEntityTypes, times(1));
+            verify(tiesDbService, atLeastOnce()).execute(anyList());
+            verify(tiesDbOperations, atLeastOnce()).selectByCmHandleFormSourceIds(any(), anyString(), anyString());
+            verify(tiesDbOperations, atLeastOnce()).deleteEntity(any(), any(), anyString());
+
+            assertEquals(1, metrics.getNumSuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumUnsuccessfullyParsedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getNumSuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(0, metrics.getNumUnsuccessfullyPersistedSourceEntityDeleteCloudEvents().count());
+            assertEquals(1, metrics.getCloudEventSourceEntityDeleteParseTime().count());
+            assertEquals(1, metrics.getCloudEventSourceEntityDeletePersistTime().count());
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/schema/ConsumerDataCacheTest.java b/teiv/src/test/java/org/oran/smo/teiv/schema/ConsumerDataCacheTest.java
new file mode 100644
index 0000000..3bc66ca
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/schema/ConsumerDataCacheTest.java
@@ -0,0 +1,68 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import org.oran.smo.teiv.exposure.spi.DataPersistanceService;
+import org.oran.smo.teiv.exposure.spi.impl.DataPersistanceServiceImpl;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ConsumerDataCacheTest {
+
+    private static final DataPersistanceService dataPersistanceService = mock(DataPersistanceServiceImpl.class);
+    private final ConsumerDataCache underTest = new ConsumerDataCache(dataPersistanceService);
+
+    @BeforeAll
+    static void beforeAll() {
+        when(dataPersistanceService.loadClassifiers()).thenReturn(Set.of("gnbdu-function-model:Rural",
+                "gnbcucp-gnbcuup-model:Weekend"));
+        when(dataPersistanceService.loadDecorators()).thenReturn(Map.of("gnbdu-function-model:location", DataType.PRIMITIVE,
+                "gnbcucp-gnbcuup-model:metadata", DataType.CONTAINER));
+    }
+
+    @Test
+    void testGetValidClassifiers() {
+        assertEquals(Set.of("gnbdu-function-model:Rural"), underTest.getValidClassifiers("gnbdu-function-model:Rural"));
+        assertEquals(Set.of("gnbdu-function-model:Rural"), underTest.getValidClassifiers("gnbdu-function-model:"));
+        assertEquals(Set.of("gnbdu-function-model:Rural", "gnbcucp-gnbcuup-model:Weekend"), underTest.getValidClassifiers(
+                ""));
+        assertEquals(Collections.emptySet(), underTest.getValidClassifiers("gnbcucp-gnbcuup-model:Weekday"));
+    }
+
+    @Test
+    void testGetClassifiers() {
+        assertEquals(Set.of("gnbdu-function-model:Rural", "gnbcucp-gnbcuup-model:Weekend"), underTest.getClassifiers());
+    }
+
+    @Test
+    void testGetDecorators() {
+        assertEquals(Map.of("gnbdu-function-model:location", DataType.PRIMITIVE, "gnbcucp-gnbcuup-model:metadata",
+                DataType.CONTAINER), underTest.getDecorators());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/schema/MockSchemaLoader.java b/teiv/src/test/java/org/oran/smo/teiv/schema/MockSchemaLoader.java
new file mode 100644
index 0000000..026a08e
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/schema/MockSchemaLoader.java
@@ -0,0 +1,595 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.oran.smo.teiv.schema.DataType.BIGINT;
+import static org.oran.smo.teiv.schema.DataType.CONTAINER;
+import static org.oran.smo.teiv.schema.DataType.DECIMAL;
+import static org.oran.smo.teiv.schema.DataType.GEOGRAPHIC;
+import static org.oran.smo.teiv.schema.DataType.PRIMITIVE;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.RELATION;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.A_SIDE;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.B_SIDE;
+
+public class MockSchemaLoader extends SchemaLoader {
+
+    @Override
+    protected void loadBidiDbNameMapper() {
+
+        Map<String, String> hashedNames = new HashMap<>();
+        hashedNames.put("GNBDUFunction", "GNBDUFunction");
+        hashedNames.put("GNBCUUPFunction", "GNBCUUPFunction");
+        hashedNames.put("NRCellDU", "NRCellDU");
+        hashedNames.put("NRSectorCarrier", "NRSectorCarrier");
+        hashedNames.put("CloudNativeApplication", "CloudNativeApplication");
+        hashedNames.put("AntennaCapability", "AntennaCapability");
+        hashedNames.put("Sector", "Sector");
+        hashedNames.put("AntennaModule", "AntennaModule");
+
+        hashedNames.put("ANTENNAMODULE_INSTALLED_AT_SITE", "ANTENNAMODULE_INSTALLED_AT_SITE");
+        hashedNames.put("GNBDUFUNCTION_PROVIDES_NRCELLDU", "GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        hashedNames.put("GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", "GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER");
+        hashedNames.put("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION",
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        hashedNames.put("NRSECTORCARRIER_USES_ANTENNACAPABILITY", "NRSECTORCARRIER_USES_ANTENNACAPABILITY");
+        hashedNames.put("SECTOR_GROUPS_ANTENNAMODULE", "SECTOR_GROUPS_ANTENNAMODULE");
+        hashedNames.put("ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE");
+
+        hashedNames.put("id", "id");
+        hashedNames.put("fdn", "fdn");
+        hashedNames.put("cmId", "cmId");
+        hashedNames.put("CD_sourceIds", "CD_sourceIds");
+
+        // GNBDUFUNCTION
+        hashedNames.put("dUpLMNId", "dUpLMNId");
+        hashedNames.put("gNBIdLength", "gNBIdLength");
+        hashedNames.put("gNBId", "gNBId");
+        hashedNames.put("gNBDUId", "gNBDUId");
+        hashedNames.put("REL_FK_managed-by-managedElement", "REL_FK_managed-by-managedElement");
+        hashedNames.put("REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION", "REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");
+
+        //NRCELLDU
+        hashedNames.put("nCI", "nCI");
+        hashedNames.put("cellLocalId", "cellLocalId");
+        hashedNames.put("nRPCI", "nRPCI");
+        hashedNames.put("nRTAC", "nRTAC");
+        hashedNames.put("REL_FK_grouped-by-sector", "REL_FK_grouped-by-sector");
+        hashedNames.put("REL_ID_SECTOR_GROUPS_NRCELLDU", "REL_ID_SECTOR_GROUPS_NRCELLDU");
+        hashedNames.put("REL_FK_provided-by-gnbduFunction", "REL_FK_provided-by-gnbduFunction");
+        hashedNames.put("REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU", "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        hashedNames.put("REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU",
+                "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU");
+
+        //NrSectorCarrier
+        hashedNames.put("frequencyDL", "frequencyDL");
+        hashedNames.put("frequencyUL", "frequencyUL");
+        hashedNames.put("arfcnUL", "arfcnUL");
+        hashedNames.put("essScLocalId", "essScLocalId");
+        hashedNames.put("arfcnDL", "arfcnDL");
+        hashedNames.put("REL_FK_used-by-nrCellDu", "REL_FK_used-by-nrCellDu");
+        hashedNames.put("REL_ID_NRCELLDU_USES_NRSECTORCARRIER", "REL_ID_NRCELLDU_USES_NRSECTORCARRIER");
+        hashedNames.put("REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", "REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER");
+        hashedNames.put("REL_FK_used-antennaCapability", "REL_FK_used-antennaCapability");
+        hashedNames.put("REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY", "REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY");
+
+        //CloudNativeApplication
+        hashedNames.put("name", "name");
+        hashedNames.put("REL_FK_realised-managedElement", "REL_FK_realised-managedElement");
+        hashedNames.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION",
+                "REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        hashedNames.put("REL_FK_comprised-by-cloudNativeSystem", "REL_FK_comprised-by-cloudNativeSystem");
+        hashedNames.put("REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION",
+                "REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION");
+        hashedNames.put("REL_FK_deployed-on-namespace", "REL_FK_deployed-on-namespace");
+        hashedNames.put("REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE",
+                "REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE");
+
+        //AntennaCapability
+        hashedNames.put("nRFqBands", "nRFqBands");
+        hashedNames.put("eUtranFqBands", "eUtranFqBands");
+        hashedNames.put("geranFqBands", "geranFqBands");
+        hashedNames.put("REL_FK_used-by-lteSectorCarrier", "REL_FK_used-by-lteSectorCarrier");
+
+        //Sector
+        hashedNames.put("sectorId", "sectorId");
+        hashedNames.put("azimuth", "azimuth");
+
+        //AntennaModule
+        hashedNames.put("positionWithinSector", "positionWithinSector");
+        hashedNames.put("antennaModelNumber", "antennaModelNumber");
+        hashedNames.put("electricalAntennaTilt", "electricalAntennaTilt");
+        hashedNames.put("mechanicalAntennaTilt", "mechanicalAntennaTilt");
+        hashedNames.put("totalTilt", "totalTilt");
+        hashedNames.put("mechanicalAntennaBearing", "mechanicalAntennaBearing");
+        hashedNames.put("REL_ID_SECTOR_GROUPS_ANTENNAMODULE", "REL_ID_SECTOR_GROUPS_ANTENNAMODULE");
+        hashedNames.put("REL_FK_installed-at-site", "REL_FK_installed-at-site");
+        hashedNames.put("REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE", "REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE");
+
+        //GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION
+        hashedNames.put("aSide_GNBDUFunction", "aSide_GNBDUFunction");
+        hashedNames.put("bSide_CloudNativeApplication", "bSide_CloudNativeApplication");
+
+        //ANTENNAMODULE_REALISED_BY_ANTENNAMODULE
+        hashedNames.put("aSide_AntennaModule", "aSide_AntennaModule");
+        hashedNames.put("bSide_AntennaModule", "bSide_AntennaModule");
+
+        Map<String, String> reverseHashedNames = new HashMap<>();
+        reverseHashedNames.put("GNBDUFunction", "GNBDUFunction");
+        reverseHashedNames.put("GNBCUUPFunction", "GNBCUUPFunction");
+        reverseHashedNames.put("NRCellDU", "NRCellDU");
+        reverseHashedNames.put("NRSectorCarrier", "NRSectorCarrier");
+        reverseHashedNames.put("CloudNativeApplication", "CloudNativeApplication");
+        reverseHashedNames.put("AntennaCapability", "AntennaCapability");
+        reverseHashedNames.put("Sector", "Sector");
+        reverseHashedNames.put("AntennaModule", "AntennaModule");
+
+        reverseHashedNames.put("ANTENNAMODULE_INSTALLED_AT_SITE", "ANTENNAMODULE_INSTALLED_AT_SITE");
+        reverseHashedNames.put("GNBDUFUNCTION_PROVIDES_NRCELLDU", "GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        reverseHashedNames.put("GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", "GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER");
+        reverseHashedNames.put("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION",
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        reverseHashedNames.put("NRSECTORCARRIER_USES_ANTENNACAPABILITY", "NRSECTORCARRIER_USES_ANTENNACAPABILITY");
+        reverseHashedNames.put("SECTOR_GROUPS_ANTENNAMODULE", "SECTOR_GROUPS_ANTENNAMODULE");
+        reverseHashedNames.put("ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE");
+
+        reverseHashedNames.put("id", "id");
+        reverseHashedNames.put("fdn", "fdn");
+        reverseHashedNames.put("cmId", "cmId");
+        reverseHashedNames.put("CD_sourceIds", "CD_sourceIds");
+
+        // GNBDUFUNCTION
+        reverseHashedNames.put("dUpLMNId", "dUpLMNId");
+        reverseHashedNames.put("gNBIdLength", "gNBIdLength");
+        reverseHashedNames.put("gNBId", "gNBId");
+        reverseHashedNames.put("gNBDUId", "gNBDUId");
+        reverseHashedNames.put("REL_FK_managed-by-managedElement", "REL_FK_managed-by-managedElement");
+        reverseHashedNames.put("REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION",
+                "REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");
+
+        //NRCELLDU
+        reverseHashedNames.put("nCI", "nCI");
+        reverseHashedNames.put("cellLocalId", "cellLocalId");
+        reverseHashedNames.put("nRPCI", "nRPCI");
+        reverseHashedNames.put("nRTAC", "nRTAC");
+        reverseHashedNames.put("REL_FK_grouped-by-sector", "REL_FK_grouped-by-sector");
+        reverseHashedNames.put("REL_ID_SECTOR_GROUPS_NRCELLDU", "REL_ID_SECTOR_GROUPS_NRCELLDU");
+        reverseHashedNames.put("REL_FK_provided-by-gnbduFunction", "REL_FK_provided-by-gnbduFunction");
+        reverseHashedNames.put("REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU", "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU");
+        reverseHashedNames.put("REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU",
+                "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU");
+
+        //NrSectorCarrier
+        reverseHashedNames.put("frequencyDL", "frequencyDL");
+        reverseHashedNames.put("frequencyUL", "frequencyUL");
+        reverseHashedNames.put("arfcnUL", "arfcnUL");
+        reverseHashedNames.put("essScLocalId", "essScLocalId");
+        reverseHashedNames.put("arfcnDL", "arfcnDL");
+        reverseHashedNames.put("REL_FK_used-by-nrCellDu", "REL_FK_used-by-nrCellDu");
+        reverseHashedNames.put("REL_ID_NRCELLDU_USES_NRSECTORCARRIER", "REL_ID_NRCELLDU_USES_NRSECTORCARRIER");
+        reverseHashedNames.put("REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER",
+                "REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER");
+        reverseHashedNames.put("REL_FK_used-antennaCapability", "REL_FK_used-antennaCapability");
+        reverseHashedNames.put("REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY",
+                "REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY");
+
+        //CloudNativeApplication
+        reverseHashedNames.put("name", "name");
+        reverseHashedNames.put("REL_FK_realised-managedElement", "REL_FK_realised-managedElement");
+        reverseHashedNames.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION",
+                "REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        reverseHashedNames.put("REL_FK_comprised-by-cloudNativeSystem", "REL_FK_comprised-by-cloudNativeSystem");
+        reverseHashedNames.put("REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION",
+                "REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION");
+        reverseHashedNames.put("REL_FK_deployed-on-namespace", "REL_FK_deployed-on-namespace");
+        reverseHashedNames.put("REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE",
+                "REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE");
+
+        //AntennaCapability
+        reverseHashedNames.put("nRFqBands", "nRFqBands");
+        reverseHashedNames.put("eUtranFqBands", "eUtranFqBands");
+        reverseHashedNames.put("geranFqBands", "geranFqBands");
+        reverseHashedNames.put("REL_FK_used-by-lteSectorCarrier", "REL_FK_used-by-lteSectorCarrier");
+
+        //Sector
+        reverseHashedNames.put("sectorId", "sectorId");
+        reverseHashedNames.put("azimuth", "azimuth");
+
+        //AntennaModule
+        reverseHashedNames.put("positionWithinSector", "positionWithinSector");
+        reverseHashedNames.put("antennaModelNumber", "antennaModelNumber");
+        reverseHashedNames.put("electricalAntennaTilt", "electricalAntennaTilt");
+        reverseHashedNames.put("mechanicalAntennaTilt", "mechanicalAntennaTilt");
+        reverseHashedNames.put("totalTilt", "totalTilt");
+        reverseHashedNames.put("mechanicalAntennaBearing", "mechanicalAntennaBearing");
+        reverseHashedNames.put("REL_ID_SECTOR_GROUPS_ANTENNAMODULE", "REL_ID_SECTOR_GROUPS_ANTENNAMODULE");
+        reverseHashedNames.put("REL_FK_installed-at-site", "REL_FK_installed-at-site");
+        reverseHashedNames.put("REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE", "REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE");
+
+        //GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION
+        reverseHashedNames.put("aSide_GNBDUFunction", "aSide_GNBDUFunction");
+        reverseHashedNames.put("bSide_CloudNativeApplication", "bSide_CloudNativeApplication");
+
+        //ANTENNAMODULE_REALISED_BY_ANTENNAMODULE
+        reverseHashedNames.put("aSide_AntennaModule", "aSide_AntennaModule");
+        reverseHashedNames.put("bSide_AntennaModule", "bSide_AntennaModule");
+
+        BidiDbNameMapper.initialize(hashedNames, reverseHashedNames);
+    }
+
+    @Override
+    protected void loadModules() {
+        Module ranLogicalModule = Module.builder().name("o-ran-smo-teiv-ran").namespace("urn:o-ran:smo-teiv-ran").domain(
+                "RAN").build();
+
+        Module ranEquipmentModule = Module.builder().name("o-ran-smo-teiv-equipment").namespace(
+                "urn:o-ran:smo-teiv-equipment").domain("EQUIPMENT").build();
+
+        Module ranCloudModule = Module.builder().name("o-ran-smo-teiv-cloud").namespace("urn:o-ran:smo-teiv-cloud").domain(
+                "CLOUD").build();
+
+        Module ranLogicalToEquipmentModule = Module.builder().name("o-ran-smo-teiv-equipment-to-ran").namespace(
+                "urn:o-ran:smo-teiv-equipment-to-ran").domain("EQUIPMENT_TO_RAN").includedModuleName("o-ran-smo-teiv-ran")
+                .includedModuleName("o-ran-smo-teiv-equipment").build();
+
+        Module ranLogicalToCloudModule = Module.builder().name("o-ran-smo-teiv-cloud-to-ran").namespace(
+                "urn:o-ran:smo-teiv-cloud-to-ran").domain("CLOUD_TO_RAN").includedModuleName("o-ran-smo-teiv-ran")
+                .includedModuleName("o-ran-smo-teiv-cloud").build();
+
+        Module ranOamModule = Module.builder().name("o-ran-smo-teiv-oam").namespace("urn:o-ran:smo-teiv-oam").domain("OAM")
+                .build();
+
+        Module ranOamToLogicalModule = Module.builder().name("o-ran-smo-teiv-oam-to-ran").namespace(
+                "urn:o-ran:smo-teiv-oam-to-ran").domain("OAM_TO_RAN").includedModuleName("o-ran-smo-teiv-oam")
+                .includedModuleName("o-ran-smo-teiv-ran").build();
+
+        Module ranOamToCloudModule = Module.builder().name("o-ran-smo-teiv-oam-to-cloud").namespace(
+                "urn:o-ran:smo-teiv-oam-to-cloud").domain("OAM_TO_CLOUD").includedModuleName("o-ran-smo-teiv-oam")
+                .includedModuleName("o-ran-smo-teiv-cloud").build();
+
+        List<Module> modules = List.of(ranLogicalModule, ranEquipmentModule, ranCloudModule, ranLogicalToEquipmentModule,
+                ranLogicalToCloudModule, ranOamModule, ranOamToLogicalModule, ranOamToCloudModule);
+        Map<String, Module> moduleMap = new HashMap<>();
+        modules.forEach(module -> moduleMap.put(module.getName(), module));
+        SchemaRegistry.initializeModules(moduleMap);
+    }
+
+    @Override
+    protected void loadEntityTypes() {
+        EntityType gnbduFunction = EntityType.builder().name("GNBDUFunction").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-ran")).fields(getGnbduFunctionFields()).build();
+        EntityType gnbcuupFunction = EntityType.builder().name("GNBCUUPFunction").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-ran")).fields(getGnbcuupFunctionFields()).build();
+
+        EntityType nrCellDU = EntityType.builder().name("NRCellDU").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-ran")).fields(getNrCellDuFields()).build();
+
+        EntityType nrSectorCarrier = EntityType.builder().name("NRSectorCarrier").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-ran")).fields(getNrSectorCarrierFields()).build();
+
+        EntityType gNBCUCPFunction = EntityType.builder().name("GNBCUCPFunction").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-cloud-to-ran")).fields(getGNBCUCPFunctionFields()).build();
+
+        EntityType managedElement = EntityType.builder().name("ManagedElement").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-oam")).fields(getManagedElementFields()).build();
+
+        EntityType cloudNativeApplication = EntityType.builder().name("CloudNativeApplication").module(SchemaRegistry
+                .getModuleByName("o-ran-smo-teiv-cloud")).fields(getCloudNativeApplicationFields()).build();
+
+        EntityType antennaCapability = EntityType.builder().name("AntennaCapability").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-ran")).fields(getAntennaCapabilityFields()).build();
+
+        EntityType sector = EntityType.builder().name("Sector").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-equipment-to-ran")).fields(getSectorFields()).build();
+
+        EntityType antennaModule = EntityType.builder().name("AntennaModule").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-equipment")).fields(getAntennaModuleFields()).build();
+
+        EntityType site = EntityType.builder().name("Site").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-equipment")).fields(getSiteFields()).build();
+
+        EntityType cloudSite = EntityType.builder().name("CloudSite").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-cloud")).fields(getCloudSiteFields()).build();
+
+        EntityType nodeCluster = EntityType.builder().name("NodeCluster").module(SchemaRegistry.getModuleByName(
+                "o-ran-smo-teiv-cloud")).fields(getNodeClusterFields()).build();
+
+        List<EntityType> entityTypes = List.of(gnbduFunction, gnbcuupFunction, nrCellDU, nrSectorCarrier, gNBCUCPFunction,
+                managedElement, cloudNativeApplication, antennaCapability, sector, antennaModule, site, cloudSite,
+                nodeCluster);
+        Map<String, EntityType> entityTypeMap = new HashMap<>();
+        entityTypes.forEach(entityType -> entityTypeMap.put(entityType.getName(), entityType));
+        SchemaRegistry.initializeEntityTypes(entityTypeMap);
+    }
+
+    @Override
+    protected void loadRelationTypes() {
+
+        RelationType antennaModuleInstalledAtSite = RelationType.builder().name("ANTENNAMODULE_INSTALLED_AT_SITE")
+                .aSideAssociation(getRelationshipAssociation("installed-at-site", 0, 9223372036854775807L)).aSide(
+                        SchemaRegistry.getEntityTypeByName("AntennaModule")).bSideAssociation(getRelationshipAssociation(
+                                "installed-antennaModule", 0, 1)).bSide(SchemaRegistry.getEntityTypeByName("Site"))
+                .connectsSameEntity(false).relationshipStorageLocation(A_SIDE).module(SchemaRegistry.getModuleByName(
+                        "o-ran-smo-teiv-equipment")).build();
+
+        RelationType gnbduFunctionProvidesNrcelldu = RelationType.builder().name("GNBDUFUNCTION_PROVIDES_NRCELLDU")
+                .aSideAssociation(getRelationshipAssociation("provided-nrCellDu", 1, 1)).aSide(SchemaRegistry
+                        .getEntityTypeByName("GNBDUFunction")).bSideAssociation(getRelationshipAssociation(
+                                "provided-by-gnbduFunction", 0, 9223372036854775807L)).bSide(SchemaRegistry
+                                        .getEntityTypeByName("NRCellDU")).connectsSameEntity(false)
+                .relationshipStorageLocation(B_SIDE).module(SchemaRegistry.getModuleByName("o-ran-smo-teiv-ran")).build();
+
+        RelationType gnbduFunctionProvidesNrsectorcarrier = RelationType.builder().name(
+                "GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER").aSideAssociation(getRelationshipAssociation(
+                        "provided-nrSectorCarrier", 1, 1)).aSide(SchemaRegistry.getEntityTypeByName("GNBDUFunction"))
+                .bSideAssociation(getRelationshipAssociation("provided-by-gnbduFunction", 0, 9223372036854775807L)).bSide(
+                        SchemaRegistry.getEntityTypeByName("NRSectorCarrier")).connectsSameEntity(false)
+                .relationshipStorageLocation(B_SIDE).module(SchemaRegistry.getModuleByName("o-ran-smo-teiv-ran")).build();
+
+        RelationType gnbduFunctionRealisedByCloudnativeapplication = RelationType.builder().name(
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION").aSideAssociation(getRelationshipAssociation(
+                        "realised-by-cloudNativeApplication", 0, 9223372036854775807L)).aSide(SchemaRegistry
+                                .getEntityTypeByName("GNBDUFunction")).bSideAssociation(getRelationshipAssociation(
+                                        "realised-gnbduFunction", 0, 9223372036854775807L)).bSide(SchemaRegistry
+                                                .getEntityTypeByName("CloudNativeApplication")).connectsSameEntity(false)
+                .relationshipStorageLocation(RELATION).module(SchemaRegistry.getModuleByName("o-ran-smo-teiv-cloud-to-ran"))
+                .build();
+
+        RelationType nrSectorcarrierUsesAntennacapability = RelationType.builder().name(
+                "NRSECTORCARRIER_USES_ANTENNACAPABILITY").aSideAssociation(getRelationshipAssociation(
+                        "used-antennaCapability", 0, 9223372036854775807L)).aSide(SchemaRegistry.getEntityTypeByName(
+                                "NRSectorCarrier")).bSideAssociation(getRelationshipAssociation("used-by-nrSectorCarrier",
+                                        0, 1)).bSide(SchemaRegistry.getEntityTypeByName("AntennaCapability"))
+                .connectsSameEntity(false).relationshipStorageLocation(A_SIDE).module(SchemaRegistry.getModuleByName(
+                        "o-ran-smo-teiv-ran")).build();
+
+        RelationType sectorGroupsAntennamodule = RelationType.builder().name("SECTOR_GROUPS_ANTENNAMODULE")
+                .aSideAssociation(getRelationshipAssociation("grouped-antennaModule", 0, 1)).aSide(SchemaRegistry
+                        .getEntityTypeByName("Sector")).bSideAssociation(getRelationshipAssociation("grouped-by-sector", 0,
+                                9223372036854775807L)).bSide(SchemaRegistry.getEntityTypeByName("AntennaModule"))
+                .connectsSameEntity(false).relationshipStorageLocation(B_SIDE).module(SchemaRegistry.getModuleByName(
+                        "o-ran-smo-teiv-equipment-to-ran")).build();
+
+        RelationType sectorGroupsNrcelldu = RelationType.builder().name("SECTOR_GROUPS_NRCELLDU").aSideAssociation(
+                getRelationshipAssociation("grouped-nrCellDu", 0, 1)).aSide(SchemaRegistry.getEntityTypeByName("Sector"))
+                .bSideAssociation(getRelationshipAssociation("grouped-by-sector", 0, 9223372036854775807L)).bSide(
+                        SchemaRegistry.getEntityTypeByName("NRCellDU")).connectsSameEntity(false)
+                .relationshipStorageLocation(B_SIDE).module(SchemaRegistry.getModuleByName(
+                        "o-ran-smo-teiv-equipment-to-ran")).build();
+
+        RelationType nrCellDuUsesNrSectorcarrier = RelationType.builder().name("NRCELLDU_USES_NRSECTORCARRIER")
+                .aSideAssociation(getRelationshipAssociation("used-nrSectorCarrier", 0, 1)).aSide(SchemaRegistry
+                        .getEntityTypeByName("NRCellDU")).bSideAssociation(getRelationshipAssociation("used-by-nrCellDu", 0,
+                                9223372036854775807L)).bSide(SchemaRegistry.getEntityTypeByName("NRSectorCarrier"))
+                .connectsSameEntity(false).relationshipStorageLocation(B_SIDE).module(SchemaRegistry.getModuleByName(
+                        "o-ran-smo-teiv-ran")).build();
+
+        RelationType managedElementManagesGNBCUCPFunction = RelationType.builder().name(
+                "MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION").aSideAssociation(getRelationshipAssociation(
+                        "managed-gnbcucpFunction", 1, 1)).aSide(SchemaRegistry.getEntityTypeByName("ManagedElement"))
+                .bSideAssociation(getRelationshipAssociation("managed-by-managedElement", 0, 9223372036854775807L)).bSide(
+                        SchemaRegistry.getEntityTypeByName("GNBCUCPFunction")).connectsSameEntity(false)
+                .relationshipStorageLocation(B_SIDE).module(SchemaRegistry.getModuleByName("o-ran-smo-teiv-oam-to-ran"))
+                .build();
+
+        RelationType nodeClusterLocatedAtCloudSite = RelationType.builder().name("NODECLUSTER_LOCATED_AT_CLOUDSITE")
+                .aSideAssociation(getRelationshipAssociation("located-at-cloudSite", 0, 9223372036854775807L)).aSide(
+                        SchemaRegistry.getEntityTypeByName("NodeCluster")).bSideAssociation(getRelationshipAssociation(
+                                "location-of-nodeCluster", 1, 1)).bSide(SchemaRegistry.getEntityTypeByName("CloudSite"))
+                .connectsSameEntity(false).relationshipStorageLocation(A_SIDE).module(SchemaRegistry.getModuleByName(
+                        "o-ran-smo-teiv-cloud")).build();
+
+        RelationType antennaModuleRealisedByAntennaModule = RelationType.builder().name(
+                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE").aSideAssociation(getRelationshipAssociation(
+                        "realised-by-antennaModule", 0, 9223372036854775807L)).aSide(SchemaRegistry.getEntityTypeByName(
+                                "AntennaModule")).bSideAssociation(getRelationshipAssociation("realised-antennaModule", 0,
+                                        9223372036854775807L)).bSide(SchemaRegistry.getEntityTypeByName("AntennaModule"))
+                .connectsSameEntity(true).relationshipStorageLocation(RELATION).module(SchemaRegistry.getModuleByName(
+                        "o-ran-smo-teiv-equipment")).build();
+
+        List<RelationType> relationTypes = List.of(gnbduFunctionProvidesNrcelldu, gnbduFunctionProvidesNrsectorcarrier,
+                gnbduFunctionRealisedByCloudnativeapplication, nrSectorcarrierUsesAntennacapability,
+                sectorGroupsAntennamodule, sectorGroupsNrcelldu, nrCellDuUsesNrSectorcarrier,
+                managedElementManagesGNBCUCPFunction, nodeClusterLocatedAtCloudSite, antennaModuleInstalledAtSite,
+                antennaModuleRealisedByAntennaModule);
+        Map<String, RelationType> relationTypeMap = new HashMap<>();
+        relationTypes.forEach(relationType -> relationTypeMap.put(relationType.getName(), relationType));
+        SchemaRegistry.initializeRelationTypes(relationTypeMap);
+    }
+
+    private Map<String, DataType> getGnbduFunctionFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("gNBDUId", BIGINT);
+        fields.put("gNBId", BIGINT);
+        fields.put("gNBIdLength", BIGINT);
+        fields.put("dUpLMNId", CONTAINER);
+        fields.put("id", PRIMITIVE);
+        fields.put("cmId", CONTAINER);
+        fields.put("fdn", PRIMITIVE);
+        fields.put("REL_FK_managed-by-managedElement", PRIMITIVE);
+        fields.put("REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getGnbcuupFunctionFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("gNBId", BIGINT);
+        fields.put("gNBIdLength", BIGINT);
+        fields.put("id", PRIMITIVE);
+        fields.put("cmId", CONTAINER);
+        fields.put("fdn", PRIMITIVE);
+        fields.put("REL_FK_managed-by-managedElement", PRIMITIVE);
+        fields.put("REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getNrCellDuFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("fdn", PRIMITIVE);
+        fields.put("nCI", BIGINT);
+        fields.put("cellLocalId", BIGINT);
+        fields.put("id", PRIMITIVE);
+        fields.put("cmId", CONTAINER);
+        fields.put("nRPCI", BIGINT);
+        fields.put("nRTAC", BIGINT);
+        fields.put("REL_FK_grouped-by-sector", PRIMITIVE);
+        fields.put("REL_ID_SECTOR_GROUPS_NRCELLDU", PRIMITIVE);
+        fields.put("REL_FK_provided-by-gnbduFunction", PRIMITIVE);
+        fields.put("REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getNrSectorCarrierFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("frequencyDL", BIGINT);
+        fields.put("fdn", PRIMITIVE);
+        fields.put("frequencyUL", BIGINT);
+        fields.put("arfcnUL", BIGINT);
+        fields.put("id", PRIMITIVE);
+        fields.put("essScLocalId", BIGINT);
+        fields.put("cmId", CONTAINER);
+        fields.put("arfcnDL", BIGINT);
+        fields.put("REL_FK_used-by-nrCellDu", PRIMITIVE);
+        fields.put("REL_ID_NRCELLDU_USES_NRSECTORCARRIER", PRIMITIVE);
+        fields.put("REL_FK_provided-by-gnbduFunction", PRIMITIVE);
+        fields.put("REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", PRIMITIVE);
+        fields.put("REL_FK_used-antennaCapability", PRIMITIVE);
+        fields.put("REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getCloudNativeApplicationFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("id", PRIMITIVE);
+        fields.put("name", PRIMITIVE);
+        fields.put("REL_FK_realised-managedElement", PRIMITIVE);
+        fields.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", PRIMITIVE);
+        fields.put("REL_FK_comprised-by-cloudNativeSystem", PRIMITIVE);
+        fields.put("REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getAntennaCapabilityFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("nRFqBands", CONTAINER);
+        fields.put("id", PRIMITIVE);
+        fields.put("eUtranFqBands", CONTAINER);
+        fields.put("cmId", CONTAINER);
+        fields.put("geranFqBands", CONTAINER);
+        fields.put("fdn", PRIMITIVE);
+        fields.put("REL_FK_used-by-lteSectorCarrier", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getSectorFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("sectorId", BIGINT);
+        fields.put("id", PRIMITIVE);
+        fields.put("azimuth", DECIMAL);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getAntennaModuleFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("positionWithinSector", PRIMITIVE);
+        fields.put("antennaModelNumber", PRIMITIVE);
+        fields.put("electricalAntennaTilt", BIGINT);
+        fields.put("mechanicalAntennaTilt", BIGINT);
+        fields.put("totalTilt", BIGINT);
+        fields.put("id", PRIMITIVE);
+        fields.put("mechanicalAntennaBearing", BIGINT);
+        fields.put("fdn", PRIMITIVE);
+        fields.put("cmId", CONTAINER);
+        fields.put("REL_FK_grouped-by-sector", PRIMITIVE);
+        fields.put("REL_ID_SECTOR_GROUPS_ANTENNAMODULE", PRIMITIVE);
+        fields.put("REL_FK_installed-at-site", PRIMITIVE);
+        fields.put("REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getSiteFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("id", PRIMITIVE);
+        fields.put("cmId", CONTAINER);
+        fields.put("name", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getCloudSiteFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("id", PRIMITIVE);
+        fields.put("name", PRIMITIVE);
+        fields.put("geo-location", GEOGRAPHIC);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getNodeClusterFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("id", PRIMITIVE);
+        fields.put("name", PRIMITIVE);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getManagedElementFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("id", PRIMITIVE);
+        fields.put("fdn", PRIMITIVE);
+        fields.put("cmId", CONTAINER);
+        fields.put("REL_FK_deployed-as-cloudNativeSystem", PRIMITIVE);
+        fields.put("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", CONTAINER);
+
+        return fields;
+    }
+
+    private Map<String, DataType> getGNBCUCPFunctionFields() {
+        Map<String, DataType> fields = new HashMap<>();
+        fields.put("id", PRIMITIVE);
+        fields.put("fdn", PRIMITIVE);
+        fields.put("pLMNId", CONTAINER);
+        fields.put("gNBCUName", PRIMITIVE);
+        fields.put("gNBId", BIGINT);
+        fields.put("cmId", CONTAINER);
+        fields.put("gNBIdLength", BIGINT);
+        fields.put("REL_FK_managed-by-managedElement", PRIMITIVE);
+        fields.put("REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION", CONTAINER);
+
+        return fields;
+    }
+
+    private Association getRelationshipAssociation(String associationName, long minCardinality, long maxCardinality) {
+        return Association.builder().name((associationName)).minCardinality(minCardinality).maxCardinality(maxCardinality)
+                .build();
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/schema/SchemaRegistryContainerizedTest.java b/teiv/src/test/java/org/oran/smo/teiv/schema/SchemaRegistryContainerizedTest.java
new file mode 100644
index 0000000..1cef7b2
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/schema/SchemaRegistryContainerizedTest.java
@@ -0,0 +1,402 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.schema;
+
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.A_SIDE;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.B_SIDE;
+import static org.oran.smo.teiv.schema.RelationshipDataLocation.RELATION;
+import static org.oran.smo.teiv.utils.TiesConstants.QUOTED_STRING;
+import static org.oran.smo.teiv.utils.TiesConstants.TEIV_DOMAIN;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.jooq.impl.DSL.field;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.sql.DataSource;
+
+import org.jooq.DSLContext;
+import org.jooq.JSONB;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.exception.TiesException;
+
+class SchemaRegistryContainerizedTest {
+    public static TestPostgresqlContainer postgreSQLContainer = TestPostgresqlContainer.getInstance();
+    private static DSLContext dslContext;
+
+    @BeforeAll
+    public static void beforeAll() throws UnsupportedOperationException, SchemaLoaderException {
+        String url = postgreSQLContainer.getJdbcUrl();
+        TestPostgresqlContainer.loadSampleData();
+        DataSource ds = DataSourceBuilder.create().url(url).username("test").password("test").build();
+        dslContext = DSL.using(ds, SQLDialect.POSTGRES);
+        PostgresSchemaLoader postgresSchemaLoader = new PostgresSchemaLoader(dslContext, new ObjectMapper());
+        postgresSchemaLoader.loadSchemaRegistry();
+    }
+
+    @BeforeEach
+    public void deleteAll() {
+        dslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(t -> dslContext
+                .truncate(t).cascade().execute());
+    }
+
+    @Test
+    void testGetModulesByName() {
+        //given
+        String expectedName = "o-ran-smo-teiv-cloud-to-ran";
+        String expectedNamespace = "urn:o-ran:smo-teiv-cloud-to-ran";
+        String expectedDomain = "CLOUD_TO_RAN";
+        List<String> expectedIncludedModules = List.of("o-ran-smo-teiv-cloud", "o-ran-smo-teiv-ran");
+        //when
+        Module logicalToCloud = SchemaRegistry.getModuleByName("o-ran-smo-teiv-cloud-to-ran");
+        //then
+        assertEquals(9, SchemaRegistry.getModuleRegistry().size());
+        assertTrue(SchemaRegistry.getModuleRegistry().containsValue(logicalToCloud));
+        assertEquals(expectedName, logicalToCloud.getName());
+        assertEquals(expectedNamespace, logicalToCloud.getNamespace());
+        assertEquals(expectedDomain, logicalToCloud.getDomain());
+        assertEquals(expectedIncludedModules, logicalToCloud.getIncludedModuleNames());
+        assertThrows(TiesException.class, () -> SchemaRegistry.getModuleByName("invalid-module"));
+    }
+
+    @Test
+    void testGetDomainsForModules() {
+        //given
+
+        Set<String> expectedDomains = Set.of(TEIV_DOMAIN, "OAM_TO_CLOUD", "EQUIPMENT_TO_RAN", "RAN", "OAM", "CLOUD",
+                "EQUIPMENT", "CLOUD_TO_RAN", "OAM_TO_RAN");
+        //when
+        Set<String> actualDomains = SchemaRegistry.getDomains();
+        //then
+        assertEquals(expectedDomains, actualDomains);
+    }
+
+    @Test
+    void testRootDomainIncludesAllAvailableDomains() {
+        //given
+        Set<String> availableDomains = SchemaRegistry.getDomains();
+        availableDomains.remove(TEIV_DOMAIN);
+        //when
+        List<String> rootIncludedDomains = SchemaRegistry.getIncludedDomains(TEIV_DOMAIN);
+        //then
+        assertEquals(availableDomains.size(), rootIncludedDomains.size());
+        assertTrue(availableDomains.containsAll(rootIncludedDomains));
+    }
+
+    @Test
+    void testGetModuleByDomainTrowsUnknownDomainException() {
+        assertThrows(TiesException.class, () -> SchemaRegistry.getModuleByDomain("throwError"));
+    }
+
+    //Entities
+    @Test
+    void testGetEntityNames() {
+        //given
+        Set<String> expectedEntityName = Set.of("Site", "ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt",
+                "ENodeBFunction", "CloudNativeApplication", "AntennaModule", "Sector",
+                "Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "NRCellDU", "LTESectorCarrier",
+                "ManagedElement", "NRCellCU", "NRSectorCarrier", "PhysicalNetworkAppliance", "Namespace", "GNBCUUPFunction",
+                "NodeCluster", "CloudNativeSystem", "NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
+                "CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm",
+                "CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                "AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+                "ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE", "GNBDUFunction", "CloudSite",
+                "EUtranCell", "GNBCUCPFunction", "AntennaCapability", "TestEntityA", "TestEntityB");
+        //when
+        Set<String> actualEntityName = SchemaRegistry.getEntityNames();
+        //then
+        assertEquals(expectedEntityName.size(), actualEntityName.size());
+        assertEquals(expectedEntityName, actualEntityName);
+    }
+
+    @Test
+    void testGetTableNameForEntity() {
+        //given
+        EntityType gnbduFunction = SchemaRegistry.getEntityTypeByName("GNBDUFunction");
+        //then
+        assertEquals("ties_data.\"GNBDUFunction\"", gnbduFunction.getTableName());
+    }
+
+    @Test
+    void testGetFieldsForEntity() {
+        //given
+        EntityType gnbduFunction = SchemaRegistry.getEntityTypeByName("GNBDUFunction");
+        //then
+        assertEquals(Set.of(field("dUpLMNId", JSONB.class).as("dUpLMNId"), field("gNBDUId").as("gNBDUId"), field("gNBId")
+                .as("gNBId"), field("gNBIdLength").as("gNBIdLength"), field("cmId", JSONB.class).as("cmId"), field("fdn")
+                        .as("fdn"), field("id").as("id"), field("CD_sourceIds").as("CD_sourceIds")), new HashSet<>(
+                                gnbduFunction.getAllFieldsWithId()));
+    }
+
+    @Test
+    void testGetAttrColumnsForEntity() {
+        //given
+        List<String> expectedColumns = List.of("ties_data.\"GNBDUFunction\".\"gNBDUId\"",
+                "ties_data.\"GNBDUFunction\".\"gNBId\"", "ties_data.\"GNBDUFunction\".\"gNBIdLength\"",
+                "ties_data.\"GNBDUFunction\".\"dUpLMNId\"", "ties_data.\"GNBDUFunction\".\"cmId\"",
+                "ties_data.\"GNBDUFunction\".\"fdn\"", "ties_data.\"GNBDUFunction\".\"id\"");
+        EntityType gnbduFunction = SchemaRegistry.getEntityTypeByName("GNBDUFunction");
+        //then
+        List<String> columns = gnbduFunction.getAttributeColumnsWithId();
+        assertEquals(expectedColumns.size(), columns.size());
+        assertTrue(expectedColumns.containsAll(columns));
+    }
+
+    @Test
+    void testGetAttrColumnsForEntityWithLongNames() {
+        //given
+        List<String> expectedColumns = List.of("ties_data.\"7D7AACEBB0E4E4732835BA4BFE708DDD3738962D\".\"gNBDUId\"",
+                "ties_data.\"7D7AACEBB0E4E4732835BA4BFE708DDD3738962D\".\"gNBId\"",
+                "ties_data.\"7D7AACEBB0E4E4732835BA4BFE708DDD3738962D\".\"gNBIdLength\"",
+                "ties_data.\"7D7AACEBB0E4E4732835BA4BFE708DDD3738962D\".\"dUpLMNId\"",
+                "ties_data.\"7D7AACEBB0E4E4732835BA4BFE708DDD3738962D\".\"cmId\"",
+                "ties_data.\"7D7AACEBB0E4E4732835BA4BFE708DDD3738962D\".\"3786A6CA64C9422F9E7FC35B7B039F345BBDDA65\"",
+                "ties_data.\"7D7AACEBB0E4E4732835BA4BFE708DDD3738962D\".\"id\"");
+        EntityType gnbduFunction = SchemaRegistry.getEntityTypeByName(
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn");
+        //then
+        List<String> columns = gnbduFunction.getAttributeColumnsWithId();
+        assertEquals(expectedColumns.size(), columns.size());
+        assertTrue(expectedColumns.containsAll(columns));
+    }
+
+    @Test
+    void testGetEntityTypesByDomain() {
+        //given
+        List<String> expectedEntities = List.of("Site", "ENodeBFunction", "AntennaModule", "Sector", "NRCellDU",
+                "LTESectorCarrier", "NRCellCU", "NRSectorCarrier", "PhysicalNetworkAppliance", "GNBCUUPFunction",
+                "GNBDUFunction", "EUtranCell", "GNBCUCPFunction", "AntennaCapability",
+                "GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
+                "AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
+                "ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE",
+                "NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU", "TestEntityA", "TestEntityB");
+        //when
+        List<String> ranLogicalToEquipmentEntityTypes = SchemaRegistry.getEntityNamesByDomain("EQUIPMENT_TO_RAN");
+        //then
+        assertEquals(expectedEntities.size(), ranLogicalToEquipmentEntityTypes.size());
+        assertTrue(expectedEntities.containsAll(ranLogicalToEquipmentEntityTypes));
+    }
+
+    //Relations
+    @Test
+    void getRelationNames() {
+        //when
+        SchemaRegistry.getRelationNames();
+        //then
+        assertEquals(41, SchemaRegistry.getRelationNames().size());
+    }
+
+    @Test
+    void testGetRelationTypeByName() {
+        //when
+        RelationType managedElementManagesEnodebfunction = SchemaRegistry.getRelationTypeByName(
+                "MANAGEDELEMENT_MANAGES_ENODEBFUNCTION");
+        //then
+        assertTrue(SchemaRegistry.getRelationTypes().contains(managedElementManagesEnodebfunction));
+        Association expectedAssociation = new Association("managed-enodebFunction", 1, 1);
+        assertEquals(expectedAssociation.toString(), managedElementManagesEnodebfunction.getASideAssociation().toString());
+
+    }
+
+    @Test
+    void testGetRelationTypesByEntityType() {
+        //given
+        List<RelationType> expectedRelationsList = new ArrayList<>();
+        expectedRelationsList.add(SchemaRegistry.getRelationTypeByName(
+                "GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION"));
+        expectedRelationsList.add(SchemaRegistry.getRelationTypeByName("GNBCUCPFUNCTION_PROVIDES_NRCELLCU"));
+        expectedRelationsList.add(SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION"));
+        //then
+        assertEquals(3, SchemaRegistry.getRelationTypesByEntityName("GNBCUCPFunction").size());
+        assertTrue(SchemaRegistry.getRelationTypesByEntityName("GNBCUCPFunction").containsAll(expectedRelationsList));
+    }
+
+    @Test
+    void testGetFullyQualifiedNameForRelation() {
+        //given
+        RelationType gnbduFunctionRealisedByCloudnativeapplication = SchemaRegistry.getRelationTypeByName(
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        //then
+        assertEquals("o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION",
+                gnbduFunctionRealisedByCloudnativeapplication.getFullyQualifiedName());
+    }
+
+    @Test
+    void testGetTableNameForRelation() {
+        //given
+        String expectedManyToMany = "ties_data.\"GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"";
+        String expectedOneToOne = "ties_data.\"ManagedElement\"";
+        String expectedOneToMany = "ties_data.\"GNBDUFunction\"";
+        String expectedManyToOne = "ties_data.\"NodeCluster\"";
+        String expectedRelConnectingSameEntity = "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"";
+        //when
+        RelationType manyToMany = SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        RelationType oneToOne = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM");
+        RelationType oneToMany = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");
+        RelationType manyToOne = SchemaRegistry.getRelationTypeByName("NODECLUSTER_LOCATED_AT_CLOUDSITE");
+        RelationType relConnectingSameEntity = SchemaRegistry.getRelationTypeByName(
+                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE");
+        //then
+        assertEquals(expectedManyToMany, manyToMany.getTableName());
+        assertEquals(expectedOneToOne, oneToOne.getTableName());
+        assertEquals(expectedOneToMany, oneToMany.getTableName());
+        assertEquals(expectedManyToOne, manyToOne.getTableName());
+        assertEquals(expectedRelConnectingSameEntity, relConnectingSameEntity.getTableName());
+    }
+
+    @Test
+    void testGetRelationshipDataLocationForRelation() {
+        //when
+        RelationType manyToMany = SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        RelationType oneToOne = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM");
+        RelationType oneToMany = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");
+        RelationType manyToOne = SchemaRegistry.getRelationTypeByName("NODECLUSTER_LOCATED_AT_CLOUDSITE");
+        RelationType relConnectingSameEntity = SchemaRegistry.getRelationTypeByName(
+                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE");
+        //then
+        assertEquals(RELATION, manyToMany.getRelationshipStorageLocation());
+        assertEquals(A_SIDE, oneToOne.getRelationshipStorageLocation());
+        assertEquals(B_SIDE, oneToMany.getRelationshipStorageLocation());
+        assertEquals(A_SIDE, manyToOne.getRelationshipStorageLocation());
+        assertEquals(RELATION, relConnectingSameEntity.getRelationshipStorageLocation());
+    }
+
+    @Test
+    void testGetIdColumnNameRelationTest() {
+        //given
+        String expectedManyToManyId = "id";
+        String expectedOneToManyId = "REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION";
+        //when
+        RelationType manyToManyRelation = SchemaRegistry.getRelationTypeByName(
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        RelationType oneToMany = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");
+        //then
+        assertEquals(expectedManyToManyId, manyToManyRelation.getIdColumnName());
+        assertEquals(expectedOneToManyId, oneToMany.getIdColumnName());
+    }
+
+    @Test
+    void testGetASideColumnNameForRelationType() {
+        //given
+        String expectedManyToMAny = "aSide_GNBDUFunction";
+        String expectedOneToOne = "id";
+        String expectedOneToMany = "REL_FK_managed-by-managedElement";
+        //when
+        RelationType manyToMany = SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        RelationType oneToOne = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM");
+        RelationType oneToMany = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");
+        //then
+        assertEquals(expectedManyToMAny, manyToMany.aSideColumnName());
+        assertEquals(expectedOneToOne, oneToOne.aSideColumnName());
+        assertEquals(expectedOneToMany, oneToMany.aSideColumnName());
+    }
+
+    @Test
+    void testGetBSideColumnNameForRelationType() {
+        //given
+        String expectedManyToMAny = "bSide_CloudNativeApplication";
+        String expectedOneToOne = "REL_FK_deployed-as-cloudNativeSystem";
+        String expectedOneToMany = "id";
+        //when
+        RelationType manyToMany = SchemaRegistry.getRelationTypeByName("GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        RelationType oneToOne = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM");
+        RelationType oneToMany = SchemaRegistry.getRelationTypeByName("MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");
+        //then
+        assertEquals(expectedManyToMAny, manyToMany.bSideColumnName());
+        assertEquals(expectedOneToOne, oneToOne.bSideColumnName());
+        assertEquals(expectedOneToMany, oneToMany.bSideColumnName());
+    }
+
+    @Test
+    void testGetFieldsForRelationType() {
+        //given
+        RelationType gnbduFunctionRealisedByCloudnativeapplication = SchemaRegistry.getRelationTypeByName(
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION");
+        //then
+        assertEquals(List.of(field(String.format(TIES_DATA,
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(QUOTED_STRING,
+                        "aSide_GNBDUFunction")), field(String.format(TIES_DATA,
+                                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(QUOTED_STRING,
+                                        "bSide_CloudNativeApplication")), field(String.format(TIES_DATA,
+                                                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(
+                                                        QUOTED_STRING, "id")), field(String.format(TIES_DATA,
+                                                                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String
+                                                                        .format(QUOTED_STRING, "CD_sourceIds"))),
+                gnbduFunctionRealisedByCloudnativeapplication.getAllFieldsWithId());
+    }
+
+    @Test
+    void testGetRelationTypesByDomain() {
+        //given
+        List<String> expectedRelations = List.of("CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION",
+                "CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE", "NRCELLDU_USES_NRSECTORCARRIER",
+                "GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", "ENODEBFUNCTION_PROVIDES_EUTRANCELL",
+                "NRSECTORCARRIER_USES_ANTENNACAPABILITY", "GNBDUFUNCTION_PROVIDES_NRCELLDU",
+                "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", "EUTRANCELL_USES_LTESECTORCARRIER",
+                "NODECLUSTER_LOCATED_AT_CLOUDSITE", "NAMESPACE_DEPLOYED_ON_NODECLUSTER",
+                "GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION",
+                "ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER", "GNBCUCPFUNCTION_PROVIDES_NRCELLCU",
+                "LTESECTORCARRIER_USES_ANTENNACAPABILITY",
+                "GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU",
+                "GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN",
+                "CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE", "TESTENTITYA_GROUPS_TESTENTITYB",
+                "TESTENTITYA_USES_TESTENTITYB", "TESTENTITYA_PROVIDES_TESTENTITYB", "SECTOR_GROUPS_NRCELLDU");
+        //when
+        List<String> ranLogicalToCloudRelations = SchemaRegistry.getRelationNamesByDomain("CLOUD_TO_RAN");
+        //then
+        assertEquals(expectedRelations.size(), ranLogicalToCloudRelations.size());
+        assertTrue(expectedRelations.containsAll(ranLogicalToCloudRelations));
+    }
+
+    @Test
+    void testGetIncludedModules() {
+        //when
+        Module module = SchemaRegistry.getModuleByName("o-ran-smo-teiv-oam-to-ran");
+        //then
+        assertEquals(2, module.getIncludedModuleNames().size());
+        assertTrue(List.of("o-ran-smo-teiv-oam", "o-ran-smo-teiv-ran").containsAll(module.getIncludedModuleNames()));
+    }
+
+    @Test
+    void testGetIncludedDomains() {
+        //when
+        List<String> includedDomains = SchemaRegistry.getIncludedDomains("CLOUD_TO_RAN");
+        //then
+        assertEquals(2, includedDomains.size());
+        assertTrue(List.of("RAN", "CLOUD").containsAll(includedDomains));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/service/EndToEndApiTest.java b/teiv/src/test/java/org/oran/smo/teiv/service/EndToEndApiTest.java
new file mode 100644
index 0000000..2b10333
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/service/EndToEndApiTest.java
@@ -0,0 +1,263 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import static org.oran.smo.teiv.utils.TiesConstants.REQUEST_MAPPING;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.List;
+
+import org.awaitility.Awaitility;
+import org.jooq.DSLContext;
+import org.jooq.JSONB;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.kafka.test.EmbeddedKafkaBroker;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.web.client.HttpClientErrorException;
+
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.service.kafka.KafkaTopicService;
+import org.oran.smo.teiv.startup.AppInit;
+import org.oran.smo.teiv.availability.DependentServiceAvailabilityKafka;
+import org.oran.smo.teiv.config.KafkaConfig;
+import org.oran.smo.teiv.listener.ListenerStarter;
+import org.oran.smo.teiv.utils.CloudEventTestUtil;
+import org.oran.smo.teiv.utils.EndToEndExpectedResults;
+import org.oran.smo.teiv.utils.EndToEndTestUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+@EmbeddedKafka
+@SpringBootTest(properties = {
+        "kafka.server.bootstrap-server-host:#{environment.getProperty(\"spring.embedded.kafka.brokers\").split(\":\")[0]}",
+        "kafka.server.bootstrap-server-port:#{environment.getProperty(\"spring.embedded.kafka.brokers\").split(\":\")[1]}",
+        "kafka.availability.retryIntervalMs:10",
+        "kafka.topic.replicas:1" }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles({ "test", "ingestion" })
+@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
+class EndToEndApiTest {
+    private static final TestPostgresqlContainer postgreSQLContainer = TestPostgresqlContainer.getInstance();
+
+    @Autowired
+    private DependentServiceAvailabilityKafka dependentServiceAvailabilityKafka;
+
+    @Autowired
+    private KafkaTopicService kafkaTopicService;
+
+    @Autowired
+    private ListenerStarter listenerStarter;
+
+    @Autowired
+    private EmbeddedKafkaBroker embeddedKafkaBroker;
+
+    @Autowired
+    private CustomMetrics customMetrics;
+
+    @LocalServerPort
+    private int port;
+
+    private AppInit appInit;
+
+    private static String URI;
+
+    @Autowired
+    private KafkaConfig kafkaConfig;
+
+    @Autowired
+    private DSLContext writeDataDslContext;
+
+    @DynamicPropertySource
+    static void setProperties(DynamicPropertyRegistry registry) {
+        registry.add("spring.datasource.read.jdbc-url", () -> postgreSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.read.username", () -> postgreSQLContainer.getUsername());
+        registry.add("spring.datasource.read.password", () -> postgreSQLContainer.getPassword());
+
+        registry.add("spring.datasource.write.jdbc-url", () -> postgreSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.write.username", () -> postgreSQLContainer.getUsername());
+        registry.add("spring.datasource.write.password", () -> postgreSQLContainer.getPassword());
+    }
+
+    @BeforeEach
+    void setUp() {
+        writeDataDslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(
+                t -> writeDataDslContext.truncate(t).cascade().execute());
+        appInit = new AppInit(dependentServiceAvailabilityKafka, kafkaTopicService, listenerStarter);
+        appInit.startUpHandler();
+        URI = String.format("http://localhost:%s%s/domains/", port, REQUEST_MAPPING);
+    }
+
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    @Test
+    void testEndToEndApi() {
+        final String TEST_EVENT_FOLDER = "src/test/resources/cloudeventdata/end-to-end/";
+        final String EXPECTED_RESULTS_FOLDER = "src/test/resources/cloudeventdata/end-to-end/expected-results/api/";
+
+        final String CREATE_MANY_TO_MANY_PATH = TEST_EVENT_FOLDER + "ce-create-many-to-many.json";
+        final String CREATE_MANY_TO_ONE_PATH = TEST_EVENT_FOLDER + "ce-create-many-to-one.json";
+        final String CREATE_ONE_TO_MANY_PATH = TEST_EVENT_FOLDER + "ce-create-one-to-many.json";
+        final String CREATE_SECOND_CASE_PATH = TEST_EVENT_FOLDER + "ce-create-second-case.json";
+        final String CREATE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH = TEST_EVENT_FOLDER + "ce-create-relationship-connecting-same-entity.json";
+
+        final String MERGE_ONE_TO_MANY_PATH = TEST_EVENT_FOLDER + "ce-merge-one-to-many-deprecated-structure.json";
+
+        final String DELETE_MANY_TO_MANY_PATH = TEST_EVENT_FOLDER + "ce-delete-many-to-many.json";
+        final String DELETE_MANY_TO_ONE_PATH = TEST_EVENT_FOLDER + "ce-delete-many-to-one.json";
+        final String DELETE_ONE_TO_MANY_PATH = TEST_EVENT_FOLDER + "ce-delete-one-to-many.json";
+        final String DELETE_EVENT_CMHANDLE_PATH = TEST_EVENT_FOLDER + "ce-source-entity-delete-cm-handle.json";
+        final String DELETE_EVENT_CMHANDLE_PATH_2 = TEST_EVENT_FOLDER + "ce-source-entity-delete-cm-handle2.json";
+        final String DELETE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH = TEST_EVENT_FOLDER + "ce-delete-relationship-connecting-same-entity.json";
+
+        final String EXP_CREATE_MANY_TO_MANY_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-many-to-many.json";
+        final String EXP_CREATE_MANY_TO_ONE_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-many-to-one.json";
+        final String EXP_CREATE_ONE_TO_MANY_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-one-to-many.json";
+        final String EXP_CREATE_SECOND_CASE_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-second-case.json";
+        final String EXP_CREATE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-relationship-connecting-same-entity.json";
+
+        final String EXP_MERGE_ONE_TO_MANY_PATH = EXPECTED_RESULTS_FOLDER + "exp-merge-one-to-many.json";
+
+        final String EXP_DELETE_MANY_TO_MANY_PATH = EXPECTED_RESULTS_FOLDER + "exp-delete-many-to-many.json";
+        final String EXP_DELETE_ONE_TO_MANY_PATH = EXPECTED_RESULTS_FOLDER + "exp-delete-one-to-many.json";
+        final String EXP_DELETE_MANY_TO_ONE_PATH = EXPECTED_RESULTS_FOLDER + "exp-delete-many-to-one.json";
+        final String EXP_SOURCE_ENTITY_DELETE_CM_HANDLE = EXPECTED_RESULTS_FOLDER + "exp-source-entity-delete-cm-handle.json";
+        final String EXP_DELETE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH = EXPECTED_RESULTS_FOLDER + "exp-delete-relationship-connecting-same-entity.json";
+
+        validateReceivedCloudEventMetrics(0, 0, 0, 0);
+
+        sendEventFromFile(CREATE_MANY_TO_MANY_PATH);
+        sendEventFromFile(CREATE_ONE_TO_MANY_PATH);
+        sendEventFromFile(CREATE_MANY_TO_ONE_PATH);
+        sendEventFromFile(CREATE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+            try {
+                validateApiResultsWithValues(EXP_CREATE_MANY_TO_MANY_PATH);
+                validateApiResultsWithValues(EXP_CREATE_ONE_TO_MANY_PATH);
+                validateApiResultsWithValues(EXP_CREATE_MANY_TO_ONE_PATH);
+                validateApiResultsWithValues(EXP_CREATE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH);
+                validateReceivedCloudEventMetrics(4, 0, 0, 0);
+            } catch (AssertionError e) {
+                throw new AssertionError("Assertion failed during validation of Create many to many event: " + e
+                        .getMessage(), e);
+            }
+        });
+
+        sendEventFromFile(MERGE_ONE_TO_MANY_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+            try {
+                validateApiResultsWithValues(EXP_MERGE_ONE_TO_MANY_PATH);
+                validateReceivedCloudEventMetrics(4, 1, 0, 0);
+            } catch (AssertionError e) {
+                throw new AssertionError("Assertion failed during validation of Merge one to many event: " + e.getMessage(),
+                        e);
+            }
+
+        });
+
+        sendEventFromFile(CREATE_SECOND_CASE_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+            try {
+                validateApiResultsWithValues(EXP_CREATE_SECOND_CASE_PATH);
+                validateReceivedCloudEventMetrics(5, 1, 0, 0);
+            } catch (AssertionError e) {
+                throw new AssertionError("Assertion failed during validation of Create with CmHandle event: " + e
+                        .getMessage(), e);
+            }
+        });
+
+        sendEventFromFile(DELETE_MANY_TO_MANY_PATH);
+        sendEventFromFile(DELETE_ONE_TO_MANY_PATH);
+        sendEventFromFile(DELETE_MANY_TO_ONE_PATH);
+        sendEventFromFile(DELETE_EVENT_CMHANDLE_PATH);
+        sendEventFromFile(DELETE_EVENT_CMHANDLE_PATH_2);
+        sendEventFromFile(DELETE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+            try {
+                validateApiResultsAfterDelete(EXP_DELETE_MANY_TO_MANY_PATH);
+                validateApiResultsAfterDelete(EXP_DELETE_ONE_TO_MANY_PATH);
+                validateApiResultsAfterDelete(EXP_DELETE_MANY_TO_ONE_PATH);
+                validateApiResultsAfterDelete(EXP_SOURCE_ENTITY_DELETE_CM_HANDLE);
+                validateApiResultsAfterDelete(EXP_DELETE_RELATIONSHIP_CONNECTING_SAME_ENTITY_PATH);
+                validateReceivedCloudEventMetrics(5, 1, 4, 2);
+            } catch (AssertionError e) {
+                throw new AssertionError("Assertion failed during validation of Delete event: " + e.getMessage(), e);
+            }
+        });
+    }
+
+    private void validateReceivedCloudEventMetrics(final int create, final int merge, final int delete,
+            final int sourceDelete) {
+        assertEquals(create, customMetrics.getNumReceivedCloudEventCreate().count());
+        assertEquals(merge, customMetrics.getNumReceivedCloudEventMerge().count());
+        assertEquals(delete, customMetrics.getNumReceivedCloudEventDelete().count());
+        assertEquals(sourceDelete, customMetrics.getNumReceivedCloudEventSourceEntityDelete().count());
+    }
+
+    private void validateApiResultsWithValues(final String expectedValuesCollectionPath) throws JsonMappingException,
+            JsonProcessingException, IOException {
+        EndToEndExpectedResults values = getExpectedResults(expectedValuesCollectionPath);
+        values.getAll().forEach((requestSubUri, responseResult) -> {
+            String apiRes = processApiCall(URI + requestSubUri);
+            String expectedRes = responseResult.toString();
+            assertEquals(JSONB.jsonb(expectedRes), JSONB.jsonb(apiRes));
+        });
+    }
+
+    private void validateApiResultsAfterDelete(String requestUrlCollectionPath) {
+        EndToEndExpectedResults values = getExpectedResults(requestUrlCollectionPath);
+        assertDoesNotThrow(() -> values.getAll(), "Reading expected results resulted in error.").keySet().forEach((key) -> {
+            assertResponseNotContainId(URI + key);
+        });
+    };
+
+    private void assertResponseNotContainId(final String requestUri) {
+        HttpClientErrorException e = assertThrows(HttpClientErrorException.class, () -> EndToEndTestUtil.processApiCall(
+                requestUri));
+        assertEquals(HttpStatusCode.valueOf(404), e.getStatusCode(), "API Response status is not 404, but it should");
+    }
+
+    private void sendEventFromFile(final String path) {
+        assertDoesNotThrow(() -> EndToEndTestUtil.sendEventList(List.of(CloudEventTestUtil.getCloudEventFromJsonFile(path)),
+                embeddedKafkaBroker, kafkaConfig), "Sending cloud event from file resulted in error.");
+    }
+
+    private EndToEndExpectedResults getExpectedResults(final String path) {
+        return assertDoesNotThrow(() -> new EndToEndExpectedResults(path), "Reading expected values resulted in error.");
+
+    }
+
+    private String processApiCall(final String uri) {
+        return assertDoesNotThrow(() -> EndToEndTestUtil.processApiCall(uri), "Processing api call resulted in error.");
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/service/EndToEndDbTest.java b/teiv/src/test/java/org/oran/smo/teiv/service/EndToEndDbTest.java
new file mode 100644
index 0000000..720447a
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/service/EndToEndDbTest.java
@@ -0,0 +1,339 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import org.awaitility.Awaitility;
+import org.jooq.DSLContext;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.oran.smo.teiv.CustomMetrics;
+import org.oran.smo.teiv.availability.DependentServiceAvailabilityKafka;
+import org.oran.smo.teiv.config.KafkaConfig;
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.listener.ListenerStarter;
+import org.oran.smo.teiv.service.kafka.KafkaTopicService;
+import org.oran.smo.teiv.startup.AppInit;
+import org.oran.smo.teiv.utils.CloudEventTestUtil;
+import org.oran.smo.teiv.utils.EndToEndExpectedResults;
+import org.oran.smo.teiv.utils.EndToEndTestUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.kafka.test.EmbeddedKafkaBroker;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+
+@EmbeddedKafka
+@SpringBootTest(properties = {
+        "kafka.server.bootstrap-server-host:#{environment.getProperty(\"spring.embedded.kafka.brokers\").split(\":\")[0]}",
+        "kafka.server.bootstrap-server-port:#{environment.getProperty(\"spring.embedded.kafka.brokers\").split(\":\")[1]}",
+        "kafka.availability.retryIntervalMs:10", "kafka.topic.replicas:1" })
+@ActiveProfiles({ "test", "ingestion" })
+public class EndToEndDbTest {
+    public static TestPostgresqlContainer postgresqlContainer = TestPostgresqlContainer.getInstance();
+
+    @Autowired
+    private DependentServiceAvailabilityKafka dependentServiceAvailabilityKafka;
+
+    @Autowired
+    private KafkaTopicService kafkaTopicService;
+
+    @Autowired
+    private ListenerStarter listenerStarter;
+
+    @Autowired
+    private EmbeddedKafkaBroker embeddedKafkaBroker;
+
+    @Autowired
+    private CustomMetrics customMetrics;
+
+    @Autowired
+    private TiesDbService tiesDbService;
+
+    private AppInit appInit;
+
+    @Autowired
+    private KafkaConfig kafkaConfig;
+
+    @Autowired
+    private DSLContext writeDataDslContext;
+
+    private final static String CNA_TABLE = "CloudNativeApplication";
+    private final static String CNS_TABLE = "CloudNativeSystem";
+    private final static String ME_TABLE = "ManagedElement";
+    private final static String GNBDU_TABLE = "GNBDUFunction";
+    private final static String GNBCUUP_TABLE = "GNBCUUPFunction";
+    private final static String GNBCUCP_TABLE = "GNBCUCPFunction";
+    private final static String NRCELLDU_TABLE = "NRCellDU";
+    private final static String GNBDU_CNA_TABLE = "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION";
+    private final static String GNBCUUP_CNA_TABLE = "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION";
+    private final static String GNBCUCP_CNA_TABLE = "GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION";
+
+    private static final String TEST_EVENT_FOLDER = "src/test/resources/cloudeventdata/end-to-end/";
+    private static final String EXPECTED_RESULTS_FOLDER = "src/test/resources/cloudeventdata/end-to-end/expected-results/db/";
+
+    @DynamicPropertySource
+    static void setProperties(DynamicPropertyRegistry registry) {
+        registry.add("spring.datasource.read.jdbc-url", () -> postgresqlContainer.getJdbcUrl());
+        registry.add("spring.datasource.read.username", () -> postgresqlContainer.getUsername());
+        registry.add("spring.datasource.read.password", () -> postgresqlContainer.getPassword());
+
+        registry.add("spring.datasource.write.jdbc-url", () -> postgresqlContainer.getJdbcUrl());
+        registry.add("spring.datasource.write.username", () -> postgresqlContainer.getUsername());
+        registry.add("spring.datasource.write.password", () -> postgresqlContainer.getPassword());
+    }
+
+    @BeforeEach
+    void setUp() {
+        writeDataDslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(
+                t -> writeDataDslContext.truncate(t).cascade().execute());
+        appInit = new AppInit(dependentServiceAvailabilityKafka, kafkaTopicService, listenerStarter);
+        appInit.startUpHandler();
+    }
+
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    @Test
+    void testEndToEndDb() throws InterruptedException, IOException {
+        final String CREATE_MANY_TO_MANY_PATH = TEST_EVENT_FOLDER + "ce-create-many-to-many.json";
+        final String CREATE_SECOND_CASE_PATH = TEST_EVENT_FOLDER + "ce-create-second-case.json";
+        final String MERGE_ONE_TO_MANY_PATH = TEST_EVENT_FOLDER + "ce-merge-one-to-many-deprecated-structure.json";
+        final String DELETE_EVENT_PATH = TEST_EVENT_FOLDER + "ce-delete-many-to-many.json";
+        final String DELETE_EVENT_ONE_TO_ONE_PATH = TEST_EVENT_FOLDER + "ce-delete-one-to-one.json";
+        final String DELETE_EVENT_CMHANDLE_PATH = TEST_EVENT_FOLDER + "ce-source-entity-delete-cm-handle.json";
+        final String CREATE_ONE_TO_ONE_PATH = TEST_EVENT_FOLDER + "ce-create-one-to-one.json";
+
+        final String EXP_CREATE_MANY_TO_MANY_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-many-to-many.json";
+        final String EXP_MERGE_ONE_TO_MANY_PATH = EXPECTED_RESULTS_FOLDER + "exp-merge-one-to-many.json";
+        final String EXP_CREATE_SECOND_CASE_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-second-case.json";
+        final String EXP_CREATE_ONE_TO_ONE_PATH = EXPECTED_RESULTS_FOLDER + "exp-create-one-to-one.json";
+        final String EXP_ONE_TO_ONE_PATH_AFTER_DELETE = EXPECTED_RESULTS_FOLDER + "exp-delete-one-to-one.json";
+
+        validateReceivedCloudEventMetrics(0, 0, 0, 0);
+        sendEventFromFile(CREATE_ONE_TO_ONE_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+            try {
+                EndToEndExpectedResults values = getExpectedResults(EXP_CREATE_ONE_TO_ONE_PATH);
+                validateDbResultsAfterOneToOneCE(values);
+                validateReceivedCloudEventMetrics(1, 0, 0, 0);
+            } catch (AssertionError e) {
+                throw new AssertionError("Assertion failed during validation of Create one to one event: " + e.getMessage(),
+                        e);
+            }
+        });
+
+        sendEventFromFile(CREATE_MANY_TO_MANY_PATH);
+        Awaitility.await().atMost(10, TimeUnit.SECONDS).pollDelay(Duration.ofSeconds(5)).untilAsserted(
+                () -> assertWithErrorMessage(() -> {
+                    EndToEndExpectedResults values = getExpectedResults(EXP_CREATE_MANY_TO_MANY_PATH);
+                    validateDbResultsAfterCreate(values);
+                    validateReceivedCloudEventMetrics(2, 0, 0, 0);
+                }, "Assertion failed during validation of Create many to many event"));
+
+        sendEventFromFile(MERGE_ONE_TO_MANY_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> assertWithErrorMessage(() -> {
+            EndToEndExpectedResults values = getExpectedResults(EXP_MERGE_ONE_TO_MANY_PATH);
+            validateDbResultsAfterMerge(values);
+            validateReceivedCloudEventMetrics(2, 1, 0, 0);
+        }, "Assertion failed during validation of Merge one to many event"));
+
+        sendEventFromFile(CREATE_SECOND_CASE_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> assertWithErrorMessage(() -> {
+            EndToEndExpectedResults values = getExpectedResults(EXP_CREATE_SECOND_CASE_PATH);
+            validateDbResultsAfterCmHandle(values);
+            validateReceivedCloudEventMetrics(3, 1, 0, 0);
+        }, "Assertion failed during validation of Create with CmHandle event"));
+
+        sendEventFromFile(DELETE_EVENT_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> assertWithErrorMessage(() -> {
+            validateDbResultsAfterDelete();
+            validateReceivedCloudEventMetrics(3, 1, 1, 0);
+        }, "Assertion failed during validation of Delete event"));
+
+        sendEventFromFile(DELETE_EVENT_ONE_TO_ONE_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+            try {
+                EndToEndExpectedResults values = getExpectedResults(EXP_ONE_TO_ONE_PATH_AFTER_DELETE);
+                validateDbResultsAfterDeleteOneToOne(values);
+                validateReceivedCloudEventMetrics(3, 1, 2, 0);
+            } catch (AssertionError e) {
+                throw new AssertionError("Assertion failed during validation of Delete one to one relationship event: " + e
+                        .getMessage(), e);
+            }
+        });
+
+        sendEventFromFile(DELETE_EVENT_CMHANDLE_PATH);
+        Awaitility.await().pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+            try {
+                validateDbResultsAfterDeleteCmHandle();
+                validateReceivedCloudEventMetrics(3, 1, 2, 1);
+            } catch (AssertionError e) {
+                throw new AssertionError("Assertion failed during validation of Delete with CmHandle event: " + e
+                        .getMessage(), e);
+            }
+        });
+
+    }
+
+    private void validateReceivedCloudEventMetrics(final int create, final int merge, final int delete,
+            final int sourceDelete) {
+        assertEquals(create, customMetrics.getNumReceivedCloudEventCreate().count());
+        assertEquals(merge, customMetrics.getNumReceivedCloudEventMerge().count());
+        assertEquals(delete, customMetrics.getNumReceivedCloudEventDelete().count());
+        assertEquals(sourceDelete, customMetrics.getNumReceivedCloudEventSourceEntityDelete().count());
+    }
+
+    private void validateDbResultsAfterCreate(final EndToEndExpectedResults values) {
+        assertDatabaseContainsValues(CNA_TABLE, values.get("entity_map_CNA_1"));
+        assertDatabaseContainsValues(CNA_TABLE, values.get("entity_map_CNA_2"));
+        assertDatabaseContainsValues(CNA_TABLE, values.get("entity_map_CNA_3"));
+        assertDatabaseContainsValues(GNBCUUP_TABLE, values.get("entity_map_GNBCUUP_1"));
+        assertDatabaseContainsValues(GNBCUCP_TABLE, values.get("entity_map_GNBCUCP_1"));
+        assertDatabaseContainsValues(GNBDU_TABLE, values.get("entity_map_GNBDU_1"));
+
+        assertDatabaseContainsValues(GNBDU_CNA_TABLE, values.get("relation_map_GNBDU_CNA_1"));
+        assertDatabaseContainsValues(GNBDU_CNA_TABLE, values.get("relation_map_GNBDU_CNA_4"));
+        assertDatabaseContainsValues(GNBCUUP_CNA_TABLE, values.get("relation_map_GNBCUUP_CNA_2"));
+        assertDatabaseContainsValues(GNBCUUP_CNA_TABLE, values.get("relation_map_GNBCUUP_CNA_5"));
+        assertDatabaseContainsValues(GNBCUCP_CNA_TABLE, values.get("relation_map_GNBCUCP_CNA_3"));
+        assertDatabaseContainsValues(GNBCUCP_CNA_TABLE, values.get("relation_map_GNBCUCP_CNA_6"));
+
+    }
+
+    private void validateDbResultsAfterOneToOneCE(final EndToEndExpectedResults values) throws IOException {
+        assertDatabaseContainsValues(CNS_TABLE, values.get("entity_map_CNS_1"));
+        assertDatabaseContainsValues(ME_TABLE, values.get("entity_map_ME_1"));
+        assertDatabaseContainsValues(CNS_TABLE, values.get("entity_map_CNS_2"));
+        assertDatabaseContainsValues(ME_TABLE, values.get("entity_map_ME_2"));
+    }
+
+    private void validateDbResultsAfterMerge(final EndToEndExpectedResults values) {
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("entity_map_NRCellDU_1"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("entity_map_NRCellDU_2"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("entity_map_NRCellDU_3"));
+
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("relation_map_GNBDU_NRCellDU_1"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("relation_map_GNBDU_NRCellDU_2"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("relation_map_GNBDU_NRCellDU_3"));
+    }
+
+    private void validateDbResultsAfterCmHandle(final EndToEndExpectedResults values) {
+        assertDatabaseContainsValues(CNA_TABLE, values.get("entity_map_CNA_4"));
+        assertDatabaseContainsValues(GNBDU_TABLE, values.get("entity_map_GNBDU_1"));
+        assertDatabaseContainsValues(GNBDU_TABLE, values.get("entity_map_GNBDU_2"));
+        assertDatabaseContainsValues(GNBCUUP_TABLE, values.get("entity_map_GNBCUUP_1"));
+        assertDatabaseContainsValues(GNBCUCP_TABLE, values.get("entity_map_GNBCUCP_1"));
+        assertDatabaseContainsValues(GNBCUCP_TABLE, values.get("entity_map_GNBCUCP_2"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("entity_map_NRCellDU_1"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("entity_map_NRCellDU_2"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("entity_map_NRCellDU_3"));
+        assertDatabaseContainsValues(GNBDU_CNA_TABLE, values.get("relation_map_GNBDU_CNA_1"));
+        assertDatabaseContainsValues(GNBCUUP_CNA_TABLE, values.get("relation_map_GNBCUUP_CNA_2"));
+        assertDatabaseContainsValues(GNBCUCP_CNA_TABLE, values.get("relation_map_GNBCUCP_CNA_3"));
+        assertDatabaseContainsValues(GNBDU_CNA_TABLE, values.get("relation_map_GNBDU_CNA_4"));
+        assertDatabaseContainsValues(GNBCUUP_CNA_TABLE, values.get("relation_map_GNBCUUP_CNA_5"));
+        assertDatabaseContainsValues(GNBCUCP_CNA_TABLE, values.get("relation_map_GNBCUCP_CNA_6"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("relation_map_GNBDU_NRCellDU_1"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("relation_map_GNBDU_NRCellDU_2"));
+        assertDatabaseContainsValues(NRCELLDU_TABLE, values.get("relation_map_GNBDU_NRCellDU_3"));
+    }
+
+    private void validateDbResultsAfterDelete() {
+        assertDatabaseDoesNotContainRecord(CNA_TABLE, "CloudNativeApplication_3");
+        assertDatabaseDoesNotContainRecord(GNBCUCP_TABLE, "GNBCUCP_1");
+        assertDatabaseDoesNotContainRecord(GNBDU_CNA_TABLE, "relation_1");
+        assertDatabaseDoesNotContainRecord(GNBCUUP_CNA_TABLE, "relation_5");
+        assertDatabaseDoesNotContainRecord(GNBCUCP_CNA_TABLE, "relation_3");
+        assertDatabaseDoesNotContainRecord(GNBCUCP_CNA_TABLE, "relation_6");
+    }
+
+    private void validateDbResultsAfterDeleteCmHandle() {
+        assertDatabaseDoesNotContainRecord(GNBDU_TABLE, "GNBDU_SED_1");
+        assertDatabaseDoesNotContainRecord(GNBCUCP_TABLE, "GNBCUCP_SED_1");
+        assertDatabaseDoesNotContainRecord(GNBCUCP_TABLE, "GNBCUCP_SED_2");
+        assertDatabaseDoesNotContainRecord(GNBCUCP_CNA_TABLE, "relation_sed_1");
+        assertDatabaseDoesNotContainRecord(GNBDU_CNA_TABLE, "relation_sed_2");
+    }
+
+    private void validateDbResultsAfterDeleteOneToOne(final EndToEndExpectedResults values) {
+        // Test case 1: Delete an entity - relationship removed from an existing entity
+        assertDatabaseDoesNotContainRecord(CNS_TABLE, "relation_11");
+        assertDatabaseDoesNotContainRecord(ME_TABLE, "relation_11");
+        assertDatabaseDoesNotContainRecord(ME_TABLE, "ManagedElement_2");
+        assertDatabaseContainsValues(CNS_TABLE, values.get("entity_map_CNS_1"));
+        // Test case 2: Delete a relationship - relationship removed from both existing
+        // entities
+        assertDatabaseDoesNotContainRecord(CNS_TABLE, "relation_12");
+        assertDatabaseDoesNotContainRecord(ME_TABLE, "relation_12");
+        assertDatabaseContainsValues(CNS_TABLE, values.get("entity_map_CNS_2"));
+        assertDatabaseContainsValues(ME_TABLE, values.get("entity_map_ME_2"));
+    }
+
+    private void assertDatabaseContainsValues(final String table, final Map<String, Object> attributes) {
+        Result<Record> results = tiesDbService.selectAllRowsFromTable("ties_data.\"" + table + "\"");
+        assertTrue(results.isNotEmpty(), String.format("Database table \"%s\" is empty, but it should not.", table));
+        assertTrue(results.stream().anyMatch(row -> attributes.keySet().stream().allMatch(attr -> Objects.equals(attributes
+                .get(attr), row.get(attr)))), String.format(
+                        "Database table \"%s\" does not contain expected data, but it should.", table));
+    }
+
+    private void assertDatabaseDoesNotContainRecord(final String table, final String id) {
+        Result<Record> results = tiesDbService.selectAllRowsFromTable("ties_data.\"" + table + "\"");
+        if (results.isNotEmpty()) {
+            boolean contains = results.stream().map(row -> row.get("id")).filter(Objects::nonNull).map(Object::toString)
+                    .anyMatch(id::equals);
+            assertFalse(contains, String.format("Database table \"%s\" contains record: \"%s\", but it should not.", table,
+                    id));
+        }
+    }
+
+    private void sendEventFromFile(final String path) {
+        assertDoesNotThrow(() -> EndToEndTestUtil.sendEventList(List.of(CloudEventTestUtil.getCloudEventFromJsonFile(path)),
+                embeddedKafkaBroker, kafkaConfig));
+    }
+
+    private EndToEndExpectedResults getExpectedResults(final String path) {
+        return assertDoesNotThrow(() -> new EndToEndExpectedResults(path));
+    }
+
+    private void assertWithErrorMessage(Runnable assertion, String errorMessage) {
+        try {
+            assertion.run();
+        } catch (Error e) {
+            throw new AssertionError(errorMessage + ": " + e.getMessage(), e);
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/service/KafkaTopicServiceTest.java b/teiv/src/test/java/org/oran/smo/teiv/service/KafkaTopicServiceTest.java
new file mode 100644
index 0000000..3d93422
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/service/KafkaTopicServiceTest.java
@@ -0,0 +1,159 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Supplier;
+
+import org.apache.kafka.clients.admin.AdminClient;
+import org.apache.kafka.clients.admin.ListTopicsOptions;
+import org.apache.kafka.clients.admin.ListTopicsResult;
+import org.apache.kafka.clients.admin.MockAdminClient;
+import org.apache.kafka.clients.admin.NewTopic;
+import org.apache.kafka.clients.admin.TopicDescription;
+import org.apache.kafka.common.KafkaException;
+import org.apache.kafka.common.KafkaFuture;
+import org.apache.kafka.common.Node;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.kafka.core.KafkaAdmin;
+import org.springframework.kafka.test.context.EmbeddedKafka;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.MethodMode;
+import org.springframework.test.context.ActiveProfiles;
+import lombok.Getter;
+
+import org.oran.smo.teiv.service.kafka.KafkaTopicService;
+
+@EmbeddedKafka
+@SpringBootTest
+@ActiveProfiles({ "test", "ingestion" })
+class KafkaTopicServiceTest {
+    @Autowired
+    private KafkaAdmin kafkaAdmin;
+
+    @Autowired
+    private KafkaTopicService kafkaTopicService;
+
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @Value("${spring.embedded.kafka.brokers}")
+    @Getter
+    private String embeddedKafkaServer;
+
+    @BeforeEach
+    public void setup() {
+        Supplier<String> brokers = () -> getEmbeddedKafkaServer();
+        kafkaAdmin.setBootstrapServersSupplier(brokers);
+    }
+
+    @AfterEach
+    protected void tearDown() {
+        AdminClient adminClient = AdminClient.create(kafkaAdmin.getConfigurationProperties());
+        ListTopicsResult listTopicsResult = adminClient.listTopics(new ListTopicsOptions().timeoutMs(1000));
+        try {
+            adminClient.deleteTopics(listTopicsResult.names().get());
+        } catch (InterruptedException | ExecutionException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Test
+    @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+    void test_setupOutputTopics() {
+        assertTrue(kafkaTopicService.buildTopics());
+
+        String topologyIngestionTopicName = "topology-inventory-ingestion";
+        Map<String, TopicDescription> topics = kafkaAdmin.describeTopics(topologyIngestionTopicName);
+        assertNotNull(topics);
+        assertEquals(4, topics.get(topologyIngestionTopicName).partitions().size());
+        assertEquals(1, topics.get(topologyIngestionTopicName).partitions().get(0).replicas().size());
+    }
+
+    @Test
+    @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+    void test_isAllTopicCreatedPass() {
+        String topologyIngestionTopicName = "test-topology-ingestion";
+        kafkaTopicService.getKafkaConfig().getTopologyIngestion().setTopicName(topologyIngestionTopicName);
+        assertThrows(KafkaException.class, () -> kafkaTopicService.isTopicCreated(topologyIngestionTopicName));
+        kafkaTopicService.buildTopics();
+        assertTrue(kafkaTopicService.isTopicCreated(topologyIngestionTopicName));
+    }
+
+    @Test
+    @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+    void test_topologyIngestionTopicCreation_Interrupted() {
+        String topicName = "test-topology-ingestion";
+        kafkaTopicService.getKafkaConfig().getTopologyIngestion().setTopicName(topicName);
+        Thread.currentThread().interrupt();
+        assertThrows(KafkaException.class, () -> kafkaTopicService.isTopicCreated("test-topology-ingestion"));
+    }
+
+    @Test
+    @DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
+    void test_isTopicCreated_ExecutionException() throws Exception {
+
+        Node controller = new Node(0, "localhost", 8121);
+        List<Node> brokers = Arrays.asList(controller, new Node(1, "localhost", 8122), new Node(2, "localhost", 8123));
+        AdminClient mockedAdminClient = new MockAdminClient(brokers, controller);
+        AdminClient spiedAdminClient = Mockito.spy(mockedAdminClient);
+        final NewTopic newTopic = new NewTopic("test_topic", 1, (short) 1);
+        mockedAdminClient.createTopics(List.of(newTopic));
+
+        ListTopicsResult topicListResult = Mockito.spy(mockedAdminClient.listTopics());
+        KafkaFuture<Set<String>> kafkaFutures = Mockito.spy(topicListResult.names());
+        doReturn(topicListResult).when(spiedAdminClient).listTopics();
+        doReturn(kafkaFutures).when(topicListResult).names();
+        doThrow(ExecutionException.class).when(kafkaFutures).get();
+
+        MockedStatic<AdminClient> mockedStaticAdminClient = Mockito.mockStatic(AdminClient.class);
+        mockedStaticAdminClient.when(() -> AdminClient.create(kafkaAdmin.getConfigurationProperties()).listTopics().names())
+                .thenReturn(spiedAdminClient);
+
+        KafkaTopicService spiedTopicService = Mockito.spy(kafkaTopicService);
+
+        assertThrows(KafkaException.class, () -> spiedTopicService.isTopicCreated("topology-inventory-ingestion"));
+
+        Mockito.reset(spiedAdminClient, topicListResult, kafkaFutures, spiedTopicService);
+        mockedStaticAdminClient.close();
+
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/service/ModelSchemaServiceTest.java b/teiv/src/test/java/org/oran/smo/teiv/service/ModelSchemaServiceTest.java
new file mode 100644
index 0000000..6a57c1e
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/service/ModelSchemaServiceTest.java
@@ -0,0 +1,206 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import org.oran.smo.teiv.api.model.OranTeivSchema;
+import org.oran.smo.teiv.api.model.OranTeivSchemaList;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.exposure.model.api.impl.ModelSchemaServiceImpl;
+import org.oran.smo.teiv.exposure.spi.DataPersistanceService;
+import org.oran.smo.teiv.exposure.spi.impl.DataPersistanceServiceImpl;
+import org.oran.smo.teiv.exposure.spi.impl.StoredSchema;
+import org.oran.smo.teiv.exposure.spi.mapper.MapperUtility;
+import org.oran.smo.teiv.exposure.spi.mapper.PageMetaData;
+import org.oran.smo.teiv.exposure.spi.mapper.PaginationMetaData;
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.mock.web.MockMultipartFile;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.oran.smo.teiv.utils.TiesConstants.IN_USAGE;
+import static org.oran.smo.teiv.utils.exposure.PaginationVerifierTestUtil.verifyResponse;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class ModelSchemaServiceTest {
+
+    private static final DataPersistanceService dataPersistanceService = mock(DataPersistanceServiceImpl.class);
+    private static final MapperUtility mapperUtility = new MapperUtility();
+    private final ModelSchemaServiceImpl service = new ModelSchemaServiceImpl(dataPersistanceService);
+
+    @BeforeAll
+    static void beforeAll() {
+        StoredSchema ranLogicalToCloud = new StoredSchema();
+        ranLogicalToCloud.setName("o-ran-smo-teiv-cloud-to-ran");
+        ranLogicalToCloud.setNamespace("urn:o-ran:smo-teiv-cloud-to-ran");
+        ranLogicalToCloud.setDomain("CLOUD_TO_RAN");
+        ranLogicalToCloud.setRevision("2023-10-24");
+        ranLogicalToCloud.setStatus(IN_USAGE);
+
+        StoredSchema ranEquipment = new StoredSchema();
+        ranEquipment.setName("o-ran-smo-teiv-equipment");
+        ranEquipment.setNamespace("urn:o-ran:smo-teiv-equipment");
+        ranEquipment.setDomain("EQUIPMENT");
+        ranEquipment.setRevision("2023-06-26");
+        ranEquipment.setStatus(IN_USAGE);
+
+        StoredSchema ranOamToCloud = new StoredSchema();
+        ranOamToCloud.setName("o-ran-smo-teiv-oam-to-cloud");
+        ranOamToCloud.setNamespace("urn:o-ran:smo-teiv-oam-to-cloud");
+        ranOamToCloud.setDomain("OAM_TO_CLOUD");
+        ranOamToCloud.setRevision("2023-10-24");
+        ranOamToCloud.setStatus(IN_USAGE);
+
+        StoredSchema ranOamToLogical = new StoredSchema();
+        ranOamToLogical.setName("o-ran-smo-teiv-oam-to-ran");
+        ranOamToLogical.setNamespace("urn:o-ran:smo-teiv-oam-to-ran");
+        ranOamToLogical.setDomain("OAM_TO_RAN");
+        ranOamToLogical.setRevision("2023-10-24");
+        ranOamToLogical.setStatus(IN_USAGE);
+
+        StoredSchema ranCloud = new StoredSchema();
+        ranCloud.setName("o-ran-smo-teiv-cloud");
+        ranCloud.setNamespace("urn:o-ran:smo-teiv-cloud");
+        ranCloud.setDomain("CLOUD");
+        ranCloud.setRevision("2023-06-26");
+        ranCloud.setStatus(IN_USAGE);
+
+        StoredSchema ranOam = new StoredSchema();
+        ranOam.setName("o-ran-smo-teiv-oam");
+        ranOam.setNamespace("urn:o-ran:smo-teiv-oam");
+        ranOam.setDomain("OAM");
+        ranOam.setRevision("2023-06-26");
+        ranOam.setContent("yang model o-ran-smo-teiv-oam {}");
+        ranOam.setStatus(IN_USAGE);
+        ranOam.setOwnerAppId("BUILT_IN_MODULE");
+
+        when(dataPersistanceService.getSchemas(PaginationDTO.builder().offset(0).limit(8).build())).thenReturn(mapperUtility
+                .wrapSchema(Arrays.asList(ranLogicalToCloud, ranEquipment, ranOamToCloud, ranOamToLogical, ranCloud,
+                        ranOam), PaginationDTO.builder().offset(0).limit(8).build()));
+        when(dataPersistanceService.getSchema("o-ran-smo-teiv-oam")).thenReturn(ranOam);
+        when(dataPersistanceService.getSchema("o-ran-smo-teiv")).thenReturn(null);
+
+        when(dataPersistanceService.getSchemas("ties_logical", PaginationDTO.builder().basePath("/schemas/ties_logical")
+                .offset(0).limit(8).build())).thenReturn(mapperUtility.wrapSchema(new ArrayList<>(), PaginationDTO.builder()
+                        .basePath("/schemas/ties_logical").offset(0).limit(8).build()));
+        when(dataPersistanceService.getSchemas("CLOUD", PaginationDTO.builder().basePath("/schemas/CLOUD").offset(0).limit(
+                8).build())).thenReturn(mapperUtility.wrapSchema(List.of(ranCloud), PaginationDTO.builder().basePath(
+                        "/schemas/CLOUD").offset(0).limit(8).build()));
+        when(dataPersistanceService.getSchemas("ran*", PaginationDTO.builder().basePath("/schemas/ran*").offset(0).limit(8)
+                .build())).thenReturn(mapperUtility.wrapSchema(Arrays.asList(ranLogicalToCloud, ranEquipment, ranOamToCloud,
+                        ranOamToLogical, ranCloud, ranOam), PaginationDTO.builder().basePath("/schemas/ran*").offset(0)
+                                .limit(8).build()));
+    }
+
+    @Test
+    void testGetSchemas() throws IOException {
+        //when
+        OranTeivSchemaList schemaItems = service.getSchemas(PaginationDTO.builder().offset(0).limit(8).build());
+        //then
+        List<OranTeivSchema> schemasMetaData = schemaItems.getItems();
+        Assertions.assertEquals(6, schemasMetaData.size());
+
+        MapperUtility mapperUtility = new MapperUtility();
+        List<Object> resultException = new ArrayList<>(schemasMetaData);
+        PaginationDTO paginationDTO = PaginationDTO.builder().basePath("/schemas").offset(100).limit(5).build();
+        paginationDTO.setTotalSize(5);
+        Assertions.assertThrows(TiesException.class, () -> mapperUtility.wrapList(resultException, paginationDTO));
+
+        Map<String, Object> fullResult = new HashMap<>();
+        fullResult.put("items", schemasMetaData);
+
+        PaginationMetaData pmd = new PaginationMetaData();
+
+        PaginationDTO paginationDTO2 = PaginationDTO.builder().basePath("/schemas").offset(0).limit(15).build();
+        paginationDTO2.setTotalSize(6);
+        fullResult.putAll(pmd.getObjectList(paginationDTO2));
+
+        verifyResponse(fullResult, mapperUtility.wrapList(resultException, PaginationDTO.builder().basePath("/schemas")
+                .offset(0).limit(15).build()));
+
+        Map<String, Object> fullResult2 = new HashMap<>();
+        fullResult2.put("items", schemasMetaData.subList(0, 5));
+
+        PageMetaData pageMetaDataSelf2 = new PageMetaData(0, PaginationDTO.builder().limit(5).basePath("/schemas").build());
+        PageMetaData pageMetaDataFirst2 = new PageMetaData(0, PaginationDTO.builder().limit(5).basePath("/schemas")
+                .build());
+        PageMetaData pageMetaDataPrev2 = new PageMetaData(0, PaginationDTO.builder().limit(5).basePath("/schemas").build());
+        PageMetaData pageMetaDataNext2 = new PageMetaData(5, PaginationDTO.builder().limit(5).basePath("/schemas").build());
+        PageMetaData pageMetaDataLast2 = new PageMetaData(5, PaginationDTO.builder().limit(5).basePath("/schemas").build());
+
+        fullResult2.put("self", pageMetaDataSelf2);
+        fullResult2.put("first", pageMetaDataFirst2);
+        fullResult2.put("prev", pageMetaDataPrev2);
+        fullResult2.put("next", pageMetaDataNext2);
+        fullResult2.put("last", pageMetaDataLast2);
+
+        verifyResponse(fullResult2, mapperUtility.wrapList(resultException, PaginationDTO.builder().basePath("/schemas")
+                .offset(0).limit(5).build()));
+    }
+
+    @Test
+    void testGetSchemasByName() {
+        //when
+        String incorrectSchemaName = "o-ran-smo-teiv";
+        String responseForCorrectSchemaName = service.getSchemaByName("o-ran-smo-teiv-oam");
+        //then
+        Assertions.assertThrowsExactly(TiesException.class, () -> service.getSchemaByName(incorrectSchemaName));
+        Assertions.assertTrue(responseForCorrectSchemaName.contains("o-ran-smo-teiv-oam"));
+    }
+
+    @Test
+    void testGetSchemasInDomain() {
+        //when
+        List<OranTeivSchema> schemasInIncorrectDomain = (List<OranTeivSchema>) service.getSchemasInDomain("ties_logical",
+                PaginationDTO.builder().basePath("/schemas/ties_logical").offset(0).limit(8).build()).getItems();
+        List<OranTeivSchema> schemasInDomainRanCloud = (List<OranTeivSchema>) service.getSchemasInDomain("CLOUD",
+                PaginationDTO.builder().basePath("/schemas/CLOUD").offset(0).limit(8).build()).getItems();
+        List<OranTeivSchema> schemasInDomainPartiallyMatchingRan = (List<OranTeivSchema>) service.getSchemasInDomain("ran*",
+                PaginationDTO.builder().basePath("/schemas/ran*").offset(0).limit(8).build()).getItems();
+        //then
+        Assertions.assertEquals(List.of(), schemasInIncorrectDomain);
+        Assertions.assertEquals(1, schemasInDomainRanCloud.size());
+        Assertions.assertEquals(6, schemasInDomainPartiallyMatchingRan.size());
+    }
+
+    @Test
+    void testCreateSchema() {
+        service.createSchema(new MockMultipartFile("yangModule.yang", "yangContent".getBytes(StandardCharsets.UTF_8)));
+    }
+
+    @Test
+    void testDeleteSchema() {
+        Assertions.assertEquals("Invalid schema name", Assertions.assertThrowsExactly(TiesException.class, () -> service
+                .deleteSchema("schemaToDelete")).getMessage());
+
+        Assertions.assertEquals("Forbidden", Assertions.assertThrowsExactly(TiesException.class, () -> service.deleteSchema(
+                "o-ran-smo-teiv-oam")).getMessage());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/service/TiesDbOperationResultsTest.java b/teiv/src/test/java/org/oran/smo/teiv/service/TiesDbOperationResultsTest.java
new file mode 100644
index 0000000..d44e3ab
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/service/TiesDbOperationResultsTest.java
@@ -0,0 +1,1111 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import static org.oran.smo.teiv.utils.TiesConstants.PROPERTY_A_SIDE;
+import static org.oran.smo.teiv.utils.TiesConstants.PROPERTY_B_SIDE;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import javax.sql.DataSource;
+
+import org.oran.smo.teiv.exception.TiesException;
+import org.jooq.DSLContext;
+import org.jooq.JSONB;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ActiveProfiles;
+
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.exception.InvalidFieldInYangDataException;
+import org.oran.smo.teiv.ingestion.DeadlockRetryPolicy;
+import org.oran.smo.teiv.ingestion.validation.IngestionOperationValidatorFactory;
+import org.oran.smo.teiv.ingestion.validation.MaximumCardinalityViolationException;
+import org.oran.smo.teiv.service.models.OperationResult;
+import org.oran.smo.teiv.schema.PostgresSchemaLoader;
+import org.oran.smo.teiv.schema.RelationType;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.service.cloudevent.CloudEventParser;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+import org.oran.smo.teiv.startup.SchemaHandler;
+import org.oran.smo.teiv.utils.CloudEventTestUtil;
+import org.oran.smo.teiv.utils.ConvertToJooqTypeUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.cloudevents.CloudEvent;
+
+@Configuration
+@SpringBootTest
+@ActiveProfiles({ "test", "ingestion" })
+public class TiesDbOperationResultsTest {
+    public static TestPostgresqlContainer postgresqlContainer = TestPostgresqlContainer.getInstance();
+    private static TiesDbService tiesDbService;
+    private static TiesDbOperations tiesDbOperations;
+    private static DSLContext dslContext;
+    private static String VALIDATE_MANY_TO_ONE_DIR = "src/test/resources/cloudeventdata/validation/many-to-one/";
+    private static String VALIDATE_ONE_TO_MANY_DIR = "src/test/resources/cloudeventdata/validation/one-to-many/";
+    private static String VALIDATE_ONE_TO_ONE_DIR = "src/test/resources/cloudeventdata/validation/one-to-one/";
+
+    @Autowired
+    CloudEventParser cloudEventParser;
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @BeforeAll
+    public static void beforeAll(@Autowired DeadlockRetryPolicy deadlockRetryPolicy) throws UnsupportedOperationException,
+            SchemaLoaderException {
+        String url = postgresqlContainer.getJdbcUrl();
+        DataSource ds = DataSourceBuilder.create().url(url).username("test").password("test").build();
+        dslContext = DSL.using(ds, SQLDialect.POSTGRES);
+        tiesDbService = new TiesDbService(dslContext, dslContext, deadlockRetryPolicy);
+        tiesDbOperations = new TiesDbOperations(tiesDbService, new IngestionOperationValidatorFactory(),
+                new RelationshipMergeValidator());
+        PostgresSchemaLoader postgresSchemaLoader = new PostgresSchemaLoader(dslContext, new ObjectMapper());
+        postgresSchemaLoader.loadSchemaRegistry();
+    }
+
+    @BeforeEach
+    public void deleteAll() {
+        dslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(t -> dslContext
+                .truncate(t).cascade().execute());
+    }
+
+    @Test
+    void testMergeEntityRelationship() {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-create-one-to-many.json");
+
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = assertDoesNotThrow(() -> tiesDbOperations
+                .executeEntityAndRelationshipMergeOperations(parsedCloudEventData));
+
+        assertEquals(3, mergeResult.size());
+        assertEquals("ManagedElement_1", mergeResult.get(0).getId());
+        assertEquals("ManagedElement", mergeResult.get(0).getEntryType());
+        assertEquals(Map.of(), mergeResult.get(0).getContent());
+
+        assertEquals("ENodeBFunction_1", mergeResult.get(1).getId());
+        assertEquals("ENodeBFunction", mergeResult.get(1).getEntryType());
+        assertEquals(Map.of(), mergeResult.get(1).getContent());
+
+        assertEquals("relation_1", mergeResult.get(2).getId());
+        assertEquals("MANAGEDELEMENT_MANAGES_ENODEBFUNCTION", mergeResult.get(2).getEntryType());
+        assertEquals(Map.of("aSide", "ManagedElement_1", "bSide", "ENodeBFunction_1"), mergeResult.get(2).getContent());
+    }
+
+    @Test
+    void testDeleteEntityById() {
+        Map<String, Object> managedElementEntity = new HashMap<>();
+        managedElementEntity.put("id", "managed_element_entity_id1");
+        managedElementEntity.put("fdn", "fdn1");
+        managedElementEntity.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElementEntity);
+
+        // Delete operation - expected to succeed
+        List<OperationResult> deleteResultMatch = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("ManagedElement"), "managed_element_entity_id1");
+
+        assertFalse(deleteResultMatch.isEmpty(), "Delete operation should return a non-empty list");
+        assertTrue(deleteResultMatch.contains(new OperationResult("managed_element_entity_id1", "ManagedElement", null)),
+                "The list should contain the delete operation result with id: 'managed_element_entity_id1'");
+
+        // Delete operation with the same EIID - expected to fail
+        List<OperationResult> deleteResultNoMatch = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("ManagedElement"), "managed_element_entity_id1");
+        assertTrue(deleteResultNoMatch.isEmpty(),
+                "Delete operation should return an empty list for already deleted/non existing ID");
+    }
+
+    @Test
+    void testDeleteOneToOneByRelationId() {
+        Map<String, Object> managedElementEntity = new HashMap<>();
+        managedElementEntity.put("id", "managed_element_entity_id1");
+        managedElementEntity.put("fdn", "fdn1");
+        managedElementEntity.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        managedElementEntity.put("REL_FK_deployed-as-cloudNativeSystem", "cloud_native_system_entity_id1");
+        managedElementEntity.put("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", "relation_eiid1");
+
+        Map<String, Object> cloudNativeSystemEntity = new HashMap<>();
+        cloudNativeSystemEntity.put("id", "cloud_native_system_entity_id1");
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity);
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElementEntity);
+
+        cloudNativeSystemEntity.put("name", "CloudNativeSystem");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity);
+
+        // Delete operation for aSide - expected to succeed
+        Optional<OperationResult> deleteASideResultMatch = tiesDbOperations.deleteRelationFromEntityTableByRelationId(
+                dslContext, "relation_eiid1", SchemaRegistry.getRelationTypeByName(
+                        "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+
+        assertTrue(deleteASideResultMatch.isPresent(), "Delete operation should return a present Optional");
+        assertEquals(new OperationResult("relation_eiid1", "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", null),
+                deleteASideResultMatch.get(), "The delete operation result should be present for: 'relation_eiid1'");
+
+        // Delete operation with the same EIID - expected to fail
+        Optional<OperationResult> deleteResultNoMatch = tiesDbOperations.deleteRelationFromEntityTableByRelationId(
+                dslContext, "relation_eiid1", SchemaRegistry.getRelationTypeByName(
+                        "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+        assertTrue(deleteResultNoMatch.isEmpty(),
+                "Delete operation should return an empty list for already deleted/non existing ID");
+
+        Result<Record> rows = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        Result<Record> rowsOnBSide = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals("managed_element_entity_id1", rows.get(0).get("id"));
+        assertEquals("fdn1", rows.get(0).get("fdn"));
+        assertEquals("cloud_native_system_entity_id1", rowsOnBSide.get(0).get("id"));
+        assertEquals("CloudNativeSystem", rowsOnBSide.get(0).get("name"));
+        assertNull(rows.get(0).get("REL_FK_deployed-as-cloudNativeSystem"));
+        assertNull(rows.get(0).get("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+        assertNull(rowsOnBSide.get(0).get("REL_FK_deployed-managedElement"));
+        assertEquals(ConvertToJooqTypeUtil.toJsonb(List.of()), rows.get(0).get(
+                "REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+    }
+
+    @Test
+    void testDeleteOneToManyByManySideEntityId() {
+        Map<String, Object> managedElement1 = new HashMap<>();
+        managedElement1.put("id", "managed_element_entity_id1");
+        managedElement1.put("fdn", "fdn1");
+        managedElement1.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+
+        Map<String, Object> cna1 = new HashMap<>();
+        cna1.put("id", "cna_entity_id1");
+        cna1.put("name", "CloudNativeApplication");
+        cna1.put("REL_FK_realised-managedElement", "managed_element_entity_id1");
+        cna1.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_eiid1");
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElement1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna1);
+
+        // Delete operation with existing relationship
+        List<OperationResult> deleteResultMatch = tiesDbOperations.deleteRelationshipByManySideEntityId(dslContext,
+                "cna_entity_id1", "id", SchemaRegistry.getRelationTypeByName(
+                        "MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION"));
+
+        assertFalse(deleteResultMatch.isEmpty(), "Delete operation should return a non-empty list");
+        assertTrue(deleteResultMatch.contains(new OperationResult("relation_eiid1",
+                "MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", null)),
+                "The list should contain the delete operation result with id: 'relation_eiid1'");
+
+        // Delete operation with the same entity ID - expected to return an empty list
+        List<OperationResult> deleteResultNoMatch = tiesDbOperations.deleteRelationshipByManySideEntityId(dslContext,
+                "cna_entity_id1", "id", SchemaRegistry.getRelationTypeByName(
+                        "MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION"));
+
+        assertTrue(deleteResultNoMatch.isEmpty(),
+                "Delete operation should return an empty list for already deleted/non existing ID");
+    }
+
+    @Test
+    void testDeleteOneToManyByOneSideEntityId() {
+        Map<String, Object> managedElement1 = new HashMap<>();
+        managedElement1.put("id", "managed_element_entity_id1");
+        managedElement1.put("fdn", "fdn1");
+        managedElement1.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+
+        Map<String, Object> cna1 = new HashMap<>();
+        cna1.put("id", "cna_entity_id1");
+        cna1.put("name", "CloudNativeApplication");
+        cna1.put("REL_FK_realised-managedElement", "managed_element_entity_id1");
+        cna1.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_eiid1");
+
+        Map<String, Object> cna2 = new HashMap<>();
+        cna2.put("id", "cna_entity_id2");
+        cna2.put("name", "CloudNativeApplication");
+        cna2.put("REL_FK_realised-managedElement", "managed_element_entity_id1");
+        cna2.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_eiid2");
+
+        Map<String, Object> cna3 = new HashMap<>();
+        cna3.put("id", "cna_entity_id3");
+        cna3.put("name", "CloudNativeApplication");
+        cna3.put("REL_FK_realised-managedElement", "managed_element_entity_id1");
+        cna3.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_eiid3");
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElement1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna2);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna3);
+
+        // Delete operation for managed_element_entity_id1
+        List<OperationResult> deleteResultMatch = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("ManagedElement"), "managed_element_entity_id1");
+        assertFalse(deleteResultMatch.isEmpty(), "Delete operation should return a non-empty list");
+
+        // Check if all expected IDs are present in the deletion result
+        assertEquals(4, deleteResultMatch.size(), "Delete operation should match expected size");
+        assertTrue(deleteResultMatch.contains(new OperationResult("managed_element_entity_id1", "ManagedElement", null)),
+                "The list should contain the delete operation result with id: 'managed_element_entity_id1'");
+
+        assertTrue(deleteResultMatch.contains(new OperationResult("relation_eiid1",
+                "MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", null)),
+                "The list should contain the delete operation result with id: 'relation_eiid1'");
+        assertTrue(deleteResultMatch.contains(new OperationResult("relation_eiid2",
+                "MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", null)),
+                "The list should contain the delete operation result with id: 'relation_eiid2'");
+        assertTrue(deleteResultMatch.contains(new OperationResult("relation_eiid3",
+                "MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", null)),
+                "The list should contain the delete operation result with id: 'relation_eiid3'");
+
+        // Verify all related entities have their relationships deleted
+        Result<Record> rows = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeApplication\"");
+        assertEquals(3, rows.size());
+        for (Record row : rows) {
+            assertNull(row.get("REL_FK_realised-managedElement"),
+                    "REL_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION should be null");
+            assertNull(row.get("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION"),
+                    "REL_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION_EIID should be null");
+        }
+    }
+
+    @Test
+    void testDeleteManyToManyByRelationshipId() {
+        Map<String, Object> gnbcucp1 = new HashMap<>();
+        gnbcucp1.put("id", "gnbcucp_id1");
+        gnbcucp1.put("fdn", "fdn1");
+        gnbcucp1.put("gNBCUName", "gNBCUName");
+        gnbcucp1.put("gNBId", 1);
+        gnbcucp1.put("gNBIdLength", 1);
+        gnbcucp1.put("pLMNId", JSONB.jsonb("{\"name\":\"pLMNId1\"}"));
+        gnbcucp1.put("cmId", JSONB.jsonb("{\"name\":\"cmId1\"}"));
+
+        Map<String, Object> cna1 = new HashMap<>();
+        cna1.put("id", "cloud_native_id1");
+        cna1.put("name", "CloudNativeApplication");
+
+        Map<String, Object> cna2 = new HashMap<>();
+        cna2.put("id", "cloud_native_id2");
+        cna2.put("name", "CloudNativeApplication");
+
+        Map<String, Object> rel1 = new HashMap<>();
+        rel1.put("id", "rel_id1");
+        rel1.put("aSide_GNBCUCPFunction", "gnbcucp_id1");
+        rel1.put("bSide_CloudNativeApplication", "cloud_native_id1");
+
+        Map<String, Object> rel2 = new HashMap<>();
+        rel2.put("id", "rel_id2");
+        rel2.put("aSide_GNBCUCPFunction", "gnbcucp_id1");
+        rel2.put("bSide_CloudNativeApplication", "cloud_native_id2");
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFunction\"", gnbcucp1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna2);
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", rel1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", rel2);
+
+        Result<Record> row1 = tiesDbService.selectAllRowsFromTable("ties_data.\"GNBCUCPFunction\"");
+        assertEquals(1, row1.size());
+        Result<Record> row2 = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeApplication\"");
+        assertEquals(2, row2.size());
+        Result<Record> row3 = tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"");
+        assertEquals(2, row3.size());
+
+        // Test deletion of a relationship by ID (expected success)
+        Optional<OperationResult> deleteResultMatch = tiesDbOperations.deleteManyToManyRelationByRelationId(dslContext,
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", "rel_id1");
+        assertTrue(deleteResultMatch.isPresent(), "Delete operation should return a present Optional");
+        assertEquals(new OperationResult("rel_id1", "GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", null),
+                deleteResultMatch.get(), "Deleted relationship ID should match 'rel_id1'");
+
+        // Test deletion of the same relationship ID again (expected failure)
+        Optional<OperationResult> deleteResultNoMatch = tiesDbOperations.deleteManyToManyRelationByRelationId(dslContext,
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", "rel_id1");
+        assertTrue(deleteResultNoMatch.isEmpty(), "Delete operation should not return a present Optional");
+    }
+
+    @Test
+    void testDeleteManyToManyByEntityId() {
+        Map<String, Object> gnbcucp1 = new HashMap<>();
+        gnbcucp1.put("id", "gnbcucp_id1");
+        gnbcucp1.put("fdn", "fdn1");
+        gnbcucp1.put("gNBCUName", "gNBCUName");
+        gnbcucp1.put("gNBId", 1);
+        gnbcucp1.put("gNBIdLength", 1);
+        gnbcucp1.put("pLMNId", JSONB.jsonb("{\"name\":\"pLMNId1\"}"));
+        gnbcucp1.put("cmId", JSONB.jsonb("{\"name\":\"cmId1\"}"));
+
+        Map<String, Object> cna1 = new HashMap<>();
+        cna1.put("id", "cloud_native_id1");
+        cna1.put("name", "CloudNativeApplication");
+
+        Map<String, Object> cna2 = new HashMap<>();
+        cna2.put("id", "cloud_native_id2");
+        cna2.put("name", "CloudNativeApplication");
+
+        Map<String, Object> rel1 = new HashMap<>();
+        rel1.put("id", "rel_id1");
+        rel1.put("aSide_GNBCUCPFunction", "gnbcucp_id1");
+        rel1.put("bSide_CloudNativeApplication", "cloud_native_id1");
+
+        Map<String, Object> rel2 = new HashMap<>();
+        rel2.put("id", "rel_id2");
+        rel2.put("aSide_GNBCUCPFunction", "gnbcucp_id1");
+        rel2.put("bSide_CloudNativeApplication", "cloud_native_id2");
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFunction\"", gnbcucp1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna2);
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", rel1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", rel2);
+
+        assertEquals(1, tiesDbService.selectAllRowsFromTable("ties_data.\"GNBCUCPFunction\"").size(),
+                "Expected one GNBCUCPFunction record");
+        assertEquals(2, tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeApplication\"").size(),
+                "Expected two CloudNativeApplication records");
+        assertEquals(2, tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"").size(),
+                "Expected two GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION relations");
+
+        // Test deletion of relations by entity ID (expected to delete two relations)
+        List<OperationResult> deleteResultMatch = tiesDbOperations.deleteManyToManyRelationByEntityId(dslContext,
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", "gnbcucp_id1", "aSide_GNBCUCPFunction",
+                "bSide_CloudNativeApplication");
+        assertEquals(2, deleteResultMatch.size(), "Expected two relations to be deleted");
+        assertTrue(deleteResultMatch.contains(new OperationResult("rel_id1",
+                "GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", null)),
+                "The list should contain the delete operation result with id: 'rel_id1'");
+
+        assertTrue(deleteResultMatch.contains(new OperationResult("rel_id2",
+                "GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", null)),
+                "The list should contain the delete operation result with id: 'rel_id2'");
+
+        // Test deletion of relations by the same entity ID again (expected to find no
+        // relations to delete)
+        List<OperationResult> deleteResultNoMatch = tiesDbOperations.deleteManyToManyRelationByEntityId(dslContext,
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", "gnbcucp_id1", "aSide_GNBCUCPFunction",
+                "bSide_CloudNativeApplication");
+        assertTrue(deleteResultNoMatch.isEmpty(),
+                "Delete operation should return an empty list for already deleted/non existing ID");
+    }
+
+    @Test
+    void testDeleteRelConnectingSameEntityByRelationshipId() {
+        Map<String, Object> antennaModule1 = new HashMap<>();
+        antennaModule1.put("id", "module_id1");
+        antennaModule1.put("mechanicalAntennaTilt", 400);
+        antennaModule1.put("fdn", "fdn_1");
+        antennaModule1.put("cmId", JSONB.jsonb("{\"name\":\"cmId1\"}"));
+        antennaModule1.put("antennaModelNumber", "['123-abc']");
+        antennaModule1.put("totalTilt", 10);
+        antennaModule1.put("mechanicalAntennaBearing", 123);
+        antennaModule1.put("positionWithinSector", "['123', '456', '789']");
+        antennaModule1.put("electricalAntennaTilt", 1);
+
+        Map<String, Object> antennaModule2 = new HashMap<>();
+        antennaModule2.put("id", "module_id2");
+        antennaModule2.put("mechanicalAntennaTilt", 401);
+        antennaModule2.put("fdn", "fdn_2");
+        antennaModule2.put("cmId", JSONB.jsonb("{\"name\":\"cmId2\"}"));
+        antennaModule2.put("antennaModelNumber", "['456-abc']");
+        antennaModule2.put("totalTilt", 11);
+        antennaModule2.put("mechanicalAntennaBearing", 456);
+        antennaModule2.put("positionWithinSector", "['123', '456', '789']");
+        antennaModule2.put("electricalAntennaTilt", 2);
+
+        Map<String, Object> rel1 = new HashMap<>();
+        rel1.put("id", "rel_id1");
+        rel1.put("aSide_AntennaModule", "module_id1");
+        rel1.put("bSide_AntennaModule", "module_id2");
+
+        Map<String, Object> rel2 = new HashMap<>();
+        rel2.put("id", "rel_id2");
+        rel2.put("bSide_AntennaModule", "module_id2");
+        rel2.put("aSide_AntennaModule", "module_id1");
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"AntennaModule\"", antennaModule1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"AntennaModule\"", antennaModule2);
+        tiesDbOperations.merge(dslContext, "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", rel1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", rel2);
+
+        Result<Record> row1 = tiesDbService.selectAllRowsFromTable("ties_data.\"AntennaModule\"");
+        assertEquals(2, row1.size());
+        Result<Record> row2 = tiesDbService.selectAllRowsFromTable("ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"");
+        assertEquals(2, row2.size());
+
+        // Test deletion of a relationship by ID (expected success)
+        Optional<OperationResult> deleteResultMatch = tiesDbOperations.deleteManyToManyRelationByRelationId(dslContext,
+                "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", "rel_id1");
+        assertTrue(deleteResultMatch.isPresent(), "Delete operation should return a present Optional");
+        assertEquals(new OperationResult("rel_id1", "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE", null), deleteResultMatch
+                .get(), "Deleted relationship ID should match 'rel_id1'");
+
+        // Test deletion of the same relationship ID again (expected failure)
+        Optional<OperationResult> deleteResultNoMatch = tiesDbOperations.deleteManyToManyRelationByRelationId(dslContext,
+                "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", "rel_id1");
+        assertTrue(deleteResultNoMatch.isEmpty(), "Delete operation should not return a present Optional");
+
+    }
+
+    @Test
+    void testDeleteRelConnectingSameEntityByEntityId() {
+        Map<String, Object> antennaModule1 = new HashMap<>();
+        antennaModule1.put("id", "module_id1");
+        antennaModule1.put("mechanicalAntennaTilt", 400);
+        antennaModule1.put("fdn", "fdn_1");
+        antennaModule1.put("cmId", JSONB.jsonb("{\"name\":\"cmId1\"}"));
+        antennaModule1.put("antennaModelNumber", "['123-abc']");
+        antennaModule1.put("totalTilt", 10);
+        antennaModule1.put("mechanicalAntennaBearing", 123);
+        antennaModule1.put("positionWithinSector", "['123', '456', '789']");
+        antennaModule1.put("electricalAntennaTilt", 1);
+
+        Map<String, Object> antennaModule2 = new HashMap<>();
+        antennaModule2.put("id", "module_id2");
+        antennaModule2.put("mechanicalAntennaTilt", 401);
+        antennaModule2.put("fdn", "fdn_2");
+        antennaModule2.put("cmId", JSONB.jsonb("{\"name\":\"cmId2\"}"));
+        antennaModule2.put("antennaModelNumber", "['456-abc']");
+        antennaModule2.put("totalTilt", 11);
+        antennaModule2.put("mechanicalAntennaBearing", 456);
+        antennaModule2.put("positionWithinSector", "['123', '456', '789']");
+        antennaModule2.put("electricalAntennaTilt", 2);
+
+        Map<String, Object> rel1 = new HashMap<>();
+        rel1.put("id", "rel_id1");
+        rel1.put("aSide_AntennaModule", "module_id1");
+        rel1.put("bSide_AntennaModule", "module_id2");
+
+        Map<String, Object> rel2 = new HashMap<>();
+        rel2.put("id", "rel_id2");
+        rel2.put("bSide_AntennaModule", "module_id2");
+        rel2.put("aSide_AntennaModule", "module_id1");
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"AntennaModule\"", antennaModule1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"AntennaModule\"", antennaModule2);
+        tiesDbOperations.merge(dslContext, "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", rel1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", rel2);
+
+        assertEquals(2, tiesDbService.selectAllRowsFromTable("ties_data.\"AntennaModule\"").size(),
+                "Expected two AntennaModule records");
+        assertEquals(2, tiesDbService.selectAllRowsFromTable("ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"")
+                .size(), "Expected two ANTENNAMODULE_REALISED_BY_ANTENNAMODULE relations");
+
+        // Test deletion of relations by entity ID (expected to delete two relations)
+        List<OperationResult> deleteResultMatch = tiesDbOperations.deleteManyToManyRelationByEntityId(dslContext,
+                "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", "module_id1", "aSide_AntennaModule",
+                "bSide_AntennaModule");
+        assertEquals(2, deleteResultMatch.size(), "Expected two relations to be deleted");
+        assertTrue(deleteResultMatch.contains(new OperationResult("rel_id1", "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE",
+                null)), "The list should contain the delete operation result with id: 'rel_id1'");
+
+        assertTrue(deleteResultMatch.contains(new OperationResult("rel_id2", "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE",
+                null)), "The list should contain the delete operation result with id: 'rel_id2'");
+
+        // Test deletion of relations by the same entity ID again (expected to find no
+        // relations to delete)
+        List<OperationResult> deleteResultNoMatch = tiesDbOperations.deleteManyToManyRelationByEntityId(dslContext,
+                "ties_data.\"ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\"", "module_id1", "aSide_AntennaModule",
+                "bSide_AntennaModule");
+        assertTrue(deleteResultNoMatch.isEmpty(),
+                "Delete operation should return an empty list for already deleted/non existing ID");
+
+    }
+
+    @Test
+    void testMergeEntityRelationshipWithLongNames() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-merge-long-names.json");
+
+        // Merge entities and relationship
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(40, mergeResult.size());
+    }
+
+    @Test
+    void testDeleteASideEntityWithLongNames() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-merge-long-names.json");
+
+        // Merge topology data
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(40, mergeResult.size());
+
+        // Entity with One_To_One relationship
+        List<OperationResult> deleteEntityResult1 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt"),
+                "ManagedElement_2");
+        assertEquals(2, deleteEntityResult1.size());
+
+        // Entity with One_To_Many relationship
+        List<OperationResult> deleteEntityResult2 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"),
+                "GNBDUFunction_2");
+        assertEquals(2, deleteEntityResult2.size());
+
+        // Entity and Many_To_One relationship
+        List<OperationResult> deleteEntityResult3 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"),
+                "CloudNativeApplication_3");
+        assertEquals(2, deleteEntityResult3.size());
+
+        // Entity with Many_To_Many relationship
+        List<OperationResult> deleteEntityResult4 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"),
+                "GNBDUFunction_1");
+        assertEquals(7, deleteEntityResult4.size());
+
+        // Entity with One_To_Many relationship ConnectingSameEntity
+        List<OperationResult> deleteEntityResult5 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"),
+                "AntennaModule_1");
+        assertEquals(2, deleteEntityResult5.size());
+
+        // Entity with One_To_One relationship ConnectingSameEntity
+        List<OperationResult> deleteEntityResult6 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"),
+                "AntennaModule_5");
+        assertEquals(2, deleteEntityResult6.size());
+    }
+
+    @Test
+    void testDeleteBSideEntityWithLongNames() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-merge-long-names.json");
+
+        // Merge topology data
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(40, mergeResult.size());
+
+        // Entity with One_To_One relationship
+        List<OperationResult> deleteEntityResult1 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm"),
+                "CloudNativeSystem_1");
+        assertEquals(2, deleteEntityResult1.size());
+
+        // Entity with One_To_Many relationship
+        List<OperationResult> deleteEntityResult2 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"), "NRCellDU_3");
+        assertEquals(2, deleteEntityResult2.size());
+
+        // Entity with Many_To_One relationship
+        List<OperationResult> deleteEntityResult3 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), "Namespace_1");
+        assertEquals(3, deleteEntityResult3.size());
+
+        // Entity with Many_To_Many relationship
+        List<OperationResult> deleteEntityResult4 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"),
+                "CloudNativeApplication_2");
+        assertEquals(2, deleteEntityResult4.size());
+
+        // Entity with One_To_Many relationship ConnectingSameEntity
+        List<OperationResult> deleteEntityResult5 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"),
+                "AntennaModule_2");
+        assertEquals(2, deleteEntityResult5.size());
+
+        // Entity with One_To_One relationship ConnectingSameEntity
+        List<OperationResult> deleteEntityResult6 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"),
+                "AntennaModule_6");
+        assertEquals(2, deleteEntityResult6.size());
+
+        // Again delete CloudNativeApplication(id=CloudNativeApplication_2) should
+        // return empty result list
+        List<OperationResult> deleteEntityResult7 = tiesDbOperations.deleteEntity(dslContext, SchemaRegistry
+                .getEntityTypeByName("CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"),
+                "CloudNativeApplication_2");
+        assertTrue(deleteEntityResult7.isEmpty(),
+                "Delete operation should return an empty list for already deleted/non existing ID");
+    }
+
+    @Test
+    void testDeleteRelationshipWithLongNames() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-merge-long-names.json");
+
+        // Merge topology data
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(40, mergeResult.size());
+
+        //One_To_One Relationship
+        Relationship oneToOneRelationship = new Relationship("o-ran-smo-teiv-oam-to-cloud",
+                "MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM",
+                "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM_relation_3", "ManagedElement_3", "CloudNativeSystem_3", List
+                        .of());
+        RelationType oneToOneRelationType = SchemaRegistry.getRelationTypeByName(oneToOneRelationship.getType());
+        Optional<OperationResult> deleteOneToOneRelationshipResult = tiesDbOperations
+                .deleteRelationFromEntityTableByRelationId(dslContext, oneToOneRelationship.getId(), oneToOneRelationType);
+        assertTrue(deleteOneToOneRelationshipResult.isPresent(), "Delete operation should return a present Optional");
+
+        //One_To_Many Relationship
+        Relationship oneToManyRelationship = new Relationship("o-ran-smo-teiv-ran",
+                "GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU",
+                "GNBDUFUNCTION_PROVIDES_NRCELLDU_relation_2", "GNBDUFunction_1", "NRCellDU_2", List.of());
+        RelationType oneToManyRelationType = SchemaRegistry.getRelationTypeByName(oneToManyRelationship.getType());
+        Optional<OperationResult> deleteOneToManyRelationshipResult = tiesDbOperations
+                .deleteRelationFromEntityTableByRelationId(dslContext, oneToManyRelationship.getId(),
+                        oneToManyRelationType);
+        assertTrue(deleteOneToManyRelationshipResult.isPresent(), "Delete operation should return a present Optional");
+
+        //Many_To_One Relationship
+        Relationship manyToOneRelationship = new Relationship("o-ran-smo-teiv-cloud",
+                "CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE",
+                "CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE_relation_3", "CloudNativeApplication_3", "Namespace_3", List
+                        .of());
+        RelationType manyToOneRelationType = SchemaRegistry.getRelationTypeByName(manyToOneRelationship.getType());
+        Optional<OperationResult> deleteManyToOneRelationshipResult = tiesDbOperations
+                .deleteRelationFromEntityTableByRelationId(dslContext, manyToOneRelationship.getId(),
+                        manyToOneRelationType);
+        assertTrue(deleteManyToOneRelationshipResult.isPresent(), "Delete operation should return a present Optional");
+
+        //Many_To_Many Relationship
+        Relationship manyToManyRelationship = new Relationship("o-ran-smo-teiv-cloud-to-ran",
+                "GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN",
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_relation_1", "GNBDUFunction_1",
+                "CloudNativeApplication_1", List.of());
+        RelationType manyToManyRelationType = SchemaRegistry.getRelationTypeByName(manyToManyRelationship.getType());
+        Optional<OperationResult> deleteManyToManyRelationshipResult = tiesDbOperations
+                .deleteManyToManyRelationByRelationId(dslContext, manyToManyRelationType.getTableName(),
+                        manyToManyRelationship.getId());
+        assertTrue(deleteManyToManyRelationshipResult.isPresent(), "Delete operation should return a present Optional");
+
+        //One_To_One Relationship ConnectingSameEntity
+        Relationship connectingSameEntityOneToOneRelationship = new Relationship("o-ran-smo-teiv-equipment",
+                "ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE",
+                "ANTENNAMODULE_DEPLOYED_ON_ANTENNAMODULE_relation_1", "AntennaModule_5", "AntennaModule_6", List.of());
+        RelationType connectingSameEntityType = SchemaRegistry.getRelationTypeByName(
+                connectingSameEntityOneToOneRelationship.getType());
+        Optional<OperationResult> deleteConnectingSameEntityOneToOneRelationshipResult = tiesDbOperations
+                .deleteManyToManyRelationByRelationId(dslContext, connectingSameEntityType.getTableName(),
+                        connectingSameEntityOneToOneRelationship.getId());
+        assertTrue(deleteConnectingSameEntityOneToOneRelationshipResult.isPresent(),
+                "Delete operation should return a present Optional");
+
+        //One_To_Many Relationship ConnectingSameEntity
+        Relationship connectingSameEntityOneToManyRelationship = new Relationship("o-ran-smo-teiv-equipment",
+                "ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE",
+                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_relation_1", "AntennaModule_1", "AntennaModule_2", List.of());
+        connectingSameEntityType = SchemaRegistry.getRelationTypeByName(connectingSameEntityOneToManyRelationship
+                .getType());
+        Optional<OperationResult> deleteConnectingSameEntityOneToManyRelationshipResult = tiesDbOperations
+                .deleteManyToManyRelationByRelationId(dslContext, connectingSameEntityType.getTableName(),
+                        connectingSameEntityOneToManyRelationship.getId());
+        assertTrue(deleteConnectingSameEntityOneToManyRelationshipResult.isPresent(),
+                "Delete operation should return a present Optional");
+    }
+
+    @Test
+    void testSelectByCmHandleFormSourceIds() {
+        Map<String, Object> cna1 = new HashMap<>();
+        cna1.put("id", "cloud_native_id1");
+        cna1.put("name", "CloudNativeApplication");
+        cna1.put("CD_sourceIds", JSONB.jsonb(
+                "[\"urn:3gpp:dn:/fdn\"," + "\"urn:cmHandle:/395221E080CCF0FD1924103B15873814\"]"));
+
+        Map<String, Object> cna2 = new HashMap<>();
+        cna2.put("id", "cloud_native_id2");
+        cna2.put("name", "CloudNativeApplication");
+        cna2.put("CD_sourceIds", JSONB.jsonb(
+                "[\"urn:3gpp:dn:/fdn\"," + "\"urn:cmHandle:/395221E080CCF0FD1924103B15873815\"]"));
+
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna1);
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cna2);
+
+        List<String> ids = tiesDbOperations.selectByCmHandleFormSourceIds(dslContext,
+                "ties_data.\"CloudNativeApplication\"", "395221E080CCF0FD1924103B15873814");
+        assertEquals(List.of("cloud_native_id1"), ids);
+    }
+
+    @Test
+    void testMergeManyToManyRelationshipWithExistingId_SidesNotUpdatable() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-many.json");
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(12, mergeResult.size());
+
+        Relationship manyToManyRelationship = new Relationship("o-ran-smo-teiv-ran",
+                "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_2", "GNBCUUP_1", "CloudNativeApplication_3",
+                new ArrayList<>());
+        final ParsedCloudEventData finalParsedCloudEventData = new ParsedCloudEventData(new ArrayList<>(), List.of(
+                manyToManyRelationship));
+        assertThrows(TiesException.class, () -> tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                finalParsedCloudEventData));
+    }
+
+    @Test
+    void testMergeManyToManyRelationshipWithExistingId_SidesSameAsUpdatables() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-many.json");
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(12, mergeResult.size());
+
+        Relationship manyToManyRelationship = new Relationship("o-ran-smo-teiv-ran",
+                "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_2", "GNBCUUP_1", "CloudNativeApplication_2",
+                new ArrayList<>());
+        final ParsedCloudEventData finalParsedCloudEventData = new ParsedCloudEventData(new ArrayList<>(), List.of(
+                manyToManyRelationship));
+        List<OperationResult> result = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                finalParsedCloudEventData);
+
+        assertEquals(1, result.size());
+    }
+
+    @Test
+    void testMergeManyToManyWithNonExistingEntities() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-many.json");
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(12, mergeResult.size());
+
+        Relationship manyToManyRelationship = new Relationship("o-ran-smo-teiv-ran",
+                "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_4", "GNBCUUP_3", "CloudNativeApplication_4",
+                new ArrayList<>());
+        parsedCloudEventData = new ParsedCloudEventData(new ArrayList<>(), List.of(manyToManyRelationship));
+        List<OperationResult> result = tiesDbOperations.executeEntityAndRelationshipMergeOperations(parsedCloudEventData);
+
+        assertEquals(3, result.size());
+    }
+
+    @Test
+    void testMergeManyToManyWithOneExistingEntity() throws InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(
+                "src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-many.json");
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        List<OperationResult> mergeResult = tiesDbOperations.executeEntityAndRelationshipMergeOperations(
+                parsedCloudEventData);
+        assertEquals(12, mergeResult.size());
+
+        Relationship manyToManyRelationship = new Relationship("o-ran-smo-teiv-ran",
+                "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_4", "GNBCUUP_1", "CloudNativeApplication_4",
+                new ArrayList<>());
+        parsedCloudEventData = new ParsedCloudEventData(new ArrayList<>(), List.of(manyToManyRelationship));
+        List<OperationResult> result = tiesDbOperations.executeEntityAndRelationshipMergeOperations(parsedCloudEventData);
+
+        assertEquals(2, result.size());
+    }
+
+    @Test // Both endpoints exist, and a new relationship ID is received.
+    void testMergeWithNewRelationshipId() throws MaximumCardinalityViolationException, InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+
+    }
+
+    @Test // Same relationship data is received twice.
+    void testMergeWithSameData() throws MaximumCardinalityViolationException, InvalidFieldInYangDataException {
+
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        manyToOneResult = mergeSingleTestEvent(VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one.json");
+        oneToManyResult = mergeSingleTestEvent(VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many.json");
+        oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+    }
+
+    @Test // Existing but free endpoints and an existing relationship ID is received.
+    void testMergeWithExistingFreeEndpoints() throws MaximumCardinalityViolationException, InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one2.json"));
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many2.json"));
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one2.json"));
+    }
+
+    @Test // Used "many" side endpoint with a new relationship ID.
+    void testMergeWithUsedManySideAndNewRelationshipId() throws MaximumCardinalityViolationException,
+            InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+
+        assertThrows(MaximumCardinalityViolationException.class, () -> mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one3.json"));
+        assertThrows(MaximumCardinalityViolationException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many3.json"));
+        assertThrows(MaximumCardinalityViolationException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one3.json"));
+    }
+
+    @Test // Used "many" side endpoint with an existing relationship ID.
+    void testMergeWithUsedManySideAndExistingRelationshipId() throws MaximumCardinalityViolationException,
+            InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one4.json"));
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many4.json"));
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one4.json"));
+    }
+
+    @Test // Missing "one" side endpoint with a new relationship ID.
+    void testMergeWithMissingOneSideAndNewRelationshipId() throws MaximumCardinalityViolationException,
+            InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one5.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many5.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one5.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+    }
+
+    @Test // Missing "many" side endpoint with a new relationship ID.
+    void testMergeWithMissingManySideAndNewRelationshipId() throws MaximumCardinalityViolationException,
+            InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one6.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many6.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one6.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+    }
+
+    @Test // Missing both "one" and "many" side endpoints with a new relationship ID.
+    void testMergeWithMissingEndpointsAndNewRelationshipId() throws MaximumCardinalityViolationException,
+            InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one7.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many7.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one7.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+    }
+
+    @Test // Missing "one" side endpoint with an existing relationship ID.
+    void testMergeWithMissingOneSideAndExistingRelationshipId() throws MaximumCardinalityViolationException,
+            InvalidFieldInYangDataException {
+        List<OperationResult> manyToOneResult = mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one.json");
+        List<OperationResult> oneToManyResult = mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many.json");
+        List<OperationResult> oneToOneResult = mergeSingleTestEvent(VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one.json");
+
+        assertEquals(3, manyToOneResult.size());
+        assertEquals(3, oneToManyResult.size());
+        assertEquals(3, oneToOneResult.size());
+
+        assertDbContainsOperationResults(manyToOneResult);
+        assertDbContainsOperationResults(oneToManyResult);
+        assertDbContainsOperationResults(oneToOneResult);
+
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_MANY_TO_ONE_DIR + "ce-create-many-to-one8.json"));
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_MANY_DIR + "ce-create-one-to-many8.json"));
+        assertThrows(TiesException.class, () -> mergeSingleTestEvent(
+                VALIDATE_ONE_TO_ONE_DIR + "ce-create-one-to-one8.json"));
+    }
+
+    @Test
+    void testOperationResultFromRelationship() {
+        Relationship relationship = new Relationship("o-ran-smo-teiv-equipment", "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE",
+                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_relation_1", "AntennaModule_1", "AntennaModule_2", List.of());
+
+        Map<String, Object> relationshipSides = new HashMap<>();
+        relationshipSides.put("aSide", relationship.getASide());
+        relationshipSides.put("bSide", relationship.getBSide());
+
+        OperationResult result = OperationResult.createFromRelationship(relationship);
+        assertEquals(result.getId(), relationship.getId());
+        assertEquals(result.getEntryType(), relationship.getType());
+        assertEquals(result.getContent(), relationshipSides);
+    }
+
+    @Test
+    void testRelationRelatedMethodsWhenRelationshipIsStoredInSeparateTable() {
+
+        Relationship manyToManyRelationship = new Relationship("o-ran-smo-teiv-ran",
+                "GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION", "relation_4", "GNBCUUP_1", "CloudNativeApplication_4",
+                new ArrayList<>());
+
+        assertNull(manyToManyRelationship.getStoringSideEntityId());
+        assertNull(manyToManyRelationship.getNotStoringSideEntityId());
+
+        RelationType manyToManyRelationType = SchemaRegistry.getRelationTypeByName(manyToManyRelationship.getType());
+
+        assertNull(manyToManyRelationType.getNotStoringSideTableName());
+        assertNull(manyToManyRelationType.getNotStoringSideEntityIdColumnNameInStoringSideTable());
+        assertNull(manyToManyRelationType.getStoringSideEntityType());
+        assertNull(manyToManyRelationType.getNotStoringSideEntityType());
+
+    }
+
+    @Test
+    void testRelationRelatedMethodsWhenRelationshipIsStoredOnBSide() {
+
+        Relationship relationship = new Relationship("o-ran-smo-teiv-ran", "GNBDUFUNCTION_PROVIDES_NRCELLDU", "relation_2",
+                "GNBDUFunction_1", "NRCellDU_5", new ArrayList<>());
+
+        assertEquals("NRCellDU_5", relationship.getStoringSideEntityId());
+        assertEquals("GNBDUFunction_1", relationship.getNotStoringSideEntityId());
+
+        RelationType relationType = SchemaRegistry.getRelationTypeByName(relationship.getType());
+
+        assertEquals("ties_data.\"GNBDUFunction\"", relationType.getNotStoringSideTableName());
+        assertEquals("REL_FK_provided-by-gnbduFunction", relationType
+                .getNotStoringSideEntityIdColumnNameInStoringSideTable());
+        assertEquals("NRCellDU", relationType.getStoringSideEntityType());
+        assertEquals("GNBDUFunction", relationType.getNotStoringSideEntityType());
+
+    }
+
+    private List<OperationResult> mergeSingleTestEvent(String path) throws MaximumCardinalityViolationException,
+            InvalidFieldInYangDataException {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEventFromJsonFile(path);
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        return tiesDbOperations.executeEntityAndRelationshipMergeOperations(parsedCloudEventData);
+    }
+
+    private void assertDbContainsOperationResults(List<OperationResult> results) {
+        for (OperationResult result : results) {
+            boolean isRelation = result.getContent().containsKey(PROPERTY_A_SIDE) && result.getContent().containsKey(
+                    PROPERTY_B_SIDE);
+            if (isRelation) {
+                RelationType relationType = SchemaRegistry.getRelationTypeByName(result.getEntryType());
+                tableContainsId(relationType.getTableName(), relationType.getIdColumnName(), result);
+            } else {
+                tableContainsId("ties_data.\"" + result.getEntryType() + "\"", "id", result);
+            }
+        }
+    }
+
+    private void tableContainsId(String tableName, String idColumn, OperationResult result) {
+        Result<Record> dbResults = tiesDbService.selectAllRowsFromTable(tableName);
+        final boolean contains = dbResults.stream().map(row -> row.get(idColumn)).filter(Objects::nonNull).map(
+                Object::toString).anyMatch(result.getId()::equals);
+        assertTrue(contains);
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/service/TiesDbServiceContainerizedTest.java b/teiv/src/test/java/org/oran/smo/teiv/service/TiesDbServiceContainerizedTest.java
new file mode 100644
index 0000000..9431880
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/service/TiesDbServiceContainerizedTest.java
@@ -0,0 +1,599 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service;
+
+import static org.oran.smo.teiv.ingestion.DeadlockRetryPolicy.POSTGRES_DEADLOCK_ERROR_CODE;
+import static org.oran.smo.teiv.utils.TiesConstants.TIES_DATA_SCHEMA;
+import static org.jooq.impl.DSL.field;
+import static org.jooq.impl.DSL.table;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+import org.oran.smo.teiv.utils.ConvertToJooqTypeUtil;
+import org.jooq.DSLContext;
+import org.jooq.JSONB;
+import org.jooq.Record;
+import org.jooq.Result;
+import org.jooq.exception.DataAccessException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+
+import org.oran.smo.teiv.db.TestPostgresqlContainer;
+import org.oran.smo.teiv.exception.TiesException;
+import org.oran.smo.teiv.schema.SchemaRegistry;
+import org.oran.smo.teiv.utils.schema.Geography;
+
+@Configuration
+@SpringBootTest
+public class TiesDbServiceContainerizedTest {
+    public static TestPostgresqlContainer postgreSQLContainer = TestPostgresqlContainer.getInstance();
+
+    @Autowired
+    private TiesDbService tiesDbService;
+
+    @Autowired
+    private TiesDbOperations tiesDbOperations;
+
+    @Autowired
+    @Qualifier("writeDataDslContext")
+    private DSLContext dslContext;
+
+    @Value("${database.retry-policies.deadlock.retry-attempts}")
+    private int maxRetryAttemptsForDeadlock;
+
+    @DynamicPropertySource
+    static void setProperties(DynamicPropertyRegistry registry) {
+        registry.add("spring.datasource.read.jdbc-url", () -> postgreSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.read.username", () -> postgreSQLContainer.getUsername());
+        registry.add("spring.datasource.read.password", () -> postgreSQLContainer.getPassword());
+
+        registry.add("spring.datasource.write.jdbc-url", () -> postgreSQLContainer.getJdbcUrl());
+        registry.add("spring.datasource.write.username", () -> postgreSQLContainer.getUsername());
+        registry.add("spring.datasource.write.password", () -> postgreSQLContainer.getPassword());
+    }
+
+    @BeforeEach
+    public void deleteAll() {
+        dslContext.meta().filterSchemas(s -> s.getName().equals(TIES_DATA_SCHEMA)).getTables().forEach(t -> dslContext
+                .truncate(t).cascade().execute());
+    }
+
+    @Test
+    void testMergeManagedElement() {
+        Map<String, Object> map1 = new HashMap<>();
+        map1.put("id", "id1");
+        map1.put("fdn", "fdn1");
+        map1.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", map1);
+
+        Result<Record> rows = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        for (Entry<String, Object> e : map1.entrySet()) {
+            assertEquals(e.getValue(), rows.get(0).get(e.getKey()));
+        }
+
+        Map<String, Object> map2 = new HashMap<>();
+        map2.put("id", "id1");
+        map2.put("fdn", "fdn2");
+        map2.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann2\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", map2);
+
+        Result<Record> rows2 = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        for (Entry<String, Object> e : map2.entrySet()) {
+            assertEquals(e.getValue(), rows2.get(0).get(e.getKey()));
+        }
+    }
+
+    @Test
+    void testMergeSector() throws IOException {
+        Map<String, Object> map = new HashMap<>();
+        map.put("id", "id1");
+        map.put("sectorId", 7);
+        map.put("geo-location", new Geography("{\"latitude\": 47.497913,\"longitude\": 19.040236}"));
+        map.put("azimuth", 7.3);
+        tiesDbOperations.merge(dslContext, "ties_data.\"Sector\"", map);
+
+        Result<?> rows = dslContext.select(field("id"), field("\"sectorId\"").as("sectorId"), field(
+                "ST_AsText(\"geo-location\")"), field("azimuth")).from(table("ties_data.\"Sector\"")).fetch();
+
+        assertEquals("id1", rows.get(0).get("id"));
+        assertEquals(7L, rows.get(0).get("sectorId"));
+
+        assertEquals("POINT(47.497913 19.040236)", rows.get(0).get("ST_AsText(\"geo-location\")"));
+        assertEquals(0, new BigDecimal("7.3").compareTo((BigDecimal) rows.get(0).get("azimuth")));
+    }
+
+    @Test
+    void testDeleteFromManagedElement() {
+        Map<String, Object> map1 = new HashMap<>();
+        map1.put("id", "id1");
+        map1.put("fdn", "fdn1");
+        map1.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", map1);
+
+        Map<String, Object> map2 = new HashMap<>();
+        map2.put("id", "id2");
+        map2.put("fdn", "fdn2");
+        map2.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann2\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", map2);
+
+        Result<Record> row1 = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals(2, row1.size());
+
+        tiesDbOperations.deleteEntity(dslContext, SchemaRegistry.getEntityTypeByName("ManagedElement"), "id1");
+
+        Result<Record> row2 = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals(1, row2.size());
+    }
+
+    @Test
+    void testCascadeOnDelete() {
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        Map<String, Object> map1 = new HashMap<>();
+        map1.put("id", "id1");
+        map1.put("fdn", "fdn1");
+        map1.put("gNBCUName", "gNBCUName");
+        map1.put("gNBId", 1);
+        map1.put("gNBIdLength", 1);
+        map1.put("pLMNId", JSONB.jsonb("{\"name\":\"pLMNId1\"}"));
+        map1.put("cmId", JSONB.jsonb("{\"name\":\"cmId1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFunction\"", map1);
+
+        Map<String, Object> map2 = new HashMap<>();
+        map2.put("id", "id1");
+        map2.put("name", "CloudNativeApplication");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", map2);
+
+        Map<String, Object> map3 = new HashMap<>();
+        map3.put("id", "id1");
+        map3.put("aSide_GNBCUCPFunction", "id1");
+        map3.put("bSide_CloudNativeApplication", "id1");
+        tiesDbOperations.merge(dslContext, "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"", map3);
+
+        Result<Record> row1 = tiesDbService.selectAllRowsFromTable("ties_data.\"GNBCUCPFunction\"");
+        assertEquals(1, row1.size());
+        Result<Record> row2 = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeApplication\"");
+        assertEquals(1, row2.size());
+        Result<Record> row3 = tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"");
+        assertEquals(1, row3.size());
+
+        dbOperations.add(dslContext -> tiesDbOperations.deleteEntity(dslContext, SchemaRegistry.getEntityTypeByName(
+                "GNBCUCPFunction"), "id1"));
+
+        assertDoesNotThrow(() -> tiesDbService.execute(dbOperations));
+
+        Result<Record> row4 = tiesDbService.selectAllRowsFromTable("ties_data.\"GNBCUCPFunction\"");
+        assertEquals(0, row4.size());
+        Result<Record> row5 = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeApplication\"");
+        assertEquals(1, row5.size());
+        Result<Record> row6 = tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\"");
+        assertEquals(0, row6.size());
+
+    }
+
+    @Test
+    void testTriggerOnDelete() {
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        Map<String, Object> map1 = new HashMap<>();
+        map1.put("id", "id1");
+        map1.put("fdn", "fdn1");
+        map1.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", map1);
+
+        Map<String, Object> map2 = new HashMap<>();
+        map2.put("id", "id1");
+        map2.put("name", "CloudNativeSystem");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", map2);
+
+        Map<String, Object> map3 = new HashMap<>();
+        map3.put("id", "id1");
+        map3.put("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", "relId");
+        map3.put("REL_FK_deployed-as-cloudNativeSystem", "id1");
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", map3);
+
+        Result<Record> row2 = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals(1, row2.size());
+        Result<Record> row1 = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals(1, row1.size());
+
+        dbOperations.add(dslContext -> tiesDbOperations.deleteEntity(dslContext, SchemaRegistry.getEntityTypeByName(
+                "CloudNativeSystem"), "id1"));
+
+        assertDoesNotThrow(() -> tiesDbService.execute(dbOperations));
+
+        Result<Record> meRecords = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals("id1", meRecords.get(0).get("id"));
+        assertEquals("fdn1", meRecords.get(0).get("fdn"));
+        assertNull(meRecords.get(0).get("REL_FK_deployed-as-cloudNativeSystem"));
+        assertNull(meRecords.get(0).get("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+        Result<Record> cnsRecords = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals(0, cnsRecords.size());
+    }
+
+    @Test
+    void testMergeOneToManyRelationship() {
+        Map<String, Object> managedElementEntity1 = new HashMap<>();
+        managedElementEntity1.put("id", "managedelement_id1");
+        managedElementEntity1.put("fdn", "managedelement_fdn1");
+        managedElementEntity1.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElementEntity1);
+
+        Map<String, Object> cloudNativeAppEntity = new HashMap<>();
+        cloudNativeAppEntity.put("id", "cna-1");
+        cloudNativeAppEntity.put("name", "CloudNativeApp1");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cloudNativeAppEntity);
+
+        Map<String, Object> meToCnaRelationship = new HashMap<>();
+        meToCnaRelationship.put("id", "cna-1");
+        meToCnaRelationship.put("REL_FK_realised-managedElement", "managedelement_id1");
+        meToCnaRelationship.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "rel_id1");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", meToCnaRelationship);
+
+        Result<?> rowsBeforeMerge = dslContext.select(field("id"), field("name"), field(
+                "\"REL_FK_realised-managedElement\"").as("REL_FK_realised-managedElement"), field(
+                        "\"REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION\"").as(
+                                "REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION")).from(table(
+                                        "ties_data.\"CloudNativeApplication\"")).fetch();
+        assertEquals("cna-1", rowsBeforeMerge.get(0).get("id"));
+        assertEquals("CloudNativeApp1", rowsBeforeMerge.get(0).get("name"));
+        assertEquals("managedelement_id1", rowsBeforeMerge.get(0).get("REL_FK_realised-managedElement"));
+        assertEquals("rel_id1", rowsBeforeMerge.get(0).get("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION"));
+
+        Map<String, Object> cloudNativeAppEntity2 = new HashMap<>();
+        cloudNativeAppEntity2.put("id", "cna-2");
+        cloudNativeAppEntity2.put("name", "CloudNativeApp2");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", cloudNativeAppEntity2);
+
+        Map<String, Object> modifiedMeToCnaRelationship = new HashMap<>();
+        modifiedMeToCnaRelationship.put("id", "cna-2");
+        modifiedMeToCnaRelationship.put("REL_FK_realised-managedElement", "managedelement_id1");
+        modifiedMeToCnaRelationship.put("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "rel_id2");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeApplication\"", modifiedMeToCnaRelationship);
+
+        Result<?> rowsAfterMerge = dslContext.select(field("id"), field("name"), field("\"REL_FK_realised-managedElement\"")
+                .as("REL_FK_realised-managedElement"), field("\"REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION\"")
+                        .as("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION")).from(table(
+                                "ties_data.\"CloudNativeApplication\"")).fetch();
+
+        assertEquals("cna-1", rowsAfterMerge.get(0).get("id"));
+        assertEquals("CloudNativeApp1", rowsAfterMerge.get(0).get("name"));
+        assertEquals("managedelement_id1", rowsAfterMerge.get(1).get("REL_FK_realised-managedElement"));
+        assertEquals("rel_id1", rowsAfterMerge.get(0).get("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION"));
+        assertEquals("cna-2", rowsAfterMerge.get(1).get("id"));
+        assertEquals("CloudNativeApp2", rowsAfterMerge.get(1).get("name"));
+        assertEquals("managedelement_id1", rowsAfterMerge.get(1).get("REL_FK_realised-managedElement"));
+        assertEquals("rel_id2", rowsAfterMerge.get(1).get("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION"));
+    }
+
+    @Test
+    void testDeleteOneToManyRelationship() {
+        Map<String, Object> managedElementEntity = new HashMap<>();
+        managedElementEntity.put("id", "me-id1");
+        managedElementEntity.put("fdn", "fdn1");
+        managedElementEntity.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElementEntity);
+
+        Map<String, Object> enodeBFunctionEntity = new HashMap<>();
+        enodeBFunctionEntity.put("id", "enodeb-id1");
+        enodeBFunctionEntity.put("eNBId", 1L);
+        tiesDbOperations.merge(dslContext, "ties_data.\"ENodeBFunction\"", enodeBFunctionEntity);
+
+        Map<String, Object> meToEnodeBFuncRelation = new HashMap<>();
+        meToEnodeBFuncRelation.put("id", "enodeb-id1");
+        meToEnodeBFuncRelation.put("REL_FK_managed-by-managedElement", "me-id1");
+        meToEnodeBFuncRelation.put("REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION", "eiid1");
+        meToEnodeBFuncRelation.put("REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION", ConvertToJooqTypeUtil.toJsonb(
+                List.of("fdn1", "cmHandleId1")));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ENodeBFunction\"", meToEnodeBFuncRelation);
+
+        tiesDbOperations.deleteRelationFromEntityTableByRelationId(dslContext, "eiid1", SchemaRegistry
+                .getRelationTypeByName("MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"));
+
+        Result<Record> rows = tiesDbService.selectAllRowsFromTable("ties_data.\"ENodeBFunction\"");
+        assertEquals("enodeb-id1", rows.get(0).get("id"));
+        assertEquals(1L, rows.get(0).get("eNBId"));
+        //assertNull(rows.get(0).get("REL_FK_managed-by-managedElement"));
+        assertNull(rows.get(0).get("REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"));
+        assertEquals(ConvertToJooqTypeUtil.toJsonb(List.of()), rows.get(0).get(
+                "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"));
+    }
+
+    @Test
+    void testTransactionalMergeSucceeds() {
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        Map<String, Object> cloudNativeSystemEntity = new HashMap<>();
+        cloudNativeSystemEntity.put("id", "cloudnative_id1");
+        cloudNativeSystemEntity.put("name", "CloudNativeSystem");
+        dbOperations.add(wrDSLContext -> tiesDbOperations.merge(wrDSLContext, "ties_data.\"CloudNativeSystem\"",
+                cloudNativeSystemEntity));
+
+        Map<String, Object> managedElementEntity = new HashMap<>();
+        managedElementEntity.put("id", "managed_element_id1");
+        managedElementEntity.put("fdn", "fdn1");
+        managedElementEntity.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        dbOperations.add(wrDSLContext -> tiesDbOperations.merge(wrDSLContext, "ties_data.\"ManagedElement\"",
+                managedElementEntity));
+
+        Map<String, Object> meTocnsRelationship = new HashMap<>();
+        meTocnsRelationship.put("id", "managed_element_id1");
+        meTocnsRelationship.put("REL_FK_deployed-as-cloudNativeSystem", "cloudnative_id1");
+        meTocnsRelationship.put("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", "eiid1");
+        meTocnsRelationship.put("REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", ConvertToJooqTypeUtil
+                .toJsonb(List.of("fdn1", "cmHandleId1")));
+        dbOperations.add(wrDSLContext -> tiesDbOperations.merge(wrDSLContext, "ties_data.\"ManagedElement\"",
+                meTocnsRelationship));
+
+        assertDoesNotThrow(() -> tiesDbService.execute(dbOperations));
+
+        Result<Record> rowsFromManagedElementTable = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals(1, rowsFromManagedElementTable.size());
+        assertEquals("cloudnative_id1", rowsFromManagedElementTable.get(0).get("REL_FK_deployed-as-cloudNativeSystem"));
+        assertEquals("eiid1", rowsFromManagedElementTable.get(0).get(
+                "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+        assertEquals(ConvertToJooqTypeUtil.toJsonb(List.of("fdn1", "cmHandleId1")), rowsFromManagedElementTable.get(0).get(
+                "REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+
+        Result<Record> rowsFromCloudNativeSystem = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals(1, rowsFromCloudNativeSystem.size());
+    }
+
+    @Test
+    void testTransactionalMergeRollsBackAfterRelationshipError() {
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        Map<String, Object> managedElementEntity = new HashMap<>();
+        managedElementEntity.put("id", "managed_element_id1");
+        managedElementEntity.put("fdn", "fdn1");
+        managedElementEntity.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        dbOperations.add(wrDSLContext -> tiesDbOperations.merge(wrDSLContext, "ties_data.\"ManagedElement\"",
+                managedElementEntity));
+
+        Map<String, Object> cloudNativeSystemEntity = new HashMap<>();
+        cloudNativeSystemEntity.put("id", "cloudnative_id1");
+        cloudNativeSystemEntity.put("name", "CloudNativeSystem");
+
+        dbOperations.add(wrDSLContext -> tiesDbOperations.merge(wrDSLContext, "ties_data.\"CloudNativeSystem\"",
+                cloudNativeSystemEntity));
+
+        // Create a faulty relationship map to trigger the rollback
+        Map<String, Object> faultyCloudNativeSystemRelationship = new HashMap<>();
+        faultyCloudNativeSystemRelationship.put("id", "cloudnative_id1");
+        faultyCloudNativeSystemRelationship.put("REL_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM_BAAAD",
+                "managed_element_id1");
+        faultyCloudNativeSystemRelationship.put("REL_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM_EIID", "eiid1");
+        dbOperations.add(wrDSLContext -> tiesDbOperations.merge(wrDSLContext, "ties_data.\"CloudNativeSystem\"",
+                faultyCloudNativeSystemRelationship));
+
+        assertThrows(TiesException.class, () -> tiesDbService.execute(dbOperations));
+
+        Result<Record> rowsFromManagedElementTable = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals(0, rowsFromManagedElementTable.size());
+
+        Result<Record> rowsFromCloudNativeSystem = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals(0, rowsFromCloudNativeSystem.size());
+    }
+
+    @Test
+    void testTransactionalDeleteSucceeds() {
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        Map<String, Object> cloudNativeSystemEntity = new HashMap<>();
+        cloudNativeSystemEntity.put("id", "cloudnative_id1");
+        cloudNativeSystemEntity.put("name", "CloudNativeSystem");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity);
+
+        Map<String, Object> managedElementEntity = new HashMap<>();
+        managedElementEntity.put("id", "managed_element_id1");
+        managedElementEntity.put("fdn", "fdn1");
+        managedElementEntity.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElementEntity);
+
+        Map<String, Object> meToCnsRelationship = new HashMap<>();
+        meToCnsRelationship.put("id", "managed_element_id1");
+        meToCnsRelationship.put("REL_FK_deployed-as-cloudNativeSystem", "cloudnative_id1");
+        meToCnsRelationship.put("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", "eiid1");
+        meToCnsRelationship.put("REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", ConvertToJooqTypeUtil
+                .toJsonb(List.of("fdn1", "cmHandleId1")));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", meToCnsRelationship);
+
+        Result<Record> rowsFromCloudNativeSystemBeforeDelete = tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"CloudNativeSystem\"");
+        assertEquals(1, rowsFromCloudNativeSystemBeforeDelete.size());
+
+        Result<Record> rowsFromManagedElementBeforeDelete = tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"ManagedElement\"");
+        assertEquals(1, rowsFromManagedElementBeforeDelete.size());
+        assertEquals("cloudnative_id1", rowsFromManagedElementBeforeDelete.get(0).get(
+                "REL_FK_deployed-as-cloudNativeSystem"));
+        assertEquals("eiid1", rowsFromManagedElementBeforeDelete.get(0).get(
+                "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+        assertEquals(ConvertToJooqTypeUtil.toJsonb(List.of("fdn1", "cmHandleId1")), rowsFromManagedElementBeforeDelete.get(
+                0).get("REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+
+        dbOperations.add(wrDSLContext -> tiesDbOperations.deleteEntity(wrDSLContext, SchemaRegistry.getEntityTypeByName(
+                "ManagedElement"), "managed_element_id1"));
+
+        dbOperations.add(wrDSLContext -> {
+            tiesDbOperations.deleteEntity(wrDSLContext, SchemaRegistry.getEntityTypeByName("CloudNativeSystem"),
+                    "cloudnative_id1");
+        });
+
+        dbOperations.add(wrDSLContext -> tiesDbOperations.deleteRelationFromEntityTableByRelationId(wrDSLContext,
+                "managed_element_id1", SchemaRegistry.getRelationTypeByName(
+                        "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM")));
+
+        assertDoesNotThrow(() -> tiesDbService.execute(dbOperations));
+
+        Result<Record> rowsFromManagedElementTable = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals(0, rowsFromManagedElementTable.size());
+
+        Result<Record> rowsFromCloudNativeSystem = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals(0, rowsFromCloudNativeSystem.size());
+    }
+
+    @Test
+    void testTransactionalDeleteRollbackAfterRelationshipError() {
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        Map<String, Object> cloudNativeSystemEntity = new HashMap<>();
+        cloudNativeSystemEntity.put("id", "cloudnative_id1");
+        cloudNativeSystemEntity.put("name", "CloudNativeSystem");
+        tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity);
+
+        Map<String, Object> managedElementEntity = new HashMap<>();
+        managedElementEntity.put("id", "managed_element_id1");
+        managedElementEntity.put("fdn", "fdn1");
+        managedElementEntity.put("cmId", JSONB.jsonb("{\"name\":\"Hellmann1\"}"));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", managedElementEntity);
+
+        Map<String, Object> cloudNativeSystemRelationship = new HashMap<>();
+        cloudNativeSystemRelationship.put("id", "managed_element_id1");
+        cloudNativeSystemRelationship.put("REL_FK_deployed-as-cloudNativeSystem", "cloudnative_id1");
+        cloudNativeSystemRelationship.put("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", "eiid1");
+        cloudNativeSystemRelationship.put("REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM",
+                ConvertToJooqTypeUtil.toJsonb(List.of("fdn1", "cmHandleId1")));
+        tiesDbOperations.merge(dslContext, "ties_data.\"ManagedElement\"", cloudNativeSystemRelationship);
+
+        Result<Record> rowsFromCloudNativeSystemBeforeDelete = tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"CloudNativeSystem\"");
+        assertEquals(1, rowsFromCloudNativeSystemBeforeDelete.size());
+
+        Result<Record> rowsFromManagedElementBeforeDelete = tiesDbService.selectAllRowsFromTable(
+                "ties_data.\"ManagedElement\"");
+        assertEquals(1, rowsFromManagedElementBeforeDelete.size());
+        assertEquals("cloudnative_id1", rowsFromManagedElementBeforeDelete.get(0).get(
+                "REL_FK_deployed-as-cloudNativeSystem"));
+        assertEquals("eiid1", rowsFromManagedElementBeforeDelete.get(0).get(
+                "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+        assertEquals(ConvertToJooqTypeUtil.toJsonb(List.of("fdn1", "cmHandleId1")), rowsFromManagedElementBeforeDelete.get(
+                0).get("REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+
+        dbOperations.add(wrDSLContext -> tiesDbOperations.deleteEntity(wrDSLContext, SchemaRegistry.getEntityTypeByName(
+                "ManagedElement"), "managed_element_id1"));
+        dbOperations.add(wrDSLContext -> tiesDbOperations.deleteEntity(wrDSLContext, SchemaRegistry.getEntityTypeByName(
+                "CloudNativeSystem"), "cloudnative_id1"));
+
+        // Add a faulty relationship delete to trigger the rollback
+        dbOperations.add(wrDSLContext -> tiesDbOperations.deleteRelationFromEntityTableByRelationId(wrDSLContext, "eiid1",
+                SchemaRegistry.getRelationTypeByName("rel_managedelement_deployed_as_cloudnativesystem_eiid")));
+
+        assertThrows(TiesException.class, () -> tiesDbService.execute(dbOperations));
+
+        Result<Record> rowsFromCloudNativeSystem = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals(1, rowsFromCloudNativeSystem.size());
+        Result<Record> rowsFromManagedElementTable = tiesDbService.selectAllRowsFromTable("ties_data.\"ManagedElement\"");
+        assertEquals(1, rowsFromManagedElementTable.size());
+        assertEquals("cloudnative_id1", rowsFromManagedElementTable.get(0).get("REL_FK_deployed-as-cloudNativeSystem"));
+        assertEquals("eiid1", rowsFromManagedElementTable.get(0).get(
+                "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+        assertEquals(ConvertToJooqTypeUtil.toJsonb(List.of("fdn1", "cmHandleId1")), rowsFromManagedElementTable.get(0).get(
+                "REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"));
+    }
+
+    @Test
+    void testDeadlockRetry() throws InterruptedException {
+        List<Consumer<DSLContext>> dbOperations1 = new ArrayList<>();
+        List<Consumer<DSLContext>> dbOperations2 = new ArrayList<>();
+
+        Map<String, Object> cloudNativeSystemEntity1 = new HashMap<>();
+        cloudNativeSystemEntity1.put("id", "id1");
+        cloudNativeSystemEntity1.put("name", "CloudNativeSystem");
+
+        Map<String, Object> cloudNativeSystemEntity2 = new HashMap<>();
+        cloudNativeSystemEntity2.put("id", "id2");
+        cloudNativeSystemEntity2.put("name", "CloudNativeSystem");
+
+        Map<String, Object> cloudNativeSystemEntity3 = new HashMap<>();
+        cloudNativeSystemEntity3.put("id", "id3");
+        cloudNativeSystemEntity3.put("name", "CloudNativeSystem");
+
+        Map<String, Object> cloudNativeSystemEntity4 = new HashMap<>();
+        cloudNativeSystemEntity4.put("id", "id4");
+        cloudNativeSystemEntity4.put("name", "CloudNativeSystem");
+
+        final CountDownLatch firstTransactionCompletedMergeEntity1 = new CountDownLatch(1);
+        final CountDownLatch secondTransactionCompletedMergeEntity2 = new CountDownLatch(1);
+        dbOperations1.add(dslContext -> {
+            tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity1);
+            firstTransactionCompletedMergeEntity1.countDown();
+            try {
+                secondTransactionCompletedMergeEntity2.await();
+                tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity2);
+                tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity3);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        });
+        //Try to add the same rows in another transaction in another order.
+        dbOperations2.add(dslContext -> {
+            try {
+                tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity2);
+                secondTransactionCompletedMergeEntity2.countDown();
+                firstTransactionCompletedMergeEntity1.await();
+                tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity1);
+                tiesDbOperations.merge(dslContext, "ties_data.\"CloudNativeSystem\"", cloudNativeSystemEntity4);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        });
+
+        Thread t1 = new Thread(() -> tiesDbService.execute(dbOperations1));
+        Thread t2 = new Thread(() -> tiesDbService.execute(dbOperations2));
+        t1.start();
+        t2.start();
+        t1.join();
+        t2.join();
+        Result<Record> rowsFromCloudNativeSystem = tiesDbService.selectAllRowsFromTable("ties_data.\"CloudNativeSystem\"");
+        assertEquals(4, rowsFromCloudNativeSystem.size());
+    }
+
+    @Test
+    void testDeadlockRetryMaxAttemptsReached() {
+        final AtomicInteger attempts = new AtomicInteger();
+        List<Consumer<DSLContext>> dbOperations = new ArrayList<>();
+        dbOperations.add(dslContext -> {
+            attempts.getAndIncrement();
+            throw new DataAccessException("A deadlock occurred in the db", new SQLException("details",
+                    POSTGRES_DEADLOCK_ERROR_CODE));
+        });
+        assertThrows(TiesException.class, () -> tiesDbService.execute(dbOperations));
+        assertEquals(maxRetryAttemptsForDeadlock, attempts.get());
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/service/cloudevent/CloudEventParserTest.java b/teiv/src/test/java/org/oran/smo/teiv/service/cloudevent/CloudEventParserTest.java
new file mode 100644
index 0000000..9623be0
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/service/cloudevent/CloudEventParserTest.java
@@ -0,0 +1,191 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.service.cloudevent;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.teiv.startup.SchemaHandler;
+import io.cloudevents.CloudEvent;
+import org.junit.jupiter.api.Assertions;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import org.oran.smo.teiv.service.cloudevent.data.Entity;
+import org.oran.smo.teiv.service.cloudevent.data.ParsedCloudEventData;
+import org.oran.smo.teiv.service.cloudevent.data.Relationship;
+import org.oran.smo.teiv.utils.CloudEventTestUtil;
+
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.annotation.DirtiesContext;
+
+@SpringBootTest
+class CloudEventParserTest {
+
+    @Autowired
+    private CloudEventParser cloudEventParser;
+
+    @MockBean
+    private SchemaHandler schemaHandler;
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testParseCloudEventData() {
+        final CloudEvent cloudEvent = cloudEventFromJson("src/test/resources/cloudeventdata/common/ce-with-data.json");
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+
+        validateEntity(parsedCloudEventData.getEntities().get(0), "o-ran-smo-teiv-ran", "NRCellDU", "entityId_1", 6, Map.of(
+                "cellLocalId", 4589L, "nRPCI", 12L, "nRTAC", 310L, "primitiveArray", "[1, 2, 3]", "singleList", "12",
+                "jsonObjectArray", "[{\"test2\":\"49\",\"test1\":\"128\"}, {\"test2\":\"50\",\"test1\":\"129\"}]"));
+
+        validateEntity(parsedCloudEventData.getEntities().get(1), "o-ran-smo-teiv-ran", "NRCellDU", "entityId_3", 6, Map.of(
+                "cellLocalId", 45891L, "nRPCI", 121L, "nRTAC", 3101L, "primitiveArray", "[1, 2, 3]", "singleList", "121",
+                "jsonObjectArray", "[{\"test2\":\"491\",\"test1\":\"1281\"}, {\"test2\":\"501\",\"test1\":\"1291\"}]"));
+
+        validateEntity(parsedCloudEventData.getEntities().get(2), "o-ran-smo-teiv-ran", "NRSectorCarrier", "entityId_2", 4,
+                Map.of("arfcnDL", 4590L, "testDouble", 32.5, "testBoolean", true, "cmId",
+                        "{\"option1\":\"test_option1\",\"option2\":\"test_option2\"}"));
+
+        final List<Relationship> relationships = parsedCloudEventData.getRelationships();
+        Assertions.assertEquals(4, relationships.size());
+
+        Relationship relationship = parsedCloudEventData.getRelationships().get(0);
+        assertEquals("o-ran-smo-teiv-ran", relationship.getModule());
+        assertEquals("NRCELLDU_USES_NRSECTORCARRIER", relationship.getType());
+        assertEquals("entityId_1", relationship.getASide());
+        assertEquals("entityId_2", relationship.getBSide());
+
+        relationship = parsedCloudEventData.getRelationships().get(1);
+        assertEquals("o-ran-smo-teiv-ran", relationship.getModule());
+        assertEquals("NRCELLDU_USES_NRSECTORCARRIER", relationship.getType());
+        assertEquals("entityId_3", relationship.getASide());
+        assertEquals("entityId_4", relationship.getBSide());
+
+        relationship = parsedCloudEventData.getRelationships().get(2);
+        assertEquals("o-ran-smo-teiv-ran", relationship.getModule());
+        assertEquals("GNBDUFunctionRealisedByCloudNativeApplication", relationship.getType());
+        assertEquals("entityId_5", relationship.getASide());
+        assertEquals("entityId_6", relationship.getBSide());
+
+        relationship = parsedCloudEventData.getRelationships().get(3);
+        assertEquals("o-ran-smo-teiv-ran", relationship.getModule());
+        assertEquals("GNBDUFunctionRealisedByCloudNativeApplication", relationship.getType());
+        assertEquals("entityId_5", relationship.getASide());
+        assertEquals("entityId_7", relationship.getBSide());
+    }
+
+    @Test
+    void testEmptyCloudEventData() {
+        final CloudEvent cloudEvent = CloudEventTestUtil.getCloudEvent("create", "{}");
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        Assertions.assertTrue(parsedCloudEventData.getEntities().isEmpty());
+        Assertions.assertTrue(parsedCloudEventData.getRelationships().isEmpty());
+    }
+
+    @Test
+    void testNoRelationshipInCloudEvent() {
+        final CloudEvent cloudEvent = cloudEventFromJson("src/test/resources/cloudeventdata/common/ce-one-entity.json");
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        validateEntity(parsedCloudEventData.getEntities().get(0), "o-ran-smo-teiv-ran", "NRCellDU", "entityId_1", 3, Map.of(
+                "cellLocalId", 4589L, "nRPCI", 12L, "nRTAC", 310L));
+        Assertions.assertTrue(parsedCloudEventData.getRelationships().isEmpty());
+    }
+
+    @Test
+    void testCloudEventDataIsNotAValidJson() {
+        final CloudEvent cloudEvent = CloudEventTestUtil.getCloudEvent("create", "{invalidjson");
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        Assertions.assertNull(parsedCloudEventData);
+    }
+
+    @Test
+    void testEntitiesAndRelationshipsAreArrays() {
+        final CloudEvent cloudEvent = CloudEventTestUtil.getCloudEvent("create", "{\"entities\":[],\"relationships\":[]}");
+        final ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+        assertEquals(new ParsedCloudEventData(List.of(), List.of()), parsedCloudEventData);
+    }
+
+    @Test
+    void testInvalidYangDataInEvent() {
+        final CloudEvent arrayEntitiesCloudEvent = CloudEventTestUtil.getCloudEvent("create",
+                "{\"entities\":[{\"some_entity_field\": 54321}]}");
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(arrayEntitiesCloudEvent);
+        Assertions.assertNull(parsedCloudEventData);
+
+        final CloudEvent objectEntitiesCloudEvent = CloudEventTestUtil.getCloudEvent("create",
+                "{\"entities\":{\"some_entity_field\": 54321}}");
+        parsedCloudEventData = cloudEventParser.getCloudEventData(objectEntitiesCloudEvent);
+        Assertions.assertNull(parsedCloudEventData);
+
+        final CloudEvent arrayRelationshipsCloudEvent = CloudEventTestUtil.getCloudEvent("create",
+                "{\"relationships\":[{\"some_relationship_field\": 54321}]}");
+        parsedCloudEventData = cloudEventParser.getCloudEventData(arrayRelationshipsCloudEvent);
+        Assertions.assertNull(parsedCloudEventData);
+
+        final CloudEvent objectRelationshipsCloudEvent = CloudEventTestUtil.getCloudEvent("create",
+                "{\"relationships\":{\"some_relationship_field\": 54321}}");
+        parsedCloudEventData = cloudEventParser.getCloudEventData(objectRelationshipsCloudEvent);
+        Assertions.assertNull(parsedCloudEventData);
+    }
+
+    @Test
+    @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD)
+    void testRelationshipsIsNotAValidYangData() {
+        CloudEvent cloudEvent = CloudEventTestUtil.getCloudEvent("create", "{\"relationships\":{\"a_field\": 123}}");
+        ParsedCloudEventData parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+
+        Assertions.assertNull(parsedCloudEventData);
+
+        cloudEvent = CloudEventTestUtil.getCloudEvent("merge", "{\"relationships\":{\"a_field\": 123}}");
+        parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+
+        Assertions.assertNull(parsedCloudEventData);
+
+        cloudEvent = CloudEventTestUtil.getCloudEvent("delete", "{\"relationships\":{\"a_field\": 123}}");
+        parsedCloudEventData = cloudEventParser.getCloudEventData(cloudEvent);
+
+        Assertions.assertNull(parsedCloudEventData);
+    }
+
+    private void validateEntity(final Entity entity, String expectedModuleReference, String expectedEntityName,
+            String expectedId, int expectedAttributeCount, Map<String, Object> expectedAttributes) {
+        assertEquals(expectedModuleReference, entity.getModule());
+        assertEquals(expectedEntityName, entity.getType());
+        assertEquals(expectedId, entity.getId());
+        final Map<String, Object> attributes = entity.getAttributes();
+        assertEquals(expectedAttributeCount, attributes.size());
+        for (Map.Entry<String, Object> entry : expectedAttributes.entrySet()) {
+            assertTrue(attributes.containsKey(entry.getKey()));
+            assertEquals(entry.getValue(), attributes.get(entry.getKey()));
+        }
+    }
+
+    private CloudEvent cloudEventFromJson(String path) {
+        return assertDoesNotThrow(() -> CloudEventTestUtil.getCloudEventFromJsonFile(path),
+                "Reading CloudEvent from JSON resulted in error.");
+
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/CloudEventTestUtil.java b/teiv/src/test/java/org/oran/smo/teiv/utils/CloudEventTestUtil.java
new file mode 100644
index 0000000..f9723b4
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/CloudEventTestUtil.java
@@ -0,0 +1,79 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.OffsetDateTime;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.cloudevents.CloudEvent;
+import io.cloudevents.SpecVersion;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+public class CloudEventTestUtil {
+
+    private CloudEventTestUtil() {
+    }
+
+    public static CloudEvent getCloudEvent(final String type, final String data) {
+        return CloudEventBuilder.v1().withId("1.0").withSource(URI.create("http://localhost:8080/local-source"))
+                .withDataContentType("application/yang-data+json").withDataSchema(URI.create(
+                        "http://localhost:8080/schema/v1/hello-world")).withExtension("correlationid",
+                                "test-correlation-id").withType("ran-logical-topology." + type).withData("application/json",
+                                        URI.create("http://localhost/schema"), data.getBytes()).build();
+    }
+
+    public static CloudEvent getCloudEventFromJsonFile(final String path) {
+        String jsonString = readJsonFileAsString(path);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            JsonNode rootNode = objectMapper.readTree(jsonString);
+
+            CloudEventBuilder cloudEventBuilder = CloudEventBuilder.fromSpecVersion(SpecVersion.parse(rootNode.get(
+                    "specversion").asText()));
+            cloudEventBuilder.withId(rootNode.get("id").asText());
+            cloudEventBuilder.withSource(URI.create(rootNode.get("source").asText()));
+            cloudEventBuilder.withType(rootNode.get("type").asText());
+            cloudEventBuilder.withTime(OffsetDateTime.parse(rootNode.get("time").asText()));
+            cloudEventBuilder.withDataContentType(rootNode.get("datacontenttype").asText());
+            cloudEventBuilder.withDataSchema(URI.create(rootNode.get("dataschema").asText()));
+            cloudEventBuilder.withData(rootNode.get("data").toString().getBytes());
+            CloudEvent event = cloudEventBuilder.build();
+            return event;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static String readJsonFileAsString(String path) {
+        try {
+            return Files.readString(Paths.get(path));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/ConvertToJooqTypeUtilTest.java b/teiv/src/test/java/org/oran/smo/teiv/utils/ConvertToJooqTypeUtilTest.java
new file mode 100644
index 0000000..d4d28fd
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/ConvertToJooqTypeUtilTest.java
@@ -0,0 +1,58 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.jooq.JSONB;
+import org.junit.Test;
+
+import org.oran.smo.teiv.exception.InvalidFieldInYangDataException;
+import org.oran.smo.teiv.utils.schema.Geography;
+
+import static org.oran.smo.teiv.utils.ConvertToJooqTypeUtil.*;
+
+public class ConvertToJooqTypeUtilTest {
+
+    @Test
+    public void testToJsonb() {
+        assertEquals(JSONB.jsonb("{}"), toJsonb("{}"));
+        assertEquals(JSONB.jsonb("{\"key\":\"value\"}"), toJsonb("{\"key\":\"value\"}"));
+        assertEquals(JSONB.jsonb("[]"), toJsonb("[]"));
+        assertEquals(JSONB.jsonb("[1]"), toJsonb("[1]"));
+        assertEquals(JSONB.jsonb("[1,2,3]"), toJsonb("[1,2,3]"));
+        assertEquals(JSONB.jsonb("[\"value1\",\"value2\"]"), toJsonb("[\"value1\",\"value2\"]"));
+        assertEquals(JSONB.jsonb("[\"leading\",\"whitespaces\"]"), toJsonb("     [\"leading\",\"whitespaces\"]"));
+        assertEquals(JSONB.jsonb("[\"a_string\"]"), toJsonb("a_string"));
+        assertEquals(JSONB.jsonb("[\"23\"]"), toJsonb("23"));
+        assertEquals(JSONB.jsonb("[54]"), toJsonb(54L));
+        assertEquals(JSONB.jsonb("[92.13]"), toJsonb(92.13));
+    }
+
+    @Test
+    public void testToGeography() throws InvalidFieldInYangDataException {
+        assertEquals(new Geography(47.497913, 19.040236), toGeography(
+                "{\"latitude\": 47.497913,\"longitude\": 19.040236}"));
+        assertThrows(InvalidFieldInYangDataException.class, () -> toGeography("{invalidjson"));
+        assertThrows(InvalidFieldInYangDataException.class, () -> toGeography(9));
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/EndToEndExpectedResults.java b/teiv/src/test/java/org/oran/smo/teiv/utils/EndToEndExpectedResults.java
new file mode 100644
index 0000000..f8c1665
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/EndToEndExpectedResults.java
@@ -0,0 +1,65 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import org.jooq.JSONB;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class EndToEndExpectedResults {
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+    private final JsonNode rootNode;
+
+    public EndToEndExpectedResults(final String jsonPath) throws IOException {
+        rootNode = OBJECT_MAPPER.readTree(Files.readString(Paths.get(jsonPath)));
+    }
+
+    public Map<String, Object> get(final String entryId) {
+        Map<String, Object> expectedValuesMap = new HashMap<>();
+        JsonNode attributesNode = rootNode.required(entryId);
+        attributesNode.fields().forEachRemaining(entry -> {
+            String key = entry.getKey();
+            JsonNode valueNode = entry.getValue();
+            if (valueNode.isContainerNode()) {
+                expectedValuesMap.put(key, JSONB.jsonb(valueNode.toString()));
+            } else if (valueNode.isTextual()) {
+                expectedValuesMap.put(key, valueNode.asText());
+            } else if (valueNode.isDouble()) {
+                expectedValuesMap.put(key, valueNode.asDouble());
+            } else if (valueNode.isNumber()) {
+                expectedValuesMap.put(key, valueNode.asLong());
+            } else if (valueNode.isBoolean()) {
+                expectedValuesMap.put(key, valueNode.asBoolean());
+            }
+        });
+        return expectedValuesMap;
+    }
+
+    public Map<String, Object> getAll() {
+        return EndToEndTestUtil.processNode(rootNode);
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/EndToEndTestUtil.java b/teiv/src/test/java/org/oran/smo/teiv/utils/EndToEndTestUtil.java
new file mode 100644
index 0000000..c1b6203
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/EndToEndTestUtil.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.test.EmbeddedKafkaBroker;
+import org.springframework.kafka.test.utils.KafkaTestUtils;
+import org.springframework.web.client.RestTemplate;
+
+import org.oran.smo.teiv.config.KafkaConfig;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.kafka.CloudEventSerializer;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class EndToEndTestUtil {
+    public static void sendEventList(final List<CloudEvent> events, EmbeddedKafkaBroker embeddedKafkaBroker,
+            KafkaConfig kafkaConfig) {
+        Map<String, Object> configs = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker));
+        Producer<String, CloudEvent> producer = new DefaultKafkaProducerFactory<>(configs, new StringSerializer(),
+                new CloudEventSerializer()).createProducer();
+        for (CloudEvent event : events) {
+            ProducerRecord<String, CloudEvent> producerRecord = new ProducerRecord<String, CloudEvent>(kafkaConfig
+                    .getTopologyIngestion().getTopicName(), null, event);
+            producer.send(producerRecord);
+        }
+    }
+
+    public static String getResponseFromApi(final String uri) {
+        RestTemplate restTemplate = new RestTemplate();
+        return restTemplate.getForObject(uri, String.class);
+    }
+
+    public static String processApiCall(final String uri) {
+        log.info("(processApiCall) Sending request for: {}", uri);
+        String responseBody = getResponseFromApi(uri);
+        log.info("(processApiCall) Response: {}", responseBody);
+        return responseBody;
+    }
+
+    public static Map<String, Object> processNode(JsonNode node) {
+        ObjectMapper mapper = new ObjectMapper();
+        return mapper.convertValue(node, new TypeReference<>() {
+        });
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/ResponseGenerator.java b/teiv/src/test/java/org/oran/smo/teiv/utils/ResponseGenerator.java
new file mode 100644
index 0000000..7bdfc87
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/ResponseGenerator.java
@@ -0,0 +1,92 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ResponseGenerator {
+
+    /**
+     * Generates a response
+     *
+     * @param entityType
+     * @param id
+     * @return response
+     */
+    public static Map<String, Object> generateResponse(String entityType, String id) {
+        Map<String, Object> response = new HashMap<>();
+        Map<String, Object> responseData = new HashMap<>();
+        Map<String, Object> attributesMap = new HashMap<>();
+        switch (entityType) {
+            case "GNBDUFunction" -> {
+                response.put("o-ran-smo-teiv-ran:GNBDUFunction", List.of(responseData));
+                responseData.put("id", "GNBDUFunction:" + id);
+                attributesMap.put("gNBDUId", null);
+                attributesMap.put("fdn", "GNBDUFunction/" + id);
+                attributesMap.put("dUpLMNId", Map.of("mcc", 456, "mnc", 82));
+                attributesMap.put("gNBId", id);
+                attributesMap.put("gNBIdLength", 2);
+            }
+            case "NRCellDU" -> {
+                response.put("o-ran-smo-teiv-ran:NRCellDU", List.of(responseData));
+                responseData.put("id", "NRCellDU:" + id);
+                attributesMap.put("fdn", "NRCellDU/" + id);
+                attributesMap.put("nCI", id);
+                attributesMap.put("id", "NRCellDU:" + id);
+                attributesMap.put("nRTAC", 456);
+                attributesMap.put("nRPCI", 789);
+            }
+        }
+        responseData.put("attributes", attributesMap);
+        return response;
+    }
+
+    /**
+     * Generates response for relationships
+     *
+     * @param aSide
+     *     url for aSide
+     * @param bSide
+     *     url for bSide
+     * @param id
+     *     of relationship
+     * @return response
+     */
+    public static Map<String, Object> generateResponse(String aSide, String bSide, String id, List sourceIds) {
+        final Map<String, Object> dataMap = new HashMap<>();
+        dataMap.put("id", id);
+        dataMap.put("aSide", aSide);
+        dataMap.put("bSide", bSide);
+        dataMap.put("sourceIds", sourceIds);
+        return dataMap;
+    }
+
+    public static Map<String, Object> generateResponse(String aSide, String bSide, String id) {
+        final Map<String, Object> dataMap = new HashMap<>();
+        dataMap.put("id", id);
+        dataMap.put("aSide", aSide);
+        dataMap.put("bSide", bSide);
+        return dataMap;
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/YangParserTest.java b/teiv/src/test/java/org/oran/smo/teiv/utils/YangParserTest.java
new file mode 100644
index 0000000..7c4aa5b
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/YangParserTest.java
@@ -0,0 +1,68 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils;
+
+import java.util.List;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.teiv.api.model.OranTeivSchema;
+
+@ExtendWith(MockitoExtension.class)
+class YangParserTest {
+
+    @InjectMocks
+    YangParser yangParser;
+
+    @Test
+    void testExtractYangData() {
+        //when
+        String deviceModelIdentity = yangParser.extractYangData().getDeviceModelIdentity();
+        List<YangModel> validYangModelInputsList = yangParser.extractYangData().getModuleRegistry().getAllYangModels();
+        //then
+        Assertions.assertEquals("r1", deviceModelIdentity);
+        //        Assertions.assertEquals(10, validYangModelInputsList.size());
+    }
+
+    @Test
+    void testReturnAllTiesSchemas() {
+        //when
+        List<OranTeivSchema> OranTeivSchemasMetaDataList = YangParser.returnAllTiesSchemas(yangParser.extractYangData());
+        //then
+        Assertions.assertEquals(10, OranTeivSchemasMetaDataList.size());
+    }
+
+    @Test
+    void testReturnSchemaByName() {
+        //when
+        String responseForIncorrectSchema = YangParser.returnSchemaByName(yangParser.extractYangData(),
+                "o-ran-smo-teiv-ran-oam");
+        String responseForCorrectSchema = YangParser.returnSchemaByName(yangParser.extractYangData(), "o-ran-smo-teiv-oam");
+        //then
+        Assertions.assertEquals("", responseForIncorrectSchema);
+        Assertions.assertTrue(responseForCorrectSchema.contains("o-ran-smo-teiv-oam"));
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/exposure/PaginationVerifierTestUtil.java b/teiv/src/test/java/org/oran/smo/teiv/utils/exposure/PaginationVerifierTestUtil.java
new file mode 100644
index 0000000..d8d8f55
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/exposure/PaginationVerifierTestUtil.java
@@ -0,0 +1,58 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.exposure;
+
+import org.oran.smo.teiv.exposure.spi.mapper.PageMetaData;
+
+import org.junit.jupiter.api.Assertions;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Arrays;
+import java.util.Map;
+
+public class PaginationVerifierTestUtil {
+
+    public static void verifyResponse(Map<String, Object> expected, Map<String, Object> actual) {
+        String[] paginationKeys = { "next", "prev", "first", "last", "self" };
+        for (String key : expected.keySet()) {
+            if (Arrays.stream(paginationKeys).anyMatch(paginationKey -> paginationKey.equals(key))) {
+                Assertions.assertEquals(((PageMetaData) expected.get(key)).getHref(), ((PageMetaData) actual.get(key))
+                        .getHref());
+            } else {
+                Assertions.assertEquals(expected.get(key), actual.get(key));
+            }
+        }
+    }
+
+    public static void verifyResponse(ResponseEntity<Object> expected, ResponseEntity<Object> actual) {
+        Map<String, Object> expectedBody = (Map<String, Object>) expected.getBody();
+        Map<String, Object> actualBody = (Map<String, Object>) actual.getBody();
+        String[] paginationKeys = { "next", "prev", "first", "last", "self" };
+        for (String key : expectedBody.keySet()) {
+            if (Arrays.stream(paginationKeys).anyMatch(paginationKey -> paginationKey.equals(key))) {
+                Assertions.assertEquals(((PageMetaData) expectedBody.get(key)).getHref(), ((PageMetaData) actualBody.get(
+                        key)).getHref());
+            } else {
+                Assertions.assertEquals(expectedBody.get(key), actualBody.get(key));
+            }
+        }
+    }
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/query/QueryMonadTest.java b/teiv/src/test/java/org/oran/smo/teiv/utils/query/QueryMonadTest.java
new file mode 100644
index 0000000..ccb870e
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/query/QueryMonadTest.java
@@ -0,0 +1,1616 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.query;
+
+import org.oran.smo.teiv.exposure.utils.PaginationDTO;
+import org.oran.smo.teiv.schema.SchemaLoaderException;
+import org.oran.smo.teiv.schema.MockSchemaLoader;
+import org.oran.smo.teiv.utils.query.exception.TiesPathException;
+
+import org.jooq.Condition;
+import org.jooq.DSLContext;
+import org.jooq.Field;
+import org.jooq.Query;
+import org.jooq.Select;
+import org.jooq.impl.DSL;
+import org.jooq.tools.jdbc.MockConnection;
+import org.jooq.tools.jdbc.MockResult;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.List;
+
+import static org.oran.smo.teiv.schema.SchemaRegistry.*;
+import static org.oran.smo.teiv.utils.TiesConstants.*;
+import static org.oran.smo.teiv.utils.query.QueryMonadTestUtil.*;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+import static org.jooq.impl.DSL.condition;
+import static org.jooq.impl.DSL.field;
+
+class QueryMonadTest {
+    private static DSLContext context;
+
+    @BeforeAll
+    public static void setUp() throws SchemaLoaderException {
+        MockSchemaLoader mockSchemaLoader = new MockSchemaLoader();
+        mockSchemaLoader.loadSchemaRegistry();
+        context = DSL.using(new MockConnection(m -> new MockResult[1]));
+    }
+
+    @Test
+    void test1i_noAttributesNorFieldsGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String attributes = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, attributes, relationships);
+
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test2i_attributesGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributes";
+        String attributes = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, attributes, relationships);
+        Select<?> builtWithQM = (Select<?>) underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(
+                context);
+        Select<?> reference = (Select<?>) createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")), field(String.format(TIES_DATA,
+                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")).as(String.format(TIES_DATA,
+                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")), field(String.format(
+                                                TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING,
+                                                        "dUpLMNId")).as(String.format(TIES_DATA,
+                                                                "GNBDUFunction") + "." + String.format(QUOTED_STRING,
+                                                                        "dUpLMNId")), field(String.format(TIES_DATA,
+                                                                                "GNBDUFunction") + "." + String.format(
+                                                                                        QUOTED_STRING, "gNBDUId")).as(String
+                                                                                                .format(TIES_DATA,
+                                                                                                        "GNBDUFunction") + "." + String
+                                                                                                                .format(QUOTED_STRING,
+                                                                                                                        "gNBDUId")),
+                field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "gNBDUId")).as(String
+                        .format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "gNBDUId")), field(String
+                                .format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "gNBIdLength")).as(
+                                        String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING,
+                                                "gNBIdLength")), field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "cmId")).as(
+                                                                String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                                                        .format(QUOTED_STRING, "cmId"))).from(String.format(
+                                                                                TIES_DATA, "GNBDUFunction")));
+
+        List<Field<?>> fieldsActual = builtWithQM.getSelect();
+        List<Field<?>> fieldsExpected = reference.getSelect();
+        Assertions.assertTrue(fieldsActual.containsAll(fieldsExpected));
+    }
+
+    @Test
+    void test2ii_attributesTypoException() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attribute/fdn; /attributes/id; /attributes/gNBId";
+        String filter = "/attributes[contains(@fdn, \"93\")]  |  /attributes[@gNBId=4000259]";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test2iii_attributesMissingSlashException() {
+        String entityType = "GNBDUFunction";
+        String fields = "attributes/fdn; /attributes/id; /attributes/gNBId";
+        String filter = "/attributes[contains(@fdn, \"93\")]  |  /attributes[@gNBId=4000259]";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test3i_attributesFdnGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributes(fdn)";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")), field(String.format(TIES_DATA,
+                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, ID_COLUMN_NAME)).as(String.format(
+                                        TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, ID_COLUMN_NAME)))
+                .from(String.format(TIES_DATA, "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test3ii_attributesFdnGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributes/fdn";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")), field(String.format(TIES_DATA,
+                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, ID_COLUMN_NAME)).as(String.format(
+                                        TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, ID_COLUMN_NAME)))
+                .from(String.format(TIES_DATA, "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test3iii_attributesFdnMissingSlashException() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributefdn";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    //should be empty response
+    @Test
+    void test3iv_attributesFdnTypoColumm() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributes/fnd";
+        String attributes = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, attributes, relationships);
+        Select<?> builtWithQM = (Select<?>) underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(
+                context);
+        Select<?> reference = (Select<?>) createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + ".id").as(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING,
+                        "id")), field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn"))
+                                .as(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")),
+                field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "dUpLMNId")).as(String
+                        .format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "dUpLMNId")), field(String
+                                .format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "gNBDUId")).as(
+                                        String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING,
+                                                "gNBDUId")), field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                                        .format(QUOTED_STRING, "gNBId")).as(String.format(TIES_DATA,
+                                                                "GNBDUFunction") + "." + String.format(QUOTED_STRING,
+                                                                        "gNBId")), field(String.format(TIES_DATA,
+                                                                                "GNBDUFunction") + "." + String.format(
+                                                                                        QUOTED_STRING, "gNBIdLength")).as(
+                                                                                                String.format(TIES_DATA,
+                                                                                                        "GNBDUFunction") + "." + String
+                                                                                                                .format(QUOTED_STRING,
+                                                                                                                        "gNBIdLength")),
+                field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "cmId")).as(String
+                        .format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "cmId"))).from(String
+                                .format(TIES_DATA, "GNBDUFunction")));
+
+        List<Field<?>> fieldsActual = builtWithQM.getSelect();
+        List<Field<?>> fieldsExpected = reference.getSelect();
+        Assertions.assertTrue(fieldsActual.containsAll(fieldsExpected));
+    }
+
+    @Test
+    void test3v_attributesFdnMissingOpeningBracketException() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributefdn)";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test3vi_attributesFdnMissingClosingBracketException() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attribute(fdn";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test4i_attributesFdnIdGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributes(fdn)";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")), field(String.format(TIES_DATA,
+                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(
+                                                TIES_DATA, "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test4ii_attributesFdnIdGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attributes/fdn";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "fdn")), field(String.format(TIES_DATA,
+                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(
+                                                TIES_DATA, "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test4iii_attributesFdnIdMissingCommaException() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attribute(fdn id)";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test4iv_attributesFdnIdMissingSemiColonException() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attribute/fdn /attribute/id";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test4v_attributesFdnIdMissingSecondSlashException() {
+        String entityType = "GNBDUFunction";
+        String fields = "/attribute/fdn; attribute/id";
+        String filter = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test5i_attributesContainsGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String attributes = "/attributes[contains (@fdn, \"/SubNetwork=Ireland/\")]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, fields, attributes, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).where(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                        .format(QUOTED_STRING, "fdn")).contains("/SubNetwork=Ireland/")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "/attributescontains (@fdn, \"/SubNetwork=Ireland/\")]",
+            "/attributes[contains (@fdn, \"/SubNetwork=Ireland/\")",
+            "/attributes[contains (fdn, \"/SubNetwork=Ireland/\")]",
+            "/attributes[contans (@fdn, \"/SubNetwork=Ireland/\")]",
+            "/attributes[contains @fdn, \"/SubNetwork=Ireland/\")]",
+            "/attributes[contains (@fdn, \"/SubNetwork=Ireland/\"]",
+            "/attributes[contains (@fdn \"/SubNetwork=Ireland/\")]", "/attributes[contains (@fdn, /SubNetwork=Ireland/\")]",
+            "/attributes[contains (@fdn, \"/SubNetwork=Ireland/)]" })
+    void test5ii_ix_attributesException(String scope) {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test5x_attributesColumnTypoEmptyList() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attributes[contains (@fnd, \"/SubNetwork=Ireland/\")]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+    }
+
+    @Test
+    void test5xi_attributesContainsWrongValueEmptyList() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attributes[contains (@fdn, \"/SubNetwork Ireland/\")]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).where(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                        .format(QUOTED_STRING, "fdn")).contains("/SubNetwork Ireland/")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test6i_attributesEqualsGood() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attributes[@gNBIdLength=3]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).where(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                        .format(QUOTED_STRING, "gNBIdLength")).eq(3)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test6iii_attributesMissingEquationSignException() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attributes[@gNBIdLength 3]";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test7i_attributesEqualsGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String attributes = "/attributes[@gNBIdLength=3 and @gNBId=111]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, fields, attributes, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).where((field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                        .format(QUOTED_STRING, "gNBIdLength")).eq(3)).and(field(String.format(TIES_DATA,
+                                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "gNBId")).eq(111))));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test7iii_attributesMissingAndException() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String filter = "/attributes[@gNBIdLength=3  @gNBId=-1]";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test7iv_attributesTypoAndException() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String filter = "/attributes[@gNBIdLength=3 adn @gNBId=111]";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test8i_attributesEqualBarEqualGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String attributes = "/attributes[@gNBIdLength=3 and @gNBId=111] | /attributes[@gNBIdLength=3 and @gNBId=112]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, fields, attributes, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).where(((field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                        .format(QUOTED_STRING, "gNBIdLength")).eq(3)).and(field(String.format(TIES_DATA,
+                                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "gNBId")).eq(111)))
+                                                        .or((field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                                                                .format(QUOTED_STRING, "gNBIdLength")).eq(3)).and(field(
+                                                                        String.format(TIES_DATA,
+                                                                                "GNBDUFunction") + "." + String.format(
+                                                                                        QUOTED_STRING, "gNBId")).eq(
+                                                                                                112)))));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test8ii_attributesEqualBarEqualMissingBarException() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String filter = "/attributes[@gNBIdLength=3 and @gNBId=111]  /attributes[@gNBIdLength=3 and @gNBId=112]";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test9i_attributesContainEqualGood() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String attributes = "/attributes[contains (@fdn, \"SubNetwork=Ireland\")] ; /attributes[@gNBIdLength=3]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, fields, attributes, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test9ii_attributesMissingSemiColonException() {
+        String entityType = "GNBDUFunction";
+        String fields = "";
+        String filter = "/attributes[contains (@fdn, \"SubNetwork=Ireland\")]  /attributes[@gNBIdLength=3]";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, fields, filter, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test10i_targetGood() {
+        String entityType = "GNBDUFunction";
+        String target = "/NRCellDU";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field("null").cast(getEntityTypeByName("NRCellDU")
+                .getField("id", null, null).getType()).as(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                        QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String.format(
+                                TIES_DATA, "NRCellDU")).on(condition(field(String.format(TIES_DATA,
+                                        "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter).union(context.select(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                        QUOTED_STRING, "id")).as(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String.format(TIES_DATA,
+                                        "NRCellDU")).on(condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String
+                                                .format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(String
+                                                        .format(TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                QUOTED_STRING, "id"))))).where(joinFilter)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test10ii_targetTypoGood() {
+        String entityType = "GNBDUFunction";
+        String target = "/NRCelldu";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test11i_targetHopsGood() {
+        String entityType = "GNBDUFunction";
+        String target = "/NRCellDU ; /NRSectorCarrier";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull()).and(field(String.format(TIES_DATA, "NRSectorCarrier") + "." + String.format(
+                        QUOTED_STRING, "id")).isNotNull());
+        // spotless:off
+        Query reference = createDistinctQuery(context, context.select(field("null").cast(getEntityTypeByName("NRCellDU").getField("id",null,null).getType()).as(String.format(
+                TIES_DATA,
+                "NRCellDU") + "." + String.format(QUOTED_STRING, "id")), field("null").cast(getEntityTypeByName("NRSectorCarrier").getField("id",null,null).getType()).as(String.format(
+                TIES_DATA,
+                "NRSectorCarrier") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                "GNBDUFunction")).
+                leftJoin(String.format(TIES_DATA, "NRCellDU")).on(condition(field(String
+                .format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+            .leftJoin(String.format(TIES_DATA, "NRSectorCarrier")).on(condition(field(String.format(TIES_DATA,
+                "NRSectorCarrier") + "." + String.format(QUOTED_STRING,
+                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))))).where(joinFilter)
+            .union(context.select(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                    "id")).as(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING, "id")), field(
+                    "null").cast(getEntityTypeByName("NRSectorCarrier").getField("id",null,null).getType()).as(String.format(TIES_DATA, "NRSectorCarrier") + "." + String.format(QUOTED_STRING,
+                    "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).
+                    leftJoin(String.format(TIES_DATA, "NRCellDU")).on(condition(field(String.format(TIES_DATA,
+                    "NRCellDU") + "." + String.format(QUOTED_STRING,
+                    "REL_FK_provided-by-gnbduFunction")).eq(field(String
+                    .format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))))).
+                    leftJoin(String.format(TIES_DATA, "NRSectorCarrier")).on(condition(field(String.format(TIES_DATA,
+                    "NRSectorCarrier") + "." + String.format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(
+                    String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter)).union(context.select(field("null").cast(getEntityTypeByName("NRCellDU").getField("id",null,null).getType()).as(String.format(
+                    TIES_DATA,
+                    "NRCellDU") + "." + String.format(QUOTED_STRING, "id")), field(String.format(TIES_DATA,
+                    "NRSectorCarrier") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA, "NRSectorCarrier") + "." + String.format(QUOTED_STRING, "id")))
+                .from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String.format(TIES_DATA,
+                    "NRCellDU")).on(condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String
+                    .format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction")
+                    + "." + String.format(QUOTED_STRING, "id"))))).leftJoin(String.format(TIES_DATA,
+                    "NRSectorCarrier")).on(condition(field(String.format(TIES_DATA,
+                    "NRSectorCarrier") + "." + String.format(QUOTED_STRING,
+                    "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." +
+                    String.format(QUOTED_STRING, "id"))))).where(joinFilter)));
+        // spotless:on
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test11ii_targetHopTypo() {
+        String entityType = "GNBDUFunction";
+        String target = "/NRCellDU ; /NRSectorCarier";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field("null").cast(getEntityTypeByName("NRCellDU")
+                .getField("id", null, null).getType()).as(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                        QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String.format(
+                                TIES_DATA, "NRCellDU")).on(condition(field(String.format(TIES_DATA,
+                                        "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter).union(context.select(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                        QUOTED_STRING, "id")).as(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String.format(TIES_DATA,
+                                        "NRCellDU")).on(condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String
+                                                .format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(String
+                                                        .format(TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                QUOTED_STRING, "id"))))).where(joinFilter)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test12i_TargetGoodWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRCellDU";
+        String target = "";
+        String relationships = "GNBDUFUNCTION_PROVIDES_NRCELLDU";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+
+        Condition relationFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "REL_FK_provided-by-gnbduFunction")).isNotNull()).and(field(String.format(TIES_DATA,
+                        "NRCellDU") + "." + String.format(QUOTED_STRING, "id")).isNotNull()).and(field(String.format(
+                                TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(field(String.format(
+                                        TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))))
+                .where(relationFilter).and(joinFilter).union(context.select(field("null").cast(getEntityTypeByName(
+                        "GNBDUFunction").getField("id", null, null).getType()).as(String.format(TIES_DATA,
+                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                        "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(field(String
+                                                .format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                        "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(
+                                                                TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                        QUOTED_STRING, "id")))).where(relationFilter).and(
+                                                                                joinFilter)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test12ii_relationshipWrongException() {
+        String entityType = "GNBDUFunction";
+        String target = "/NRCellDU";
+        String scope = "";
+        String relationships = "USES";
+
+        QueryMonad underTest = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Invalid relationship name");
+    }
+
+    @Test
+    void test13i_RelationshipsGoodWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRCellDU | /CloudNativeApplication";
+        String target = "";
+        String relationships = "GNBDUFUNCTION_PROVIDES_NRCELLDU, GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull()).and(field(String.format(TIES_DATA, "CloudNativeApplication") + "." + String.format(
+                        QUOTED_STRING, "id")).isNotNull());
+
+        Condition relationFilter1 = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).isNotNull()).and(field(String.format(TIES_DATA,
+                        "NRCellDU") + "." + String.format(QUOTED_STRING, "id")).isNotNull()).and(field(String.format(
+                                TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU")).isNotNull());
+
+        Condition relationFilter2 = condition(field(String.format(TIES_DATA,
+                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(QUOTED_STRING,
+                        "aSide_GNBDUFunction")).isNotNull()).and(field(String.format(TIES_DATA,
+                                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(QUOTED_STRING,
+                                        "bSide_CloudNativeApplication")).isNotNull()).and(field(String.format(TIES_DATA,
+                                                "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(
+                                                        QUOTED_STRING, "id")).isNotNull());
+
+        // spotless:off
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction"))
+                .eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))).
+                join(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION"))
+            .on(field(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String
+                .format(QUOTED_STRING, "aSide_GNBDUFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." +
+                String.format(QUOTED_STRING, "id")))).leftJoin(String.format(TIES_DATA, "CloudNativeApplication"))
+            .on(field(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(
+                QUOTED_STRING, "bSide_CloudNativeApplication")).eq(field(String.format(TIES_DATA, "CloudNativeApplication") + "." + String.format(QUOTED_STRING, "id"))))
+
+            .where(relationFilter1).and(relationFilter2).and(joinFilter).union(context.select(field("null").cast(getEntityTypeByName("GNBDUFunction").getField("id",null,null).getType()).as(String
+                    .format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).
+                    leftJoin(String.format(TIES_DATA, "NRCellDU")).on(field(String.format(TIES_DATA,
+                    "NRCellDU") + "." + String.format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))))
+                .join(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION"))
+                .on(field(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." +
+                    String.format(QUOTED_STRING, "aSide_GNBDUFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                    .format(QUOTED_STRING, "id")))).leftJoin(String.format(TIES_DATA,
+                    "CloudNativeApplication"))
+                .on(field(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String
+                    .format(QUOTED_STRING, "bSide_CloudNativeApplication")).eq(field(String.format(TIES_DATA,
+                    "CloudNativeApplication") + "." + String
+                    .format(QUOTED_STRING, "id"))))
+
+                .where(relationFilter1).and(relationFilter2).and(joinFilter)).union(context.select(field("null").cast(getEntityTypeByName("GNBDUFunction").getField("id",null,null).getType()).as(String.format(
+                    TIES_DATA, "GNBDUFunction") +
+                    "." + String.format(QUOTED_STRING, "id")))
+                .from(String.format(TIES_DATA, "GNBDUFunction"))
+                .leftJoin(String.format(TIES_DATA, "NRCellDU")).
+                    on(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction"))
+                    .eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))))
+                .join(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION"))
+                .on(field(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String.format(QUOTED_STRING, "aSide_GNBDUFunction"))
+                    .eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))))
+                .leftJoin(String.format(TIES_DATA, "CloudNativeApplication")).on(field(String.format(TIES_DATA, "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION") + "." + String
+                    .format(QUOTED_STRING, "bSide_CloudNativeApplication"))
+                    .eq(field(String.format(TIES_DATA, "CloudNativeApplication") + "." + String.format(QUOTED_STRING, "id"))))
+                .where(relationFilter1).and(relationFilter2).and(joinFilter)));
+        // spotless:on
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test13ii_RelationshipsOnlyOneGoodWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRCellDU | /CloudNativeApplication";
+        String target = "";
+        String relationships = "GNBDUFUNCTION_PROVIDES_NRCELLDU";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+        Condition relationFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "REL_FK_provided-by-gnbduFunction")).isNotNull()).and(field(String.format(TIES_DATA,
+                        "NRCellDU") + "." + String.format(QUOTED_STRING, "id")).isNotNull()).and(field(String.format(
+                                TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(field(String.format(
+                                        TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))))
+                .where(relationFilter).and(joinFilter).union(context.select(field("null").cast(getEntityTypeByName(
+                        "GNBDUFunction").getField("id", null, null).getType()).as(String.format(TIES_DATA,
+                                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                        "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(field(String
+                                                .format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                        "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(
+                                                                TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                        QUOTED_STRING, "id")))).where(relationFilter).and(
+                                                                                joinFilter)).union(context.select(field(
+                                                                                        "null").cast(getEntityTypeByName(
+                                                                                                "GNBDUFunction").getField(
+                                                                                                        "id", null, null)
+                                                                                                        .getType()).as(
+                                                                                                                String.format(
+                                                                                                                        TIES_DATA,
+                                                                                                                        "GNBDUFunction") + "." + String
+                                                                                                                                .format(QUOTED_STRING,
+                                                                                                                                        "id")))
+                                                                                        .from(String.format(TIES_DATA,
+                                                                                                "GNBDUFunction")).leftJoin(
+                                                                                                        String.format(
+                                                                                                                TIES_DATA,
+                                                                                                                "NRCellDU"))
+                                                                                        .on(field(String.format(TIES_DATA,
+                                                                                                "NRCellDU") + "." + String
+                                                                                                        .format(QUOTED_STRING,
+                                                                                                                "REL_FK_provided-by-gnbduFunction"))
+                                                                                                                        .eq(field(
+                                                                                                                                String.format(
+                                                                                                                                        TIES_DATA,
+                                                                                                                                        "GNBDUFunction") + "." + String
+                                                                                                                                                .format(QUOTED_STRING,
+                                                                                                                                                        "id"))))
+                                                                                        .where(relationFilter).and(
+                                                                                                joinFilter)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test13iii_RelationshipsInvalidWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRCellDU | /CloudNativeApplication";
+        String target = "";
+        String relationships = "GNBDUFUNCTION_PROVIDES_NRCELLDU_2";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Invalid relationship name");
+    }
+
+    @Test
+    void test13iv_RelationshipsInvalidWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRCellDU | /CloudNativeApplication";
+        String target = "";
+        String relationships = "GNBDUFUNCTION_PROVIDES_NRCELLDU GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Invalid relationship name");
+    }
+
+    @Test
+    void test14i_ScopeGoodWithHop() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRCellDU";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(condition(field(String
+                                        .format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter).union(context.select(field("null").cast(getEntityTypeByName("GNBDUFunction").getField(
+                        "id", null, null).getType()).as(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String
+                                        .format(TIES_DATA, "NRCellDU")).on(condition(field(String.format(TIES_DATA,
+                                                "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                        "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(
+                                                                TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                        QUOTED_STRING, "id"))))).where(joinFilter)));
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test14ii_ScopeInvalidWithHop() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRCellDU_2";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test14iii_ScopeInvalidWithHop() {
+        String entityType = "GNBDUFunction";
+        String scope = "/AntennaCapability";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test15i_FilterOrGoodWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/NRSectorCarrier | /NRCellDU";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRSectorCarrier") + "." + String.format(
+                QUOTED_STRING, "id")).isNotNull()).and(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                        QUOTED_STRING, "id")).isNotNull());
+        // spotless:off
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))
+            .from(String.format(TIES_DATA, "GNBDUFunction"))
+            .leftJoin(String.format(TIES_DATA, "NRSectorCarrier"))
+            .on(condition(field(String.format(TIES_DATA, "NRSectorCarrier") + "." + String.format(QUOTED_STRING,
+                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." +
+                String.format(QUOTED_STRING, "id")))))
+            .leftJoin(String.format(TIES_DATA, "NRCellDU"))
+            .on(condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+            .where(joinFilter)
+            .union(context.select(field("null").cast(getEntityTypeByName("GNBDUFunction").getField("id",null,null).getType()).as(String.format(
+                    TIES_DATA, "GNBDUFunction") + "." +
+                    String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction"))
+                .leftJoin(String.format(TIES_DATA, "NRSectorCarrier"))
+                .on(condition(field(String.format(TIES_DATA, "NRSectorCarrier") + "." + String.format(
+                    QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .leftJoin(String.format(TIES_DATA, "NRCellDU"))
+                .on(condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                    "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") +
+                    "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter))
+            .union(context.select(field("null").cast(getEntityTypeByName("GNBDUFunction").getField("id",null,null).getType()).as(String.format(
+                    TIES_DATA, "GNBDUFunction") + "." +
+                    String.format(QUOTED_STRING, "id")))
+                .from(String.format(TIES_DATA, "GNBDUFunction"))
+                .leftJoin(String.format(TIES_DATA, "NRSectorCarrier"))
+                .on(condition(field(String.format(TIES_DATA, "NRSectorCarrier") + "." +
+                    String.format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(
+                    String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .leftJoin(String.format(TIES_DATA, "NRCellDU"))
+                .on(condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                    "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA, "GNBDUFunction") + "." + String
+                    .format(QUOTED_STRING, "id")))))
+                .where(joinFilter)));
+        // spotless:on
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test15ii_ScopeOrOneGoodWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/AntennaCapability | /NRCellDU";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(condition(field(String
+                                        .format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter).union(context.select(field("null").cast(getEntityTypeByName("GNBDUFunction").getField(
+                        "id", null, null).getType()).as(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String
+                                        .format(TIES_DATA, "NRCellDU")).on(condition(field(String.format(TIES_DATA,
+                                                "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                        "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(
+                                                                TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                        QUOTED_STRING, "id"))))).where(joinFilter)));
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test15iii_ScopeTypoWithHops() {
+        String entityType = "GNBDUFunction";
+        String scope = "/AntennaCapability2 | /NRCellDU";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")).leftJoin(String.format(TIES_DATA, "NRCellDU")).on(condition(field(String
+                                        .format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter).union(context.select(field("null").cast(getEntityTypeByName("GNBDUFunction").getField(
+                        "id", null, null).getType()).as(String.format(TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String
+                                        .format(TIES_DATA, "NRCellDU")).on(condition(field(String.format(TIES_DATA,
+                                                "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                        "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(
+                                                                TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                        QUOTED_STRING, "id"))))).where(joinFilter)));
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "//attributes", "///attributes" })
+    void test16i_targetSlashes(String target) {
+        String entityType = "GNBDUFunction";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "//attributes", "///attributes" })
+    void test16i_scopeSlashes(String scope) {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "/attributes[@gNBIdLength>3]", "/attributes[@gNBIdLength<3]" })
+    void test17i_scopeConditions(String scope) {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test18i_scopeOr() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attribute[@gNBIdLength=3 or @gNBIdLength=4]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test19i_targetWrongColumn() {
+        String entityType = "GNBDUFunction";
+        String target = "/attribute(gnbidLength)";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+    }
+
+    @Test
+    void test19i_scopeWrongColumn() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attribute[@gnbiLength=3]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+    }
+
+    @Test
+    void test20i_wrongTargetEntity() {
+        String entityType = "GNBDUFunction";
+        String target = "/AntennaCapability";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Objects are not related");
+    }
+
+    @Test
+    void test21_manyToOneTest() {
+        String entityType = "NRSectorCarrier";
+        String target = "/AntennaCapability";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "AntennaCapability") + "." + String.format(
+                QUOTED_STRING, "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field("null").cast(getEntityTypeByName("NRCellDU")
+                .getField("id", null, null).getType()).as(String.format(TIES_DATA, "AntennaCapability") + "." + String
+                        .format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "NRSectorCarrier")).leftJoin(String
+                                .format(TIES_DATA, "AntennaCapability")).on(condition(field(String.format(TIES_DATA,
+                                        "NRSectorCarrier") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_used-antennaCapability")).eq(field(String.format(TIES_DATA,
+                                                        "AntennaCapability") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter).union(context.select(field(String.format(TIES_DATA, "AntennaCapability") + "." + String
+                        .format(QUOTED_STRING, "id")).as(String.format(TIES_DATA, "AntennaCapability") + "." + String
+                                .format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "NRSectorCarrier")).leftJoin(
+                                        String.format(TIES_DATA, "AntennaCapability")).on(condition(field(String.format(
+                                                TIES_DATA, "NRSectorCarrier") + "." + String.format(QUOTED_STRING,
+                                                        "REL_FK_used-antennaCapability")).eq(field(String.format(TIES_DATA,
+                                                                "AntennaCapability") + "." + String.format(QUOTED_STRING,
+                                                                        "id"))))).where(joinFilter)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test22i_processTargetAttributeError() {
+        String entityType = "GNBDUFunction";
+        String target = "/id/fdn";
+        String scope = "/attributes[@gNBId=3000696]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test22ii_processTargetAttributeError() {
+        String entityType = "GNBDUFunction";
+        String target = "/fdn";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test22iii_processTargetAttributeError() {
+        String entityType = "GNBDUFunction";
+        String target = "/dummyText/fdn";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test23i_processTargetAttribute() {
+        String entityType = "GNBDUFunction";
+        String target = "/id";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad underTest = getQueryMonad(entityType, target, scope, relationships);
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "GNBDUFunction")));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test23ii_processTargetAttribute() {
+        String entityType = "GNBDUFunction";
+        String target = "/NRCellDU/id";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+        Query builtWithQM = qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field("null").cast(getEntityTypeByName("NRCellDU")
+                .getField("id", null, null).getType()).as(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                        QUOTED_STRING, "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String.format(
+                                TIES_DATA, "NRCellDU")).on(condition(field(String.format(TIES_DATA,
+                                        "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                                "REL_FK_provided-by-gnbduFunction")).eq(field(String.format(TIES_DATA,
+                                                        "GNBDUFunction") + "." + String.format(QUOTED_STRING, "id")))))
+                .where(joinFilter).union(context.select(field(String.format(TIES_DATA, "NRCellDU") + "." + String.format(
+                        QUOTED_STRING, "id")).as(String.format(TIES_DATA, "NRCellDU") + "." + String.format(QUOTED_STRING,
+                                "id"))).from(String.format(TIES_DATA, "GNBDUFunction")).leftJoin(String.format(TIES_DATA,
+                                        "NRCellDU")).on(condition(field(String.format(TIES_DATA, "NRCellDU") + "." + String
+                                                .format(QUOTED_STRING, "REL_FK_provided-by-gnbduFunction")).eq(field(String
+                                                        .format(TIES_DATA, "GNBDUFunction") + "." + String.format(
+                                                                QUOTED_STRING, "id"))))).where(joinFilter)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test24i_addTargetAttributeError() {
+        String entityType = "GNBDUFunction";
+        String target = "/id(fdn)";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test24ii_addTargetAttributeError() {
+        String entityType = "GNBDUFunction";
+        String target = "/attributes(id)";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+    }
+
+    @Test
+    void test24iii_addTargetAttributeError() {
+        String entityType = "GNBDUFunction";
+        String target = "/attributes(notExistingColumn)";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+    }
+
+    @Test
+    void test24iiii_addTargetAttributeError() {
+        String entityType = "GNBDUFunction";
+        String target = "/attr(fdn)";
+        String scope = "";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test25_checkIdAttributesError() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attr[@fdn=\"Solar\"]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test26i_checkIdExpressionsError() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attributes[@id=\"123\"]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test26ii_checkIdExpressionsError() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/id[@gNBId=12]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test26iii_checkIdExpressionsError() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/id[contains (@fdn,\"12\")]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test26iiii_checkIdExpressionsError() {
+        String entityType = "GNBDUFunction";
+        String target = "";
+        String scope = "/attributes[contains (@id,\"987\")]";
+        String relationships = "";
+
+        QueryMonad qm = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test27i_getTopologyByTargetFilterError() {
+        String entityType = null;
+        String target = "/CloudSite/attributes/";
+        String scope = "";
+        String relationships = "";
+        String domain = "RAN_LOGICAL";
+
+        QueryMonad qm = getQueryMonadWithDomain(entityType, target, scope, relationships, domain);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test27ii_getTopologyByTargetFilterError() {
+        String entityType = null;
+        String target = "/attributes";
+        String scope = "";
+        String relationships = "SECTOR_GROUPS_ANTENNAMODULE";
+        String domain = "RAN";
+
+        QueryMonad qm = getQueryMonadWithDomain(entityType, target, scope, relationships, domain);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Objects are not related");
+    }
+
+    @Test
+    void test27iii_getTopologyByTargetFilterError() {
+        String entityType = null;
+        String target = "/NRCellDU";
+        String scope = "";
+        String relationships = "SECTOR_GROUPS_ANTENNAMODULE";
+        String domain = "RAN";
+
+        QueryMonad qm = getQueryMonadWithDomain(entityType, target, scope, relationships, domain);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Objects are not related");
+    }
+
+    @Test
+    void test27iiii_getTopologyByTargetFilterError() {
+        String entityType = null;
+        String target = "/attributes/name";
+        String scope = "";
+        String relationships = "";
+        String domain = "RAN";
+
+        QueryMonad qm = getQueryMonadWithDomain(entityType, target, scope, relationships, domain);
+
+        assertThatThrownBy(() -> qm.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar error");
+    }
+
+    @Test
+    void test27iiiii_getTopologyByTargetFilterError() {
+        String entityType = "CloudNativeApplication";
+        String target1 = "/attributes/id";
+        String target2 = "/attributes(id)";
+        String scope = "";
+        String relationships = "";
+        String domain = "RAN_LOGICAL";
+
+        QueryMonad qm1 = getQueryMonadWithDomain(entityType, target1, scope, relationships, domain);
+        QueryMonad qm2 = getQueryMonadWithDomain(entityType, target2, scope, relationships, domain);
+
+        assertThatThrownBy(() -> qm1.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+
+        assertThatThrownBy(() -> qm2.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Grammar Error");
+    }
+
+    @Test
+    void test28i_getTopologyByTargetFilter() {
+        String entityType = null;
+        String target = "/Sector/id";
+        String scope = "";
+        String relationships = "";
+        String domain = "EQUIPMENT_TO_RAN";
+
+        QueryMonad underTest = getQueryMonadWithDomain(entityType, target, scope, relationships, domain);
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Query reference = createDistinctQuery(context, context.select(field("null").cast(getEntityTypeByName("Sector")
+                .getField("id", null, null).getType()).as(String.format(TIES_DATA, "Sector") + "." + String.format(
+                        QUOTED_STRING, "id"))).from("(SELECT '') as dual_table").leftJoin(String.format(TIES_DATA,
+                                "Sector")).on(condition(field(String.format(TIES_DATA, "Sector") + "." + "id").eq(field(
+                                        "(SELECT '')")))).where(field(String.format(TIES_DATA, "Sector") + "." + String
+                                                .format(QUOTED_STRING, "id")).isNotNull()).union(context.select(field(String
+                                                        .format(TIES_DATA, "Sector") + "." + String.format(QUOTED_STRING,
+                                                                "id")).as(String.format(TIES_DATA, "Sector") + "." + String
+                                                                        .format(QUOTED_STRING, "id"))).from(
+                                                                                "(SELECT '') as dual_table").rightJoin(
+                                                                                        String.format(TIES_DATA, "Sector"))
+                                                        .on(condition(field(String.format(TIES_DATA, "Sector") + "." + "id")
+                                                                .eq(field("(SELECT '')")))).where(field(String.format(
+                                                                        TIES_DATA, "Sector") + "." + String.format(
+                                                                                QUOTED_STRING, "id")).isNotNull()))
+
+        );
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test50_relConnectingSameEntityTest() {
+        String entityType = "AntennaModule";
+        String target = "/AntennaModule";
+        String scope = "";
+        String relationships = "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE";
+
+        QueryMonad underTest = getQueryMonad(entityType, target, scope, relationships);
+
+        Query builtWithQM = underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context);
+
+        Condition joinFilter = condition(field(String.format(TIES_DATA, "AntennaModule") + "." + String.format(
+                QUOTED_STRING, "id")).isNotNull());
+
+        Condition relationFilter = condition(field(String.format(TIES_DATA,
+                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE") + "." + String.format(QUOTED_STRING, "aSide_AntennaModule"))
+                        .isNotNull()).and(field(String.format(TIES_DATA,
+                                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE") + "." + String.format(QUOTED_STRING,
+                                        "bSide_AntennaModule")).isNotNull()).and(field(String.format(TIES_DATA,
+                                                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE") + "." + String.format(
+                                                        QUOTED_STRING, "id")).isNotNull());
+
+        Query reference = createDistinctQuery(context, context.select(field(String.format(TIES_DATA,
+                "AntennaModule") + "." + String.format(QUOTED_STRING, "id")).as(String.format(TIES_DATA,
+                        "AntennaModule") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                "AntennaModule")).join(String.format(TIES_DATA, "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE"))
+                .on(field(String.format(TIES_DATA, "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE") + "." + String.format(
+                        QUOTED_STRING, "bSide_AntennaModule")).eq(field(String.format(TIES_DATA,
+                                "AntennaModule") + "." + String.format(QUOTED_STRING, "id")))).or(field(String.format(
+                                        TIES_DATA, "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE") + "." + String.format(
+                                                QUOTED_STRING, "aSide_AntennaModule")).eq(field(String.format(TIES_DATA,
+                                                        "AntennaModule") + "." + String.format(QUOTED_STRING, "id"))))
+                .where(relationFilter).and(joinFilter).union(context.select(field("null").cast(getEntityTypeByName(
+                        "AntennaModule").getField("id", null, null).getType()).as(String.format(TIES_DATA,
+                                "AntennaModule") + "." + String.format(QUOTED_STRING, "id"))).from(String.format(TIES_DATA,
+                                        "AntennaModule")).join(String.format(TIES_DATA,
+                                                "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE")).on(field(String.format(
+                                                        TIES_DATA, "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE") + "." + String
+                                                                .format(QUOTED_STRING, "bSide_AntennaModule")).eq(field(
+                                                                        String.format(TIES_DATA,
+                                                                                "AntennaModule") + "." + String.format(
+                                                                                        QUOTED_STRING, "id")))).or(field(
+                                                                                                String.format(TIES_DATA,
+                                                                                                        "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE") + "." + String
+                                                                                                                .format(QUOTED_STRING,
+                                                                                                                        "aSide_AntennaModule"))
+                                                                                                                                .eq(field(
+                                                                                                                                        String.format(
+                                                                                                                                                TIES_DATA,
+                                                                                                                                                "AntennaModule") + "." + String
+                                                                                                                                                        .format(QUOTED_STRING,
+                                                                                                                                                                "id"))))
+                        .where(relationFilter).and(joinFilter)));
+
+        Assertions.assertEquals(reference, builtWithQM);
+    }
+
+    @Test
+    void test50_relConnectingSameEntityTest_unrelatedEntities() {
+        String entityType = "AntennaModule";
+        String target = "/AntennaModule";
+        String scope = "";
+        String relationships = "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION";
+
+        QueryMonad underTest = getQueryMonad(entityType, target, scope, relationships);
+
+        assertThatThrownBy(() -> underTest.withSchema(PaginationDTO.builder().offset(0).limit(5).build()).apply(context))
+                .isInstanceOf(TiesPathException.class).hasMessage("Objects are not related");
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/query/QueryMonadTestUtil.java b/teiv/src/test/java/org/oran/smo/teiv/utils/query/QueryMonadTestUtil.java
new file mode 100644
index 0000000..a8c02ec
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/query/QueryMonadTestUtil.java
@@ -0,0 +1,46 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.query;
+
+import org.jooq.DSLContext;
+import org.jooq.Query;
+import org.jooq.Select;
+
+import static org.jooq.impl.DSL.asterisk;
+import static org.jooq.impl.DSL.one;
+
+public class QueryMonadTestUtil {
+    public static QueryMonad getQueryMonad(String entityType, String fields, String attributes, String relationships) {
+        return QueryMonad.builder().managedObject(entityType).targets(fields).scope(attributes).relationships(relationships)
+                .build();
+    }
+
+    public static Query createDistinctQuery(DSLContext context, Select query) {
+        return context.selectDistinct(asterisk()).from(query.asTable("TiesPathQuery")).orderBy(one().asc()).limit(0, 5);
+    }
+
+    public static QueryMonad getQueryMonadWithDomain(String entityType, String fields, String attributes,
+            String relationships, String domain) {
+        return QueryMonad.builder().managedObject(entityType).targets(fields).scope(attributes).relationships(relationships)
+                .domain(domain).build();
+    }
+
+}
diff --git a/teiv/src/test/java/org/oran/smo/teiv/utils/schema/GeographyTest.java b/teiv/src/test/java/org/oran/smo/teiv/utils/schema/GeographyTest.java
new file mode 100644
index 0000000..ff29bc5
--- /dev/null
+++ b/teiv/src/test/java/org/oran/smo/teiv/utils/schema/GeographyTest.java
@@ -0,0 +1,42 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.teiv.utils.schema;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.Test;
+
+public class GeographyTest {
+
+    @Test
+    public void testCreateFromJson() throws IOException {
+        assertEquals("POINT(47.497913 19.040236)", new Geography("{\"latitude\": 47.497913,\"longitude\": 19.040236}")
+                .toString());
+        assertThrows(IOException.class, () -> new Geography("{\"latitude\": 47.497913}"));
+        assertEquals("POINT(47.497913 19.040236)", new Geography(
+                "{\"location\":{\"ellipsoid\":{\"latitude\": 47.497913,\"longitude\":19.040236}}}").toString());
+        assertEquals("POINT(47.497913 19.040236)", new Geography(
+                "{\"location\":{\"latitude\": 47.497913,\"longitude\":19.040236}}").toString());
+    }
+}
diff --git a/teiv/src/test/resources/META-INF/MANIFEST.MF b/teiv/src/test/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..254272e
--- /dev/null
+++ b/teiv/src/test/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+
diff --git a/teiv/src/test/resources/application.yaml b/teiv/src/test/resources/application.yaml
new file mode 100644
index 0000000..ad17d91
--- /dev/null
+++ b/teiv/src/test/resources/application.yaml
@@ -0,0 +1,100 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+spring.profiles.active: test
+
+#Metrics related configurations
+management:
+  endpoint:
+    metrics:
+      enabled: "true"
+    prometheus:
+      enabled: "true"
+    health:
+      probes:
+        enabled: "false"
+      show-details: "always"
+      show-components: "always"
+      group:
+        readiness:
+          include: ""
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  prometheus:
+    metrics:
+      export:
+        enabled: "true"
+  metrics:
+    web:
+      server:
+        request:
+          autotime:
+            enabled: "true"
+
+logging.level.root: ${ROOT_LOG_LEVEL:"INFO"}
+logging.level.org.apache: "ERROR"
+logging.level.kafka: "ERROR"
+logging.level.state.change: "ERROR"
+
+spring.datasource.read.maximum-pool-size: 2
+spring.datasource.write.maximum-pool-size: 2
+spring.caching.consumer-data-ttl-ms: 60000
+
+kafka:
+  server:
+    bootstrap-server-host: kafka
+    bootstrap-server-port: 9092
+  admin:
+    retry: 3
+    retry-backoff-ms: 100
+    reconnect-backoff-ms: 3
+    reconnect-backoff-max-ms: 30000
+    request-timeout-ms: 30000
+  availability:
+    retry-attempts: 3
+    retry-interval-ms: 1000
+  topology-ingestion:
+    consumer:
+      topic:
+        name: topology-inventory-ingestion
+        partitions: 4
+        replicas: 1
+        retention-ms: 86400000
+      group-id: topology-inventory-ingestion-consumer
+      auto-offset-reset: earliest
+      max-poll-records: 500
+      max-poll-interval-ms: 300000
+      fetch-min-bytes: 1
+      fetch-max-wait-ms: 500
+      retry-attempts: 3
+      retry-backoff-ms: 5000
+      concurrency: 1
+
+database:
+  retry-policies:
+    deadlock:
+      retry-attempts: 3
+      retry-backoff-ms: 200
+
+feature_flags:
+  use_alternate_delete_logic: false
\ No newline at end of file
diff --git a/teiv/src/test/resources/cloudeventdata/common/ce-data-only.json b/teiv/src/test/resources/cloudeventdata/common/ce-data-only.json
new file mode 100644
index 0000000..a02d18f
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/common/ce-data-only.json
@@ -0,0 +1,104 @@
+{
+    "entities": [
+        {
+            "o-ran-smo-teiv-ran:NRCellDU": [
+                {
+                    "id": "entityId_1",
+                    "attributes": {
+                        "cellLocalId": 4589,
+                        "nRPCI": 12,
+                        "nRTAC": 310,
+                        "primitiveArray": [
+                            1,
+                            2,
+                            3
+                        ],
+                        "singleList": [
+                            "12"
+                        ],
+                        "jsonObjectArray": [
+                            {
+                                "test1": "128",
+                                "test2": "49"
+                            },
+                            {
+                                "test1": "129",
+                                "test2": "50"
+                            }
+                        ]
+                    }
+                },
+                {
+                    "id": "entityId_3",
+                    "attributes": {
+                        "cellLocalId": 45891,
+                        "nRPCI": 121,
+                        "nRTAC": 3101,
+                        "primitiveArray": [
+                            1,
+                            2,
+                            3
+                        ],
+                        "singleList": [
+                            "121"
+                        ],
+                        "jsonObjectArray": [
+                            {
+                                "test1": "1281",
+                                "test2": "491"
+                            },
+                            {
+                                "test1": "1291",
+                                "test2": "501"
+                            }
+                        ]
+                    }
+                }
+            ]
+        },
+        {
+            "o-ran-smo-teiv-ran:NRSectorCarrier": [
+                {
+                    "id": "entityId_2",
+                    "attributes": {
+                        "arfcnDL": 4590,
+                        "testDouble": 32.5,
+                        "testBoolean": true,
+                        "cmId": {
+                            "option1": "test_option1",
+                            "option2": "test_option2"
+                        }
+                    }
+                }
+            ]
+        }
+    ],
+    "relationships": [
+        {
+            "o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER": [
+                {
+                    "id": "relationshipId",
+                    "aSide": "entityId_1",
+                    "bSide": "entityId_2"
+                },
+                {
+                    "id": "relationshipId2",
+                    "aSide": "entityId_3",
+                    "bSide": "entityId_4"
+                }
+            ],
+            "o-ran-smo-teiv-ran:GNBDUFunctionRealisedByCloudNativeApplication": [
+                {
+                    "id": "relationshipId3",
+                    "aSide": "entityId_5",
+                    "bSide": "entityId_6"
+                },
+                {
+                    "id": "relationshipId4",
+                    "aSide": "entityId_5",
+                    "bSide": "entityId_7"
+                }
+            ]
+        }
+    ]
+}
diff --git a/teiv/src/test/resources/cloudeventdata/common/ce-one-entity.json b/teiv/src/test/resources/cloudeventdata/common/ce-one-entity.json
new file mode 100644
index 0000000..68b6cb3
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/common/ce-one-entity.json
@@ -0,0 +1,25 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0001",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-ran:NRCellDU": [
+                    {
+                        "id": "entityId_1",
+                        "attributes": {
+                            "cellLocalId": 4589,
+                            "nRPCI": 12,
+                            "nRTAC": 310
+                        }
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/common/ce-with-data.json b/teiv/src/test/resources/cloudeventdata/common/ce-with-data.json
new file mode 100644
index 0000000..ef26639
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/common/ce-with-data.json
@@ -0,0 +1,115 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0001",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-ran:NRCellDU": [
+                    {
+                        "id": "entityId_1",
+                        "attributes": {
+                            "cellLocalId": 4589,
+                            "nRPCI": 12,
+                            "nRTAC": 310,
+                            "primitiveArray": [
+                                1,
+                                2,
+                                3
+                            ],
+                            "singleList": [
+                                "12"
+                            ],
+                            "jsonObjectArray": [
+                                {
+                                    "test1": "128",
+                                    "test2": "49"
+                                },
+                                {
+                                    "test1": "129",
+                                    "test2": "50"
+                                }
+                            ]
+                        }
+                    },
+                    {
+                        "id": "entityId_3",
+                        "attributes": {
+                            "cellLocalId": 45891,
+                            "nRPCI": 121,
+                            "nRTAC": 3101,
+                            "primitiveArray": [
+                                1,
+                                2,
+                                3
+                            ],
+                            "singleList": [
+                                "121"
+                            ],
+                            "jsonObjectArray": [
+                                {
+                                    "test1": "1281",
+                                    "test2": "491"
+                                },
+                                {
+                                    "test1": "1291",
+                                    "test2": "501"
+                                }
+                            ]
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:NRSectorCarrier": [
+                    {
+                        "id": "entityId_2",
+                        "attributes": {
+                            "arfcnDL": 4590,
+                            "testDouble": 32.5,
+                            "testBoolean": true,
+                            "cmId": {
+                                "option1": "test_option1",
+                                "option2": "test_option2"
+                            }
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-ran:NRCELLDU_USES_NRSECTORCARRIER": [
+                    {
+                        "id": "relationshipId",
+                        "aSide": "entityId_1",
+                        "bSide": "entityId_2"
+                    },
+                    {
+                        "id": "relationshipId2",
+                        "aSide": "entityId_3",
+                        "bSide": "entityId_4"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBDUFunctionRealisedByCloudNativeApplication": [
+                    {
+                        "id": "relationshipId3",
+                        "aSide": "entityId_5",
+                        "bSide": "entityId_6"
+                    },
+                    {
+                        "id": "relationshipId4",
+                        "aSide": "entityId_5",
+                        "bSide": "entityId_7"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-geo-location.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-geo-location.json
new file mode 100644
index 0000000..834c647
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-geo-location.json
@@ -0,0 +1,29 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f1113",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-cloud:CloudSite": [
+                    {
+                        "id": "CloudSite1",
+                        "attributes": {
+                            "name": "geo-location1",
+                            "geo-location": {
+                                "location": {
+                                    "latitude": 12.78232,
+                                    "longitude": 56.7455
+                                }
+                            }
+                        }
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-many.json
new file mode 100644
index 0000000..99507d6
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-many.json
@@ -0,0 +1,137 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0001",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-cloud:CloudNativeApplication": [
+                    {
+                        "id": "CloudNativeApplication_1",
+                        "attributes": {
+                            "name": "Test_CloudNativeApplication_1"
+                        }
+                    },
+                    {
+                        "id": "CloudNativeApplication_2",
+                        "attributes": {
+                            "name": "Test_CloudNativeApplication_2"
+                        }
+                    },
+                    {
+                        "id": "CloudNativeApplication_3",
+                        "attributes": {
+                            "name": "Test_CloudNativeApplication_3"
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBDUFunction": [
+                    {
+                        "id": "GNBDU_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1",
+                            "dUpLMNId": {
+                                "mcc": "110",
+                                "mnc": "210"
+                            },
+                            "gNBDUId": 111,
+                            "gNBId": 123,
+                            "gNBIdLength": 3,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+                            }
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBCUUPFunction": [
+                    {
+                        "id": "GNBCUUP_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUUPFunction=1",
+                            "gNBId": 123,
+                            "gNBIdLength": 3,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUUPFunction]/o-ran-smo-GNBCUUP:GNBCUUPFunction[@id=1]"
+                            }
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBCUCPFunction": [
+                    {
+                        "id": "GNBCUCP_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUCPFunction=1",
+                            "gNBCUName": "Test_gNBCU",
+                            "gNBId": 123,
+                            "gNBIdLength": 3,
+                            "pLMNId": {
+                                "mcc": "110",
+                                "mnc": "210"
+                            },
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUCPFunction]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]"
+                            }
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION": [
+                    {
+                        "id": "relation_1",
+                        "aSide": "GNBDU_1",
+                        "bSide": "CloudNativeApplication_1"
+                    },
+                    {
+                        "id": "relation_4",
+                        "aSide": "GNBDU_1",
+                        "bSide": "CloudNativeApplication_2"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION": [
+                    {
+                        "id": "relation_2",
+                        "aSide": "GNBCUUP_1",
+                        "bSide": "CloudNativeApplication_2"
+                    },
+                    {
+                        "id": "relation_5",
+                        "aSide": "GNBCUUP_1",
+                        "bSide": "CloudNativeApplication_3"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION": [
+                    {
+                        "id": "relation_3",
+                        "aSide": "GNBCUCP_1",
+                        "bSide": "CloudNativeApplication_3"
+                    },
+                    {
+                        "id": "relation_6",
+                        "aSide": "GNBCUCP_1",
+                        "bSide": "CloudNativeApplication_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-one.json
new file mode 100644
index 0000000..2729d70
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-many-to-one.json
@@ -0,0 +1,76 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-cloud:NodeCluster": [
+                    {
+                        "id": "NodeCluster_1",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:AntennaCapability": [
+                    {
+                        "id": "AntennaCapability_1",
+                        "attributes": {
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873820",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:NodeCluster[@id=2]"
+                            }
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:NRSectorCarrier": [
+                    {
+                        "id": "NRSectorCarrier_1",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudSite": [
+                    {
+                        "id": "CloudSite_1",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-cloud:NODECLUSTER_LOCATED_AT_CLOUDSITE": [
+                    {
+                        "id": "relation_1",
+                        "aSide": "NodeCluster_1",
+                        "bSide": "CloudSite_1"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                    {
+                        "id": "relation_10",
+                        "aSide": "NRSectorCarrier_1",
+                        "bSide": "AntennaCapability_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-one-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-one-to-many.json
new file mode 100644
index 0000000..2b8d3aa
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-one-to-many.json
@@ -0,0 +1,50 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-oam:ManagedElement": [
+                    {
+                        "id": "ManagedElement_1",
+                        "attributes": {
+
+                        },
+                        "sourceIds": []
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:ENodeBFunction": [
+                    {
+                        "id": "ENodeBFunction_1",
+                        "attributes": {
+
+                        },
+                        "sourceIds": []
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_ENODEBFUNCTION": [
+                    {
+                        "id": "relation_1",
+                        "aSide": "ManagedElement_1",
+                        "bSide": "ENodeBFunction_1",
+                        "sourceIds": [
+                            "fdn_1",
+                            "cmHandleId_1"
+                        ]
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-one-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-one-to-one.json
new file mode 100644
index 0000000..4c4cdb1
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-one-to-one.json
@@ -0,0 +1,61 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-oam:ManagedElement": [
+                    {
+                        "id": "ManagedElement_2",
+                        "attributes": {
+
+                        }
+                    },
+                    {
+                        "id": "ManagedElement_3",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudNativeSystem": [
+                    {
+                        "id": "CloudNativeSystem_2",
+                        "attributes": {
+
+                        }
+                    },
+                    {
+                        "id": "CloudNativeSystem_3",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                    {
+                        "id": "relation_11",
+                        "aSide": "ManagedElement_2",
+                        "bSide": "CloudNativeSystem_2"
+                    },
+                    {
+                        "id": "relation_12",
+                        "aSide": "ManagedElement_3",
+                        "bSide": "CloudNativeSystem_3"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-relationship-connecting-same-entity.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-relationship-connecting-same-entity.json
new file mode 100644
index 0000000..a411b47
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-relationship-connecting-same-entity.json
@@ -0,0 +1,86 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0100",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-equipment-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-equipment:AntennaModule": [
+                    {
+                        "id": "AntennaModule_1",
+                        "attributes": {
+
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_2",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-equipment:AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": [
+                    {
+                        "id": "AntennaModule_3",
+                        "attributes": {
+                            "fdn": "AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=21"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_4",
+                        "attributes": {
+                            "fdn": "AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=22"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_5",
+                        "attributes": {
+                            "fdn": "AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=31"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_6",
+                        "attributes": {
+                            "fdn": "AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=32"
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE": [
+                    {
+                        "id": "many_to_many_relation_1",
+                        "aSide": "AntennaModule_1",
+                        "bSide": "AntennaModule_2"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE": [
+                    {
+                        "id": "one_to_many_relation_1",
+                        "aSide": "AntennaModule_3",
+                        "bSide": "AntennaModule_4"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE": [
+                    {
+                        "id": "one_to_one_relation_1",
+                        "aSide": "AntennaModule_5",
+                        "bSide": "AntennaModule_6"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-second-case.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-second-case.json
new file mode 100644
index 0000000..fd427e6
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-create-second-case.json
@@ -0,0 +1,102 @@
+{
+    "specversion": "1.0",
+    "id": "26504e8e-838e-11ee-b962-0242ac120002",
+    "source": "dmi-plugin:nm-3",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-ran:CloudNativeApplication": [
+                    {
+                        "id": "CNA_SED_1",
+                        "attributes": {
+                            "name": "CNA_1"
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBDUFunction": [
+                    {
+                        "id": "GNBDU_SED_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00009,ManagedElement=NR01gNodeBRadio00009,GNBDUFunction=1",
+                            "dUpLMNId": {
+                                "mcc": "110",
+                                "mnc": "210"
+                            },
+                            "gNBDUId": 111,
+                            "gNBId": 123,
+                            "gNBIdLength": 3,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1929103B15999999",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00009]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+                            }
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBCUCPFunction": [
+                    {
+                        "id": "GNBCUCP_SED_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00009,ManagedElement=NR01gNodeBRadio00009,GNBCUCPFunction=1",
+                            "gNBCUName": "Test_sed_gNBCU",
+                            "gNBId": 123,
+                            "gNBIdLength": 3,
+                            "pLMNId": {
+                                "mcc": "110",
+                                "mnc": "210"
+                            },
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1929103B15999999",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00009]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]"
+                            }
+                        }
+                    },
+                    {
+                        "id": "GNBCUCP_SED_2",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00009,ManagedElement=NR01gNodeBRadio00009,GNBCUCPFunction=2",
+                            "gNBCUName": "Test_sed_gNBCU2",
+                            "gNBId": 123,
+                            "gNBIdLength": 3,
+                            "pLMNId": {
+                                "mcc": "110",
+                                "mnc": "210"
+                            },
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1929103B15999999",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00009]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=2]"
+                            }
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION": [
+                    {
+                        "id": "relation_sed_1",
+                        "aSide": "GNBDU_SED_1",
+                        "bSide": "CNA_SED_1"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION": [
+                    {
+                        "id": "relation_sed_2",
+                        "aSide": "GNBCUCP_SED_1",
+                        "bSide": "CNA_SED_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-many-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-many-to-many.json
new file mode 100644
index 0000000..8b5797b
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-many-to-many.json
@@ -0,0 +1,36 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.delete",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-ran:CloudNativeApplication": [
+                    {
+                        "id": "CloudNativeApplication_3"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBCUCPFunction": [
+                    {
+                        "id": "GNBCUCP_1"
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION": [
+                    {
+                        "id": "relation_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-many-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-many-to-one.json
new file mode 100644
index 0000000..6ba8fc8
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-many-to-one.json
@@ -0,0 +1,36 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.delete",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-cloud:NodeCluster": [
+                    {
+                        "id": "NodeCluster_1"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudSite": [
+                    {
+                        "id": "CloudSite_1"
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-cloud:NODECLUSTER_LOCATED_AT_CLOUDSITE": [
+                    {
+                        "id": "relation_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-one-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-one-to-many.json
new file mode 100644
index 0000000..b3d93ee
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-one-to-many.json
@@ -0,0 +1,36 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.delete",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-oam:ManagedElement": [
+                    {
+                        "id": "ManagedElement_1"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:ENodeBFunction": [
+                    {
+                        "id": "ENodeBFunction_1"
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-oam-to-logical:MANAGEDELEMENT_MANAGES_ENODEBFUNCTION": [
+                    {
+                        "id": "relation_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-one-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-one-to-one.json
new file mode 100644
index 0000000..ccd5081
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-one-to-one.json
@@ -0,0 +1,29 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.delete",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-oam:ManagedElement": [
+                    {
+                        "id": "ManagedElement_2"
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                    {
+                        "id": "relation_12"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-relationship-connecting-same-entity.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-relationship-connecting-same-entity.json
new file mode 100644
index 0000000..e4844a0
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-delete-relationship-connecting-same-entity.json
@@ -0,0 +1,39 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0103",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-equipment-topology.delete",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-equipment:AntennaModule": [
+                    {
+                        "id": "AntennaModule_1"
+                    },
+                    {
+                        "id": "AntennaModule_2"
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE": [
+                    {
+                        "id": "one_to_many_relation_1"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE": [
+                    {
+                        "id": "one_to_one_relation_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-long-names.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-long-names.json
new file mode 100644
index 0000000..ee90fb1
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-long-names.json
@@ -0,0 +1,364 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0002",
+    "source": "dmi-plugin:nm-1",
+    "type": "ties.merge",
+    "time": "2023-10-25T13:30:12Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology-yang",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-cloud:Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": [
+                    {
+                        "id": "Namespace_1",
+                        "attributes": {
+                            "name": "Namespace_1"
+                        }
+                    },
+                    {
+                        "id": "Namespace_2",
+                        "attributes": {
+                            "name": "Namespace_2"
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-oam:ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt": [
+                    {
+                        "id": "ManagedElement_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001",
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]"
+                            }
+                        }
+                    },
+                    {
+                        "id": "ManagedElement_2",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00002,ManagedElement=NR01gNodeBRadio00002",
+                            "cmId": {
+                                "cmHandle": "F0FD1924103B15873814395221E080CC",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00002]"
+                            }
+                        }
+                    },
+                    {
+                        "id": "ManagedElement_3",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00003,ManagedElement=NR01gNodeBRadio00003",
+                            "cmId": {
+                                "cmHandle": "B15873F0FD192410381439E080CC5221",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00003]"
+                            }
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm": [
+                    {
+                        "id": "CloudNativeSystem_1",
+                        "attributes": {
+                            "name": "Test_CloudNativeSystem_1"
+                        }
+                    },
+                    {
+                        "id": "CloudNativeSystem_2",
+                        "attributes": {
+                            "name": "Test_CloudNativeSystem_2"
+                        }
+                    },
+                    {
+                        "id": "CloudNativeSystem_3",
+                        "attributes": {
+                            "name": "Test_CloudNativeSystem_3"
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn": [
+                    {
+                        "id": "CloudNativeApplication_1",
+                        "attributes": {
+                            "name": "Test_CloudNativeApplication_1"
+                        }
+                    },
+                    {
+                        "id": "CloudNativeApplication_2",
+                        "attributes": {
+                            "name": "Test_CloudNativeApplication_2"
+                        }
+                    },
+                    {
+                        "id": "CloudNativeApplication_3",
+                        "attributes": {
+                            "name": "Test_CloudNativeApplication_3"
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn": [
+                    {
+                        "id": "GNBDUFunction_1",
+                        "attributes": {
+                            "fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1",
+                            "dUpLMNId": {
+                                "mcc": "110",
+                                "mnc": "210"
+                            },
+                            "gNBDUId": 12,
+                            "gNBId": 1234,
+                            "gNBIdLength": 4,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+                            }
+                        }
+                    },
+                    {
+                        "id": "GNBDUFunction_2",
+                        "attributes": {
+                            "fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=2",
+                            "dUpLMNId": {
+                                "mcc": "110",
+                                "mnc": "210"
+                            },
+                            "gNBDUId": 12,
+                            "gNBId": 1234,
+                            "gNBIdLength": 4,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=2]"
+                            }
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU": [
+                    {
+                        "id": "NRCellDU_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1,NRCellDU=1",
+                            "cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd": 4589,
+                            "nCI": 1,
+                            "nRPCI": 12,
+                            "nRTAC": 310,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-NRCellDU:NRCellDU[@id=1]"
+                            }
+                        }
+                    },
+                    {
+                        "id": "NRCellDU_2",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1,NRCellDU=2",
+                            "cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd": 45891,
+                            "nCI": 2,
+                            "nRPCI": 121,
+                            "nRTAC": 3101,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-NRCellDU:NRCellDU[@id=2]"
+                            }
+                        }
+                    },
+                    {
+                        "id": "NRCellDU_3",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1,NRCellDU=3",
+                            "cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd": 469,
+                            "nCI": 3,
+                            "nRPCI": 15,
+                            "nRTAC": 301,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]/o-ran-smo-NRCellDU:NRCellDU[@id=3]"
+                            }
+                        }
+                    },
+                    {
+                        "id": "NRCellDU_4",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=2,NRCellDU=4",
+                            "cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd": 469,
+                            "nCI": 4,
+                            "nRPCI": 15,
+                            "nRTAC": 301,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=2]/o-ran-smo-NRCellDU:NRCellDU[@id=4]"
+                            }
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-equipment:AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": [
+                    {
+                        "id": "AntennaModule_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=11"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_2",
+                        "attributes": {
+                            "fdn": "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=12"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_3",
+                        "attributes": {
+                            "fdn": "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=21"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_4",
+                        "attributes": {
+                            "fdn": "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=22"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_5",
+                        "attributes": {
+                            "fdn": "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=31"
+                        }
+                    },
+                    {
+                        "id": "AntennaModule_6",
+                        "attributes": {
+                            "fdn": "SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=32"
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-cloud:CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE": [
+                    {
+                        "id": "CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE_relation_1",
+                        "aSide": "CloudNativeApplication_1",
+                        "bSide": "Namespace_1"
+                    },
+                    {
+                        "id": "CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE_relation_2",
+                        "aSide": "CloudNativeApplication_2",
+                        "bSide": "Namespace_1"
+                    },
+                    {
+                        "id": "CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE_relation_3",
+                        "aSide": "CloudNativeApplication_3",
+                        "bSide": "Namespace_2"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM": [
+                    {
+                        "id": "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM_relation_1",
+                        "aSide": "ManagedElement_1",
+                        "bSide": "CloudNativeSystem_1"
+                    },
+                    {
+                        "id": "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM_relation_2",
+                        "aSide": "ManagedElement_2",
+                        "bSide": "CloudNativeSystem_2"
+                    },
+                    {
+                        "id": "MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM_relation_3",
+                        "aSide": "ManagedElement_3",
+                        "bSide": "CloudNativeSystem_3"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENTTTTTTTTT_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNN": [
+                    {
+                        "id": "MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION_relation_1",
+                        "aSide": "ManagedElement_1",
+                        "bSide": "CloudNativeApplication_1"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran-to-cloud:GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN": [
+                    {
+                        "id": "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_relation_1",
+                        "aSide": "GNBDUFunction_1",
+                        "bSide": "CloudNativeApplication_1"
+                    },
+                    {
+                        "id": "GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_relation_2",
+                        "aSide": "GNBDUFunction_1",
+                        "bSide": "CloudNativeApplication_2"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN": [
+                    {
+                        "id": "MANAGEDELEMENT_MANAGES_GNBDUFUNCTION_relation_1",
+                        "aSide": "ManagedElement_1",
+                        "bSide": "GNBDUFunction_1"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU": [
+                    {
+                        "id": "GNBDUFUNCTION_PROVIDES_NRCELLDU_relation_1",
+                        "aSide": "GNBDUFunction_1",
+                        "bSide": "NRCellDU_1"
+                    },
+                    {
+                        "id": "GNBDUFUNCTION_PROVIDES_NRCELLDU_relation_2",
+                        "aSide": "GNBDUFunction_1",
+                        "bSide": "NRCellDU_2"
+                    },
+                    {
+                        "id": "GNBDUFUNCTION_PROVIDES_NRCELLDU_relation_3",
+                        "aSide": "GNBDUFunction_1",
+                        "bSide": "NRCellDU_3"
+                    },
+                    {
+                        "id": "GNBDUFUNCTION_PROVIDES_NRCELLDU_relation_4",
+                        "aSide": "GNBDUFunction_2",
+                        "bSide": "NRCellDU_4"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE": [
+                    {
+                        "id": "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_relation_1",
+                        "aSide": "AntennaModule_1",
+                        "bSide": "AntennaModule_2"
+                    },
+                    {
+                        "id": "ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_relation_2",
+                        "aSide": "AntennaModule_3",
+                        "bSide": "AntennaModule_4"
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE": [
+                    {
+                        "id": "ANTENNAMODULE_DEPLOYED_ON_ANTENNAMODULE_relation_1",
+                        "aSide": "AntennaModule_5",
+                        "bSide": "AntennaModule_6"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-one-to-many-deprecated-structure.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-one-to-many-deprecated-structure.json
new file mode 100644
index 0000000..b4d75c5
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-one-to-many-deprecated-structure.json
@@ -0,0 +1,95 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0002",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.merge",
+    "time": "2023-10-25T13:30:12Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-ran:GNBDUFunction": [
+                {
+                    "id": "GNBDU_1",
+                    "attributes": {
+                        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction[@id=1]",
+                        "dUpLMNId": {
+                            "mcc": "110",
+                            "mnc": "210"
+                        },
+                        "gNBDUId": 12,
+                        "gNBId": 1234,
+                        "gNBIdLength": 4,
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873814",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+                        }
+                    }
+                }
+            ],
+            "o-ran-smo-teiv-ran:NRCellDU": [
+                {
+                    "id": "NRCellDU_1",
+                    "attributes": {
+                        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=1",
+                        "cellLocalId": 4589,
+                        "nCI": 1,
+                        "nRPCI": 12,
+                        "nRTAC": 310,
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873814",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_1]/o-ran-smo-NRCellDU:NRCellDU[@id=1]"
+                        }
+                    }
+                },
+                {
+                    "id": "NRCellDU_2",
+                    "attributes": {
+                        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=2",
+                        "cellLocalId": 45891,
+                        "nCI": 2,
+                        "nRPCI": 121,
+                        "nRTAC": 3101,
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873814",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_2]/o-ran-smo-NRCellDU:NRCellDU[@id=2]"
+                        }
+                    }
+                },
+                {
+                    "id": "NRCellDU_3",
+                    "attributes": {
+                        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=3",
+                        "cellLocalId": 469,
+                        "nCI": 3,
+                        "nRPCI": 15,
+                        "nRTAC": 301,
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873814",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_3]/o-ran-smo-NRCellDU:NRCellDU[@id=3]"
+                        }
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU": [
+                {
+                    "id": "relation_7",
+                    "aSide": "GNBDU_1",
+                    "bSide": "NRCellDU_1"
+                },
+                {
+                    "id": "relation_8",
+                    "aSide": "GNBDU_1",
+                    "bSide": "NRCellDU_2"
+                },
+                {
+                    "id": "relation_9",
+                    "aSide": "GNBDU_1",
+                    "bSide": "NRCellDU_3"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-one-to-many2.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-one-to-many2.json
new file mode 100644
index 0000000..6032e29
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-merge-one-to-many2.json
@@ -0,0 +1,82 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f1113",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.merge",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-oam:ManagedElement": [
+                    {
+                        "id": "ManagedElement_1",
+                        "attributes": {
+
+                        },
+                        "sourceIds": []
+                    },
+                    {
+                        "id": "ManagedElement_2",
+                        "attributes": {
+
+                        },
+                        "sourceIds": []
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudNativeSystem": [
+                    {
+                        "id": "CloudNativeSystem_1",
+                        "attributes": {
+
+                        },
+                        "sourceIds": []
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-ran:GNBDUFunction": [
+                    {
+                        "id": "GNBDU_1",
+                        "attributes": {
+                            "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1",
+                            "dUpLMNId": {
+                                "mcc": 110,
+                                "mnc": 210
+                            },
+                            "gNBDUId": 111,
+                            "gNBId": 123,
+                            "gNBIdLength": 3,
+                            "cmId": {
+                                "cmHandle": "395221E080CCF0FD1924103B15873814",
+                                "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+                            }
+                        },
+                        "sourceIds": [
+                            "urn:3gpp:dn:/SubNetwork=Europe/SubNetwork=Ireland/MeContext=NR01gNodeBRadio00001/ManagedElement=NR01gNodeBRadio00001/GNBDUFunction=1",
+                            "urn:cmHandle:/395221E080CCF0FD1924103B15873814"
+                        ]
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                    {
+                        "id": "relation_1",
+                        "aSide": "ManagedElement_1",
+                        "bSide": "CloudNativeSystem_1",
+                        "sourceIds": [
+                            "fdn_1",
+                            "cmHandleId_1"
+                        ]
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-source-entity-delete-cm-handle.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-source-entity-delete-cm-handle.json
new file mode 100644
index 0000000..6f5ce38
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-source-entity-delete-cm-handle.json
@@ -0,0 +1,13 @@
+{
+    "specversion": "1.0",
+    "id": "063b0da2-8396-11ee-b962-0242ac120002",
+    "source": "dmi-plugin:nm-3",
+    "type": "ran-logical-topology.source-entity-delete",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/source-entity-delete",
+    "data": {
+        "type": "cmHandle",
+        "value": "395221E080CCF0FD1929103B15999999"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/ce-source-entity-delete-cm-handle2.json b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-source-entity-delete-cm-handle2.json
new file mode 100644
index 0000000..81dd6e0
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/ce-source-entity-delete-cm-handle2.json
@@ -0,0 +1,13 @@
+{
+    "specversion": "1.0",
+    "id": "063b0da2-8396-11ee-b962-0242ac120002",
+    "source": "dmi-plugin:nm-3",
+    "type": "ran-logical-topology.source-entity-delete",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/source-entity-delete",
+    "data": {
+        "type": "cmHandle",
+        "value": "395221E080CCF0FD1924103B15873820"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-many-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-many-to-many.json
new file mode 100644
index 0000000..fe79568
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-many-to-many.json
@@ -0,0 +1,14 @@
+{
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_6": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_1\",\"aSide\":\"GNBCUCP_1\",\"id\":\"relation_6\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_3": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_3\",\"aSide\":\"GNBCUCP_1\",\"id\":\"relation_3\",\"sourceIds\":[]}]}",
+    "RAN/entity-types/GNBCUCPFunction/entities/GNBCUCP_1": "{\"o-ran-smo-teiv-ran:GNBCUCPFunction\":[{\"id\":\"GNBCUCP_1\",\"sourceIds\":[],\"attributes\":{\"gNBIdLength\":3,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=GNBCUCPFunction]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,GNBCUCPFunction=1\",\"pLMNId\":{\"mcc\":\"110\",\"mnc\":\"210\"},\"gNBCUName\":\"Test_gNBCU\",\"gNBId\":123}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_3": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_3\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_3\"}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_2": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_2\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_2\"}}]}",
+    "TEIV/entity-types/CloudNativeApplication/entities/CloudNativeApplication_1": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_1\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_1\"}}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_4": "{\"o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_2\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_4\",\"sourceIds\":[]}]}",
+    "RAN/entity-types/GNBDUFunction/entities/GNBDU_1": "{\"o-ran-smo-teiv-ran:GNBDUFunction\":[{\"id\":\"GNBDU_1\",\"sourceIds\":[],\"attributes\":{\"gNBIdLength\":3,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1\",\"dUpLMNId\":{\"mcc\":\"110\",\"mnc\":\"210\"},\"gNBDUId\":111,\"gNBId\":123}}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_2": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_2\",\"aSide\":\"GNBCUUP_1\",\"id\":\"relation_2\",\"sourceIds\":[]}]}",
+    "TEIV/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_1": "{\"o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_1\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_1\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_5": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_3\",\"aSide\":\"GNBCUUP_1\",\"id\":\"relation_5\",\"sourceIds\":[]}]}",
+    "RAN/entity-types/GNBCUUPFunction/entities/GNBCUUP_1": "{\"o-ran-smo-teiv-ran:GNBCUUPFunction\":[{\"id\":\"GNBCUUP_1\",\"sourceIds\":[],\"attributes\":{\"gNBId\":123,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=GNBCUUPFunction]/o-ran-smo-GNBCUUP:GNBCUUPFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,GNBCUUPFunction=1\",\"gNBIdLength\":3}}]}"
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-many-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-many-to-one.json
new file mode 100644
index 0000000..154a265
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-many-to-one.json
@@ -0,0 +1,5 @@
+{
+    "CLOUD/entity-types/NodeCluster/entities/NodeCluster_1": "{\"o-ran-smo-teiv-cloud:NodeCluster\":[{\"id\":\"NodeCluster_1\",\"sourceIds\":[],\"attributes\":{\"name\":null}}]}",
+    "CLOUD/entity-types/CloudSite/entities/CloudSite_1": "{\"o-ran-smo-teiv-cloud:CloudSite\":[{\"id\":\"CloudSite_1\",\"sourceIds\":[],\"attributes\":{\"geo-location\":null,\"name\":null}}]}",
+    "CLOUD/relationship-types/NODECLUSTER_LOCATED_AT_CLOUDSITE/relationships/relation_1": "{\"o-ran-smo-teiv-cloud:NODECLUSTER_LOCATED_AT_CLOUDSITE\":[{\"bSide\":\"CloudSite_1\",\"aSide\":\"NodeCluster_1\",\"id\":\"relation_1\",\"sourceIds\":[]}]}"
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-one-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-one-to-many.json
new file mode 100644
index 0000000..55b15db
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-one-to-many.json
@@ -0,0 +1,5 @@
+{
+    "RAN/entity-types/ENodeBFunction/entities/ENodeBFunction_1": "{\"o-ran-smo-teiv-ran:ENodeBFunction\":[{\"id\":\"ENodeBFunction_1\",\"sourceIds\":[],\"attributes\":{\"eNodeBPlmnId\":null,\"fdn\":null,\"eNBId\":null,\"cmId\":null},\"id\":\"ENodeBFunction_1\"}]}",
+    "OAM_TO_RAN/relationship-types/MANAGEDELEMENT_MANAGES_ENODEBFUNCTION/relationships/relation_1": "{\"o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_ENODEBFUNCTION\":[{\"bSide\":\"ENodeBFunction_1\",\"aSide\":\"ManagedElement_1\",\"id\":\"relation_1\",\"sourceIds\":[\"fdn_1\",\"cmHandleId_1\"]}]}",
+    "OAM/entity-types/ManagedElement/entities/ManagedElement_1": "{\"o-ran-smo-teiv-oam:ManagedElement\":[{\"id\":\"ManagedElement_1\",\"sourceIds\":[],\"attributes\":{\"fdn\":null,\"cmId\":null}}]}"
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-relationship-connecting-same-entity.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-relationship-connecting-same-entity.json
new file mode 100644
index 0000000..08a8ef1
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-relationship-connecting-same-entity.json
@@ -0,0 +1,11 @@
+{
+    "EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships/many_to_many_relation_1": "{\"o-ran-smo-teiv-equipment:ANTENNAMODULE_REALISED_BY_ANTENNAMODULE\":[{\"bSide\":\"AntennaModule_2\",\"aSide\":\"AntennaModule_1\",\"id\":\"many_to_many_relation_1\",\"sourceIds\":[]}]}",
+    "EQUIPMENT/relationship-types/ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE/relationships/one_to_many_relation_1": "{\"o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE\":[{\"bSide\":\"AntennaModule_4\",\"aSide\":\"AntennaModule_3\",\"id\":\"one_to_many_relation_1\",\"sourceIds\":[]}]}",
+    "EQUIPMENT/relationship-types/ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE/relationships/one_to_one_relation_1": "{\"o-ran-smo-teiv-equipment:ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE\":[{\"bSide\":\"AntennaModule_6\",\"aSide\":\"AntennaModule_5\",\"id\":\"one_to_one_relation_1\",\"sourceIds\":[]}]}",
+    "EQUIPMENT/entity-types/AntennaModule/entities/AntennaModule_1": "{\"o-ran-smo-teiv-equipment:AntennaModule\":[{\"id\":\"AntennaModule_1\",\"sourceIds\":[],\"attributes\":{\"totalTilt\":null,\"mechanicalAntennaBearing\":null,\"fdn\":null,\"antennaModelNumber\":null,\"mechanicalAntennaTilt\":null,\"positionWithinSector\":null,\"cmId\":null,\"electricalAntennaTilt\":null}}]}",
+    "EQUIPMENT/entity-types/AntennaModule/entities/AntennaModule_2": "{\"o-ran-smo-teiv-equipment:AntennaModule\":[{\"id\":\"AntennaModule_2\",\"sourceIds\":[],\"attributes\":{\"totalTilt\":null,\"mechanicalAntennaBearing\":null,\"fdn\":null,\"antennaModelNumber\":null,\"mechanicalAntennaTilt\":null,\"positionWithinSector\":null,\"cmId\":null,\"electricalAntennaTilt\":null}}]}",
+    "EQUIPMENT/entity-types/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/entities/AntennaModule_3": "{\"o-ran-smo-teiv-equipment:AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\":[{\"attributes\":{\"fdn\":\"AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=21\"},\"id\":\"AntennaModule_3\",\"sourceIds\":[]}]}",
+    "EQUIPMENT/entity-types/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/entities/AntennaModule_4": "{\"o-ran-smo-teiv-equipment:AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\":[{\"attributes\":{\"fdn\":\"AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=22\"},\"id\":\"AntennaModule_4\",\"sourceIds\":[]}]}",
+    "EQUIPMENT/entity-types/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/entities/AntennaModule_5": "{\"o-ran-smo-teiv-equipment:AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\":[{\"attributes\":{\"fdn\":\"AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=31\"},\"id\":\"AntennaModule_5\",\"sourceIds\":[]}]}",
+    "EQUIPMENT/entity-types/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee/entities/AntennaModule_6": "{\"o-ran-smo-teiv-equipment:AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\":[{\"attributes\":{\"fdn\":\"AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=32\"},\"id\":\"AntennaModule_6\",\"sourceIds\":[]}]}"
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-second-case.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-second-case.json
new file mode 100644
index 0000000..ac685fe
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-create-second-case.json
@@ -0,0 +1,24 @@
+{
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_1": "{\"o-ran-smo-teiv-ran:NRCellDU\":[{\"id\":\"NRCellDU_1\",\"sourceIds\":[],\"attributes\":{\"nCI\":1,\"nRTAC\":310,\"cellLocalId\":4589,\"nRPCI\":12,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_1]/o-ran-smo-NRCellDU:NRCellDU[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=1\"}}]}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_2": "{\"o-ran-smo-teiv-ran:NRCellDU\":[{\"id\":\"NRCellDU_2\",\"sourceIds\":[],\"attributes\":{\"nCI\":2,\"nRTAC\":3101,\"cellLocalId\":45891,\"nRPCI\":121,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_2]/o-ran-smo-NRCellDU:NRCellDU[@id=2]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=2\"}}]}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_3": "{\"o-ran-smo-teiv-ran:NRCellDU\":[{\"id\":\"NRCellDU_3\",\"sourceIds\":[],\"attributes\":{\"nCI\":3,\"nRTAC\":301,\"cellLocalId\":469,\"nRPCI\":15,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_3]/o-ran-smo-NRCellDU:NRCellDU[@id=3]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=3\"}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CNA_SED_1": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CNA_SED_1\",\"sourceIds\":[],\"attributes\":{\"name\":\"CNA_1\"}}]}",
+    "RAN/entity-types/GNBCUCPFunction/entities/GNBCUCP_1": "{\"o-ran-smo-teiv-ran:GNBCUCPFunction\":[{\"id\":\"GNBCUCP_1\",\"sourceIds\":[],\"attributes\":{\"pLMNId\":{\"mcc\":\"110\",\"mnc\":\"210\"},\"gNBCUName\":\"Test_gNBCU\",\"gNBId\":123,\"gNBIdLength\":3,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=GNBCUCPFunction]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,GNBCUCPFunction=1\"}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_3": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_3\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_3\"}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_2": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_2\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_2\"}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_1": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_1\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_1\"}}]}",
+    "RAN/entity-types/GNBCUCPFunction/entities/GNBCUCP_SED_1": "{\"o-ran-smo-teiv-ran:GNBCUCPFunction\":[{\"id\":\"GNBCUCP_SED_1\",\"sourceIds\":[],\"attributes\":{\"pLMNId\":{\"mcc\":\"110\",\"mnc\":\"210\"},\"gNBCUName\":\"Test_sed_gNBCU\",\"gNBId\":123,\"gNBIdLength\":3,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1929103B15999999\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00009]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00009,ManagedElement=NR01gNodeBRadio00009,GNBCUCPFunction=1\"}}]}",
+    "RAN/entity-types/GNBDUFunction/entities/GNBDU_1": "{\"o-ran-smo-teiv-ran:GNBDUFunction\":[{\"id\":\"GNBDU_1\",\"sourceIds\":[],\"attributes\":{\"dUpLMNId\":{\"mcc\":\"110\",\"mnc\":\"210\"},\"gNBDUId\":12,\"gNBId\":1234,\"gNBIdLength\":4,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction[@id=1]\"}}]}",
+    "RAN/entity-types/GNBCUUPFunction/entities/GNBCUUP_1": "{\"o-ran-smo-teiv-ran:GNBCUUPFunction\":[{\"id\":\"GNBCUUP_1\",\"sourceIds\":[],\"attributes\":{\"gNBId\":123,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=GNBCUUPFunction]/o-ran-smo-GNBCUUP:GNBCUUPFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,GNBCUUPFunction=1\",\"gNBIdLength\":3}}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_6": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_1\",\"aSide\":\"GNBCUCP_1\",\"id\":\"relation_6\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_3": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_3\",\"aSide\":\"GNBCUCP_1\",\"id\":\"relation_3\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_sed_2": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CNA_SED_1\",\"aSide\":\"GNBCUCP_SED_1\",\"id\":\"relation_sed_2\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_4": "{\"o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_2\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_4\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_2": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_2\",\"aSide\":\"GNBCUUP_1\",\"id\":\"relation_2\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_1": "{\"o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_1\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_1\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_5": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_3\",\"aSide\":\"GNBCUUP_1\",\"id\":\"relation_5\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_sed_1": "{\"o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CNA_SED_1\",\"aSide\":\"GNBDU_SED_1\",\"id\":\"relation_sed_1\",\"sourceIds\":[]}]}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_1/relationships": "{\"next\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"last\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"prev\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"self\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"totalCount\":1,\"items\":[{\"o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU\":[{\"bSide\":\"NRCellDU_1\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_7\"}]}],\"first\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"}}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_2/relationships": "{\"next\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"last\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"prev\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"self\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"totalCount\":1,\"items\":[{\"o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU\":[{\"bSide\":\"NRCellDU_2\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_8\"}]}],\"first\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"}}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_3/relationships": "{\"next\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"last\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"prev\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"self\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"totalCount\":1,\"items\":[{\"o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU\":[{\"bSide\":\"NRCellDU_3\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_9\"}]}],\"first\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"}}"
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-many-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-many-to-many.json
new file mode 100644
index 0000000..6b66aaa
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-many-to-many.json
@@ -0,0 +1,20 @@
+{
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_3": {
+
+    },
+    "RAN/entity-types/GNBCUCPFunction/entities/GNBCUCP_1": {
+
+    },
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_1": {
+
+    },
+    "CLOUD_TO_RAN/relationship-types/GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_5": {
+
+    },
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_3": {
+
+    },
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_6": {
+
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-many-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-many-to-one.json
new file mode 100644
index 0000000..cc9c604
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-many-to-one.json
@@ -0,0 +1,11 @@
+{
+    "CLOUD/entity-types/NodeCluster/entities/NodeCluster_1": {
+
+    },
+    "CLOUD/entity-types/CloudSite/entities/CloudSite_1": {
+
+    },
+    "CLOUD/relationship-types/NODECLUSTER_LOCATED_AT_CLOUDSITE/relationships/relation_1": {
+
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-one-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-one-to-many.json
new file mode 100644
index 0000000..d8bc339
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-one-to-many.json
@@ -0,0 +1,11 @@
+{
+    "RAN/entity-types/ENodeBFunction/entities/ENodeBFunction_1": {
+
+    },
+    "OAM_TO_RAN/relationship-types/MANAGEDELEMENT_MANAGES_ENODEBFUNCTION/relationships/relation_1": {
+
+    },
+    "OAM/entity-types/ManagedElement/entities/ManagedElement_1": {
+
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-relationship-connecting-same-entity.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-relationship-connecting-same-entity.json
new file mode 100644
index 0000000..66c6280
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-delete-relationship-connecting-same-entity.json
@@ -0,0 +1,17 @@
+{
+    "EQUIPMENT/entity-types/AntennaModule/entities/AntennaModule_1": {
+
+    },
+    "EQUIPMENT/entity-types/AntennaModule/entities/AntennaModule_2": {
+
+    },
+    "EQUIPMENT/relationship-types/ANTENNAMODULE_REALISED_BY_ANTENNAMODULE/relationships/many_to_many_relation_1": {
+
+    },
+    "EQUIPMENT/relationship-types/ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE/relationships/one_to_many_relation_1": {
+
+    },
+    "EQUIPMENT/relationship-types/ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE/relationships/one_to_one_relation_1": {
+
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-merge-one-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-merge-one-to-many.json
new file mode 100644
index 0000000..434b0b4
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-merge-one-to-many.json
@@ -0,0 +1,20 @@
+{
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_1": "{\"o-ran-smo-teiv-ran:NRCellDU\":[{\"id\":\"NRCellDU_1\",\"sourceIds\":[],\"attributes\":{\"nRPCI\":12,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_1]/o-ran-smo-NRCellDU:NRCellDU[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=1\",\"nCI\":1,\"nRTAC\":310,\"cellLocalId\":4589}}]}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_2": "{\"o-ran-smo-teiv-ran:NRCellDU\":[{\"id\":\"NRCellDU_2\",\"sourceIds\":[],\"attributes\":{\"nRPCI\":121,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_2]/o-ran-smo-NRCellDU:NRCellDU[@id=2]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=2\",\"nCI\":2,\"nRTAC\":3101,\"cellLocalId\":45891}}]}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_3": "{\"o-ran-smo-teiv-ran:NRCellDU\":[{\"id\":\"NRCellDU_3\",\"sourceIds\":[],\"attributes\":{\"nRPCI\":15,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_3]/o-ran-smo-NRCellDU:NRCellDU[@id=3]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=3\",\"nCI\":3,\"nRTAC\":301,\"cellLocalId\":469}}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_6": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_1\",\"aSide\":\"GNBCUCP_1\",\"id\":\"relation_6\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_3": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_3\",\"aSide\":\"GNBCUCP_1\",\"id\":\"relation_3\",\"sourceIds\":[]}]}",
+    "RAN/entity-types/GNBCUCPFunction/entities/GNBCUCP_1": "{\"o-ran-smo-teiv-ran:GNBCUCPFunction\":[{\"id\":\"GNBCUCP_1\",\"sourceIds\":[],\"attributes\":{\"gNBIdLength\":3,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=GNBCUCPFunction]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,GNBCUCPFunction=1\",\"pLMNId\":{\"mcc\":\"110\",\"mnc\":\"210\"},\"gNBCUName\":\"Test_gNBCU\",\"gNBId\":123}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_3": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_3\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_3\"}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_2": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_2\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_2\"}}]}",
+    "CLOUD/entity-types/CloudNativeApplication/entities/CloudNativeApplication_1": "{\"o-ran-smo-teiv-cloud:CloudNativeApplication\":[{\"id\":\"CloudNativeApplication_1\",\"sourceIds\":[],\"attributes\":{\"name\":\"Test_CloudNativeApplication_1\"}}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_4": "{\"o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_2\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_4\",\"sourceIds\":[]}]}",
+    "RAN/entity-types/GNBDUFunction/entities/GNBDU_1": "{\"o-ran-smo-teiv-ran:GNBDUFunction\":[{\"id\":\"GNBDU_1\",\"sourceIds\":[],\"attributes\":{\"gNBIdLength\":4,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction[@id=1]\",\"dUpLMNId\":{\"mcc\":\"110\",\"mnc\":\"210\"},\"gNBDUId\":12,\"gNBId\":1234}}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_2": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_2\",\"aSide\":\"GNBCUUP_1\",\"id\":\"relation_2\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_1": "{\"o-ran-smo-teiv-cloud-to-ran:GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_1\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_1\",\"sourceIds\":[]}]}",
+    "CLOUD_TO_RAN/relationship-types/GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_5": "{\"o-ran-smo-teiv-cloud-to-ran:GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION\":[{\"bSide\":\"CloudNativeApplication_3\",\"aSide\":\"GNBCUUP_1\",\"id\":\"relation_5\",\"sourceIds\":[]}]}",
+    "RAN/entity-types/GNBCUUPFunction/entities/GNBCUUP_1": "{\"o-ran-smo-teiv-ran:GNBCUUPFunction\":[{\"id\":\"GNBCUUP_1\",\"sourceIds\":[],\"attributes\":{\"gNBId\":123,\"cmId\":{\"cmHandle\":\"395221E080CCF0FD1924103B15873814\",\"resourceIdentifier\":\"/o-ran-smo-ComTop:ManagedElement[@id=GNBCUUPFunction]/o-ran-smo-GNBCUUP:GNBCUUPFunction[@id=1]\"},\"fdn\":\"SubNetwork=Europe,SubNetwork=Ireland,GNBCUUPFunction=1\",\"gNBIdLength\":3}}]}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_1/relationships": "{\"next\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"last\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"prev\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"self\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"},\"totalCount\":1,\"items\":[{\"o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU\":[{\"bSide\":\"NRCellDU_1\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_7\"}]}],\"first\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_1\\/relationships?offset=0&limit=500\"}}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_2/relationships": "{\"next\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"last\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"prev\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"self\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"},\"totalCount\":1,\"items\":[{\"o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU\":[{\"bSide\":\"NRCellDU_2\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_8\"}]}],\"first\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_2\\/relationships?offset=0&limit=500\"}}",
+    "RAN/entity-types/NRCellDU/entities/NRCellDU_3/relationships": "{\"next\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"last\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"prev\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"self\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"},\"totalCount\":1,\"items\":[{\"o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU\":[{\"bSide\":\"NRCellDU_3\",\"aSide\":\"GNBDU_1\",\"id\":\"relation_9\"}]}],\"first\":{\"href\":\"\\/domains\\/RAN\\/entity-types\\/NRCellDU\\/entities\\/NRCellDU_3\\/relationships?offset=0&limit=500\"}}"
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-source-entity-delete-cm-handle.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-source-entity-delete-cm-handle.json
new file mode 100644
index 0000000..5828231
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/api/exp-source-entity-delete-cm-handle.json
@@ -0,0 +1,14 @@
+{
+    "RAN/entity-types/GNBDUFunction/entities/GNBDU_SED_1": {
+
+    },
+    "RAN/entity-types/GNBCUCPFunction/entities/GNBCUCP_SED_1": {
+
+    },
+    "CLOUD_TO_RAN/relationship-types/GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_sed_1": {
+
+    },
+    "CLOUD_TO_RAN/relationship-types/GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION/relationships/relation_sed_2": {
+
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-many.json
new file mode 100644
index 0000000..d2a873a
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-many.json
@@ -0,0 +1,84 @@
+{
+    "entity_map_CNA_1": {
+        "id": "CloudNativeApplication_1",
+        "name": "Test_CloudNativeApplication_1"
+    },
+    "entity_map_CNA_2": {
+        "id": "CloudNativeApplication_2",
+        "name": "Test_CloudNativeApplication_2"
+    },
+    "entity_map_CNA_3": {
+        "id": "CloudNativeApplication_3",
+        "name": "Test_CloudNativeApplication_3"
+    },
+    "entity_map_GNBDU_1": {
+        "id": "GNBDU_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction=1",
+        "dUpLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "gNBDUId": 111,
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBCUUP_1": {
+        "id": "GNBCUUP_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUUPFunction=1",
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUUPFunction]/o-ran-smo-GNBCUUP:GNBCUUPFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBCUCP_1": {
+        "id": "GNBCUCP_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUCPFunction=1",
+        "gNBCUName": "Test_gNBCU",
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "pLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUCPFunction]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]"
+        }
+    },
+    "relation_map_GNBDU_CNA_1": {
+        "id": "relation_1",
+        "aSide_GNBDUFunction": "GNBDU_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_1"
+    },
+    "relation_map_GNBCUUP_CNA_2": {
+        "id": "relation_2",
+        "aSide_GNBCUUPFunction": "GNBCUUP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_2"
+    },
+    "relation_map_GNBCUCP_CNA_3": {
+        "id": "relation_3",
+        "aSide_GNBCUCPFunction": "GNBCUCP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_3"
+    },
+    "relation_map_GNBDU_CNA_4": {
+        "id": "relation_4",
+        "aSide_GNBDUFunction": "GNBDU_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_2"
+    },
+    "relation_map_GNBCUUP_CNA_5": {
+        "id": "relation_5",
+        "aSide_GNBCUUPFunction": "GNBCUUP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_3"
+    },
+    "relation_map_GNBCUCP_CNA_6": {
+        "id": "relation_6",
+        "aSide_GNBCUCPFunction": "GNBCUCP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_1"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one2.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one2.json
new file mode 100644
index 0000000..e9337b0
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one2.json
@@ -0,0 +1,17 @@
+{
+    "entity_map_NRSectorCarrier_1": {
+        "id": "NRSectorCarrier_1"
+    },
+    "entity_map_AntennaCapability_1": {
+        "id": "AntennaCapability_1",
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873820",
+            "resourceIdentifier": "/o-ran-smo-ComTop:NodeCluster[@id=2]"
+        }
+    },
+    "relation_map_NRSC_AC_1": {
+        "REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY": "relation_1",
+        "id": "NRSectorCarrier_1",
+        "REL_FK_used-antennaCapability": "AntennaCapability_1"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one3.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one3.json
new file mode 100644
index 0000000..bbe2ca7
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one3.json
@@ -0,0 +1,13 @@
+{
+    "entity_map_NRSectorCarrier_1": {
+        "id": "NRSectorCarrier_1"
+    },
+    "entity_map_AntennaCapability_1": {
+        "id": "AntennaCapability_1"
+    },
+    "relation_map_NRSC_AC_1": {
+        "REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY": "relation_1",
+        "id": "NRSectorCarrier_1",
+        "REL_FK_used-antennaCapability": "AntennaCapability_1"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one5.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one5.json
new file mode 100644
index 0000000..6c49856
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-many-to-one5.json
@@ -0,0 +1,14 @@
+{
+    "entity_map_AntennaCapability_2": {
+        "id": "AntennaCapability_2",
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873820",
+            "resourceIdentifier": "/o-ran-smo-ComTop:NodeCluster[@id=2]"
+        }
+    },
+    "relation_map_NRSC_AC_2": {
+        "REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY": "relation_2",
+        "id": "NRSectorCarrier_2",
+        "REL_FK_used-antennaCapability": "AntennaCapability_2"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-one-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-one-to-one.json
new file mode 100644
index 0000000..aeb6ab3
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-one-to-one.json
@@ -0,0 +1,18 @@
+{
+    "entity_map_CNS_1": {
+        "id": "CloudNativeSystem_2"
+    },
+    "entity_map_ME_1": {
+        "id": "ManagedElement_2",
+        "REL_FK_deployed-as-cloudNativeSystem": "CloudNativeSystem_2",
+        "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": "relation_11"
+    },
+    "entity_map_CNS_2": {
+        "id": "CloudNativeSystem_3"
+    },
+    "entity_map_ME_2": {
+        "id": "ManagedElement_3",
+        "REL_FK_deployed-as-cloudNativeSystem": "CloudNativeSystem_3",
+        "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": "relation_12"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-second-case.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-second-case.json
new file mode 100644
index 0000000..8e8a229
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-create-second-case.json
@@ -0,0 +1,169 @@
+{
+    "entity_map_CNA_1": {
+        "id": "CloudNativeApplication_1",
+        "name": "Test_CloudNativeApplication_1"
+    },
+    "entity_map_CNA_2": {
+        "id": "CloudNativeApplication_2",
+        "name": "Test_CloudNativeApplication_2"
+    },
+    "entity_map_CNA_3": {
+        "id": "CloudNativeApplication_3",
+        "name": "Test_CloudNativeApplication_3"
+    },
+    "entity_map_CNA_4": {
+        "id": "CNA_SED_1",
+        "name": "CNA_1"
+    },
+    "entity_map_GNBDU_1": {
+        "id": "GNBDU_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction[@id=1]",
+        "dUpLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "gNBDUId": 12,
+        "gNBId": 1234,
+        "gNBIdLength": 4,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBDU_2": {
+        "id": "GNBDU_SED_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00009,ManagedElement=NR01gNodeBRadio00009,GNBDUFunction=1",
+        "dUpLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "gNBDUId": 111,
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1929103B15999999",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00009]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBCUUP_1": {
+        "id": "GNBCUUP_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUUPFunction=1",
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUUPFunction]/o-ran-smo-GNBCUUP:GNBCUUPFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBCUCP_1": {
+        "id": "GNBCUCP_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUCPFunction=1",
+        "gNBCUName": "Test_gNBCU",
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "pLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUCPFunction]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBCUCP_2": {
+        "id": "GNBCUCP_SED_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00009,ManagedElement=NR01gNodeBRadio00009,GNBCUCPFunction=1",
+        "gNBCUName": "Test_sed_gNBCU",
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "pLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1929103B15999999",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00009]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]"
+        }
+    },
+    "entity_map_NRCellDU_1": {
+        "id": "NRCellDU_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=1",
+        "cellLocalId": 4589,
+        "nCI": 1,
+        "nRPCI": 12,
+        "nRTAC": 310,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_1]/o-ran-smo-NRCellDU:NRCellDU[@id=1]"
+        }
+    },
+    "entity_map_NRCellDU_2": {
+        "id": "NRCellDU_2",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=2",
+        "cellLocalId": 45891,
+        "nCI": 2,
+        "nRPCI": 121,
+        "nRTAC": 3101,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_2]/o-ran-smo-NRCellDU:NRCellDU[@id=2]"
+        }
+    },
+    "entity_map_NRCellDU_3": {
+        "id": "NRCellDU_3",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=3",
+        "cellLocalId": 469,
+        "nCI": 3,
+        "nRPCI": 15,
+        "nRTAC": 301,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_3]/o-ran-smo-NRCellDU:NRCellDU[@id=3]"
+        }
+    },
+    "relation_map_GNBDU_CNA_1": {
+        "id": "relation_1",
+        "aSide_GNBDUFunction": "GNBDU_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_1"
+    },
+    "relation_map_GNBCUUP_CNA_2": {
+        "id": "relation_2",
+        "aSide_GNBCUUPFunction": "GNBCUUP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_2"
+    },
+    "relation_map_GNBCUCP_CNA_3": {
+        "id": "relation_3",
+        "aSide_GNBCUCPFunction": "GNBCUCP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_3"
+    },
+    "relation_map_GNBDU_CNA_4": {
+        "id": "relation_4",
+        "aSide_GNBDUFunction": "GNBDU_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_2"
+    },
+    "relation_map_GNBCUUP_CNA_5": {
+        "id": "relation_5",
+        "aSide_GNBCUUPFunction": "GNBCUUP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_3"
+    },
+    "relation_map_GNBCUCP_CNA_6": {
+        "id": "relation_6",
+        "aSide_GNBCUCPFunction": "GNBCUCP_1",
+        "bSide_CloudNativeApplication": "CloudNativeApplication_1"
+    },
+    "relation_map_GNBDU_NRCellDU_1": {
+        "id": "NRCellDU_1",
+        "REL_FK_provided-by-gnbduFunction": "GNBDU_1",
+        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU": "relation_7"
+    },
+    "relation_map_GNBDU_NRCellDU_2": {
+        "id": "NRCellDU_2",
+        "REL_FK_provided-by-gnbduFunction": "GNBDU_1",
+        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU": "relation_8"
+    },
+    "relation_map_GNBDU_NRCellDU_3": {
+        "id": "NRCellDU_3",
+        "REL_FK_provided-by-gnbduFunction": "GNBDU_1",
+        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU": "relation_9"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-delete-one-to-one.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-delete-one-to-one.json
new file mode 100644
index 0000000..daad7a1
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-delete-one-to-one.json
@@ -0,0 +1,15 @@
+{
+    "entity_map_CNS_1": {
+        "id": "CloudNativeSystem_2",
+        "REL_FK_deployed-managedElement": null
+    },
+    "entity_map_CNS_2": {
+        "id": "CloudNativeSystem_3",
+        "REL_FK_deployed-managedElement": null
+    },
+    "entity_map_ME_2": {
+        "id": "ManagedElement_3",
+        "REL_FK_deployed-as-cloudNativeSystem": null,
+        "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": null
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-merge-one-to-many.json b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-merge-one-to-many.json
new file mode 100644
index 0000000..c889cf2
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/end-to-end/expected-results/db/exp-merge-one-to-many.json
@@ -0,0 +1,150 @@
+{
+    "entity_map_CNA_1": {
+        "id": "CloudNativeApplication_1",
+        "name": "Test_CloudNativeApplication_1"
+    },
+    "entity_map_CNA_2": {
+        "id": "CloudNativeApplication_2",
+        "name": "Test_CloudNativeApplication_2"
+    },
+    "entity_map_CNA_3": {
+        "id": "CloudNativeApplication_3",
+        "name": "Test_CloudNativeApplication_3"
+    },
+    "entity_map_GNBDU_1": {
+        "id": "GNBDU_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,MeContext=NR01gNodeBRadio00001,ManagedElement=NR01gNodeBRadio00001,GNBDUFunction[@id=1]",
+        "dUpLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "gNBDUId": 12,
+        "gNBId": 1234,
+        "gNBIdLength": 4,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NR01gNodeBRadio00001]/o-ran-smo-GNBDU:GNBDUFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBCUUP_1": {
+        "id": "GNBCUUP_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUUPFunction=1",
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUUPFunction]/o-ran-smo-GNBCUUP:GNBCUUPFunction[@id=1]"
+        }
+    },
+    "entity_map_GNBCUCP_1": {
+        "id": "GNBCUCP_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,GNBCUCPFunction=1",
+        "gNBCUName": "Test_gNBCU",
+        "gNBId": 123,
+        "gNBIdLength": 3,
+        "pLMNId": {
+            "mcc": "110",
+            "mnc": "210"
+        },
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=GNBCUCPFunction]/o-ran-smo-GNBCUCP:GNBCUCPFunction[@id=1]"
+        }
+    },
+    "entity_map_NRCellDU_1": {
+        "id": "NRCellDU_1",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=1",
+        "cellLocalId": 4589,
+        "nCI": 1,
+        "nRPCI": 12,
+        "nRTAC": 310,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_1]/o-ran-smo-NRCellDU:NRCellDU[@id=1]"
+        }
+    },
+    "entity_map_NRCellDU_2": {
+        "id": "NRCellDU_2",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=2",
+        "cellLocalId": 45891,
+        "nCI": 2,
+        "nRPCI": 121,
+        "nRTAC": 3101,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_2]/o-ran-smo-NRCellDU:NRCellDU[@id=2]"
+        }
+    },
+    "entity_map_NRCellDU_3": {
+        "id": "NRCellDU_3",
+        "fdn": "SubNetwork=Europe,SubNetwork=Ireland,NRCellDU=3",
+        "cellLocalId": 469,
+        "nCI": 3,
+        "nRPCI": 15,
+        "nRTAC": 301,
+        "cmId": {
+            "cmHandle": "395221E080CCF0FD1924103B15873814",
+            "resourceIdentifier": "/o-ran-smo-ComTop:ManagedElement[@id=NRCellDU_3]/o-ran-smo-NRCellDU:NRCellDU[@id=3]"
+        }
+    },
+    "relation_map_GNBDU_CNA_1": {
+        "id": "relation_1",
+        "gnbdufunction": "GNBDU_1",
+        "cloudnativeapplication": "CloudNativeApplication_1"
+    },
+    "relation_map_GNBCUUP_CNA_2": {
+        "id": "relation_2",
+        "gnbcuupfunction": "GNBCUUP_1",
+        "cloudnativeapplication": "CloudNativeApplication_2"
+    },
+    "relation_map_GNBCUCP_CNA_3": {
+        "id": "relation_3",
+        "gnbcucpfunction": "GNBCUCP_1",
+        "cloudnativeapplication": "CloudNativeApplication_3"
+    },
+    "relation_map_GNBDU_CNA_4": {
+        "id": "relation_4",
+        "gnbdufunction": "GNBDU_1",
+        "cloudnativeapplication": "CloudNativeApplication_2"
+    },
+    "relation_map_GNBCUUP_CNA_5": {
+        "id": "relation_5",
+        "gnbcuupfunction": "GNBCUUP_1",
+        "cloudnativeapplication": "CloudNativeApplication_3"
+    },
+    "relation_map_GNBCUCP_CNA_6": {
+        "id": "relation_6",
+        "gnbcucpfunction": "GNBCUCP_1",
+        "cloudnativeapplication": "CloudNativeApplication_1"
+    },
+    "relation_map_GNBDU_NRCellDU_1": {
+        "id": "NRCellDU_1",
+        "REL_FK_provided-by-gnbduFunction": "GNBDU_1",
+        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU": "relation_7"
+    },
+    "relation_map_GNBDU_NRCellDU_2": {
+        "id": "NRCellDU_2",
+        "REL_FK_provided-by-gnbduFunction": "GNBDU_1",
+        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU": "relation_8"
+    },
+    "relation_map_GNBDU_NRCellDU_3": {
+        "id": "NRCellDU_3",
+        "REL_FK_provided-by-gnbduFunction": "GNBDU_1",
+        "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU": "relation_9"
+    },
+    "relation_map_GNBDU_NRCellDU_REL_7": {
+        "id": "relation_7",
+        "gnbdufunction": "GNBDU_1",
+        "nrcelldu": "NRCellDU_1"
+    },
+    "relation_map_GNBDU_NRCellDU_REL_8": {
+        "id": "relation_8",
+        "gnbdufunction": "GNBDU_1",
+        "nrcelldu": "NRCellDU_2"
+    },
+    "relation_map_GNBDU_NRCellDU_REL_9": {
+        "id": "relation_9",
+        "gnbdufunction": "GNBDU_1",
+        "nrcelldu": "NRCellDU_3"
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one.json
new file mode 100644
index 0000000..df95133
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one.json
@@ -0,0 +1,41 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-ran:AntennaCapability": [
+                {
+                    "id": "AntennaCapability_1",
+                    "attributes": {
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873820",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:NodeCluster[@id=2]"
+                        }
+                    }
+                }
+            ],
+            "o-ran-smo-teiv-ran:NRSectorCarrier": [
+                {
+                    "id": "NRSectorCarrier_1",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_1",
+                    "aSide": "NRSectorCarrier_1",
+                    "bSide": "AntennaCapability_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one2.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one2.json
new file mode 100644
index 0000000..524818d
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one2.json
@@ -0,0 +1,41 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-ran:AntennaCapability": [
+                {
+                    "id": "AntennaCapability_2",
+                    "attributes": {
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873820",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:NodeCluster[@id=2]"
+                        }
+                    }
+                }
+            ],
+            "o-ran-smo-teiv-ran:NRSectorCarrier": [
+                {
+                    "id": "NRSectorCarrier_2",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_1",
+                    "aSide": "NRSectorCarrier_2",
+                    "bSide": "AntennaCapability_2"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one3.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one3.json
new file mode 100644
index 0000000..1e82283
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one3.json
@@ -0,0 +1,33 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-ran:AntennaCapability": [
+                {
+                    "id": "AntennaCapability_2",
+                    "attributes": {
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873820",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:NodeCluster[@id=2]"
+                        }
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_2",
+                    "aSide": "NRSectorCarrier_1",
+                    "bSide": "AntennaCapability_2"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one4.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one4.json
new file mode 100644
index 0000000..402a2ae
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one4.json
@@ -0,0 +1,20 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_1",
+                    "aSide": "NRSectorCarrier_1",
+                    "bSide": "AntennaCapability_2"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one5.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one5.json
new file mode 100644
index 0000000..c3e131e
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one5.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-ran:NRSectorCarrier": [
+                {
+                    "id": "NRSectorCarrier_1",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_1",
+                    "aSide": "NRSectorCarrier_1",
+                    "bSide": "AntennaCapability_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one6.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one6.json
new file mode 100644
index 0000000..4404948
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one6.json
@@ -0,0 +1,33 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-ran:AntennaCapability": [
+                {
+                    "id": "AntennaCapability_1",
+                    "attributes": {
+                        "cmId": {
+                            "cmHandle": "395221E080CCF0FD1924103B15873820",
+                            "resourceIdentifier": "/o-ran-smo-ComTop:NodeCluster[@id=2]"
+                        }
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_1",
+                    "aSide": "NRSectorCarrier_1",
+                    "bSide": "AntennaCapability_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one7.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one7.json
new file mode 100644
index 0000000..35328aa
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one7.json
@@ -0,0 +1,20 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_1",
+                    "aSide": "NRSectorCarrier_1",
+                    "bSide": "AntennaCapability_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one8.json b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one8.json
new file mode 100644
index 0000000..7536b5e
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/many-to-one/ce-create-many-to-one8.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-ran:NRSectorCarrier": [
+                {
+                    "id": "NRSectorCarrier_2",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran:NRSECTORCARRIER_USES_ANTENNACAPABILITY": [
+                {
+                    "id": "Relation_ManyToOne_1",
+                    "aSide": "NRSectorCarrier_2",
+                    "bSide": "AntennaCapability_2"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many.json
new file mode 100644
index 0000000..81d6d14
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many.json
@@ -0,0 +1,38 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-oam:ManagedElement": [
+                {
+                    "id": "ManagedElement_1",
+                    "attributes": {
+
+                    }
+                }
+            ],
+            "o-ran-smo-teiv-cloud-to-logical:GNBCUCPFunction": [
+                {
+                    "id": "GNBCUCPFunction_1",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_1",
+                    "aSide": "ManagedElement_1",
+                    "bSide": "GNBCUCPFunction_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many2.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many2.json
new file mode 100644
index 0000000..836faff
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many2.json
@@ -0,0 +1,38 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-oam:ManagedElement": [
+                {
+                    "id": "ManagedElement_2",
+                    "attributes": {
+
+                    }
+                }
+            ],
+            "o-ran-smo-teiv-ran:GNBCUCPFunction": [
+                {
+                    "id": "GNBCUCPFunction_2",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_1",
+                    "aSide": "ManagedElement_2",
+                    "bSide": "GNBCUCPFunction_2"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many3.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many3.json
new file mode 100644
index 0000000..f966e80
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many3.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-oam:ManagedElement": [
+                {
+                    "id": "ManagedElement_2",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_2",
+                    "aSide": "ManagedElement_2",
+                    "bSide": "GNBCUCPFunction_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many4.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many4.json
new file mode 100644
index 0000000..fec6466
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many4.json
@@ -0,0 +1,20 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_1",
+                    "aSide": "ManagedElement_2",
+                    "bSide": "GNBCUCPFunction_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many5.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many5.json
new file mode 100644
index 0000000..c174ad9
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many5.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-cloud-to-ran:GNBCUCPFunction": [
+                {
+                    "id": "GNBCUCPFunction_1",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_1",
+                    "aSide": "ManagedElement_1",
+                    "bSide": "GNBCUCPFunction_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many6.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many6.json
new file mode 100644
index 0000000..5929e58
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many6.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-oam:ManagedElement": [
+                {
+                    "id": "ManagedElement_1",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_1",
+                    "aSide": "ManagedElement_1",
+                    "bSide": "GNBCUCPFunction_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many7.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many7.json
new file mode 100644
index 0000000..36c989d
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many7.json
@@ -0,0 +1,20 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_1",
+                    "aSide": "ManagedElement_1",
+                    "bSide": "GNBCUCPFunction_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many8.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many8.json
new file mode 100644
index 0000000..c7625d1
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-many/ce-create-one-to-many8.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-cloud-to-ran:GNBCUCPFunction": [
+                {
+                    "id": "GNBCUCPFunction_2",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION": [
+                {
+                    "id": "Relation_OneToMany_1",
+                    "aSide": "ManagedElement_2",
+                    "bSide": "GNBCUCPFunction_2"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one.json
new file mode 100644
index 0000000..d8433c3
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one.json
@@ -0,0 +1,44 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-oam:ManagedElement": [
+                    {
+                        "id": "ManagedElement_O2O_1",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudNativeSystem": [
+                    {
+                        "id": "CloudNativeSystem_1",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                    {
+                        "id": "Relation_OneToOne_1",
+                        "aSide": "ManagedElement_O2O_1",
+                        "bSide": "CloudNativeSystem_1"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one2.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one2.json
new file mode 100644
index 0000000..3e12fed
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one2.json
@@ -0,0 +1,44 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": [
+            {
+                "o-ran-smo-teiv-oam:ManagedElement": [
+                    {
+                        "id": "ManagedElement_O2O_2",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            },
+            {
+                "o-ran-smo-teiv-cloud:CloudNativeSystem": [
+                    {
+                        "id": "CloudNativeSystem_2",
+                        "attributes": {
+
+                        }
+                    }
+                ]
+            }
+        ],
+        "relationships": [
+            {
+                "o-ran-smo-teiv-oam-to-cloud:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                    {
+                        "id": "Relation_OneToOne_1",
+                        "aSide": "ManagedElement_O2O_2",
+                        "bSide": "CloudNativeSystem_2"
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one3.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one3.json
new file mode 100644
index 0000000..495a9e6
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one3.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-oam:ManagedElement": [
+                {
+                    "id": "ManagedElement_O2O_2",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                {
+                    "id": "Relation_OneToOne_2",
+                    "aSide": "ManagedElement_O2O_2",
+                    "bSide": "CloudNativeSystem_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one4.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one4.json
new file mode 100644
index 0000000..7504f91
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one4.json
@@ -0,0 +1,20 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                {
+                    "id": "Relation_OneToOne_1",
+                    "aSide": "ManagedElement_O2O_2",
+                    "bSide": "CloudNativeSystem_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one5.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one5.json
new file mode 100644
index 0000000..e87aaaa
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one5.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-cloud:CloudNativeSystem": [
+                {
+                    "id": "CloudNativeSystem_1",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                {
+                    "id": "Relation_OneToOne_1",
+                    "aSide": "ManagedElement_O2O_1",
+                    "bSide": "CloudNativeSystem_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one6.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one6.json
new file mode 100644
index 0000000..2151339
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one6.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-oam:ManagedElement": [
+                {
+                    "id": "ManagedElement_O2O_1",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-ran-oam-to-ran:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                {
+                    "id": "Relation_OneToOne_1",
+                    "aSide": "ManagedElement_1",
+                    "bSide": "CloudNativeSystem_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one7.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one7.json
new file mode 100644
index 0000000..552e334
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one7.json
@@ -0,0 +1,20 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "relationships": {
+            "o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                {
+                    "id": "Relation_OneToOne_1",
+                    "aSide": "ManagedElement_O2O_1",
+                    "bSide": "CloudNativeSystem_1"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one8.json b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one8.json
new file mode 100644
index 0000000..e4f46f6
--- /dev/null
+++ b/teiv/src/test/resources/cloudeventdata/validation/one-to-one/ce-create-one-to-one8.json
@@ -0,0 +1,30 @@
+{
+    "specversion": "1.0",
+    "id": "a30e63c9-d29e-46ff-b99a-b63ed83f0003",
+    "source": "dmi-plugin:nm-1",
+    "type": "ran-logical-topology.create",
+    "time": "2023-10-25T13:30:01Z",
+    "datacontenttype": "application/json",
+    "dataschema": "https://ties:8080/schemas/v1/r1-topology",
+    "data": {
+        "entities": {
+            "o-ran-smo-teiv-cloud:CloudNativeSystem": [
+                {
+                    "id": "CloudNativeSystem_2",
+                    "attributes": {
+
+                    }
+                }
+            ]
+        },
+        "relationships": {
+            "o-ran-smo-teiv-oam-to-ran:MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM": [
+                {
+                    "id": "Relation_OneToOne_1",
+                    "aSide": "ManagedElement_O2O_2",
+                    "bSide": "CloudNativeSystem_2"
+                }
+            ]
+        }
+    }
+}
diff --git a/teiv/src/test/resources/contracts/ran/GNBDUFunction/getAllRelationships.groovy b/teiv/src/test/resources/contracts/ran/GNBDUFunction/getAllRelationships.groovy
new file mode 100644
index 0000000..2b78695
--- /dev/null
+++ b/teiv/src/test/resources/contracts/ran/GNBDUFunction/getAllRelationships.groovy
@@ -0,0 +1,87 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package contracts.ran.GNBDUFunction
+
+import org.springframework.cloud.contract.spec.Contract
+
+[
+    Contract.make {
+        description "SUCCESS - 200: Get a list of all relationships for GNBDUFunction 1"
+        request {
+            method GET()
+            url "/topology-inventory/v1alpha11/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D1/relationships?offset=0&limit=100"
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/json')
+            }
+            body('''{
+    "items": [
+        {
+            "o-ran-smo-teiv-ran:GNBDUFUNCTION_PROVIDES_NRCELLDU": [
+                {
+                    "id": "urn:sha512:R05CRFVGdW5jdGlvbjpTdWJOZXR3b3JrPUV1cm9wZSxTdWJOZXR3",
+                    "aSide": "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1",
+                    "bSide": "urn:3gpp:dn:ManagedElement=1,GNBDUFunction=1,NRCellDU=1",
+                    "decorators": {
+                        "location": "Stockholm"
+                    },
+                    "classifiers": [
+                        "Rural"
+                    ],
+                    "sourceIds": [],
+                    "metadata": {
+                        "trustLevel": "RELIABLE"
+                    }
+                }
+            ]
+        }
+    ],
+    "self": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100"
+    },
+    "first": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100"
+    },
+    "prev": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100"
+    },
+    "next": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100"
+    },
+    "last": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FManagedElement%3D1%2FGNBDUFunction%3D1/relationships?offset=0&limit=100"
+    }
+}''')
+        }
+    },
+    Contract.make {
+        description "BAD_REQUEST - 400: Get a list of all relationships for an unknown objectType"
+        request {
+            method GET()
+            url "/topology-inventory/v1alpha11/domains/RAN/entity-types/5GCell/entities/R05CRFVGdW5jdGlvbg/relationships?offset=1&limit=100"
+        }
+        response {
+            status BAD_REQUEST()
+        }
+    }
+]
diff --git a/teiv/src/test/resources/contracts/ran/GNBDUFunction/getTopologyById.groovy b/teiv/src/test/resources/contracts/ran/GNBDUFunction/getTopologyById.groovy
new file mode 100644
index 0000000..07f37dc
--- /dev/null
+++ b/teiv/src/test/resources/contracts/ran/GNBDUFunction/getTopologyById.groovy
@@ -0,0 +1,128 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package contracts.ran.GNBDUFunction
+
+import org.springframework.cloud.contract.spec.Contract
+
+[
+    Contract.make {
+        description "SUCCESS - 200: Get topology for object type by GNBDUFunction 1"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D1")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/yang.data+json')
+            }
+            body('''{
+    "o-ran-smo-teiv-ran:GNBDUFunction": [
+        {
+            "id": "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1",
+            "attributes": {
+                "gNBId": 1,
+                "gNBDUId": 1,
+                "gNBIdLength": 2,
+                "dUpLMNId": {
+                    "mcc": "110",
+                    "mnc": "210"
+                }
+            },
+            "decorators": {
+                "location": "Stockholm"
+            },
+            "classifiers": [
+                "Rural"
+            ],
+            "sourceIds": [
+                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1"
+            ],
+            "metadata": {
+                "trustLevel": "RELIABLE"
+            }
+        }
+    ]
+}''')
+        }
+    },
+    Contract.make {
+        description "SUCCESS - 200: Get topology for object type by GNBDUFunction 2"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D2")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/yang.data+json')
+            }
+            body('''{
+    "o-ran-smo-teiv-ran:GNBDUFunction": [
+        {
+            "id": "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=2",
+            "attributes": {
+                "gNBId": 2,
+                "gNBDUId": 2,
+                "gNBIdLength": 2,
+                "dUpLMNId": {
+                    "mcc": "110",
+                    "mnc": "210"
+                }
+            },
+            "decorators": {
+                "location": "Stockholm"
+            },
+            "classifiers": [
+                "Rural"
+            ],
+            "sourceIds": [
+                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=2"
+            ],
+            "metadata": {
+                "trustLevel": "RELIABLE"
+            }
+        }
+    ]
+}''')
+        }
+    },
+    Contract.make {
+        description "NOT_FOUND - 404: Get unknown for object type by GNBDUFunction 1"
+        request {
+            method GET()
+            url "/ties/v1alpha11/domains/RAN/entity-types/GNBDUFunction/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D1"
+        }
+        response {
+            status NOT_FOUND()
+        }
+    },
+    Contract.make {
+        description "BAD_REQUEST - 400: Get topology for unknown object type by GNBDUFunction 1"
+        request {
+            method GET()
+            url "/topology-inventory/v1alpha11/domains/RAN/entity-types/GBFunction/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio00001%2FGNBDUFunction%3D1"
+        }
+        response {
+            status BAD_REQUEST()
+        }
+    }
+]
diff --git a/teiv/src/test/resources/contracts/ran/GNBDUFunction/getTopologyByType.groovy b/teiv/src/test/resources/contracts/ran/GNBDUFunction/getTopologyByType.groovy
new file mode 100644
index 0000000..e8426b5
--- /dev/null
+++ b/teiv/src/test/resources/contracts/ran/GNBDUFunction/getTopologyByType.groovy
@@ -0,0 +1,162 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package contracts.ran.GNBDUFunction
+
+import org.springframework.cloud.contract.spec.Contract
+
+[
+    /**************************
+     * 'targetFilter' query parameter
+     ***************************/
+    Contract.make {
+        description "SUCCESS - 200: Get topology for GNBDUFunction using 'targetFilter' query parameter"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/json')
+            }
+            body('''{
+    "items": [
+        {
+            "o-ran-smo-teiv-ran:GNBDUFunction": [
+                {
+                    "id": "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1",
+                    "attributes": {
+                        "gNBDUId": 1
+                    },
+                    "metadata": {
+                        "trustLevel": "RELIABLE"
+                    }
+                }
+            ]
+        }
+    ],
+    "self": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50"
+    },
+    "first": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50"
+    },
+    "prev": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50"
+    },
+    "next": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50"
+    },
+    "last": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&offset=0&limit=50"
+    }
+}''')
+        }
+    },
+    Contract.make {
+        description "NOT_FOUND - 404: Get topology for GNBDUFunction using unknown 'targetFilter' query parameter"
+        request {
+            method GET()
+            url "/ties/v1alpha11/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2F%2FGNBDUFunction&offset=1&limit=100"
+        }
+        response {
+            status NOT_FOUND()
+        }
+    },
+    Contract.make {
+        description "BAD_REQUEST - 400: The provided request is not valid"
+        request {
+            method GET()
+            url "/topology-inventory/v1alpha11/domains/RAN/entity-types/GNBBUFunction/entities?targetFilter=%2F%2FGNBBUFunction&offset=1&limit=100"
+        }
+        response {
+            status BAD_REQUEST()
+        }
+    },
+    /***************************************
+     * 'targetFilter' and 'scopeFilter' query parameter
+     ****************************************/
+    Contract.make {
+        description "SUCCESS - 200: Get topology for GNBDUFunction using 'targetFilter' and 'scopeFilter' query parameter"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/json')
+            }
+            body('''{
+    "items": [
+        {
+            "o-ran-smo-teiv-ran:GNBDUFunction": [
+                {
+                    "id": "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1",
+                    "attributes": {
+                        "gNBDUId": 1
+                    },
+                    "metadata": {
+                        "trustLevel": "RELIABLE"
+                    }
+                }
+            ]
+        }
+    ],
+    "self": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100"
+    },
+    "first": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100"
+    },
+    "prev": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100"
+    },
+    "next": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100"
+    },
+    "last": {
+        "href": "/domains/RAN/entity-types/GNBDUFunction/entities?targetFilter=%2Fattributes(gNBDUId)&scopeFilter=%2Fattributes[@gNBDUId=1]&offset=0&limit=100"
+    }
+}''')
+        }
+    },
+    Contract.make {
+        description "NOT_FOUND - 404: Get unknown for GNBCUCPFunction using 'targetFilter' and 'scopeFilter' query parameter"
+        request {
+            method GET()
+            url "/ties/v1alpha11/domains/RAN/entity-type/GNBDUFunction/entities?targetFilter=%2F%2FGNBDUFunction&scopeFilter=%2F%2FNRCellDU%2FnRTAC%3D50&offset=1&limit=100"
+        }
+        response {
+            status NOT_FOUND()
+        }
+    },
+    Contract.make {
+        description "BAD_REQUEST - 400: The provided request is not valid"
+        request {
+            method GET()
+            url "/topology-inventory/v1alpha11/domains/RAN/entity-types/GNBBUFunction/entities?targetFilter=%2F%2FGNBDUFunction&scopeFilter=%2F%2FNRCellDU%2FnRTAC%3D50&offset=1&limit=100"
+        }
+        response {
+            status BAD_REQUEST()
+        }
+    }
+]
diff --git a/teiv/src/test/resources/contracts/ran/NRCellDU/getTopologyById.groovy b/teiv/src/test/resources/contracts/ran/NRCellDU/getTopologyById.groovy
new file mode 100644
index 0000000..20f1580
--- /dev/null
+++ b/teiv/src/test/resources/contracts/ran/NRCellDU/getTopologyById.groovy
@@ -0,0 +1,122 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package contracts.ran.NRCellDU
+
+import org.springframework.cloud.contract.spec.Contract
+
+[
+    Contract.make {
+        description "SUCCESS - 200: Get topology for object type by NRCellDU 1"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/domains/RAN/entity-types/NRCellDU/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio%2FGNBDUFunction%3D1%2FNRCellDU%3D1")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/yang.data+json')
+            }
+            body('''{
+    "o-ran-smo-teiv-ran:NRCellDU": [
+        {
+            "id": "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=1",
+            "attributes": {
+                "cellLocalId": 91,
+                "nCI": 1,
+                "nRPCI": 35,
+                "nRTAC": 50
+            },
+            "decorators": {
+                "location": "Stockholm"
+            },
+            "classifiers": [
+                "Rural"
+            ],
+            "sourceIds": [
+                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=1"
+            ],
+            "metadata": {
+                "trustLevel": "RELIABLE"
+            }
+        }
+    ]
+}''')
+        }
+    },
+    Contract.make {
+        description "SUCCESS - 200: Get topology for object type by NRCellDU 2"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/domains/RAN/entity-types/NRCellDU/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio%2FGNBDUFunction%3D1%2FNRCellDU%3D2")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/yang.data+json')
+            }
+            body('''{
+    "o-ran-smo-teiv-ran:NRCellDU": [
+        {
+            "id": "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=2",
+            "attributes": {
+                "cellLocalId": 95,
+                "nCI": 5,
+                "nRPCI": 35,
+                "nRTAC": 50
+            },
+            "decorators": {
+                "location": "Stockholm"
+            },
+            "classifiers": [
+                "Rural"
+            ],
+            "sourceIds": [
+                "urn:3gpp:dn:MeContext=NR01,ManagedElement=NR01gNodeBRadio,GNBDUFunction=1,NRCellDU=2"
+            ],
+            "metadata": {
+                "trustLevel": "RELIABLE"
+            }
+        }
+    ]
+}''')
+        }
+    },
+    Contract.make {
+        description "NOT_FOUND - 404: Get unknown for object type by NRCellDU 1"
+        request {
+            method GET()
+            url "/ties/v1alpha11/domains/RAN/entity-types/NRCellDU/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio%2FGNBDUFunction%3D1%2FNRCellDU%3D1"
+        }
+        response {
+            status NOT_FOUND()
+        }
+    },
+    Contract.make {
+        description "BAD_REQUEST - 400: Get topology for unknown object type by NRCellDU 1"
+        request {
+            method GET()
+            url "/topology-inventory/v1alpha11/domains/RAN/entity-types/NRDU/entities/urn%3A3gpp%3Adn%3A%2FMeContext%3DNR01%2FManagedElement%3DNR01gNodeBRadio%2FGNBDUFunction%3D1%2FNRCellDU%3D1"
+        }
+        response {
+            status BAD_REQUEST()
+        }
+    }
+]
diff --git a/teiv/src/test/resources/contracts/ran/schemas/getAllSchemas.groovy b/teiv/src/test/resources/contracts/ran/schemas/getAllSchemas.groovy
new file mode 100644
index 0000000..edc2ccb
--- /dev/null
+++ b/teiv/src/test/resources/contracts/ran/schemas/getAllSchemas.groovy
@@ -0,0 +1,68 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package contracts.ran.schemas
+import org.springframework.cloud.contract.spec.Contract
+
+[
+    Contract.make {
+        description "SUCCESS - 200: Get a list of all schemas"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/schemas?offset=0&limit=100")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/json')
+            }
+            body('''{
+    "items": [
+        {
+            "name": "o-ran-smo-teiv-cloud-to-ran",
+            "domain": [
+                "RAN",
+                "CLOUD"
+            ],
+            "revision": "2023-06-26",
+            "content": {
+                "href": "/schemas/o-ran-smo-teiv-cloud-to-ran/content"
+            }
+        }
+    ],
+    "self": {
+        "href": "/schemas?offset=0&limit=100"
+    },
+    "first": {
+        "href": "/schemas?offset=0&limit=100"
+    },
+    "prev": {
+        "href": "/schemas?offset=0&limit=100"
+    },
+    "next": {
+        "href": "/schemas?offset=0&limit=100"
+    },
+    "last": {
+        "href": "/schemas?offset=0&limit=100"
+    }
+}''')
+        }
+    }
+]
diff --git a/teiv/src/test/resources/contracts/ran/schemas/getSchemaByName.groovy b/teiv/src/test/resources/contracts/ran/schemas/getSchemaByName.groovy
new file mode 100644
index 0000000..9aba34a
--- /dev/null
+++ b/teiv/src/test/resources/contracts/ran/schemas/getSchemaByName.groovy
@@ -0,0 +1,40 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package contracts.ran.schemas
+
+import org.springframework.cloud.contract.spec.Contract
+
+[
+    Contract.make {
+        description "SUCCESS - 200: Get schema with name o-ran-smo-teiv-cloud-to-ran"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/schemas/o-ran-smo-teiv-cloud-to-ran/content")
+        }
+        response {
+            body("module o-ran-smo-teiv-cloud-to-ran { yang-version 1.1; }")
+            status OK()
+            headers {
+                contentType('text/plain')
+            }
+        }
+    }
+]
diff --git a/teiv/src/test/resources/contracts/ran/schemas/getSchemasInDomain.groovy b/teiv/src/test/resources/contracts/ran/schemas/getSchemasInDomain.groovy
new file mode 100644
index 0000000..2de7c73
--- /dev/null
+++ b/teiv/src/test/resources/contracts/ran/schemas/getSchemasInDomain.groovy
@@ -0,0 +1,99 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package contracts.ran.schemas
+import org.springframework.cloud.contract.spec.Contract
+
+[
+    Contract.make {
+        description "SUCCESS - 200: Get a list of all schemas in RAN domain"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/schemas?domain=RAN&offset=0&limit=8")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/json')
+            }
+            body('''{
+    "items": [
+        {
+            "name": "o-ran-smo-teiv-cloud-to-ran",
+            "domain": [
+                "RAN",
+                "CLOUD"
+            ],
+            "revision": "2023-06-26",
+            "content": {
+                "href": "/schemas/o-ran-smo-teiv-cloud-to-ran/content"
+            }
+        }
+    ],
+    "self": {
+        "href": "/schemas?domain=RAN&offset=0&limit=8"
+    },
+    "first": {
+        "href": "/schemas?domain=RAN&offset=0&limit=8"
+    },
+    "prev": {
+        "href": "/schemas?domain=RAN&offset=0&limit=8"
+    },
+    "next": {
+        "href": "/schemas?domain=RAN&offset=0&limit=8"
+    },
+    "last": {
+        "href": "/schemas?domain=RAN&offset=0&limit=8"
+    }
+}''')
+        }
+    },
+    Contract.make {
+        description "SUCCESS - Get list of all schemas in unknown domain"
+        request {
+            method GET()
+            url("/topology-inventory/v1alpha11/schemas?domain=LOGICAL")
+        }
+        response {
+            status OK()
+            headers {
+                contentType('application/json')
+            }
+            body('''{
+    "items": [],
+    "self": {
+        "href": "/schemas?domain=LOGICAL&offset=0&limit=500"
+    },
+    "first": {
+        "href": "/schemas?domain=LOGICAL&offset=0&limit=500"
+    },
+    "prev": {
+        "href": "/schemas?domain=LOGICAL&offset=0&limit=500"
+    },
+    "next": {
+        "href": "/schemas?domain=LOGICAL&offset=0&limit=500"
+    },
+    "last": {
+        "href": "/schemas?domain=LOGICAL&offset=0&limit=500"
+    }
+}''')
+        }
+    }
+]
diff --git a/teiv/src/test/resources/data/data-deprecated.sql b/teiv/src/test/resources/data/data-deprecated.sql
new file mode 100644
index 0000000..32c628c
--- /dev/null
+++ b/teiv/src/test/resources/data/data-deprecated.sql
@@ -0,0 +1,865 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+COPY ties_data."ManagedElement" (id, fdn) FROM stdin;
+45EF31D8A1FD624D7276390A1215BFC3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=1
+5BF1EECFD543243BE2C1BC52C7B484A0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=2
+23616B5A7FC56C146E3799DD7CA3B0C3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=3
+09ADB418B558918F8E858ECA77CAF22B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=4
+5F404149FF9EDF096764B00CC8D052A3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=5
+E1A1CA9D697DE4371C4014D587088498	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=6
+0DC59E39BAC5E54E5B646D346039C003	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=7
+E07B72DA5F4CD284C9A9EB5A6AE0D5AC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=8
+DA1039E77700A9EEFFA280049ECE9227	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=9
+6F02817AFE4D53237DB235EBE5378613	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=10
+0181BB891A56BBD886771EBA3A69F19A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=11
+1E113BF2E3ABD819E0FBC6C6128BEFE5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=12
+27500EB447000209EE6E3CA1B31FBA92	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=13
+06222D277EE209CD8DCA1FE61CE752E6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=14
+436C59D4065E5222414DAD697C8842D2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=15
+DC86CA7724113F4C0DF42BFEAA17FD53	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=16
+1F0B4F7CEC39A09ADC16EB8D787978E6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=17
+AEAFE291F1DE32DEFFF0073D297B7693	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=18
+8D51EFC759166044DACBCA63C4EDFC51	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=19
+5BCC1BC502B66423981F90A6EA8D157E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=20
+87812D4D8A6E7AD11694CF6D4815B5C7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=21
+577CA8F71FFC2FC3C39D93D0F28E47EC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=22
+E87AF3DB09EE273C6F153AA00D4D1171	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=23
+A73755B1422176B1169546D884BD9FCC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=24
+D76CCB4E654B2CF5D248196E9B9524AD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=25
+E7CEF72CB78163D1B26B8B2A7A39757A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=26
+E57C2A20E96A8C9E7099BAD60957B59A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=27
+E64371CD4D12ED0CED200DD3A7591784	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=28
+\.
+
+COPY ties_data."CloudSite" (id, "geo-location", name) FROM stdin;
+82AD1C754500A0512FBB57A738F15DE9	POINT(59.4019881 17.9419888)	ORAN
+D1E0DC52CF1A6A05C0B59A61A8217005	POINT(59.4019881 17.9419888)	ORAN
+C09038081DDD8B353CB2BFF554542D6F	POINT(59.4019881 17.9419888)	ORAN
+6B24CE7976414BBF5CC71D543F8AD0DD	POINT(59.4019881 17.9419888)	ORAN
+27871D75A71FEDB483F45CBD138A1323	POINT(59.4019881 17.9419888)	ORAN
+B2ED7B123B5733E2B03742988A64FD6B	POINT(59.4019881 17.9419888)	ORAN
+B240FE61456BDA8398C49FD8B562541F	POINT(59.4019881 17.9419888)	ORAN
+86353E518688D3CA4BB314BED0324003	POINT(59.4019881 17.9419888)	ORAN
+16EE17AE89DF11B69E94B3F6827C2C0E	POINT(59.4019881 17.9419888)	ORAN
+\.
+
+COPY ties_data."NodeCluster" (id, name, "REL_NODECLUSTER_LOCATED_AT_CLOUDSITE_EIID", "REL_NODECLUSTER_LOCATED_AT_CLOUDSITE") FROM stdin;
+3BFA0DD4B1C990F9E49FA4DB5C24FECD	Example NodeCluster/1	urn:base64:Tm9kZUNsdXN0ZXI6M0JGQTBERDRCMUM5OTBGOUU0OUZBNERCNUMyNEZFQ0Q6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODJBRDFDNzU0NTAwQTA1MTJGQkI1N0E3MzhGMTVERTk=	82AD1C754500A0512FBB57A738F15DE9
+1C3FB0A56E3FFFFEAC5DE407715ADDE6	Example NodeCluster/2	urn:base64:Tm9kZUNsdXN0ZXI6MUMzRkIwQTU2RTNGRkZGRUFDNURFNDA3NzE1QURERTY6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODJBRDFDNzU0NTAwQTA1MTJGQkI1N0E3MzhGMTVERTk=	82AD1C754500A0512FBB57A738F15DE9
+7FCF92B9827D67BF58138B16DBDC8249	Example NodeCluster/3	urn:base64:Tm9kZUNsdXN0ZXI6N0ZDRjkyQjk4MjdENjdCRjU4MTM4QjE2REJEQzgyNDk6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODJBRDFDNzU0NTAwQTA1MTJGQkI1N0E3MzhGMTVERTk=	82AD1C754500A0512FBB57A738F15DE9
+F6C0D9E3B2FEA197951D542042665BFD	Example NodeCluster/4	urn:base64:Tm9kZUNsdXN0ZXI6RjZDMEQ5RTNCMkZFQTE5Nzk1MUQ1NDIwNDI2NjVCRkQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODJBRDFDNzU0NTAwQTA1MTJGQkI1N0E3MzhGMTVERTk=	82AD1C754500A0512FBB57A738F15DE9
+0CA91F4FA7764AA056EA8F2F759A3305	Example NodeCluster/5	urn:base64:Tm9kZUNsdXN0ZXI6MENBOTFGNEZBNzc2NEFBMDU2RUE4RjJGNzU5QTMzMDU6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODJBRDFDNzU0NTAwQTA1MTJGQkI1N0E3MzhGMTVERTk=	82AD1C754500A0512FBB57A738F15DE9
+B6E895E10C7F1D8EEAE6808C7FAEACF1	Example NodeCluster/6	urn:base64:Tm9kZUNsdXN0ZXI6QjZFODk1RTEwQzdGMUQ4RUVBRTY4MDhDN0ZBRUFDRjE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6RDFFMERDNTJDRjFBNkEwNUMwQjU5QTYxQTgyMTcwMDU=	D1E0DC52CF1A6A05C0B59A61A8217005
+2042FF5409C9FA615811F92B1F14149D	Example NodeCluster/7	urn:base64:Tm9kZUNsdXN0ZXI6MjA0MkZGNTQwOUM5RkE2MTU4MTFGOTJCMUYxNDE0OUQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6RDFFMERDNTJDRjFBNkEwNUMwQjU5QTYxQTgyMTcwMDU=	D1E0DC52CF1A6A05C0B59A61A8217005
+E962ADB61C68FD1ACE07F83EA334F78D	Example NodeCluster/8	urn:base64:Tm9kZUNsdXN0ZXI6RTk2MkFEQjYxQzY4RkQxQUNFMDdGODNFQTMzNEY3OEQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6RDFFMERDNTJDRjFBNkEwNUMwQjU5QTYxQTgyMTcwMDU=	D1E0DC52CF1A6A05C0B59A61A8217005
+8A697137B4C22CC4E695328CD65EBD8E	Example NodeCluster/9	urn:base64:Tm9kZUNsdXN0ZXI6OEE2OTcxMzdCNEMyMkNDNEU2OTUzMjhDRDY1RUJEOEU6TE9DQVRFRF9BVDpDbG91ZFNpdGU6RDFFMERDNTJDRjFBNkEwNUMwQjU5QTYxQTgyMTcwMDU=	D1E0DC52CF1A6A05C0B59A61A8217005
+AA0464766269B073ABA3071C11ADA3F7	Example NodeCluster/10	urn:base64:Tm9kZUNsdXN0ZXI6QUEwNDY0NzY2MjY5QjA3M0FCQTMwNzFDMTFBREEzRjc6TE9DQVRFRF9BVDpDbG91ZFNpdGU6RDFFMERDNTJDRjFBNkEwNUMwQjU5QTYxQTgyMTcwMDU=	D1E0DC52CF1A6A05C0B59A61A8217005
+2C4DB604B5B43CB9DF25FC16E38C1D2E	Example NodeCluster/11	urn:base64:Tm9kZUNsdXN0ZXI6MkM0REI2MDRCNUI0M0NCOURGMjVGQzE2RTM4QzFEMkU6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QzA5MDM4MDgxREREOEIzNTNDQjJCRkY1NTQ1NDJENkY=	C09038081DDD8B353CB2BFF554542D6F
+CB85F0EFBF093300F010C902394C46F8	Example NodeCluster/12	urn:base64:Tm9kZUNsdXN0ZXI6Q0I4NUYwRUZCRjA5MzMwMEYwMTBDOTAyMzk0QzQ2Rjg6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QzA5MDM4MDgxREREOEIzNTNDQjJCRkY1NTQ1NDJENkY=	C09038081DDD8B353CB2BFF554542D6F
+12807C5AD5CB31F393B7C68649F0EF84	Example NodeCluster/13	urn:base64:Tm9kZUNsdXN0ZXI6MTI4MDdDNUFENUNCMzFGMzkzQjdDNjg2NDlGMEVGODQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QzA5MDM4MDgxREREOEIzNTNDQjJCRkY1NTQ1NDJENkY=	C09038081DDD8B353CB2BFF554542D6F
+54EE0DE8C9D5E252D805255B0BF58E41	Example NodeCluster/14	urn:base64:Tm9kZUNsdXN0ZXI6NTRFRTBERThDOUQ1RTI1MkQ4MDUyNTVCMEJGNThFNDE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QzA5MDM4MDgxREREOEIzNTNDQjJCRkY1NTQ1NDJENkY=	C09038081DDD8B353CB2BFF554542D6F
+7D2F0470FF10929C4B6D39DC6951DCB2	Example NodeCluster/15	urn:base64:Tm9kZUNsdXN0ZXI6N0QyRjA0NzBGRjEwOTI5QzRCNkQzOURDNjk1MURDQjI6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QzA5MDM4MDgxREREOEIzNTNDQjJCRkY1NTQ1NDJENkY=	C09038081DDD8B353CB2BFF554542D6F
+74636E2CF21AF96670DE0DBB5E2B90F1	Example NodeCluster/16	urn:base64:Tm9kZUNsdXN0ZXI6NzQ2MzZFMkNGMjFBRjk2NjcwREUwREJCNUUyQjkwRjE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6NkIyNENFNzk3NjQxNEJCRjVDQzcxRDU0M0Y4QUQwREQ=	6B24CE7976414BBF5CC71D543F8AD0DD
+8B12422C6BB2F246C612BE17E0058736	Example NodeCluster/17	urn:base64:Tm9kZUNsdXN0ZXI6OEIxMjQyMkM2QkIyRjI0NkM2MTJCRTE3RTAwNTg3MzY6TE9DQVRFRF9BVDpDbG91ZFNpdGU6NkIyNENFNzk3NjQxNEJCRjVDQzcxRDU0M0Y4QUQwREQ=	6B24CE7976414BBF5CC71D543F8AD0DD
+991F7BF0D7D8DF69688B7350F7D9F2E1	Example NodeCluster/18	urn:base64:Tm9kZUNsdXN0ZXI6OTkxRjdCRjBEN0Q4REY2OTY4OEI3MzUwRjdEOUYyRTE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6NkIyNENFNzk3NjQxNEJCRjVDQzcxRDU0M0Y4QUQwREQ=	6B24CE7976414BBF5CC71D543F8AD0DD
+6573EA8ED582F620FAD70B281DC47478	Example NodeCluster/19	urn:base64:Tm9kZUNsdXN0ZXI6NjU3M0VBOEVENTgyRjYyMEZBRDcwQjI4MURDNDc0Nzg6TE9DQVRFRF9BVDpDbG91ZFNpdGU6NkIyNENFNzk3NjQxNEJCRjVDQzcxRDU0M0Y4QUQwREQ=	6B24CE7976414BBF5CC71D543F8AD0DD
+552617FC00CF6ECA407ECCC723D3B243	Example NodeCluster/20	urn:base64:Tm9kZUNsdXN0ZXI6NTUyNjE3RkMwMENGNkVDQTQwN0VDQ0M3MjNEM0IyNDM6TE9DQVRFRF9BVDpDbG91ZFNpdGU6NkIyNENFNzk3NjQxNEJCRjVDQzcxRDU0M0Y4QUQwREQ=	6B24CE7976414BBF5CC71D543F8AD0DD
+61DAD3343C482495F9CBF9A1EF2020EA	Example NodeCluster/21	urn:base64:Tm9kZUNsdXN0ZXI6NjFEQUQzMzQzQzQ4MjQ5NUY5Q0JGOUExRUYyMDIwRUE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6Mjc4NzFENzVBNzFGRURCNDgzRjQ1Q0JEMTM4QTEzMjM=	27871D75A71FEDB483F45CBD138A1323
+207070CCC4BA41259CB15A6B0BB6F4F4	Example NodeCluster/22	urn:base64:Tm9kZUNsdXN0ZXI6MjA3MDcwQ0NDNEJBNDEyNTlDQjE1QTZCMEJCNkY0RjQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6Mjc4NzFENzVBNzFGRURCNDgzRjQ1Q0JEMTM4QTEzMjM=	27871D75A71FEDB483F45CBD138A1323
+5395111326D89044A150717321939D41	Example NodeCluster/23	urn:base64:Tm9kZUNsdXN0ZXI6NTM5NTExMTMyNkQ4OTA0NEExNTA3MTczMjE5MzlENDE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6Mjc4NzFENzVBNzFGRURCNDgzRjQ1Q0JEMTM4QTEzMjM=	27871D75A71FEDB483F45CBD138A1323
+084678E3BB0D6240078965404C74B6FF	Example NodeCluster/24	urn:base64:Tm9kZUNsdXN0ZXI6MDg0Njc4RTNCQjBENjI0MDA3ODk2NTQwNEM3NEI2RkY6TE9DQVRFRF9BVDpDbG91ZFNpdGU6Mjc4NzFENzVBNzFGRURCNDgzRjQ1Q0JEMTM4QTEzMjM=	27871D75A71FEDB483F45CBD138A1323
+7244579FE2C5F8DDD4525AA6839917EA	Example NodeCluster/25	urn:base64:Tm9kZUNsdXN0ZXI6NzI0NDU3OUZFMkM1RjhEREQ0NTI1QUE2ODM5OTE3RUE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6Mjc4NzFENzVBNzFGRURCNDgzRjQ1Q0JEMTM4QTEzMjM=	27871D75A71FEDB483F45CBD138A1323
+CD5E53D1750F210853FA38EE343B434C	Example NodeCluster/26	urn:base64:Tm9kZUNsdXN0ZXI6Q0Q1RTUzRDE3NTBGMjEwODUzRkEzOEVFMzQzQjQzNEM6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjJFRDdCMTIzQjU3MzNFMkIwMzc0Mjk4OEE2NEZENkI=	B2ED7B123B5733E2B03742988A64FD6B
+BB008AB249D485F90D558BEDFA7A6A29	Example NodeCluster/27	urn:base64:Tm9kZUNsdXN0ZXI6QkIwMDhBQjI0OUQ0ODVGOTBENTU4QkVERkE3QTZBMjk6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjJFRDdCMTIzQjU3MzNFMkIwMzc0Mjk4OEE2NEZENkI=	B2ED7B123B5733E2B03742988A64FD6B
+9C83FE039C3D4B947150A8C7E50846E2	Example NodeCluster/28	urn:base64:Tm9kZUNsdXN0ZXI6OUM4M0ZFMDM5QzNENEI5NDcxNTBBOEM3RTUwODQ2RTI6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjJFRDdCMTIzQjU3MzNFMkIwMzc0Mjk4OEE2NEZENkI=	B2ED7B123B5733E2B03742988A64FD6B
+180299E1533E0CB3B042512A96794E08	Example NodeCluster/29	urn:base64:Tm9kZUNsdXN0ZXI6MTgwMjk5RTE1MzNFMENCM0IwNDI1MTJBOTY3OTRFMDg6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjJFRDdCMTIzQjU3MzNFMkIwMzc0Mjk4OEE2NEZENkI=	B2ED7B123B5733E2B03742988A64FD6B
+A69CE50897277B7DA8EF138A7F9D5FC9	Example NodeCluster/30	urn:base64:Tm9kZUNsdXN0ZXI6QTY5Q0U1MDg5NzI3N0I3REE4RUYxMzhBN0Y5RDVGQzk6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjJFRDdCMTIzQjU3MzNFMkIwMzc0Mjk4OEE2NEZENkI=	B2ED7B123B5733E2B03742988A64FD6B
+38CE1C3DC2803C49DFDE0538CD645034	Example NodeCluster/31	urn:base64:Tm9kZUNsdXN0ZXI6MzhDRTFDM0RDMjgwM0M0OURGREUwNTM4Q0Q2NDUwMzQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjI0MEZFNjE0NTZCREE4Mzk4QzQ5RkQ4QjU2MjU0MUY=	B240FE61456BDA8398C49FD8B562541F
+1AF73F476CA8B4E7AC219D8109121290	Example NodeCluster/32	urn:base64:Tm9kZUNsdXN0ZXI6MUFGNzNGNDc2Q0E4QjRFN0FDMjE5RDgxMDkxMjEyOTA6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjI0MEZFNjE0NTZCREE4Mzk4QzQ5RkQ4QjU2MjU0MUY=	B240FE61456BDA8398C49FD8B562541F
+8D6BCDE855B4C31B5918FA7DFE26B34B	Example NodeCluster/33	urn:base64:Tm9kZUNsdXN0ZXI6OEQ2QkNERTg1NUI0QzMxQjU5MThGQTdERkUyNkIzNEI6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjI0MEZFNjE0NTZCREE4Mzk4QzQ5RkQ4QjU2MjU0MUY=	B240FE61456BDA8398C49FD8B562541F
+78E1E5E47D1B07B9E4DC0FB6A73BC572	Example NodeCluster/34	urn:base64:Tm9kZUNsdXN0ZXI6NzhFMUU1RTQ3RDFCMDdCOUU0REMwRkI2QTczQkM1NzI6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjI0MEZFNjE0NTZCREE4Mzk4QzQ5RkQ4QjU2MjU0MUY=	B240FE61456BDA8398C49FD8B562541F
+8C4711B835D99C1E3AA64259E4AA06A9	Example NodeCluster/35	urn:base64:Tm9kZUNsdXN0ZXI6OEM0NzExQjgzNUQ5OUMxRTNBQTY0MjU5RTRBQTA2QTk6TE9DQVRFRF9BVDpDbG91ZFNpdGU6QjI0MEZFNjE0NTZCREE4Mzk4QzQ5RkQ4QjU2MjU0MUY=	B240FE61456BDA8398C49FD8B562541F
+6EA78A3CAC43487D90F36348CD9C2178	Example NodeCluster/36	urn:base64:Tm9kZUNsdXN0ZXI6NkVBNzhBM0NBQzQzNDg3RDkwRjM2MzQ4Q0Q5QzIxNzg6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODYzNTNFNTE4Njg4RDNDQTRCQjMxNEJFRDAzMjQwMDM=	86353E518688D3CA4BB314BED0324003
+1EA071C4D492F58C098420D5B5893503	Example NodeCluster/37	urn:base64:Tm9kZUNsdXN0ZXI6MUVBMDcxQzRENDkyRjU4QzA5ODQyMEQ1QjU4OTM1MDM6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODYzNTNFNTE4Njg4RDNDQTRCQjMxNEJFRDAzMjQwMDM=	86353E518688D3CA4BB314BED0324003
+A72AFCF80A62839E814834BEB2DF3340	Example NodeCluster/38	urn:base64:Tm9kZUNsdXN0ZXI6QTcyQUZDRjgwQTYyODM5RTgxNDgzNEJFQjJERjMzNDA6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODYzNTNFNTE4Njg4RDNDQTRCQjMxNEJFRDAzMjQwMDM=	86353E518688D3CA4BB314BED0324003
+0E8B476E1A6445D91FC5C4BAB3A1B1AD	Example NodeCluster/39	urn:base64:Tm9kZUNsdXN0ZXI6MEU4QjQ3NkUxQTY0NDVEOTFGQzVDNEJBQjNBMUIxQUQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODYzNTNFNTE4Njg4RDNDQTRCQjMxNEJFRDAzMjQwMDM=	86353E518688D3CA4BB314BED0324003
+41ED2035E0528C57D1BD4EA14B8E967A	Example NodeCluster/40	urn:base64:Tm9kZUNsdXN0ZXI6NDFFRDIwMzVFMDUyOEM1N0QxQkQ0RUExNEI4RTk2N0E6TE9DQVRFRF9BVDpDbG91ZFNpdGU6ODYzNTNFNTE4Njg4RDNDQTRCQjMxNEJFRDAzMjQwMDM=	86353E518688D3CA4BB314BED0324003
+E5B6851160FD2CD82AC2192D4A52A19B	Example NodeCluster/41	urn:base64:Tm9kZUNsdXN0ZXI6RTVCNjg1MTE2MEZEMkNEODJBQzIxOTJENEE1MkExOUI6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=	16EE17AE89DF11B69E94B3F6827C2C0E
+DB12707FF0A63962F755848557C4596B	Example NodeCluster/42	urn:base64:Tm9kZUNsdXN0ZXI6REIxMjcwN0ZGMEE2Mzk2MkY3NTU4NDg1NTdDNDU5NkI6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=	16EE17AE89DF11B69E94B3F6827C2C0E
+5E2A9B569BE24D557067D21AE0849711	Example NodeCluster/43	urn:base64:Tm9kZUNsdXN0ZXI6NUUyQTlCNTY5QkUyNEQ1NTcwNjdEMjFBRTA4NDk3MTE6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=	16EE17AE89DF11B69E94B3F6827C2C0E
+E6CA370A107FF270A70C74FCEE6684B4	Example NodeCluster/44	urn:base64:Tm9kZUNsdXN0ZXI6RTZDQTM3MEExMDdGRjI3MEE3MEM3NEZDRUU2Njg0QjQ6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=	16EE17AE89DF11B69E94B3F6827C2C0E
+015C2DDBD7AC722B34ED6A20EDEEB9C3	Example NodeCluster/45	urn:base64:Tm9kZUNsdXN0ZXI6MDE1QzJEREJEN0FDNzIyQjM0RUQ2QTIwRURFRUI5QzM6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=	16EE17AE89DF11B69E94B3F6827C2C0E
+\.
+
+COPY ties_data."Namespace" (id, name, "REL_NAMESPACE_DEPLOYED_ON_NODECLUSTER_EIID", "REL_NAMESPACE_DEPLOYED_ON_NODECLUSTER") FROM stdin;
+1C02E96B2AAE036C7AE404BC38C308E0	Example Namespace/1	urn:base64:TmFtZXNwYWNlOjFDMDJFOTZCMkFBRTAzNkM3QUU0MDRCQzM4QzMwOEUwOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjNCRkEwREQ0QjFDOTkwRjlFNDlGQTREQjVDMjRGRUNE	3BFA0DD4B1C990F9E49FA4DB5C24FECD
+D6793A463BCA7441E9B10877E4C128C4	Example Namespace/2	urn:base64:TmFtZXNwYWNlOkQ2NzkzQTQ2M0JDQTc0NDFFOUIxMDg3N0U0QzEyOEM0OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjFDM0ZCMEE1NkUzRkZGRkVBQzVERTQwNzcxNUFEREU2	1C3FB0A56E3FFFFEAC5DE407715ADDE6
+7B123B5DBDD7765C3CA7538D1560E719	Example Namespace/3	urn:base64:TmFtZXNwYWNlOjdCMTIzQjVEQkRENzc2NUMzQ0E3NTM4RDE1NjBFNzE5OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjdGQ0Y5MkI5ODI3RDY3QkY1ODEzOEIxNkRCREM4MjQ5	7FCF92B9827D67BF58138B16DBDC8249
+C54B31AF0763C1B0EFB566092E8AAF87	Example Namespace/4	urn:base64:TmFtZXNwYWNlOkM1NEIzMUFGMDc2M0MxQjBFRkI1NjYwOTJFOEFBRjg3OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkY2QzBEOUUzQjJGRUExOTc5NTFENTQyMDQyNjY1QkZE	F6C0D9E3B2FEA197951D542042665BFD
+E7F976985B600C2D3FDC03B081722302	Example Namespace/5	urn:base64:TmFtZXNwYWNlOkU3Rjk3Njk4NUI2MDBDMkQzRkRDMDNCMDgxNzIyMzAyOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjBDQTkxRjRGQTc3NjRBQTA1NkVBOEYyRjc1OUEzMzA1	0CA91F4FA7764AA056EA8F2F759A3305
+C301DBCF5A62CB67E0F62A2FB72344A2	Example Namespace/6	urn:base64:TmFtZXNwYWNlOkMzMDFEQkNGNUE2MkNCNjdFMEY2MkEyRkI3MjM0NEEyOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkI2RTg5NUUxMEM3RjFEOEVFQUU2ODA4QzdGQUVBQ0Yx	B6E895E10C7F1D8EEAE6808C7FAEACF1
+6FDE215C3AB39D58BB5A537A04AC2797	Example Namespace/7	urn:base64:TmFtZXNwYWNlOjZGREUyMTVDM0FCMzlENThCQjVBNTM3QTA0QUMyNzk3OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjIwNDJGRjU0MDlDOUZBNjE1ODExRjkyQjFGMTQxNDlE	2042FF5409C9FA615811F92B1F14149D
+A825CC3BC40369FDBA3EA0F5B80841FF	Example Namespace/8	urn:base64:TmFtZXNwYWNlOkE4MjVDQzNCQzQwMzY5RkRCQTNFQTBGNUI4MDg0MUZGOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkU5NjJBREI2MUM2OEZEMUFDRTA3RjgzRUEzMzRGNzhE	E962ADB61C68FD1ACE07F83EA334F78D
+BF54B16C14A151E2A5E1445BFD892314	Example Namespace/9	urn:base64:TmFtZXNwYWNlOkJGNTRCMTZDMTRBMTUxRTJBNUUxNDQ1QkZEODkyMzE0OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjhBNjk3MTM3QjRDMjJDQzRFNjk1MzI4Q0Q2NUVCRDhF	8A697137B4C22CC4E695328CD65EBD8E
+9496E75F7F81F8C530FEC4D26480EAE8	Example Namespace/10	urn:base64:TmFtZXNwYWNlOjk0OTZFNzVGN0Y4MUY4QzUzMEZFQzREMjY0ODBFQUU4OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkFBMDQ2NDc2NjI2OUIwNzNBQkEzMDcxQzExQURBM0Y3	AA0464766269B073ABA3071C11ADA3F7
+7356625DD5EA8B67E356404E47DBF16C	Example Namespace/11	urn:base64:TmFtZXNwYWNlOjczNTY2MjVERDVFQThCNjdFMzU2NDA0RTQ3REJGMTZDOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjJDNERCNjA0QjVCNDNDQjlERjI1RkMxNkUzOEMxRDJF	2C4DB604B5B43CB9DF25FC16E38C1D2E
+93EDFACF7A68994F570D179531475632	Example Namespace/12	urn:base64:TmFtZXNwYWNlOjkzRURGQUNGN0E2ODk5NEY1NzBEMTc5NTMxNDc1NjMyOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkNCODVGMEVGQkYwOTMzMDBGMDEwQzkwMjM5NEM0NkY4	CB85F0EFBF093300F010C902394C46F8
+D209029D9DE5877417CE68865DAEAD10	Example Namespace/13	urn:base64:TmFtZXNwYWNlOkQyMDkwMjlEOURFNTg3NzQxN0NFNjg4NjVEQUVBRDEwOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjEyODA3QzVBRDVDQjMxRjM5M0I3QzY4NjQ5RjBFRjg0	12807C5AD5CB31F393B7C68649F0EF84
+A2F83B34AC21F25ED7C36C791242DBAC	Example Namespace/14	urn:base64:TmFtZXNwYWNlOkEyRjgzQjM0QUMyMUYyNUVEN0MzNkM3OTEyNDJEQkFDOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjU0RUUwREU4QzlENUUyNTJEODA1MjU1QjBCRjU4RTQx	54EE0DE8C9D5E252D805255B0BF58E41
+BD45F5227967629FACAF93AEB32B7AAA	Example Namespace/15	urn:base64:TmFtZXNwYWNlOkJENDVGNTIyNzk2NzYyOUZBQ0FGOTNBRUIzMkI3QUFBOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjdEMkYwNDcwRkYxMDkyOUM0QjZEMzlEQzY5NTFEQ0Iy	7D2F0470FF10929C4B6D39DC6951DCB2
+77B84B77570AD583F3CF82DE06110D43	Example Namespace/16	urn:base64:TmFtZXNwYWNlOjc3Qjg0Qjc3NTcwQUQ1ODNGM0NGODJERTA2MTEwRDQzOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjc0NjM2RTJDRjIxQUY5NjY3MERFMERCQjVFMkI5MEYx	74636E2CF21AF96670DE0DBB5E2B90F1
+6CB8279BB6185B07910D3DCF733F835C	Example Namespace/17	urn:base64:TmFtZXNwYWNlOjZDQjgyNzlCQjYxODVCMDc5MTBEM0RDRjczM0Y4MzVDOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjhCMTI0MjJDNkJCMkYyNDZDNjEyQkUxN0UwMDU4NzM2	8B12422C6BB2F246C612BE17E0058736
+99FF8A4C85B4D5BE0C655823110E2E62	Example Namespace/18	urn:base64:TmFtZXNwYWNlOjk5RkY4QTRDODVCNEQ1QkUwQzY1NTgyMzExMEUyRTYyOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjk5MUY3QkYwRDdEOERGNjk2ODhCNzM1MEY3RDlGMkUx	991F7BF0D7D8DF69688B7350F7D9F2E1
+B6C983B1A9FF9182F5C5127CF54E439A	Example Namespace/19	urn:base64:TmFtZXNwYWNlOkI2Qzk4M0IxQTlGRjkxODJGNUM1MTI3Q0Y1NEU0MzlBOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjY1NzNFQThFRDU4MkY2MjBGQUQ3MEIyODFEQzQ3NDc4	6573EA8ED582F620FAD70B281DC47478
+68B28BB43280552647D1E5D6AA24F311	Example Namespace/20	urn:base64:TmFtZXNwYWNlOjY4QjI4QkI0MzI4MDU1MjY0N0QxRTVENkFBMjRGMzExOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjU1MjYxN0ZDMDBDRjZFQ0E0MDdFQ0NDNzIzRDNCMjQz	552617FC00CF6ECA407ECCC723D3B243
+237CF729D2AB78689BE74C573AB2B5B8	Example Namespace/21	urn:base64:TmFtZXNwYWNlOjIzN0NGNzI5RDJBQjc4Njg5QkU3NEM1NzNBQjJCNUI4OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjYxREFEMzM0M0M0ODI0OTVGOUNCRjlBMUVGMjAyMEVB	61DAD3343C482495F9CBF9A1EF2020EA
+3CEDADD22281B7EDA5409BE8480BFAF8	Example Namespace/22	urn:base64:TmFtZXNwYWNlOjNDRURBREQyMjI4MUI3RURBNTQwOUJFODQ4MEJGQUY4OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjIwNzA3MENDQzRCQTQxMjU5Q0IxNUE2QjBCQjZGNEY0	207070CCC4BA41259CB15A6B0BB6F4F4
+10EE338B3F5FB2BC8F6F0DCD36EA3636	Example Namespace/23	urn:base64:TmFtZXNwYWNlOjEwRUUzMzhCM0Y1RkIyQkM4RjZGMERDRDM2RUEzNjM2OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjUzOTUxMTEzMjZEODkwNDRBMTUwNzE3MzIxOTM5RDQx	5395111326D89044A150717321939D41
+3AF02CA25A9ABB1D9069CD55609D70CD	Example Namespace/24	urn:base64:TmFtZXNwYWNlOjNBRjAyQ0EyNUE5QUJCMUQ5MDY5Q0Q1NTYwOUQ3MENEOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjA4NDY3OEUzQkIwRDYyNDAwNzg5NjU0MDRDNzRCNkZG	084678E3BB0D6240078965404C74B6FF
+463096647F96E6715E66B77C861E7228	Example Namespace/25	urn:base64:TmFtZXNwYWNlOjQ2MzA5NjY0N0Y5NkU2NzE1RTY2Qjc3Qzg2MUU3MjI4OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjcyNDQ1NzlGRTJDNUY4RERENDUyNUFBNjgzOTkxN0VB	7244579FE2C5F8DDD4525AA6839917EA
+89B40DF9B82BA836BB124B3031A0DEE7	Example Namespace/26	urn:base64:TmFtZXNwYWNlOjg5QjQwREY5QjgyQkE4MzZCQjEyNEIzMDMxQTBERUU3OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkNENUU1M0QxNzUwRjIxMDg1M0ZBMzhFRTM0M0I0MzRD	CD5E53D1750F210853FA38EE343B434C
+B9DB1B8A51399D227D92CCF8D25D9ED8	Example Namespace/27	urn:base64:TmFtZXNwYWNlOkI5REIxQjhBNTEzOTlEMjI3RDkyQ0NGOEQyNUQ5RUQ4OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkJCMDA4QUIyNDlENDg1RjkwRDU1OEJFREZBN0E2QTI5	BB008AB249D485F90D558BEDFA7A6A29
+ABDE267D2832D00BD5B6F809A3F9AAD1	Example Namespace/28	urn:base64:TmFtZXNwYWNlOkFCREUyNjdEMjgzMkQwMEJENUI2RjgwOUEzRjlBQUQxOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjlDODNGRTAzOUMzRDRCOTQ3MTUwQThDN0U1MDg0NkUy	9C83FE039C3D4B947150A8C7E50846E2
+C0EA0E88845F50E0E10E321C5AE00F0D	Example Namespace/29	urn:base64:TmFtZXNwYWNlOkMwRUEwRTg4ODQ1RjUwRTBFMTBFMzIxQzVBRTAwRjBEOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjE4MDI5OUUxNTMzRTBDQjNCMDQyNTEyQTk2Nzk0RTA4	180299E1533E0CB3B042512A96794E08
+E6B77CA230DEBFCB876A03109D1819A5	Example Namespace/30	urn:base64:TmFtZXNwYWNlOkU2Qjc3Q0EyMzBERUJGQ0I4NzZBMDMxMDlEMTgxOUE1OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkE2OUNFNTA4OTcyNzdCN0RBOEVGMTM4QTdGOUQ1RkM5	A69CE50897277B7DA8EF138A7F9D5FC9
+67FCEBFEB15DA38E662EA79B31BC2CD5	Example Namespace/31	urn:base64:TmFtZXNwYWNlOjY3RkNFQkZFQjE1REEzOEU2NjJFQTc5QjMxQkMyQ0Q1OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjM4Q0UxQzNEQzI4MDNDNDlERkRFMDUzOENENjQ1MDM0	38CE1C3DC2803C49DFDE0538CD645034
+0984650B561EF9BE8FEE1B33EDB7189E	Example Namespace/32	urn:base64:TmFtZXNwYWNlOjA5ODQ2NTBCNTYxRUY5QkU4RkVFMUIzM0VEQjcxODlFOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjFBRjczRjQ3NkNBOEI0RTdBQzIxOUQ4MTA5MTIxMjkw	1AF73F476CA8B4E7AC219D8109121290
+E359C47090CB00D507049AD6BB3FDE97	Example Namespace/33	urn:base64:TmFtZXNwYWNlOkUzNTlDNDcwOTBDQjAwRDUwNzA0OUFENkJCM0ZERTk3OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjhENkJDREU4NTVCNEMzMUI1OTE4RkE3REZFMjZCMzRC	8D6BCDE855B4C31B5918FA7DFE26B34B
+24940564BAA7F334DB11E6E3DAAD755F	Example Namespace/34	urn:base64:TmFtZXNwYWNlOjI0OTQwNTY0QkFBN0YzMzREQjExRTZFM0RBQUQ3NTVGOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjc4RTFFNUU0N0QxQjA3QjlFNERDMEZCNkE3M0JDNTcy	78E1E5E47D1B07B9E4DC0FB6A73BC572
+DD195B66C11B125675CD5EA66322C7CF	Example Namespace/35	urn:base64:TmFtZXNwYWNlOkREMTk1QjY2QzExQjEyNTY3NUNENUVBNjYzMjJDN0NGOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjhDNDcxMUI4MzVEOTlDMUUzQUE2NDI1OUU0QUEwNkE5	8C4711B835D99C1E3AA64259E4AA06A9
+2EE8638B774A12E7916E5093ABCB6CCB	Example Namespace/36	urn:base64:TmFtZXNwYWNlOjJFRTg2MzhCNzc0QTEyRTc5MTZFNTA5M0FCQ0I2Q0NCOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjZFQTc4QTNDQUM0MzQ4N0Q5MEYzNjM0OENEOUMyMTc4	6EA78A3CAC43487D90F36348CD9C2178
+09987E806682D5962E54216F9E34639A	Example Namespace/37	urn:base64:TmFtZXNwYWNlOjA5OTg3RTgwNjY4MkQ1OTYyRTU0MjE2RjlFMzQ2MzlBOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjFFQTA3MUM0RDQ5MkY1OEMwOTg0MjBENUI1ODkzNTAz	1EA071C4D492F58C098420D5B5893503
+5144ADDAA56F7167E163213D4DF3AFB7	Example Namespace/38	urn:base64:TmFtZXNwYWNlOjUxNDRBRERBQTU2RjcxNjdFMTYzMjEzRDRERjNBRkI3OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkE3MkFGQ0Y4MEE2MjgzOUU4MTQ4MzRCRUIyREYzMzQw	A72AFCF80A62839E814834BEB2DF3340
+EA83F8E7D1A61B9532686F560FD8052B	Example Namespace/39	urn:base64:TmFtZXNwYWNlOkVBODNGOEU3RDFBNjFCOTUzMjY4NkY1NjBGRDgwNTJCOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjBFOEI0NzZFMUE2NDQ1RDkxRkM1QzRCQUIzQTFCMUFE	0E8B476E1A6445D91FC5C4BAB3A1B1AD
+970E5C8E5AED1F50439AA40CBD2929BA	Example Namespace/40	urn:base64:TmFtZXNwYWNlOjk3MEU1QzhFNUFFRDFGNTA0MzlBQTQwQ0JEMjkyOUJBOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjQxRUQyMDM1RTA1MjhDNTdEMUJENEVBMTRCOEU5NjdB	41ED2035E0528C57D1BD4EA14B8E967A
+18A8EE78E6D774FE7A1D7E86A35436D4	Example Namespace/41	urn:base64:TmFtZXNwYWNlOjE4QThFRTc4RTZENzc0RkU3QTFEN0U4NkEzNTQzNkQ0OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkU1QjY4NTExNjBGRDJDRDgyQUMyMTkyRDRBNTJBMTlC	E5B6851160FD2CD82AC2192D4A52A19B
+316C81D156DE5326C6C56B4399328391	Example Namespace/42	urn:base64:TmFtZXNwYWNlOjMxNkM4MUQxNTZERTUzMjZDNkM1NkI0Mzk5MzI4MzkxOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkRCMTI3MDdGRjBBNjM5NjJGNzU1ODQ4NTU3QzQ1OTZC	DB12707FF0A63962F755848557C4596B
+9A74548A7CA0BA0973B994DBE28D5A17	Example Namespace/43	urn:base64:TmFtZXNwYWNlOjlBNzQ1NDhBN0NBMEJBMDk3M0I5OTREQkUyOEQ1QTE3OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjVFMkE5QjU2OUJFMjRENTU3MDY3RDIxQUUwODQ5NzEx	5E2A9B569BE24D557067D21AE0849711
+60AAC83B3405AED74F6451CC769293DF	Example Namespace/44	urn:base64:TmFtZXNwYWNlOjYwQUFDODNCMzQwNUFFRDc0RjY0NTFDQzc2OTI5M0RGOkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOkU2Q0EzNzBBMTA3RkYyNzBBNzBDNzRGQ0VFNjY4NEI0	E6CA370A107FF270A70C74FCEE6684B4
+63E484676DB1A4FFA9E3386F3B7D95B6	Example Namespace/45	urn:base64:TmFtZXNwYWNlOjYzRTQ4NDY3NkRCMUE0RkZBOUUzMzg2RjNCN0Q5NUI2OkRFUExPWUVEX09OOk5vZGVDbHVzdGVyOjAxNUMyRERCRDdBQzcyMkIzNEVENkEyMEVERUVCOUMz	015C2DDBD7AC722B34ED6A20EDEEB9C3
+\.
+
+COPY ties_data."CloudNativeSystem" (id, name, "REL_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM", "REL_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM_EIID") FROM stdin;
+C4E311A55666726FD9FE25CA572AFAF9	Example Cloud Native System/1	45EF31D8A1FD624D7276390A1215BFC3	urn:base64:TWFuYWdlZEVsZW1lbnQ6NDVFRjMxRDhBMUZENjI0RDcyNzYzOTBBMTIxNUJGQzM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06QzRFMzExQTU1NjY2NzI2RkQ5RkUyNUNBNTcyQUZBRjk=
+C79051FEBCA3BDB0B8D121931E443BD4	Example Cloud Native System/2	5BF1EECFD543243BE2C1BC52C7B484A0	urn:base64:TWFuYWdlZEVsZW1lbnQ6NUJGMUVFQ0ZENTQzMjQzQkUyQzFCQzUyQzdCNDg0QTA6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06Qzc5MDUxRkVCQ0EzQkRCMEI4RDEyMTkzMUU0NDNCRDQ=
+35FB71EBDD4D242270CC8C6A806BE701	Example Cloud Native System/3	23616B5A7FC56C146E3799DD7CA3B0C3	urn:base64:TWFuYWdlZEVsZW1lbnQ6MjM2MTZCNUE3RkM1NkMxNDZFMzc5OUREN0NBM0IwQzM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06MzVGQjcxRUJERDREMjQyMjcwQ0M4QzZBODA2QkU3MDE=
+F5CE6D5CE4918294F900930501ED5390	Example Cloud Native System/4	09ADB418B558918F8E858ECA77CAF22B	urn:base64:TWFuYWdlZEVsZW1lbnQ6MDlBREI0MThCNTU4OTE4RjhFODU4RUNBNzdDQUYyMkI6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06RjVDRTZENUNFNDkxODI5NEY5MDA5MzA1MDFFRDUzOTA=
+97DCC126365008869DFEB7EE6E0F5C1B	Example Cloud Native System/5	5F404149FF9EDF096764B00CC8D052A3	urn:base64:TWFuYWdlZEVsZW1lbnQ6NUY0MDQxNDlGRjlFREYwOTY3NjRCMDBDQzhEMDUyQTM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06OTdEQ0MxMjYzNjUwMDg4NjlERkVCN0VFNkUwRjVDMUI=
+201071BD2CED5D5E37E5C8AD9BDCC211	Example Cloud Native System/6	E1A1CA9D697DE4371C4014D587088498	urn:base64:TWFuYWdlZEVsZW1lbnQ6RTFBMUNBOUQ2OTdERTQzNzFDNDAxNEQ1ODcwODg0OTg6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06MjAxMDcxQkQyQ0VENUQ1RTM3RTVDOEFEOUJEQ0MyMTE=
+9B3DF0A93139581F46AD73129E4AA545	Example Cloud Native System/7	0DC59E39BAC5E54E5B646D346039C003	urn:base64:TWFuYWdlZEVsZW1lbnQ6MERDNTlFMzlCQUM1RTU0RTVCNjQ2RDM0NjAzOUMwMDM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06OUIzREYwQTkzMTM5NTgxRjQ2QUQ3MzEyOUU0QUE1NDU=
+372D4EF30659770D7600CF5E37A26320	Example Cloud Native System/8	E07B72DA5F4CD284C9A9EB5A6AE0D5AC	urn:base64:TWFuYWdlZEVsZW1lbnQ6RTA3QjcyREE1RjRDRDI4NEM5QTlFQjVBNkFFMEQ1QUM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06MzcyRDRFRjMwNjU5NzcwRDc2MDBDRjVFMzdBMjYzMjA=
+\.
+
+COPY ties_data."CloudNativeApplication" (id, name, "REL_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION_EIID", "REL_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE_EIID", "REL_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "REL_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION_EIID", "REL_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION", "REL_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE") FROM stdin;
+3256120E73ADD4026A43A971DCE5C151	Cloud Native CUCPApp/1	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06QzRFMzExQTU1NjY2NzI2RkQ5RkUyNUNBNTcyQUZBRjk6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246MzI1NjEyMEU3M0FERDQwMjZBNDNBOTcxRENFNUMxNTE=	\N	\N	\N	C4E311A55666726FD9FE25CA572AFAF9	\N
+EE2D4ADA10FF687FF6A865CC9E56A436	Cloud Native CUUPApp/2	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06Qzc5MDUxRkVCQ0EzQkRCMEI4RDEyMTkzMUU0NDNCRDQ6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246RUUyRDRBREExMEZGNjg3RkY2QTg2NUNDOUU1NkE0MzY=	\N	\N	\N	C79051FEBCA3BDB0B8D121931E443BD4	\N
+C4E28932357FA0076CA96CF7FF2C51BD	Cloud Native CUUPApp/3	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06MzVGQjcxRUJERDREMjQyMjcwQ0M4QzZBODA2QkU3MDE6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246QzRFMjg5MzIzNTdGQTAwNzZDQTk2Q0Y3RkYyQzUxQkQ=	\N	\N	\N	35FB71EBDD4D242270CC8C6A806BE701	\N
+41234DBD3CCEC010E2E9258527229950	Cloud Native CUUPApp/4	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06RjVDRTZENUNFNDkxODI5NEY5MDA5MzA1MDFFRDUzOTA6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246NDEyMzREQkQzQ0NFQzAxMEUyRTkyNTg1MjcyMjk5NTA=	\N	\N	\N	F5CE6D5CE4918294F900930501ED5390	\N
+E5E8A11419E09966604C14FDE5E09DF5	Cloud Native CUUPApp/5	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06OTdEQ0MxMjYzNjUwMDg4NjlERkVCN0VFNkUwRjVDMUI6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246RTVFOEExMTQxOUUwOTk2NjYwNEMxNEZERTVFMDlERjU=	\N	\N	\N	97DCC126365008869DFEB7EE6E0F5C1B	\N
+398DD19A5FD902C981E4D59F44E27F07	Cloud Native CUUPApp/6	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06MjAxMDcxQkQyQ0VENUQ1RTM3RTVDOEFEOUJEQ0MyMTE6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246Mzk4REQxOUE1RkQ5MDJDOTgxRTRENTlGNDRFMjdGMDc=	\N	\N	\N	201071BD2CED5D5E37E5C8AD9BDCC211	\N
+9800D81C743BF4246FEB95063D6B0F6B	Cloud Native CUUPApp/7	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06OUIzREYwQTkzMTM5NTgxRjQ2QUQ3MzEyOUU0QUE1NDU6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246OTgwMEQ4MUM3NDNCRjQyNDZGRUI5NTA2M0Q2QjBGNkI=	\N	\N	\N	9B3DF0A93139581F46AD73129E4AA545	\N
+AD42D90497E93D276215DF6D3B899E17	Cloud Native CUUPApp/8	urn:base64:Q2xvdWROYXRpdmVTeXN0ZW06MzcyRDRFRjMwNjU5NzcwRDc2MDBDRjVFMzdBMjYzMjA6Q09NUFJJU0VTOkNsb3VkTmF0aXZlQXBwbGljYXRpb246QUQ0MkQ5MDQ5N0U5M0QyNzYyMTVERjZEM0I4OTlFMTc=	\N	\N	\N	372D4EF30659770D7600CF5E37A26320	\N
+719BD5C7CD8A939D76A83DA95DA45C01	Example Cloud App/9	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6MUMwMkU5NkIyQUFFMDM2QzdBRTQwNEJDMzhDMzA4RTA=	DA1039E77700A9EEFFA280049ECE9227	urn:base64:TWFuYWdlZEVsZW1lbnQ6REExMDM5RTc3NzAwQTlFRUZGQTI4MDA0OUVDRTkyMjc6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMQ==	\N	1C02E96B2AAE036C7AE404BC38C308E0
+416F31E6EB09055326621F4919D35BFF	Example Cloud App/10	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo0MTZGMzFFNkVCMDkwNTUzMjY2MjFGNDkxOUQzNUJGRjpERVBMT1lFRF9PTjpOYW1lc3BhY2U6RDY3OTNBNDYzQkNBNzQ0MUU5QjEwODc3RTRDMTI4QzQ=	6F02817AFE4D53237DB235EBE5378613	urn:base64:TWFuYWdlZEVsZW1lbnQ6NkYwMjgxN0FGRTRENTMyMzdEQjIzNUVCRTUzNzg2MTM6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo0MTZGMzFFNkVCMDkwNTUzMjY2MjFGNDkxOUQzNUJGRg==	\N	D6793A463BCA7441E9B10877E4C128C4
+072549B6F55210EA967D66FB38DF4D02	Example Cloud App/11	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjowNzI1NDlCNkY1NTIxMEVBOTY3RDY2RkIzOERGNEQwMjpERVBMT1lFRF9PTjpOYW1lc3BhY2U6N0IxMjNCNURCREQ3NzY1QzNDQTc1MzhEMTU2MEU3MTk=	0181BB891A56BBD886771EBA3A69F19A	urn:base64:TWFuYWdlZEVsZW1lbnQ6MDE4MUJCODkxQTU2QkJEODg2NzcxRUJBM0E2OUYxOUE6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjowNzI1NDlCNkY1NTIxMEVBOTY3RDY2RkIzOERGNEQwMg==	\N	7B123B5DBDD7765C3CA7538D1560E719
+60E685C53F4A1D700AA12499B8513700	Example Cloud App/12	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo2MEU2ODVDNTNGNEExRDcwMEFBMTI0OTlCODUxMzcwMDpERVBMT1lFRF9PTjpOYW1lc3BhY2U6QzU0QjMxQUYwNzYzQzFCMEVGQjU2NjA5MkU4QUFGODc=	1E113BF2E3ABD819E0FBC6C6128BEFE5	urn:base64:TWFuYWdlZEVsZW1lbnQ6MUUxMTNCRjJFM0FCRDgxOUUwRkJDNkM2MTI4QkVGRTU6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo2MEU2ODVDNTNGNEExRDcwMEFBMTI0OTlCODUxMzcwMA==	\N	C54B31AF0763C1B0EFB566092E8AAF87
+D80E092432EA673E6D26F833FD456DAB	Example Cloud App/13	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjpEODBFMDkyNDMyRUE2NzNFNkQyNkY4MzNGRDQ1NkRBQjpERVBMT1lFRF9PTjpOYW1lc3BhY2U6RTdGOTc2OTg1QjYwMEMyRDNGREMwM0IwODE3MjIzMDI=	27500EB447000209EE6E3CA1B31FBA92	urn:base64:TWFuYWdlZEVsZW1lbnQ6Mjc1MDBFQjQ0NzAwMDIwOUVFNkUzQ0ExQjMxRkJBOTI6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjpEODBFMDkyNDMyRUE2NzNFNkQyNkY4MzNGRDQ1NkRBQg==	\N	E7F976985B600C2D3FDC03B081722302
+3F2580E9F469F9A3CD97B9FCF6CF4FB7	Example Cloud App/14	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjozRjI1ODBFOUY0NjlGOUEzQ0Q5N0I5RkNGNkNGNEZCNzpERVBMT1lFRF9PTjpOYW1lc3BhY2U6QzMwMURCQ0Y1QTYyQ0I2N0UwRjYyQTJGQjcyMzQ0QTI=	06222D277EE209CD8DCA1FE61CE752E6	urn:base64:TWFuYWdlZEVsZW1lbnQ6MDYyMjJEMjc3RUUyMDlDRDhEQ0ExRkU2MUNFNzUyRTY6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjozRjI1ODBFOUY0NjlGOUEzQ0Q5N0I5RkNGNkNGNEZCNw==	\N	C301DBCF5A62CB67E0F62A2FB72344A2
+0DBDAF357A69C373FC2A98B68485DDE3	Example Cloud App/15	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjowREJEQUYzNTdBNjlDMzczRkMyQTk4QjY4NDg1RERFMzpERVBMT1lFRF9PTjpOYW1lc3BhY2U6NkZERTIxNUMzQUIzOUQ1OEJCNUE1MzdBMDRBQzI3OTc=	436C59D4065E5222414DAD697C8842D2	urn:base64:TWFuYWdlZEVsZW1lbnQ6NDM2QzU5RDQwNjVFNTIyMjQxNERBRDY5N0M4ODQyRDI6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjowREJEQUYzNTdBNjlDMzczRkMyQTk4QjY4NDg1RERFMw==	\N	6FDE215C3AB39D58BB5A537A04AC2797
+E128C30D7E2ADB7DEF904CE7E936A586	Example Cloud App/16	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjpFMTI4QzMwRDdFMkFEQjdERUY5MDRDRTdFOTM2QTU4NjpERVBMT1lFRF9PTjpOYW1lc3BhY2U6QTgyNUNDM0JDNDAzNjlGREJBM0VBMEY1QjgwODQxRkY=	DC86CA7724113F4C0DF42BFEAA17FD53	urn:base64:TWFuYWdlZEVsZW1lbnQ6REM4NkNBNzcyNDExM0Y0QzBERjQyQkZFQUExN0ZENTM6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjpFMTI4QzMwRDdFMkFEQjdERUY5MDRDRTdFOTM2QTU4Ng==	\N	A825CC3BC40369FDBA3EA0F5B80841FF
+6B655971564C02F1FB7E5D7E84F9DDAF	Example Cloud App/17	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo2QjY1NTk3MTU2NEMwMkYxRkI3RTVEN0U4NEY5RERBRjpERVBMT1lFRF9PTjpOYW1lc3BhY2U6QkY1NEIxNkMxNEExNTFFMkE1RTE0NDVCRkQ4OTIzMTQ=	1F0B4F7CEC39A09ADC16EB8D787978E6	urn:base64:TWFuYWdlZEVsZW1lbnQ6MUYwQjRGN0NFQzM5QTA5QURDMTZFQjhENzg3OTc4RTY6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo2QjY1NTk3MTU2NEMwMkYxRkI3RTVEN0U4NEY5RERBRg==	\N	BF54B16C14A151E2A5E1445BFD892314
+9E0291689435200AE1332FBBB992C151	Example Cloud App/18	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo5RTAyOTE2ODk0MzUyMDBBRTEzMzJGQkJCOTkyQzE1MTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6OTQ5NkU3NUY3RjgxRjhDNTMwRkVDNEQyNjQ4MEVBRTg=	AEAFE291F1DE32DEFFF0073D297B7693	urn:base64:TWFuYWdlZEVsZW1lbnQ6QUVBRkUyOTFGMURFMzJERUZGRjAwNzNEMjk3Qjc2OTM6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo5RTAyOTE2ODk0MzUyMDBBRTEzMzJGQkJCOTkyQzE1MQ==	\N	9496E75F7F81F8C530FEC4D26480EAE8
+C549905CF3CC890CE5746C5E10ACF00D	Example Cloud App/19	\N	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjpDNTQ5OTA1Q0YzQ0M4OTBDRTU3NDZDNUUxMEFDRjAwRDpERVBMT1lFRF9PTjpOYW1lc3BhY2U6NzM1NjYyNURENUVBOEI2N0UzNTY0MDRFNDdEQkYxNkM=	8D51EFC759166044DACBCA63C4EDFC51	urn:base64:TWFuYWdlZEVsZW1lbnQ6OEQ1MUVGQzc1OTE2NjA0NERBQ0JDQTYzQzRFREZDNTE6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjpDNTQ5OTA1Q0YzQ0M4OTBDRTU3NDZDNUUxMEFDRjAwRA==	\N	7356625DD5EA8B67E356404E47DBF16C
+\.
+
+COPY ties_data."GNBDUFunction" (id, fdn, "dUpLMNId", "gNBId", "gNBIdLength", "REL_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION", "REL_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION_EIID") FROM stdin;
+5A548EA9D166341776CA0695837E55D8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=16	{"mnc":"82","mcc":"456"}	16	2	DC86CA7724113F4C0DF42BFEAA17FD53	urn:base64:TWFuYWdlZEVsZW1lbnQ6REM4NkNBNzcyNDExM0Y0QzBERjQyQkZFQUExN0ZENTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjVBNTQ4RUE5RDE2NjM0MTc3NkNBMDY5NTgzN0U1NUQ4
+7D80E5C6E0C9EC246370E86B7E524F8C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=17	{"mnc":"82","mcc":"456"}	17	2	1F0B4F7CEC39A09ADC16EB8D787978E6	urn:base64:TWFuYWdlZEVsZW1lbnQ6MUYwQjRGN0NFQzM5QTA5QURDMTZFQjhENzg3OTc4RTY6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjdEODBFNUM2RTBDOUVDMjQ2MzcwRTg2QjdFNTI0RjhD
+BBB3C42A4F8AC94091B297DF708DD50B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=18	{"mnc":"82","mcc":"456"}	18	2	AEAFE291F1DE32DEFFF0073D297B7693	urn:base64:TWFuYWdlZEVsZW1lbnQ6QUVBRkUyOTFGMURFMzJERUZGRjAwNzNEMjk3Qjc2OTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOkJCQjNDNDJBNEY4QUM5NDA5MUIyOTdERjcwOERENTBC
+4CFF136200A2DE36205A13559C55DB2A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=19	{"mnc":"82","mcc":"456"}	19	2	8D51EFC759166044DACBCA63C4EDFC51	urn:base64:TWFuYWdlZEVsZW1lbnQ6OEQ1MUVGQzc1OTE2NjA0NERBQ0JDQTYzQzRFREZDNTE6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjRDRkYxMzYyMDBBMkRFMzYyMDVBMTM1NTlDNTVEQjJB
+D3215E08570BE58339C7463626B50E37	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=9	{"mnc":"82","mcc":"456"}	9	1	DA1039E77700A9EEFFA280049ECE9227	urn:base64:TWFuYWdlZEVsZW1lbnQ6REExMDM5RTc3NzAwQTlFRUZGQTI4MDA0OUVDRTkyMjc6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOkQzMjE1RTA4NTcwQkU1ODMzOUM3NDYzNjI2QjUwRTM3
+1050570EBB1315E1AE7A9FD5E1400A00	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=10	{"mnc":"82","mcc":"456"}	10	2	6F02817AFE4D53237DB235EBE5378613	urn:base64:TWFuYWdlZEVsZW1lbnQ6NkYwMjgxN0FGRTRENTMyMzdEQjIzNUVCRTUzNzg2MTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjEwNTA1NzBFQkIxMzE1RTFBRTdBOUZENUUxNDAwQTAw
+B6A6DE7D0965F02D48ECA86706A4454F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=11	{"mnc":"82","mcc":"456"}	11	2	0181BB891A56BBD886771EBA3A69F19A	urn:base64:TWFuYWdlZEVsZW1lbnQ6MDE4MUJCODkxQTU2QkJEODg2NzcxRUJBM0E2OUYxOUE6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOkI2QTZERTdEMDk2NUYwMkQ0OEVDQTg2NzA2QTQ0NTRG
+E5FD5ACD55C553A92738477ECB0465B9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=12	{"mnc":"82","mcc":"456"}	12	2	1E113BF2E3ABD819E0FBC6C6128BEFE5	urn:base64:TWFuYWdlZEVsZW1lbnQ6MUUxMTNCRjJFM0FCRDgxOUUwRkJDNkM2MTI4QkVGRTU6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOkU1RkQ1QUNENTVDNTUzQTkyNzM4NDc3RUNCMDQ2NUI5
+25E690E22BDA90B9C4FEE1F083CBA597	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=13	{"mnc":"82","mcc":"456"}	13	2	27500EB447000209EE6E3CA1B31FBA92	urn:base64:TWFuYWdlZEVsZW1lbnQ6Mjc1MDBFQjQ0NzAwMDIwOUVFNkUzQ0ExQjMxRkJBOTI6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjI1RTY5MEUyMkJEQTkwQjlDNEZFRTFGMDgzQ0JBNTk3
+5A3085C3400C3096E2ED2321452766B1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=14	{"mnc":"82","mcc":"456"}	14	2	06222D277EE209CD8DCA1FE61CE752E6	urn:base64:TWFuYWdlZEVsZW1lbnQ6MDYyMjJEMjc3RUUyMDlDRDhEQ0ExRkU2MUNFNzUyRTY6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjVBMzA4NUMzNDAwQzMwOTZFMkVEMjMyMTQ1Mjc2NkIx
+7F16F93D8816D9EBC76E52BB44A3CFF5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=15	{"mnc":"82","mcc":"456"}	15	2	436C59D4065E5222414DAD697C8842D2	urn:base64:TWFuYWdlZEVsZW1lbnQ6NDM2QzU5RDQwNjVFNTIyMjQxNERBRDY5N0M4ODQyRDI6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjdGMTZGOTNEODgxNkQ5RUJDNzZFNTJCQjQ0QTNDRkY1
+\.
+
+COPY ties_data."GNBCUCPFunction" (id, fdn, "gNBId", "gNBIdLength", "REL_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION", "REL_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION_EIID") FROM stdin;
+0525930249302B9649FC8F201EC4F7FC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUCPFunction=1	1	1	5BCC1BC502B66423981F90A6EA8D157E	urn:base64:TWFuYWdlZEVsZW1lbnQ6NUJDQzFCQzUwMkI2NjQyMzk4MUY5MEE2RUE4RDE1N0U6TUFOQUdFUzpHTkJDVUNQRnVuY3Rpb246MDUyNTkzMDI0OTMwMkI5NjQ5RkM4RjIwMUVDNEY3RkM=
+\.
+
+COPY ties_data."GNBCUUPFunction" (id, fdn, "gNBId", "gNBIdLength", "REL_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION", "REL_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION_EIID") FROM stdin;
+9B007881A1B8DE33D1D3063BE601D4B6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=2	2	1	577CA8F71FFC2FC3C39D93D0F28E47EC	urn:base64:TWFuYWdlZEVsZW1lbnQ6NTc3Q0E4RjcxRkZDMkZDM0MzOUQ5M0QwRjI4RTQ3RUM6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246OUIwMDc4ODFBMUI4REUzM0QxRDMwNjNCRTYwMUQ0QjY=
+9806ABE2985BDD4FE6BD2B38549C973C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=3	3	1	E87AF3DB09EE273C6F153AA00D4D1171	urn:base64:TWFuYWdlZEVsZW1lbnQ6RTg3QUYzREIwOUVFMjczQzZGMTUzQUEwMEQ0RDExNzE6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246OTgwNkFCRTI5ODVCREQ0RkU2QkQyQjM4NTQ5Qzk3M0M=
+99BBA3EC64BE596400B38FEBD9677FC6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=4	4	1	A73755B1422176B1169546D884BD9FCC	urn:base64:TWFuYWdlZEVsZW1lbnQ6QTczNzU1QjE0MjIxNzZCMTE2OTU0NkQ4ODRCRDlGQ0M6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246OTlCQkEzRUM2NEJFNTk2NDAwQjM4RkVCRDk2NzdGQzY=
+6B3E56B6C991F4E569115DE5633B0AA0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=5	5	1	D76CCB4E654B2CF5D248196E9B9524AD	urn:base64:TWFuYWdlZEVsZW1lbnQ6RDc2Q0NCNEU2NTRCMkNGNUQyNDgxOTZFOUI5NTI0QUQ6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246NkIzRTU2QjZDOTkxRjRFNTY5MTE1REU1NjMzQjBBQTA=
+A18F3452C918E8F2C54E600F42005DBD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=6	6	1	E7CEF72CB78163D1B26B8B2A7A39757A	urn:base64:TWFuYWdlZEVsZW1lbnQ6RTdDRUY3MkNCNzgxNjNEMUIyNkI4QjJBN0EzOTc1N0E6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246QTE4RjM0NTJDOTE4RThGMkM1NEU2MDBGNDIwMDVEQkQ=
+F1C32B9DECA2230D9765BE2F54F1EDFE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=7	7	1	E57C2A20E96A8C9E7099BAD60957B59A	urn:base64:TWFuYWdlZEVsZW1lbnQ6RTU3QzJBMjBFOTZBOEM5RTcwOTlCQUQ2MDk1N0I1OUE6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246RjFDMzJCOURFQ0EyMjMwRDk3NjVCRTJGNTRGMUVERkU=
+BFEEAC2CE60273CB0A78319CC201A7FE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=8	8	1	E64371CD4D12ED0CED200DD3A7591784	urn:base64:TWFuYWdlZEVsZW1lbnQ6RTY0MzcxQ0Q0RDEyRUQwQ0VEMjAwREQzQTc1OTE3ODQ6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246QkZFRUFDMkNFNjAyNzNDQjBBNzgzMTlDQzIwMUE3RkU=
+\.
+
+COPY ties_data."NRCellCU" (id, fdn, "cellLocalId", "plmnId", "nCI", "nRTAC", "REL_GNBCUCPFUNCTION_PROVIDES_NRCELLCU_EIID", "REL_GNBCUCPFUNCTION_PROVIDES_NRCELLCU") FROM stdin;
+ED15B5C47ACEB0B4975D7A7B6B9FD4F8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=1	1	{"mnc":"82","mcc":"456"}	1	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOkVEMTVCNUM0N0FDRUIwQjQ5NzVEN0E3QjZCOUZENEY4	0525930249302B9649FC8F201EC4F7FC
+C21ED6B73BFC01F0A98F1D492DFD7FBD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=2	2	{"mnc":"82","mcc":"456"}	2	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOkMyMUVENkI3M0JGQzAxRjBBOThGMUQ0OTJERkQ3RkJE	0525930249302B9649FC8F201EC4F7FC
+D1462F73968E5CC050AAD327331494D9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=3	3	{"mnc":"82","mcc":"456"}	3	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOkQxNDYyRjczOTY4RTVDQzA1MEFBRDMyNzMzMTQ5NEQ5	0525930249302B9649FC8F201EC4F7FC
+4B83304C790B86803348D83594CA8578	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=4	4	{"mnc":"82","mcc":"456"}	4	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOjRCODMzMDRDNzkwQjg2ODAzMzQ4RDgzNTk0Q0E4NTc4	0525930249302B9649FC8F201EC4F7FC
+DD35C095CD62BD45AA9B3E5DDAEDD638	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=5	5	{"mnc":"82","mcc":"456"}	5	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOkREMzVDMDk1Q0Q2MkJENDVBQTlCM0U1RERBRURENjM4	0525930249302B9649FC8F201EC4F7FC
+926C4E16A00453D7AF0BDC1B44956DEE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=6	6	{"mnc":"82","mcc":"456"}	6	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOjkyNkM0RTE2QTAwNDUzRDdBRjBCREMxQjQ0OTU2REVF	0525930249302B9649FC8F201EC4F7FC
+48CF862C4FBAC260A3A32C858BE8DCD8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=7	7	{"mnc":"82","mcc":"456"}	7	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOjQ4Q0Y4NjJDNEZCQUMyNjBBM0EzMkM4NThCRThEQ0Q4	0525930249302B9649FC8F201EC4F7FC
+EC3400C5121E6AACC4DA117C244C3661	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=8	8	{"mnc":"82","mcc":"456"}	8	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOkVDMzQwMEM1MTIxRTZBQUNDNERBMTE3QzI0NEMzNjYx	0525930249302B9649FC8F201EC4F7FC
+FFC97655D55AC9CC4FB8A7EC0C7941E8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=9	9	{"mnc":"82","mcc":"456"}	9	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOkZGQzk3NjU1RDU1QUM5Q0M0RkI4QTdFQzBDNzk0MUU4	0525930249302B9649FC8F201EC4F7FC
+2F1E5910D92D1C199360545C6A798E9C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=10	10	{"mnc":"82","mcc":"456"}	10	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOjJGMUU1OTEwRDkyRDFDMTk5MzYwNTQ1QzZBNzk4RTlD	0525930249302B9649FC8F201EC4F7FC
+A212C979D6E32F6021E7E05879C797F5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellCU=11	11	{"mnc":"82","mcc":"456"}	11	456	urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlBST1ZJREVTOk5SQ2VsbENVOkEyMTJDOTc5RDZFMzJGNjAyMUU3RTA1ODc5Qzc5N0Y1	0525930249302B9649FC8F201EC4F7FC
+\.
+
+COPY ties_data."Sector" (id, azimuth, "geo-location") FROM stdin;
+2F445AA5744FA3D230FD6838531F1407	1	POINT(59.4019881 17.9419888)
+F5128C172A70C4FCD4739650B06DE9E2	2	POINT(59.4019881 17.9419888)
+ADB1BAAC878C0BEEFE3175C60F44BB1D	3	POINT(59.4019881 17.9419888)
+\.
+
+COPY ties_data."AntennaCapability" (id, fdn, "eUtranFqBands", "geranFqBands", "nRFqBands") FROM stdin;
+5835F77BE9D4E102316BD59195F6370B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=1	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+04F39EBAB72454E4D3331D6C3367B45F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=2	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+A77B237A541B2D3225B4B61D3098E4AA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=3	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C30981A489A45BE4BF70667FC66992CF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=4	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+4A850F99EBA0935B7CDE6EF446C0499C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=5	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C83E08A53438EF9678D515E73DB667F7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=6	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+5E1C63A3F32A8625A5F282727D36B0C8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=7	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+1B338F478087F93C91E0287CC87CDC56	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=8	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+599313CDD35F498EE899CF51C9A09BF5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=9	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+B04E223337F275C0BF59B459A06EE6C3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=10	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+2D71F6CDCC5DFD1D712D9AB01BAA4706	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=11	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+D74172358AD4BA418E2423A3D54151ED	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=12	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+114BD7BD46D2EA6BF851251287F2CF95	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=13	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+B00699B5EA33C867EEE7E044EE844D34	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=14	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+A537D7A9EFDEE0C47B3FB4CF3B1F06A7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=15	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+E1C3E95944942F4AD1831719203A1672	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=16	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+9252E3CCA88AE559BCB1C838FFDA1C27	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=17	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+F283F19F4F0842E724BA72E9718EA5CB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=18	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+B74B892954E97112DD4B4E5AF9D3A4F7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=19	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+87CC4E7F74292FE85340F280A32EEB2D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=20	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+04273FC64436DA523865CF849E5F7CC9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=21	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+D5B9090E3B6A10DBDC243ED14EF294BF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=22	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+02443DE0807D801D661495D9EFB8D836	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=23	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C6823D2B7AFA064CE774795E01D6228B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=24	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+DF26AE442110DB0281DAD4545436B720	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=25	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+7A1C6FE9351008B3D539166D94222762	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=26	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+70A1F129E10EE7D31DFE1E1AA6C7437D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=27	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+7DE91C78F8DCE4292F2F0C3B34DEACAB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=28	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+145A1BF561DB297F25FD3F12417D2A50	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=29	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+9188D975D837A1E0397167A23E721B0C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=30	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+D314DADAFA3D896445E78EBCC15A16F7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=31	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+28AD3EE844766DF508F6287CD1CE18A4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=32	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C398D6C673267A081C781D84438F4B74	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=33	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+0BDAD5DDC19A696244536421E6D26FE3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=34	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+49205881C9121F208BD79149FA799877	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=35	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+A32DB9E278FC1DE41FB4A3B50F802650	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=36	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+BDE381BACC67290E447BC0177E038AEB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=37	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+B4BC4D1B13EB651690F3195E622CC4BD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=38	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+32EE385EACD26A0046BAD5CC84905ECB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=39	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+43B63106B27FB05C618400EE5AE91637	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=40	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C813E18657C2C5837A3F237BAD557944	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=41	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+462DCCDEA5A2892B8C8630724679B676	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=42	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+F6D0FF2069F038FF64D072C818DD9BFD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=43	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C5C598511C7514061E86DA24F8DB359D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=44	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+13876FECEEDF45AE4DCA8C393E478237	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=45	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+00833903891D07D0628E03FF4463A14A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=46	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C4A283EEFD5F1463B7EE0CA782409DFB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=47	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+AFFEAF1D0F2D30524C49BA86D52F39EE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=48	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+E2A13CF56C0E187C62FF9716BB0FCED6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=49	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+E3E1FB31FB5F4FB1CA808036474BDD95	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=50	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+5769C026D7993C666C45535EDD8C3EAD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=51	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+2A32475EF4F4AB41904B5AAAA8FF2CA1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=52	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+EB1301BA22E0691114A23445323B649B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=53	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+285A7590CEC0BC46F0C1A8A3D1AA2BA5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=54	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C606AF1A1AC5A96A43B0B8EBFC1B047C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=55	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+40FB5481402DCE8AD6B3B0357B00CF82	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=56	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+FD8F3DE8B8AF2FD102F39D0ED89B3714	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=57	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+5CEA2470D99A8A2BB3ED90BC15DB1140	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=58	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+6A23A8B8B5ACEA775D6E98BAC1534373	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=59	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+1D273FDD45618CBD438D0083873314D5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=60	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+E07F76EEFA3F6D1A5083C99F3D202CCD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=61	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+173388785CB4761B154F448AE6372ADC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=62	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+AA17CE1504CD4512121267C22034620A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=63	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+542D562E72C8025DD560D718FFDE1D45	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=64	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+E3C96BA5D7C0755A3011D12A32971BA1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=65	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+B4C333ECD92A7351A38EE3BC510B5DA7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=66	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+6F75116BB289ECD8EB1A96252FD8F7C0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=67	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+16B870511FAAF1183FC92E641B2C3804	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=68	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+2C7AA809CD1A92FD74EC4151D7C16A8D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=69	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+2C21D1069460F35FF38952F1050DF7CC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=70	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+AA3ED0C82A9FE6D7412B7C558A96CDA5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=71	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+B5D36905C87DA636611C137159727CEE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=72	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+3EF4C71354EC527AB033A3FB820F48E4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=73	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+0B3681F195584EF1051B914EB63EBBCB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=74	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+59A77FBBDC8E1819741E4728596C435C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=75	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+BDC8E4EAC53C9C39800B4BDC0309C8BB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=76	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+37332299BE1398193F7B7452C16521F8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=77	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+83B8FC3409E9E34F8D4B22CD514CC078	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=78	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+587ADBD46FA0A770E1C3ABA210DB57ED	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=79	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+604A22BFC72A960115D6B21C3F186841	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=80	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+1D4CBC43D62A01B27FA0C7442F9AD0D8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=81	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+892BAE0B45865D3F4DC776662BB37654	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=82	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+EE1EAAFDB85206259AA9D9D4BA01BDA2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=83	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+111BD123DCA1B937F0E15E5BEFDE08E9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=84	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+DF7837EEAB65A06859110366E5F45297	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=85	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+D0AAE9631AF1554B8F390932E377EA19	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=86	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+89B9FE5D2D4A07CCD54E705BFE2D10F0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=87	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+A6E97BA30832C1B7AC36F4D79DD38B71	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=88	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+DFA6202FF96DD418EAD4C930F27F0C78	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=89	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+01945D7B7D2AFB0B3DFE23822D2C9CCB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=90	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+BE50AC57AB1FAE73531ADD181324067F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=91	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+82D055DE15B97CD866CF454A9688F4DB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=92	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+362EC3B7758D873DF98AE2A9EC2472B5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=93	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+DA5D8A3D1CDC3D55447F7C86EDD8FE50	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=94	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+6A39B151C50F73F029B5772299DCF289	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=95	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+B0FE880DF9474AA29C7A4BAAA946E55D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=96	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+C23D9D0807E45EF55DC6B7D35EEB08B1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=97	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+CF8EF723BB46C6170DB0490D1FA26B85	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=98	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+E1C340DF0FFA51211DDB5F829E2A27EE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=99	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+59E39AEB2CD8EC0018853D7EF75E4E77	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=100	["123","4564","789"]	["123","456","789"]	["123","456","789"]
+\.
+
+COPY ties_data."Site" (id, name, "geo-location") FROM stdin;
+CF89C174D06854C0C41B74D2C46846DD	ORAN Stockholm	POINT(59.4019881 17.9419888)
+26874D3241CEFFF60E084FEFCC72B973	ORAN Stockholm	POINT(59.4019881 17.9419888)
+0778A57645DE9D3E4B74D31F9F5CB858	ORAN Stockholm	POINT(59.4019881 17.9419888)
+F4B3E6619BBD176B4F2DB754AF6524BC	ORAN Stockholm	POINT(59.4019881 17.9419888)
+08ECC9E4A381754174EC4B0045418F53	ORAN Stockholm	POINT(59.4019881 17.9419888)
+12B7642C4550D657BE0D0F5FFB6975B4	ORAN Stockholm	POINT(59.4019881 17.9419888)
+09C568700E28185534A836946A406656	ORAN Stockholm	POINT(59.4019881 17.9419888)
+FEF2244182BB579F5D67C024ADBE8510	ORAN Stockholm	POINT(59.4019881 17.9419888)
+8661AEDC92C7A428BBB5137150A84EFF	ORAN Stockholm	POINT(59.4019881 17.9419888)
+07674D494908D2B78DFD4A9555E8FEC7	ORAN Stockholm	POINT(59.4019881 17.9419888)
+45125B217DEAE03E6FFE99E6410827CB	ORAN Stockholm	POINT(59.4019881 17.9419888)
+D6C8C26018EC6B009B466590E0E8CA89	ORAN Stockholm	POINT(59.4019881 17.9419888)
+C30A8ED14ED558C42D40AB507E45A20B	ORAN Stockholm	POINT(59.4019881 17.9419888)
+AB78BB4CCABEBDA1FAF28B583FECE1F7	ORAN Stockholm	POINT(59.4019881 17.9419888)
+0EF3B3C355A1B8229477C73003331ECE	ORAN Stockholm	POINT(59.4019881 17.9419888)
+547D71B43F80440CCCF5BBAA592F0BE9	ORAN Stockholm	POINT(59.4019881 17.9419888)
+6DA0466361FC7FA801992523CEEBB708	ORAN Stockholm	POINT(59.4019881 17.9419888)
+E62D579A6EE1200742024580932FCAB3	ORAN Stockholm	POINT(59.4019881 17.9419888)
+DF8BC33203F929BA85E9CE51906C39E7	ORAN Stockholm	POINT(59.4019881 17.9419888)
+77B0CCE60DA3CB1A6B7710356F98BF2D	ORAN Stockholm	POINT(59.4019881 17.9419888)
+BAE093E95F2AC5FF08C8830896F4074B	ORAN Stockholm	POINT(59.4019881 17.9419888)
+80E537AB048E79909DA40298E06B089D	ORAN Stockholm	POINT(59.4019881 17.9419888)
+E8BA1F7434A4842150FA259506A55435	ORAN Stockholm	POINT(59.4019881 17.9419888)
+2DDD59CA2E860E28CB8DEB1FEAB3CAB4	ORAN Stockholm	POINT(59.4019881 17.9419888)
+0B2DBD5B2C81D9283BB458A03ABC305C	ORAN Stockholm	POINT(59.4019881 17.9419888)
+EFE3F092FF55C768B4D1E459B2A93DD8	ORAN Stockholm	POINT(59.4019881 17.9419888)
+\.
+
+COPY ties_data."AntennaModule" (id, fdn, "antennaModelNumber", "mechanicalAntennaBearing", "mechanicalAntennaTilt", "positionWithinSector", "totalTilt", "electricalAntennaTilt", "REL_ANTENNAMODULE_INSTALLED_AT_SITE_EIID", "REL_SECTOR_GROUPS_ANTENNAMODULE_EIID", "REL_ANTENNAMODULE_INSTALLED_AT_SITE", "REL_SECTOR_GROUPS_ANTENNAMODULE") FROM stdin;
+CBAB40BEF2646D20F66542E9D10D7FCA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=1	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpDQkFCNDBCRUYyNjQ2RDIwRjY2NTQyRTlEMTBEN0ZDQTpJTlNUQUxMRURfQVQ6U2l0ZToyNjg3NEQzMjQxQ0VGRkY2MEUwODRGRUZDQzcyQjk3Mw==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOkNCQUI0MEJFRjI2NDZEMjBGNjY1NDJFOUQxMEQ3RkNB	26874D3241CEFFF60E084FEFCC72B973	2F445AA5744FA3D230FD6838531F1407
+7ECED4BE8CF47661D5D3E8674586A9B1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=2	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTo3RUNFRDRCRThDRjQ3NjYxRDVEM0U4Njc0NTg2QTlCMTpJTlNUQUxMRURfQVQ6U2l0ZTowNzc4QTU3NjQ1REU5RDNFNEI3NEQzMUY5RjVDQjg1OA==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOjdFQ0VENEJFOENGNDc2NjFENUQzRTg2NzQ1ODZBOUIx	0778A57645DE9D3E4B74D31F9F5CB858	2F445AA5744FA3D230FD6838531F1407
+AA48999302DFC8EC8879572623C0085A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=3	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpBQTQ4OTk5MzAyREZDOEVDODg3OTU3MjYyM0MwMDg1QTpJTlNUQUxMRURfQVQ6U2l0ZTpGNEIzRTY2MTlCQkQxNzZCNEYyREI3NTRBRjY1MjRCQw==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOkFBNDg5OTkzMDJERkM4RUM4ODc5NTcyNjIzQzAwODVB	F4B3E6619BBD176B4F2DB754AF6524BC	2F445AA5744FA3D230FD6838531F1407
+07C63BA08B0C43E18CC964F0B6F4E24D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=4	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTowN0M2M0JBMDhCMEM0M0UxOENDOTY0RjBCNkY0RTI0RDpJTlNUQUxMRURfQVQ6U2l0ZTowOEVDQzlFNEEzODE3NTQxNzRFQzRCMDA0NTQxOEY1Mw==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOjA3QzYzQkEwOEIwQzQzRTE4Q0M5NjRGMEI2RjRFMjRE	08ECC9E4A381754174EC4B0045418F53	2F445AA5744FA3D230FD6838531F1407
+FF21E2266B36E92F3C298C9C3497BDAD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=5	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpGRjIxRTIyNjZCMzZFOTJGM0MyOThDOUMzNDk3QkRBRDpJTlNUQUxMRURfQVQ6U2l0ZToxMkI3NjQyQzQ1NTBENjU3QkUwRDBGNUZGQjY5NzVCNA==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOkZGMjFFMjI2NkIzNkU5MkYzQzI5OEM5QzM0OTdCREFE	12B7642C4550D657BE0D0F5FFB6975B4	2F445AA5744FA3D230FD6838531F1407
+002B0219B739B88C8A813552EF1E8942	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=6	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTowMDJCMDIxOUI3MzlCODhDOEE4MTM1NTJFRjFFODk0MjpJTlNUQUxMRURfQVQ6U2l0ZTowOUM1Njg3MDBFMjgxODU1MzRBODM2OTQ2QTQwNjY1Ng==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOjAwMkIwMjE5QjczOUI4OEM4QTgxMzU1MkVGMUU4OTQy	09C568700E28185534A836946A406656	2F445AA5744FA3D230FD6838531F1407
+BEB01B90AC0099CA7C730D54C6A99F56	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=7	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpCRUIwMUI5MEFDMDA5OUNBN0M3MzBENTRDNkE5OUY1NjpJTlNUQUxMRURfQVQ6U2l0ZTpGRUYyMjQ0MTgyQkI1NzlGNUQ2N0MwMjRBREJFODUxMA==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOkJFQjAxQjkwQUMwMDk5Q0E3QzczMEQ1NEM2QTk5RjU2	FEF2244182BB579F5D67C024ADBE8510	2F445AA5744FA3D230FD6838531F1407
+1319EDC0A95609084682B331F0A05E82	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=8	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZToxMzE5RURDMEE5NTYwOTA4NDY4MkIzMzFGMEEwNUU4MjpJTlNUQUxMRURfQVQ6U2l0ZTo4NjYxQUVEQzkyQzdBNDI4QkJCNTEzNzE1MEE4NEVGRg==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpBbnRlbm5hTW9kdWxlOjEzMTlFREMwQTk1NjA5MDg0NjgyQjMzMUYwQTA1RTgy	8661AEDC92C7A428BBB5137150A84EFF	2F445AA5744FA3D230FD6838531F1407
+BD0E10BC55B7286F699DB340045053CA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=9	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpCRDBFMTBCQzU1QjcyODZGNjk5REIzNDAwNDUwNTNDQTpJTlNUQUxMRURfQVQ6U2l0ZTowNzY3NEQ0OTQ5MDhEMkI3OERGRDRBOTU1NUU4RkVDNw==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOkJEMEUxMEJDNTVCNzI4NkY2OTlEQjM0MDA0NTA1M0NB	07674D494908D2B78DFD4A9555E8FEC7	F5128C172A70C4FCD4739650B06DE9E2
+B4125EFB79D46BF9895709F985C92E99	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=10	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpCNDEyNUVGQjc5RDQ2QkY5ODk1NzA5Rjk4NUM5MkU5OTpJTlNUQUxMRURfQVQ6U2l0ZTo0NTEyNUIyMTdERUFFMDNFNkZGRTk5RTY0MTA4MjdDQg==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOkI0MTI1RUZCNzlENDZCRjk4OTU3MDlGOTg1QzkyRTk5	45125B217DEAE03E6FFE99E6410827CB	F5128C172A70C4FCD4739650B06DE9E2
+72C76C03ED0B42FA3FE4F9D22C4AF9E1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=11	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTo3MkM3NkMwM0VEMEI0MkZBM0ZFNEY5RDIyQzRBRjlFMTpJTlNUQUxMRURfQVQ6U2l0ZTpENkM4QzI2MDE4RUM2QjAwOUI0NjY1OTBFMEU4Q0E4OQ==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOjcyQzc2QzAzRUQwQjQyRkEzRkU0RjlEMjJDNEFGOUUx	D6C8C26018EC6B009B466590E0E8CA89	F5128C172A70C4FCD4739650B06DE9E2
+AD2DD15AC4E1DE0506843887B47C51A3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=12	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpBRDJERDE1QUM0RTFERTA1MDY4NDM4ODdCNDdDNTFBMzpJTlNUQUxMRURfQVQ6U2l0ZTpDMzBBOEVEMTRFRDU1OEM0MkQ0MEFCNTA3RTQ1QTIwQg==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOkFEMkREMTVBQzRFMURFMDUwNjg0Mzg4N0I0N0M1MUEz	C30A8ED14ED558C42D40AB507E45A20B	F5128C172A70C4FCD4739650B06DE9E2
+4C4E9998DAE30C954A93D78959FD511B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=13	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTo0QzRFOTk5OERBRTMwQzk1NEE5M0Q3ODk1OUZENTExQjpJTlNUQUxMRURfQVQ6U2l0ZTpBQjc4QkI0Q0NBQkVCREExRkFGMjhCNTgzRkVDRTFGNw==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOjRDNEU5OTk4REFFMzBDOTU0QTkzRDc4OTU5RkQ1MTFC	AB78BB4CCABEBDA1FAF28B583FECE1F7	F5128C172A70C4FCD4739650B06DE9E2
+4ECA02165275FA17BE60AF1D27AAB529	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=14	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTo0RUNBMDIxNjUyNzVGQTE3QkU2MEFGMUQyN0FBQjUyOTpJTlNUQUxMRURfQVQ6U2l0ZTowRUYzQjNDMzU1QTFCODIyOTQ3N0M3MzAwMzMzMUVDRQ==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOjRFQ0EwMjE2NTI3NUZBMTdCRTYwQUYxRDI3QUFCNTI5	0EF3B3C355A1B8229477C73003331ECE	F5128C172A70C4FCD4739650B06DE9E2
+AF388619F8517CBEAF23D06B4D3744FF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=15	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpBRjM4ODYxOUY4NTE3Q0JFQUYyM0QwNkI0RDM3NDRGRjpJTlNUQUxMRURfQVQ6U2l0ZTo1NDdENzFCNDNGODA0NDBDQ0NGNUJCQUE1OTJGMEJFOQ==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOkFGMzg4NjE5Rjg1MTdDQkVBRjIzRDA2QjREMzc0NEZG	547D71B43F80440CCCF5BBAA592F0BE9	F5128C172A70C4FCD4739650B06DE9E2
+42B4EEF09E97378B0E365F9BAAB50E1B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=16	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTo0MkI0RUVGMDlFOTczNzhCMEUzNjVGOUJBQUI1MEUxQjpJTlNUQUxMRURfQVQ6U2l0ZTo2REEwNDY2MzYxRkM3RkE4MDE5OTI1MjNDRUVCQjcwOA==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpBbnRlbm5hTW9kdWxlOjQyQjRFRUYwOUU5NzM3OEIwRTM2NUY5QkFBQjUwRTFC	6DA0466361FC7FA801992523CEEBB708	F5128C172A70C4FCD4739650B06DE9E2
+278A05C67D47D117C2DC5BDF5E00AE70	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=17	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZToyNzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpJTlNUQUxMRURfQVQ6U2l0ZTpFNjJENTc5QTZFRTEyMDA3NDIwMjQ1ODA5MzJGQ0FCMw==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOjI3OEEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcw	E62D579A6EE1200742024580932FCAB3	ADB1BAAC878C0BEEFE3175C60F44BB1D
+D52B212EDCBA464468608400BD348C29	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=18	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpENTJCMjEyRURDQkE0NjQ0Njg2MDg0MDBCRDM0OEMyOTpJTlNUQUxMRURfQVQ6U2l0ZTpERjhCQzMzMjAzRjkyOUJBODVFOUNFNTE5MDZDMzlFNw==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOkQ1MkIyMTJFRENCQTQ2NDQ2ODYwODQwMEJEMzQ4QzI5	DF8BC33203F929BA85E9CE51906C39E7	ADB1BAAC878C0BEEFE3175C60F44BB1D
+164612A68D6604469057C98DD4E4E3A5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=19	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZToxNjQ2MTJBNjhENjYwNDQ2OTA1N0M5OERENEU0RTNBNTpJTlNUQUxMRURfQVQ6U2l0ZTo3N0IwQ0NFNjBEQTNDQjFBNkI3NzEwMzU2Rjk4QkYyRA==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOjE2NDYxMkE2OEQ2NjA0NDY5MDU3Qzk4REQ0RTRFM0E1	77B0CCE60DA3CB1A6B7710356F98BF2D	ADB1BAAC878C0BEEFE3175C60F44BB1D
+07608E09EFA9DDDAC261FFF29353EB7C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=20	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTowNzYwOEUwOUVGQTlERERBQzI2MUZGRjI5MzUzRUI3QzpJTlNUQUxMRURfQVQ6U2l0ZTpCQUUwOTNFOTVGMkFDNUZGMDhDODgzMDg5NkY0MDc0Qg==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOjA3NjA4RTA5RUZBOUREREFDMjYxRkZGMjkzNTNFQjdD	BAE093E95F2AC5FF08C8830896F4074B	ADB1BAAC878C0BEEFE3175C60F44BB1D
+D0D8E6F7F0C3E9A975C1A6EC002BB838	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=21	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpEMEQ4RTZGN0YwQzNFOUE5NzVDMUE2RUMwMDJCQjgzODpJTlNUQUxMRURfQVQ6U2l0ZTo4MEU1MzdBQjA0OEU3OTkwOURBNDAyOThFMDZCMDg5RA==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOkQwRDhFNkY3RjBDM0U5QTk3NUMxQTZFQzAwMkJCODM4	80E537AB048E79909DA40298E06B089D	ADB1BAAC878C0BEEFE3175C60F44BB1D
+407B61608934EBEA646149D59327A8BA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=22	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTo0MDdCNjE2MDg5MzRFQkVBNjQ2MTQ5RDU5MzI3QThCQTpJTlNUQUxMRURfQVQ6U2l0ZTpFOEJBMUY3NDM0QTQ4NDIxNTBGQTI1OTUwNkE1NTQzNQ==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOjQwN0I2MTYwODkzNEVCRUE2NDYxNDlENTkzMjdBOEJB	E8BA1F7434A4842150FA259506A55435	ADB1BAAC878C0BEEFE3175C60F44BB1D
+0582853FB1CB183BDCCFD5F309FE9BF4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=23	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTowNTgyODUzRkIxQ0IxODNCRENDRkQ1RjMwOUZFOUJGNDpJTlNUQUxMRURfQVQ6U2l0ZToyRERENTlDQTJFODYwRTI4Q0I4REVCMUZFQUIzQ0FCNA==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOjA1ODI4NTNGQjFDQjE4M0JEQ0NGRDVGMzA5RkU5QkY0	2DDD59CA2E860E28CB8DEB1FEAB3CAB4	ADB1BAAC878C0BEEFE3175C60F44BB1D
+D14658CD5DB0F54275424F619076E408	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=24	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTpEMTQ2NThDRDVEQjBGNTQyNzU0MjRGNjE5MDc2RTQwODpJTlNUQUxMRURfQVQ6U2l0ZTowQjJEQkQ1QjJDODFEOTI4M0JCNDU4QTAzQUJDMzA1Qw==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOkQxNDY1OENENURCMEY1NDI3NTQyNEY2MTkwNzZFNDA4	0B2DBD5B2C81D9283BB458A03ABC305C	ADB1BAAC878C0BEEFE3175C60F44BB1D
+041E829548475CF0AAFC5D4F8F4AB0A3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=25	['123-abc']	123	123	['123', '456', '789']	45	1	urn:base64:QW50ZW5uYU1vZHVsZTowNDFFODI5NTQ4NDc1Q0YwQUFGQzVENEY4RjRBQjBBMzpJTlNUQUxMRURfQVQ6U2l0ZTpFRkUzRjA5MkZGNTVDNzY4QjREMUU0NTlCMkE5M0REOA==	\N	EFE3F092FF55C768B4D1E459B2A93DD8	\N
+\.
+
+COPY ties_data."PhysicalNetworkAppliance" (id, name, type, "geo-location", "REL_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE_EIID", "REL_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE") FROM stdin;
+055A9686FA759CD56ADB783408497661	PhysicalNetworkAppliance=LTE00001234/1	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjA1NUE5Njg2RkE3NTlDRDU2QURCNzgzNDA4NDk3NjYxOklOU1RBTExFRF9BVDpTaXRlOkNGODlDMTc0RDA2ODU0QzBDNDFCNzREMkM0Njg0NkRE	CF89C174D06854C0C41B74D2C46846DD
+D6158434F8DD2DC217EC2198636A5643	PhysicalNetworkAppliance=LTE00001234/2	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkQ2MTU4NDM0RjhERDJEQzIxN0VDMjE5ODYzNkE1NjQzOklOU1RBTExFRF9BVDpTaXRlOjI2ODc0RDMyNDFDRUZGRjYwRTA4NEZFRkNDNzJCOTcz	26874D3241CEFFF60E084FEFCC72B973
+B42BAF4C45D638133FEBDCC87E48866B	PhysicalNetworkAppliance=LTE00001234/3	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkI0MkJBRjRDNDVENjM4MTMzRkVCRENDODdFNDg4NjZCOklOU1RBTExFRF9BVDpTaXRlOjA3NzhBNTc2NDVERTlEM0U0Qjc0RDMxRjlGNUNCODU4	0778A57645DE9D3E4B74D31F9F5CB858
+C29237C44DB2950D7A0AC8508B4B6B18	PhysicalNetworkAppliance=LTE00001234/4	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkMyOTIzN0M0NERCMjk1MEQ3QTBBQzg1MDhCNEI2QjE4OklOU1RBTExFRF9BVDpTaXRlOkY0QjNFNjYxOUJCRDE3NkI0RjJEQjc1NEFGNjUyNEJD	F4B3E6619BBD176B4F2DB754AF6524BC
+E817613E06A4F215CDC8A67C1A0DD937	PhysicalNetworkAppliance=LTE00001234/5	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkU4MTc2MTNFMDZBNEYyMTVDREM4QTY3QzFBMEREOTM3OklOU1RBTExFRF9BVDpTaXRlOjA4RUNDOUU0QTM4MTc1NDE3NEVDNEIwMDQ1NDE4RjUz	08ECC9E4A381754174EC4B0045418F53
+13E106D008FBEED974FAB64773963AF9	PhysicalNetworkAppliance=LTE00001234/6	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjEzRTEwNkQwMDhGQkVFRDk3NEZBQjY0NzczOTYzQUY5OklOU1RBTExFRF9BVDpTaXRlOjEyQjc2NDJDNDU1MEQ2NTdCRTBEMEY1RkZCNjk3NUI0	12B7642C4550D657BE0D0F5FFB6975B4
+6AC6021909616829AD166CC7C924B638	PhysicalNetworkAppliance=LTE00001234/7	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjZBQzYwMjE5MDk2MTY4MjlBRDE2NkNDN0M5MjRCNjM4OklOU1RBTExFRF9BVDpTaXRlOjA5QzU2ODcwMEUyODE4NTUzNEE4MzY5NDZBNDA2NjU2	09C568700E28185534A836946A406656
+EE539591F77499CD48820297DC00441A	PhysicalNetworkAppliance=LTE00001234/8	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkVFNTM5NTkxRjc3NDk5Q0Q0ODgyMDI5N0RDMDA0NDFBOklOU1RBTExFRF9BVDpTaXRlOkZFRjIyNDQxODJCQjU3OUY1RDY3QzAyNEFEQkU4NTEw	FEF2244182BB579F5D67C024ADBE8510
+C9DD6DD96075F773CC2164519956D80A	PhysicalNetworkAppliance=LTE00001234/9	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkM5REQ2REQ5NjA3NUY3NzNDQzIxNjQ1MTk5NTZEODBBOklOU1RBTExFRF9BVDpTaXRlOjg2NjFBRURDOTJDN0E0MjhCQkI1MTM3MTUwQTg0RUZG	8661AEDC92C7A428BBB5137150A84EFF
+1EBBE2C584784CF60E565DDC8D02B3C4	PhysicalNetworkAppliance=LTE00001234/10	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjFFQkJFMkM1ODQ3ODRDRjYwRTU2NUREQzhEMDJCM0M0OklOU1RBTExFRF9BVDpTaXRlOjA3Njc0RDQ5NDkwOEQyQjc4REZENEE5NTU1RThGRUM3	07674D494908D2B78DFD4A9555E8FEC7
+34B63E1FC50D1DA429CF5CA947157EFC	PhysicalNetworkAppliance=LTE00001234/11	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjM0QjYzRTFGQzUwRDFEQTQyOUNGNUNBOTQ3MTU3RUZDOklOU1RBTExFRF9BVDpTaXRlOjQ1MTI1QjIxN0RFQUUwM0U2RkZFOTlFNjQxMDgyN0NC	45125B217DEAE03E6FFE99E6410827CB
+E23C9147FAD7958E85552A805D6DFCFF	PhysicalNetworkAppliance=LTE00001234/12	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkUyM0M5MTQ3RkFENzk1OEU4NTU1MkE4MDVENkRGQ0ZGOklOU1RBTExFRF9BVDpTaXRlOkQ2QzhDMjYwMThFQzZCMDA5QjQ2NjU5MEUwRThDQTg5	D6C8C26018EC6B009B466590E0E8CA89
+EA2953CF0A080F10E6722AE92E858CBB	PhysicalNetworkAppliance=LTE00001234/13	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkVBMjk1M0NGMEEwODBGMTBFNjcyMkFFOTJFODU4Q0JCOklOU1RBTExFRF9BVDpTaXRlOkMzMEE4RUQxNEVENTU4QzQyRDQwQUI1MDdFNDVBMjBC	C30A8ED14ED558C42D40AB507E45A20B
+D92495521DCCC7DE492B5FEDC9D4A6E1	PhysicalNetworkAppliance=LTE00001234/14	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkQ5MjQ5NTUyMURDQ0M3REU0OTJCNUZFREM5RDRBNkUxOklOU1RBTExFRF9BVDpTaXRlOkFCNzhCQjRDQ0FCRUJEQTFGQUYyOEI1ODNGRUNFMUY3	AB78BB4CCABEBDA1FAF28B583FECE1F7
+B9B042D33BCC1CB074144DA3D5351DBF	PhysicalNetworkAppliance=LTE00001234/15	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkI5QjA0MkQzM0JDQzFDQjA3NDE0NERBM0Q1MzUxREJGOklOU1RBTExFRF9BVDpTaXRlOjBFRjNCM0MzNTVBMUI4MjI5NDc3QzczMDAzMzMxRUNF	0EF3B3C355A1B8229477C73003331ECE
+2E27426BC7D0DC99770528300F2DC74C	PhysicalNetworkAppliance=LTE00001234/16	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjJFMjc0MjZCQzdEMERDOTk3NzA1MjgzMDBGMkRDNzRDOklOU1RBTExFRF9BVDpTaXRlOjU0N0Q3MUI0M0Y4MDQ0MENDQ0Y1QkJBQTU5MkYwQkU5	547D71B43F80440CCCF5BBAA592F0BE9
+2312B923E694DBE508AC94E232D87CFF	PhysicalNetworkAppliance=LTE00001234/17	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjIzMTJCOTIzRTY5NERCRTUwOEFDOTRFMjMyRDg3Q0ZGOklOU1RBTExFRF9BVDpTaXRlOjZEQTA0NjYzNjFGQzdGQTgwMTk5MjUyM0NFRUJCNzA4	6DA0466361FC7FA801992523CEEBB708
+041FA4CF0EE87A4C8F4D77C18A382819	PhysicalNetworkAppliance=LTE00001234/18	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjA0MUZBNENGMEVFODdBNEM4RjRENzdDMThBMzgyODE5OklOU1RBTExFRF9BVDpTaXRlOkU2MkQ1NzlBNkVFMTIwMDc0MjAyNDU4MDkzMkZDQUIz	E62D579A6EE1200742024580932FCAB3
+268C22D2FBF9BFD9A46FCABD79E7423A	PhysicalNetworkAppliance=LTE00001234/19	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjI2OEMyMkQyRkJGOUJGRDlBNDZGQ0FCRDc5RTc0MjNBOklOU1RBTExFRF9BVDpTaXRlOkRGOEJDMzMyMDNGOTI5QkE4NUU5Q0U1MTkwNkMzOUU3	DF8BC33203F929BA85E9CE51906C39E7
+3B02F5A1C69470E91834432761CAEBFB	PhysicalNetworkAppliance=LTE00001234/20	ExampleType	POINT(59.4019881 17.9419888)	urn:base64:UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjNCMDJGNUExQzY5NDcwRTkxODM0NDMyNzYxQ0FFQkZCOklOU1RBTExFRF9BVDpTaXRlOjc3QjBDQ0U2MERBM0NCMUE2Qjc3MTAzNTZGOThCRjJE	77B0CCE60DA3CB1A6B7710356F98BF2D
+\.
+
+COPY ties_data."ENodeBFunction" (id, fdn, "eNBId", "eNodeBPlmnId", "REL_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE_EIID", "REL_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE") FROM stdin;
+8EFAD2F305499DCD360040BD6F57B54E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=1	1	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjA1NUE5Njg2RkE3NTlDRDU2QURCNzgzNDA4NDk3NjYx	055A9686FA759CD56ADB783408497661
+C6694F03768AF9EE83DC293C10473076	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=2	2	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkQ2MTU4NDM0RjhERDJEQzIxN0VDMjE5ODYzNkE1NjQz	D6158434F8DD2DC217EC2198636A5643
+54D62577A2B3ED373FA47BBD89A67473	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=3	3	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkI0MkJBRjRDNDVENjM4MTMzRkVCRENDODdFNDg4NjZC	B42BAF4C45D638133FEBDCC87E48866B
+3B603CD3E74F0F9053DEF063EFAF2012	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=4	4	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkMyOTIzN0M0NERCMjk1MEQ3QTBBQzg1MDhCNEI2QjE4	C29237C44DB2950D7A0AC8508B4B6B18
+1D9917590E5F75F44DF7EF626592C2C7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=5	5	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkU4MTc2MTNFMDZBNEYyMTVDREM4QTY3QzFBMEREOTM3	E817613E06A4F215CDC8A67C1A0DD937
+B3B3845E7D8910D6906B5EB41A8E0696	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=6	6	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjEzRTEwNkQwMDhGQkVFRDk3NEZBQjY0NzczOTYzQUY5	13E106D008FBEED974FAB64773963AF9
+4C8B24AC011A734A5FEBF321C77289AB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=7	7	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjZBQzYwMjE5MDk2MTY4MjlBRDE2NkNDN0M5MjRCNjM4	6AC6021909616829AD166CC7C924B638
+96220B64D4A4C6F6B17DF30B12B841D3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=8	8	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkVFNTM5NTkxRjc3NDk5Q0Q0ODgyMDI5N0RDMDA0NDFB	EE539591F77499CD48820297DC00441A
+4FBA45FB12D28F9106A09E045DE90254	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=9	9	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkM5REQ2REQ5NjA3NUY3NzNDQzIxNjQ1MTk5NTZEODBB	C9DD6DD96075F773CC2164519956D80A
+222B3B5942A23115B9C1AC2B94AF8548	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=10	10	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjFFQkJFMkM1ODQ3ODRDRjYwRTU2NUREQzhEMDJCM0M0	1EBBE2C584784CF60E565DDC8D02B3C4
+FDB1D1C7AC573BA174781DD2DD7359FE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=11	11	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjM0QjYzRTFGQzUwRDFEQTQyOUNGNUNBOTQ3MTU3RUZD	34B63E1FC50D1DA429CF5CA947157EFC
+FE3075645E2303A67B9D0BAD3CCB29BC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=12	12	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkUyM0M5MTQ3RkFENzk1OEU4NTU1MkE4MDVENkRGQ0ZG	E23C9147FAD7958E85552A805D6DFCFF
+CF6B05084CD85A8C0943B77317510652	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=13	13	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkVBMjk1M0NGMEEwODBGMTBFNjcyMkFFOTJFODU4Q0JC	EA2953CF0A080F10E6722AE92E858CBB
+8094F5C9E30C346536F0A08A851338F6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=14	14	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkQ5MjQ5NTUyMURDQ0M3REU0OTJCNUZFREM5RDRBNkUx	D92495521DCCC7DE492B5FEDC9D4A6E1
+E87A72FDF835513E6BACBF730D5BA6C8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=15	15	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOkI5QjA0MkQzM0JDQzFDQjA3NDE0NERBM0Q1MzUxREJG	B9B042D33BCC1CB074144DA3D5351DBF
+8E99154C3A70826BBD373F06BC1C752B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=16	16	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjJFMjc0MjZCQzdEMERDOTk3NzA1MjgzMDBGMkRDNzRD	2E27426BC7D0DC99770528300F2DC74C
+CEE5D7B02D903A316D0A017C50FC9993	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=17	17	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjIzMTJCOTIzRTY5NERCRTUwOEFDOTRFMjMyRDg3Q0ZG	2312B923E694DBE508AC94E232D87CFF
+E240B26BA8EE38087134B6D22E24BBDB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=18	18	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjA0MUZBNENGMEVFODdBNEM4RjRENzdDMThBMzgyODE5	041FA4CF0EE87A4C8F4D77C18A382819
+FC195225D4CD060E249281C9BBDAF964	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=19	19	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjI2OEMyMkQyRkJGOUJGRDlBNDZGQ0FCRDc5RTc0MjNB	268C22D2FBF9BFD9A46FCABD79E7423A
+0C2651AB5D430123729B336E8635E0E0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ENodeBFunction=20	20	{"mcc": "02", "mnc": "456", "mncLength": "3"}	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UkVBTElTRURfQlk6UGh5c2ljYWxOZXR3b3JrQXBwbGlhbmNlOjNCMDJGNUExQzY5NDcwRTkxODM0NDMyNzYxQ0FFQkZC	3B02F5A1C69470E91834432761CAEBFB
+\.
+
+COPY ties_data."EUtranCell" (id, fdn, "cellId", earfcndl, earfcnul, earfcn, tac, "duplexType", "REL_ENODEBFUNCTION_PROVIDES_EUTRANCELL_EIID", "REL_SECTOR_GROUPS_EUTRANCELL_EIID", "REL_ENODEBFUNCTION_PROVIDES_EUTRANCELL", "REL_SECTOR_GROUPS_EUTRANCELL") FROM stdin;
+12AE3AAB332B7CBA75F5B61A3E11D9D7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=1	1	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6RVV0cmFuQ2VsbDoxMkFFM0FBQjMzMkI3Q0JBNzVGNUI2MUEzRTExRDlENw==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjEyQUUzQUFCMzMyQjdDQkE3NUY1QjYxQTNFMTFEOUQ3	8EFAD2F305499DCD360040BD6F57B54E	2F445AA5744FA3D230FD6838531F1407
+21212B52246A87F922337659491424E2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=2	2	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6RVV0cmFuQ2VsbDoyMTIxMkI1MjI0NkE4N0Y5MjIzMzc2NTk0OTE0MjRFMg==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjIxMjEyQjUyMjQ2QTg3RjkyMjMzNzY1OTQ5MTQyNEUy	8EFAD2F305499DCD360040BD6F57B54E	2F445AA5744FA3D230FD6838531F1407
+C9DD733A18BC9CA66EAE0AA5688EE685	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=3	3	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6RVV0cmFuQ2VsbDpDOURENzMzQTE4QkM5Q0E2NkVBRTBBQTU2ODhFRTY4NQ==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOkM5REQ3MzNBMThCQzlDQTY2RUFFMEFBNTY4OEVFNjg1	8EFAD2F305499DCD360040BD6F57B54E	2F445AA5744FA3D230FD6838531F1407
+63E88935744D6C3EB59EFE02CDABC063	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=4	4	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6RVV0cmFuQ2VsbDo2M0U4ODkzNTc0NEQ2QzNFQjU5RUZFMDJDREFCQzA2Mw==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjYzRTg4OTM1NzQ0RDZDM0VCNTlFRkUwMkNEQUJDMDYz	8EFAD2F305499DCD360040BD6F57B54E	2F445AA5744FA3D230FD6838531F1407
+59A2204924C4C1601A19AC8847D302E8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=5	5	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6RVV0cmFuQ2VsbDo1OUEyMjA0OTI0QzRDMTYwMUExOUFDODg0N0QzMDJFOA==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjU5QTIyMDQ5MjRDNEMxNjAxQTE5QUM4ODQ3RDMwMkU4	C6694F03768AF9EE83DC293C10473076	2F445AA5744FA3D230FD6838531F1407
+8926691599892761C9FF8CF3F325068E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=6	6	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6RVV0cmFuQ2VsbDo4OTI2NjkxNTk5ODkyNzYxQzlGRjhDRjNGMzI1MDY4RQ==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjg5MjY2OTE1OTk4OTI3NjFDOUZGOENGM0YzMjUwNjhF	C6694F03768AF9EE83DC293C10473076	2F445AA5744FA3D230FD6838531F1407
+689B6BBFDD5B426FEDA6B1CE46F8B893	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=7	7	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6RVV0cmFuQ2VsbDo2ODlCNkJCRkRENUI0MjZGRURBNkIxQ0U0NkY4Qjg5Mw==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjY4OUI2QkJGREQ1QjQyNkZFREE2QjFDRTQ2RjhCODkz	C6694F03768AF9EE83DC293C10473076	2F445AA5744FA3D230FD6838531F1407
+A275D1706536A77D7ABA6BA2A3C56DFE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=8	8	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6RVV0cmFuQ2VsbDpBMjc1RDE3MDY1MzZBNzdEN0FCQTZCQTJBM0M1NkRGRQ==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOkEyNzVEMTcwNjUzNkE3N0Q3QUJBNkJBMkEzQzU2REZF	C6694F03768AF9EE83DC293C10473076	2F445AA5744FA3D230FD6838531F1407
+08ABC73D86C5B8380BBC5B524CCEC862	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=9	9	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6RVV0cmFuQ2VsbDowOEFCQzczRDg2QzVCODM4MEJCQzVCNTI0Q0NFQzg2Mg==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjA4QUJDNzNEODZDNUI4MzgwQkJDNUI1MjRDQ0VDODYy	54D62577A2B3ED373FA47BBD89A67473	2F445AA5744FA3D230FD6838531F1407
+B611F63DE77FC5C333A17EC047E5EF43	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=10	10	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6RVV0cmFuQ2VsbDpCNjExRjYzREU3N0ZDNUMzMzNBMTdFQzA0N0U1RUY0Mw==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOkI2MTFGNjNERTc3RkM1QzMzM0ExN0VDMDQ3RTVFRjQz	54D62577A2B3ED373FA47BBD89A67473	2F445AA5744FA3D230FD6838531F1407
+CF8344F795B13350050E52C83B97DCB9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=11	11	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6RVV0cmFuQ2VsbDpDRjgzNDRGNzk1QjEzMzUwMDUwRTUyQzgzQjk3RENCOQ==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOkNGODM0NEY3OTVCMTMzNTAwNTBFNTJDODNCOTdEQ0I5	54D62577A2B3ED373FA47BBD89A67473	2F445AA5744FA3D230FD6838531F1407
+59A2E7E8504125EB8DF3765FAEBAA53B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=12	12	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6RVV0cmFuQ2VsbDo1OUEyRTdFODUwNDEyNUVCOERGMzc2NUZBRUJBQTUzQg==	urn:base64:U2VjdG9yOjJGNDQ1QUE1NzQ0RkEzRDIzMEZENjgzODUzMUYxNDA3OkdST1VQUzpFVXRyYW5DZWxsOjU5QTJFN0U4NTA0MTI1RUI4REYzNzY1RkFFQkFBNTNC	54D62577A2B3ED373FA47BBD89A67473	2F445AA5744FA3D230FD6838531F1407
+DBA83230C0FA71993F8FDD836354223E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=13	13	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6RVV0cmFuQ2VsbDpEQkE4MzIzMEMwRkE3MTk5M0Y4RkREODM2MzU0MjIzRQ==	\N	3B603CD3E74F0F9053DEF063EFAF2012	\N
+E0FECB6B51C69932562B6C194362CC8E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=14	14	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6RVV0cmFuQ2VsbDpFMEZFQ0I2QjUxQzY5OTMyNTYyQjZDMTk0MzYyQ0M4RQ==	\N	3B603CD3E74F0F9053DEF063EFAF2012	\N
+227EC58BE9277A999B66B53E6C616CF8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=15	15	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6RVV0cmFuQ2VsbDoyMjdFQzU4QkU5Mjc3QTk5OUI2NkI1M0U2QzYxNkNGOA==	\N	3B603CD3E74F0F9053DEF063EFAF2012	\N
+A5D220B1DFEA928C17B8BB92DF126488	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=16	16	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6RVV0cmFuQ2VsbDpBNUQyMjBCMURGRUE5MjhDMTdCOEJCOTJERjEyNjQ4OA==	\N	3B603CD3E74F0F9053DEF063EFAF2012	\N
+67FFC7F75A2EF0CAAC8CE70AAF72B105	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=17	17	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6RVV0cmFuQ2VsbDo2N0ZGQzdGNzVBMkVGMENBQUM4Q0U3MEFBRjcyQjEwNQ==	\N	1D9917590E5F75F44DF7EF626592C2C7	\N
+BB1843D2601AE705F34BF12D2A422033	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=18	18	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6RVV0cmFuQ2VsbDpCQjE4NDNEMjYwMUFFNzA1RjM0QkYxMkQyQTQyMjAzMw==	\N	1D9917590E5F75F44DF7EF626592C2C7	\N
+8F6E230CF265F8C5A14792C09A668690	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=19	19	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6RVV0cmFuQ2VsbDo4RjZFMjMwQ0YyNjVGOEM1QTE0NzkyQzA5QTY2ODY5MA==	\N	1D9917590E5F75F44DF7EF626592C2C7	\N
+65A7BB72ABC34E7D2C9D20BD22B03F60	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=20	20	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6RVV0cmFuQ2VsbDo2NUE3QkI3MkFCQzM0RTdEMkM5RDIwQkQyMkIwM0Y2MA==	\N	1D9917590E5F75F44DF7EF626592C2C7	\N
+47518775399CE9F74BA299FC7C033732	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=21	21	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6RVV0cmFuQ2VsbDo0NzUxODc3NTM5OUNFOUY3NEJBMjk5RkM3QzAzMzczMg==	\N	B3B3845E7D8910D6906B5EB41A8E0696	\N
+F4C7D348240B9E2AE1C30DBA8A8225FC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=22	22	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6RVV0cmFuQ2VsbDpGNEM3RDM0ODI0MEI5RTJBRTFDMzBEQkE4QTgyMjVGQw==	\N	B3B3845E7D8910D6906B5EB41A8E0696	\N
+0157056AAD7D700AB74649AD23AB3516	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=23	23	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6RVV0cmFuQ2VsbDowMTU3MDU2QUFEN0Q3MDBBQjc0NjQ5QUQyM0FCMzUxNg==	\N	B3B3845E7D8910D6906B5EB41A8E0696	\N
+B4066E743DCF48F02433A30045B2BD67	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=24	24	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6RVV0cmFuQ2VsbDpCNDA2NkU3NDNEQ0Y0OEYwMjQzM0EzMDA0NUIyQkQ2Nw==	\N	B3B3845E7D8910D6906B5EB41A8E0696	\N
+9481FE5EE7027E8FFC5F6C5054E0458D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=25	25	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6RVV0cmFuQ2VsbDo5NDgxRkU1RUU3MDI3RThGRkM1RjZDNTA1NEUwNDU4RA==	\N	4C8B24AC011A734A5FEBF321C77289AB	\N
+642E1BBE8723AC9C4590F6703EDC44F1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=26	26	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6RVV0cmFuQ2VsbDo2NDJFMUJCRTg3MjNBQzlDNDU5MEY2NzAzRURDNDRGMQ==	\N	4C8B24AC011A734A5FEBF321C77289AB	\N
+123345DFD745627E51F8E140993329B1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=27	27	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6RVV0cmFuQ2VsbDoxMjMzNDVERkQ3NDU2MjdFNTFGOEUxNDA5OTMzMjlCMQ==	\N	4C8B24AC011A734A5FEBF321C77289AB	\N
+204DA5409FF80E9758648DB75A639FB3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=28	28	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6RVV0cmFuQ2VsbDoyMDREQTU0MDlGRjgwRTk3NTg2NDhEQjc1QTYzOUZCMw==	\N	4C8B24AC011A734A5FEBF321C77289AB	\N
+02D627EE69354C3244CF3CE887BE50F3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=29	29	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6RVV0cmFuQ2VsbDowMkQ2MjdFRTY5MzU0QzMyNDRDRjNDRTg4N0JFNTBGMw==	\N	96220B64D4A4C6F6B17DF30B12B841D3	\N
+E7970AA806886DD3DD228D9AD939E8B5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=30	30	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6RVV0cmFuQ2VsbDpFNzk3MEFBODA2ODg2REQzREQyMjhEOUFEOTM5RThCNQ==	\N	96220B64D4A4C6F6B17DF30B12B841D3	\N
+C677054B2AA8339E00BCD230E3785DA3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=31	31	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6RVV0cmFuQ2VsbDpDNjc3MDU0QjJBQTgzMzlFMDBCQ0QyMzBFMzc4NURBMw==	\N	96220B64D4A4C6F6B17DF30B12B841D3	\N
+7FAE51F52ECAC791B2407BDB68B5A7F7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=32	32	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6RVV0cmFuQ2VsbDo3RkFFNTFGNTJFQ0FDNzkxQjI0MDdCREI2OEI1QTdGNw==	\N	96220B64D4A4C6F6B17DF30B12B841D3	\N
+67D200D0CC216063129C7A9E844BF0F0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=33	33	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6RVV0cmFuQ2VsbDo2N0QyMDBEMENDMjE2MDYzMTI5QzdBOUU4NDRCRjBGMA==	\N	4FBA45FB12D28F9106A09E045DE90254	\N
+30B303C19C0C8F057A1D2397105D346E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=34	34	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6RVV0cmFuQ2VsbDozMEIzMDNDMTlDMEM4RjA1N0ExRDIzOTcxMDVEMzQ2RQ==	\N	4FBA45FB12D28F9106A09E045DE90254	\N
+98037769BA85EBE942522D5C4C6CB02F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=35	35	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6RVV0cmFuQ2VsbDo5ODAzNzc2OUJBODVFQkU5NDI1MjJENUM0QzZDQjAyRg==	\N	4FBA45FB12D28F9106A09E045DE90254	\N
+B2C3516887144F66EF3F31F641737DA0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=36	36	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6RVV0cmFuQ2VsbDpCMkMzNTE2ODg3MTQ0RjY2RUYzRjMxRjY0MTczN0RBMA==	\N	4FBA45FB12D28F9106A09E045DE90254	\N
+E312426E3CEA83823D343B265B38818A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=37	37	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6RVV0cmFuQ2VsbDpFMzEyNDI2RTNDRUE4MzgyM0QzNDNCMjY1QjM4ODE4QQ==	\N	222B3B5942A23115B9C1AC2B94AF8548	\N
+A7925E8575009D0F16D185E257879770	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=38	38	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6RVV0cmFuQ2VsbDpBNzkyNUU4NTc1MDA5RDBGMTZEMTg1RTI1Nzg3OTc3MA==	\N	222B3B5942A23115B9C1AC2B94AF8548	\N
+72BC25B5613B9BC530820958F393E90C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=39	39	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6RVV0cmFuQ2VsbDo3MkJDMjVCNTYxM0I5QkM1MzA4MjA5NThGMzkzRTkwQw==	\N	222B3B5942A23115B9C1AC2B94AF8548	\N
+AAF63B5C5CE80B318F4452560C9B5E5B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=40	40	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6RVV0cmFuQ2VsbDpBQUY2M0I1QzVDRTgwQjMxOEY0NDUyNTYwQzlCNUU1Qg==	\N	222B3B5942A23115B9C1AC2B94AF8548	\N
+E0F686B41ABE51CF5C009608A1BB984F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=41	41	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6RVV0cmFuQ2VsbDpFMEY2ODZCNDFBQkU1MUNGNUMwMDk2MDhBMUJCOTg0Rg==	\N	FDB1D1C7AC573BA174781DD2DD7359FE	\N
+0AB0C425E937EE4E7B798798520F1CA3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=42	42	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6RVV0cmFuQ2VsbDowQUIwQzQyNUU5MzdFRTRFN0I3OTg3OTg1MjBGMUNBMw==	\N	FDB1D1C7AC573BA174781DD2DD7359FE	\N
+ABAC1A34D71EAE18E71987C15DED1D71	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=43	43	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6RVV0cmFuQ2VsbDpBQkFDMUEzNEQ3MUVBRTE4RTcxOTg3QzE1REVEMUQ3MQ==	\N	FDB1D1C7AC573BA174781DD2DD7359FE	\N
+BB47B85699CA2CACFF9F2011FA2D6CC2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=44	44	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6RVV0cmFuQ2VsbDpCQjQ3Qjg1Njk5Q0EyQ0FDRkY5RjIwMTFGQTJENkNDMg==	\N	FDB1D1C7AC573BA174781DD2DD7359FE	\N
+FB6CBB0CBBC6F11868B94ED977156677	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=45	45	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6RVV0cmFuQ2VsbDpGQjZDQkIwQ0JCQzZGMTE4NjhCOTRFRDk3NzE1NjY3Nw==	\N	FE3075645E2303A67B9D0BAD3CCB29BC	\N
+04288A9A95188D1F1DD59C90A49D2649	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=46	46	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6RVV0cmFuQ2VsbDowNDI4OEE5QTk1MTg4RDFGMURENTlDOTBBNDlEMjY0OQ==	\N	FE3075645E2303A67B9D0BAD3CCB29BC	\N
+2A6054CCCD7179F09BC118B2818B1ADE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=47	47	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6RVV0cmFuQ2VsbDoyQTYwNTRDQ0NENzE3OUYwOUJDMTE4QjI4MThCMUFERQ==	\N	FE3075645E2303A67B9D0BAD3CCB29BC	\N
+51C5046896461BA89744F75384ABDB93	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=48	48	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6RVV0cmFuQ2VsbDo1MUM1MDQ2ODk2NDYxQkE4OTc0NEY3NTM4NEFCREI5Mw==	\N	FE3075645E2303A67B9D0BAD3CCB29BC	\N
+7C9D2459365CC80BCEC84E4DB9713120	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=49	49	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6RVV0cmFuQ2VsbDo3QzlEMjQ1OTM2NUNDODBCQ0VDODRFNERCOTcxMzEyMA==	\N	CF6B05084CD85A8C0943B77317510652	\N
+9C4358CADC08E56A19E8FEE1C01A706F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=50	50	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6RVV0cmFuQ2VsbDo5QzQzNThDQURDMDhFNTZBMTlFOEZFRTFDMDFBNzA2Rg==	\N	CF6B05084CD85A8C0943B77317510652	\N
+F40242B0F0708E09BB07635BC7505776	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=51	51	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6RVV0cmFuQ2VsbDpGNDAyNDJCMEYwNzA4RTA5QkIwNzYzNUJDNzUwNTc3Ng==	\N	CF6B05084CD85A8C0943B77317510652	\N
+353E445EAFE3FA586D6768F72A2623A4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=52	52	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6RVV0cmFuQ2VsbDozNTNFNDQ1RUFGRTNGQTU4NkQ2NzY4RjcyQTI2MjNBNA==	\N	CF6B05084CD85A8C0943B77317510652	\N
+7DF9374EADA6885BF3CEF2318894608C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=53	53	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6RVV0cmFuQ2VsbDo3REY5Mzc0RUFEQTY4ODVCRjNDRUYyMzE4ODk0NjA4Qw==	\N	8094F5C9E30C346536F0A08A851338F6	\N
+3DA35D49D1D9C51A234035AD3A3FD37E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=54	54	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6RVV0cmFuQ2VsbDozREEzNUQ0OUQxRDlDNTFBMjM0MDM1QUQzQTNGRDM3RQ==	\N	8094F5C9E30C346536F0A08A851338F6	\N
+2A112353EC75F9AC2BA43EE708296A01	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=55	55	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6RVV0cmFuQ2VsbDoyQTExMjM1M0VDNzVGOUFDMkJBNDNFRTcwODI5NkEwMQ==	\N	8094F5C9E30C346536F0A08A851338F6	\N
+139F0AD2D641D97177702FBF5EFF30FE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=56	56	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6RVV0cmFuQ2VsbDoxMzlGMEFEMkQ2NDFEOTcxNzc3MDJGQkY1RUZGMzBGRQ==	\N	8094F5C9E30C346536F0A08A851338F6	\N
+8FF0611DA8F0CD68E3A215AA07CBB20D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=57	57	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6RVV0cmFuQ2VsbDo4RkYwNjExREE4RjBDRDY4RTNBMjE1QUEwN0NCQjIwRA==	\N	E87A72FDF835513E6BACBF730D5BA6C8	\N
+5CAC3487A85DDDD336B1F580FD5F72DD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=58	58	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6RVV0cmFuQ2VsbDo1Q0FDMzQ4N0E4NUREREQzMzZCMUY1ODBGRDVGNzJERA==	\N	E87A72FDF835513E6BACBF730D5BA6C8	\N
+73C0EC78E9DAEE5347D45F10570EC851	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=59	59	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6RVV0cmFuQ2VsbDo3M0MwRUM3OEU5REFFRTUzNDdENDVGMTA1NzBFQzg1MQ==	\N	E87A72FDF835513E6BACBF730D5BA6C8	\N
+98BDDA8B54B7B8927675E77C927D8283	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=60	60	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6RVV0cmFuQ2VsbDo5OEJEREE4QjU0QjdCODkyNzY3NUU3N0M5MjdEODI4Mw==	\N	E87A72FDF835513E6BACBF730D5BA6C8	\N
+71356FCE5C6358DAE8F8BF3F7C9BF014	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=61	61	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6RVV0cmFuQ2VsbDo3MTM1NkZDRTVDNjM1OERBRThGOEJGM0Y3QzlCRjAxNA==	\N	8E99154C3A70826BBD373F06BC1C752B	\N
+E5489E6D6CC07891F541BE41EF37AA63	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=62	62	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6RVV0cmFuQ2VsbDpFNTQ4OUU2RDZDQzA3ODkxRjU0MUJFNDFFRjM3QUE2Mw==	\N	8E99154C3A70826BBD373F06BC1C752B	\N
+D0EA58BE0AC1671B936F15C67DEA8892	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=63	63	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6RVV0cmFuQ2VsbDpEMEVBNThCRTBBQzE2NzFCOTM2RjE1QzY3REVBODg5Mg==	\N	8E99154C3A70826BBD373F06BC1C752B	\N
+9A030D9EDC0C8B04A0C5D24A3A223137	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=64	64	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6RVV0cmFuQ2VsbDo5QTAzMEQ5RURDMEM4QjA0QTBDNUQyNEEzQTIyMzEzNw==	\N	8E99154C3A70826BBD373F06BC1C752B	\N
+566B9566A40AB0CCF1684A8C75D6E8F0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=65	65	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6RVV0cmFuQ2VsbDo1NjZCOTU2NkE0MEFCMENDRjE2ODRBOEM3NUQ2RThGMA==	\N	CEE5D7B02D903A316D0A017C50FC9993	\N
+A5587D51DDB4D1AAF88075EFAFD3FF1A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=66	66	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6RVV0cmFuQ2VsbDpBNTU4N0Q1MUREQjREMUFBRjg4MDc1RUZBRkQzRkYxQQ==	\N	CEE5D7B02D903A316D0A017C50FC9993	\N
+792FC15FA3F55562373FF5B67C8979D9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=67	67	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6RVV0cmFuQ2VsbDo3OTJGQzE1RkEzRjU1NTYyMzczRkY1QjY3Qzg5NzlEOQ==	\N	CEE5D7B02D903A316D0A017C50FC9993	\N
+6FAAB53473F084DC886D1E04265EEAD1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=68	68	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6RVV0cmFuQ2VsbDo2RkFBQjUzNDczRjA4NERDODg2RDFFMDQyNjVFRUFEMQ==	\N	CEE5D7B02D903A316D0A017C50FC9993	\N
+07B3711677085E16F48AED99BEA40966	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=69	69	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6RVV0cmFuQ2VsbDowN0IzNzExNjc3MDg1RTE2RjQ4QUVEOTlCRUE0MDk2Ng==	\N	E240B26BA8EE38087134B6D22E24BBDB	\N
+B95EBE4245801D7185E1D05E5BBDA3F3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=70	70	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6RVV0cmFuQ2VsbDpCOTVFQkU0MjQ1ODAxRDcxODVFMUQwNUU1QkJEQTNGMw==	\N	E240B26BA8EE38087134B6D22E24BBDB	\N
+ABFBE9EA7673A191DB6A51439D5515D5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=71	71	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6RVV0cmFuQ2VsbDpBQkZCRTlFQTc2NzNBMTkxREI2QTUxNDM5RDU1MTVENQ==	\N	E240B26BA8EE38087134B6D22E24BBDB	\N
+62EDC7D4D6A1D361E12FEB2688E43A89	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=72	72	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6RVV0cmFuQ2VsbDo2MkVEQzdENEQ2QTFEMzYxRTEyRkVCMjY4OEU0M0E4OQ==	\N	E240B26BA8EE38087134B6D22E24BBDB	\N
+EE7B5EBAE21343E68AC197150FA2655E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=73	73	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6RVV0cmFuQ2VsbDpFRTdCNUVCQUUyMTM0M0U2OEFDMTk3MTUwRkEyNjU1RQ==	\N	FC195225D4CD060E249281C9BBDAF964	\N
+478CB1731C71BE849B0D82F3208F70CF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=74	74	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6RVV0cmFuQ2VsbDo0NzhDQjE3MzFDNzFCRTg0OUIwRDgyRjMyMDhGNzBDRg==	\N	FC195225D4CD060E249281C9BBDAF964	\N
+5D6F3B494FECE0D7BC46735D63ECA50B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=75	75	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6RVV0cmFuQ2VsbDo1RDZGM0I0OTRGRUNFMEQ3QkM0NjczNUQ2M0VDQTUwQg==	\N	FC195225D4CD060E249281C9BBDAF964	\N
+F818AA36B5E1456B32FB3B90157F15AD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=76	76	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6RVV0cmFuQ2VsbDpGODE4QUEzNkI1RTE0NTZCMzJGQjNCOTAxNTdGMTVBRA==	\N	FC195225D4CD060E249281C9BBDAF964	\N
+8EAABBB2C9D4996C8AD94154903052CC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=77	77	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6RVV0cmFuQ2VsbDo4RUFBQkJCMkM5RDQ5OTZDOEFEOTQxNTQ5MDMwNTJDQw==	\N	0C2651AB5D430123729B336E8635E0E0	\N
+CAC6EF5CC954F7A7F5294A643CD7A160	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=78	78	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6RVV0cmFuQ2VsbDpDQUM2RUY1Q0M5NTRGN0E3RjUyOTRBNjQzQ0Q3QTE2MA==	\N	0C2651AB5D430123729B336E8635E0E0	\N
+1053CE2AEBEE6B32C846C33B07E0B047	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=79	79	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6RVV0cmFuQ2VsbDoxMDUzQ0UyQUVCRUU2QjMyQzg0NkMzM0IwN0UwQjA0Nw==	\N	0C2651AB5D430123729B336E8635E0E0	\N
+803132C8AC37DED60CB9CB9986D9BC3D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/EUtranCell=80	80	456	789	123	1	FDD	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6RVV0cmFuQ2VsbDo4MDMxMzJDOEFDMzdERUQ2MENCOUNCOTk4NkQ5QkMzRA==	\N	0C2651AB5D430123729B336E8635E0E0	\N
+\.
+
+COPY ties_data."NRCellDU" (id, fdn, "cellLocalId", "nCI", "nRPCI", "nRTAC", "REL_GNBDUFUNCTION_PROVIDES_NRCELLDU_EIID", "REL_SECTOR_GROUPS_NRCELLDU_EIID", "REL_GNBDUFUNCTION_PROVIDES_NRCELLDU", "REL_SECTOR_GROUPS_NRCELLDU") FROM stdin;
+98C3A4591A37718E1330F0294E23B62A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=1	1	1	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+F9546E82313AC1D5E690DCD7BE55606F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=2	2	2	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpGOTU0NkU4MjMxM0FDMUQ1RTY5MERDRDdCRTU1NjA2Rg==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpGOTU0NkU4MjMxM0FDMUQ1RTY5MERDRDdCRTU1NjA2Rg==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+B480427E8A0C0B8D994E437784BB382F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=3	3	3	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+484B341310A36215155122DE74EAE16A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=4	4	4	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo0ODRCMzQxMzEwQTM2MjE1MTU1MTIyREU3NEVBRTE2QQ==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo0ODRCMzQxMzEwQTM2MjE1MTU1MTIyREU3NEVBRTE2QQ==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+377AA96B4B3A8FE106C9BAF63FE8460B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=5	5	5	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTozNzdBQTk2QjRCM0E4RkUxMDZDOUJBRjYzRkU4NDYwQg==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTozNzdBQTk2QjRCM0E4RkUxMDZDOUJBRjYzRkU4NDYwQg==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+3AF2208A5956F07644D8F3ED7C62BDCF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=6	6	6	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTozQUYyMjA4QTU5NTZGMDc2NDREOEYzRUQ3QzYyQkRDRg==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTozQUYyMjA4QTU5NTZGMDc2NDREOEYzRUQ3QzYyQkRDRg==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+44ABAEE2A77A5FC2C8121B95FFA5626D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=7	7	7	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo0NEFCQUVFMkE3N0E1RkMyQzgxMjFCOTVGRkE1NjI2RA==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo0NEFCQUVFMkE3N0E1RkMyQzgxMjFCOTVGRkE1NjI2RA==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+4E40B4CB518D7F6C4B0288A90DB81347	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=8	8	8	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo0RTQwQjRDQjUxOEQ3RjZDNEIwMjg4QTkwREI4MTM0Nw==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo0RTQwQjRDQjUxOEQ3RjZDNEIwMjg4QTkwREI4MTM0Nw==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+CF729A0BBC39E5077CB5674206A67359	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=9	9	9	789	456	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpDRjcyOUEwQkJDMzlFNTA3N0NCNTY3NDIwNkE2NzM1OQ==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpDRjcyOUEwQkJDMzlFNTA3N0NCNTY3NDIwNkE2NzM1OQ==	D3215E08570BE58339C7463626B50E37	F5128C172A70C4FCD4739650B06DE9E2
+FB7A92ED495FE5B08EA1E32353F67608	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=10	10	10	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTpGQjdBOTJFRDQ5NUZFNUIwOEVBMUUzMjM1M0Y2NzYwOA==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpGQjdBOTJFRDQ5NUZFNUIwOEVBMUUzMjM1M0Y2NzYwOA==	1050570EBB1315E1AE7A9FD5E1400A00	F5128C172A70C4FCD4739650B06DE9E2
+E8065644717ED15F3504B5EE71BB0894	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=11	11	11	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTpFODA2NTY0NDcxN0VEMTVGMzUwNEI1RUU3MUJCMDg5NA==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpFODA2NTY0NDcxN0VEMTVGMzUwNEI1RUU3MUJCMDg5NA==	1050570EBB1315E1AE7A9FD5E1400A00	F5128C172A70C4FCD4739650B06DE9E2
+4463C3D2F7B388323A82105E854AEA1C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=12	12	12	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTo0NDYzQzNEMkY3QjM4ODMyM0E4MjEwNUU4NTRBRUExQw==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo0NDYzQzNEMkY3QjM4ODMyM0E4MjEwNUU4NTRBRUExQw==	1050570EBB1315E1AE7A9FD5E1400A00	F5128C172A70C4FCD4739650B06DE9E2
+897C562A5D8EE22746AC4D4804505B69	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=13	13	13	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTo4OTdDNTYyQTVEOEVFMjI3NDZBQzRENDgwNDUwNUI2OQ==	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo4OTdDNTYyQTVEOEVFMjI3NDZBQzRENDgwNDUwNUI2OQ==	1050570EBB1315E1AE7A9FD5E1400A00	F5128C172A70C4FCD4739650B06DE9E2
+84E7155DAD6793A5EBFFE72449F7749B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=14	14	14	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTo4NEU3MTU1REFENjc5M0E1RUJGRkU3MjQ0OUY3NzQ5Qg==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTo4NEU3MTU1REFENjc5M0E1RUJGRkU3MjQ0OUY3NzQ5Qg==	1050570EBB1315E1AE7A9FD5E1400A00	ADB1BAAC878C0BEEFE3175C60F44BB1D
+0646A41A30151B59BC1D91073C162257	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=15	15	15	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTowNjQ2QTQxQTMwMTUxQjU5QkMxRDkxMDczQzE2MjI1Nw==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTowNjQ2QTQxQTMwMTUxQjU5QkMxRDkxMDczQzE2MjI1Nw==	1050570EBB1315E1AE7A9FD5E1400A00	ADB1BAAC878C0BEEFE3175C60F44BB1D
+45627D636D7A45357F6F23661BA77C85	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=16	16	16	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTo0NTYyN0Q2MzZEN0E0NTM1N0Y2RjIzNjYxQkE3N0M4NQ==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTo0NTYyN0Q2MzZEN0E0NTM1N0Y2RjIzNjYxQkE3N0M4NQ==	1050570EBB1315E1AE7A9FD5E1400A00	ADB1BAAC878C0BEEFE3175C60F44BB1D
+D21CDF704760EE66CC67AC8C5585C4FC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=17	17	17	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTpEMjFDREY3MDQ3NjBFRTY2Q0M2N0FDOEM1NTg1QzRGQw==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTpEMjFDREY3MDQ3NjBFRTY2Q0M2N0FDOEM1NTg1QzRGQw==	1050570EBB1315E1AE7A9FD5E1400A00	ADB1BAAC878C0BEEFE3175C60F44BB1D
+8219CA8C4641376B06FE4067FEE8CDB4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=18	18	18	789	456	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUkNlbGxEVTo4MjE5Q0E4QzQ2NDEzNzZCMDZGRTQwNjdGRUU4Q0RCNA==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTo4MjE5Q0E4QzQ2NDEzNzZCMDZGRTQwNjdGRUU4Q0RCNA==	1050570EBB1315E1AE7A9FD5E1400A00	ADB1BAAC878C0BEEFE3175C60F44BB1D
+5B3CC81B3284D3F665F03A477439FA98	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=19	19	19	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTo1QjNDQzgxQjMyODREM0Y2NjVGMDNBNDc3NDM5RkE5OA==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTo1QjNDQzgxQjMyODREM0Y2NjVGMDNBNDc3NDM5RkE5OA==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+C1944A262081F82A98CF050FEE41B8FF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=20	20	20	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTpDMTk0NEEyNjIwODFGODJBOThDRjA1MEZFRTQxQjhGRg==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTpDMTk0NEEyNjIwODFGODJBOThDRjA1MEZFRTQxQjhGRg==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+4BA799C33CDAA2C9F386060631E2FD2A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=21	21	21	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTo0QkE3OTlDMzNDREFBMkM5RjM4NjA2MDYzMUUyRkQyQQ==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTo0QkE3OTlDMzNDREFBMkM5RjM4NjA2MDYzMUUyRkQyQQ==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+F73AACF2BA432B687DFD62C47C9DFF1A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=22	22	22	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTpGNzNBQUNGMkJBNDMyQjY4N0RGRDYyQzQ3QzlERkYxQQ==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTpGNzNBQUNGMkJBNDMyQjY4N0RGRDYyQzQ3QzlERkYxQQ==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+51D49922CA6CCD2CE451D96BA224011F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=23	23	23	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTo1MUQ0OTkyMkNBNkNDRDJDRTQ1MUQ5NkJBMjI0MDExRg==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTo1MUQ0OTkyMkNBNkNDRDJDRTQ1MUQ5NkJBMjI0MDExRg==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+D042DE2D38F8FFE70D7387020215B254	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=24	24	24	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTpEMDQyREUyRDM4RjhGRkU3MEQ3Mzg3MDIwMjE1QjI1NA==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTpEMDQyREUyRDM4RjhGRkU3MEQ3Mzg3MDIwMjE1QjI1NA==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+15E91C33BA99354EDF0A667B5CAF81A5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=25	25	25	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVToxNUU5MUMzM0JBOTkzNTRFREYwQTY2N0I1Q0FGODFBNQ==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVToxNUU5MUMzM0JBOTkzNTRFREYwQTY2N0I1Q0FGODFBNQ==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+9ED010B29BD97379B4739B6C0F318874	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=26	26	26	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTo5RUQwMTBCMjlCRDk3Mzc5QjQ3MzlCNkMwRjMxODg3NA==	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpOUkNlbGxEVTo5RUQwMTBCMjlCRDk3Mzc5QjQ3MzlCNkMwRjMxODg3NA==	B6A6DE7D0965F02D48ECA86706A4454F	ADB1BAAC878C0BEEFE3175C60F44BB1D
+4D0F5CC361F2187DFBA4E243F489EC0E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=27	27	27	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUkNlbGxEVTo0RDBGNUNDMzYxRjIxODdERkJBNEUyNDNGNDg5RUMwRQ==	\N	B6A6DE7D0965F02D48ECA86706A4454F	\N
+36C251FB23A570A67C499D28F87DA94F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=28	28	28	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTozNkMyNTFGQjIzQTU3MEE2N0M0OTlEMjhGODdEQTk0Rg==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+EC786A721A064FA26BE40BE173FB92E1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=29	29	29	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTpFQzc4NkE3MjFBMDY0RkEyNkJFNDBCRTE3M0ZCOTJFMQ==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+CC6ED6DFD42AEBDE8A1F805D307622A9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=30	30	30	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTpDQzZFRDZERkQ0MkFFQkRFOEExRjgwNUQzMDc2MjJBOQ==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+C35F4A46EDE95D1BC57919C1ABA0A150	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=31	31	31	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTpDMzVGNEE0NkVERTk1RDFCQzU3OTE5QzFBQkEwQTE1MA==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+BC62404392D968AEEAFA290B6E029596	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=32	32	32	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTpCQzYyNDA0MzkyRDk2OEFFRUFGQTI5MEI2RTAyOTU5Ng==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+549AE94A5E8B74CD745AEF5648B8C524	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=33	33	33	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTo1NDlBRTk0QTVFOEI3NENENzQ1QUVGNTY0OEI4QzUyNA==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+148EB92D8802E953FF26CFD174B6D804	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=34	34	34	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVToxNDhFQjkyRDg4MDJFOTUzRkYyNkNGRDE3NEI2RDgwNA==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+4B1EE73EBD46801582B2FFA52130524F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=35	35	35	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTo0QjFFRTczRUJENDY4MDE1ODJCMkZGQTUyMTMwNTI0Rg==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+7467CEF2AC0808F3595444C7D31A1710	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=36	36	36	789	456	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUkNlbGxEVTo3NDY3Q0VGMkFDMDgwOEYzNTk1NDQ0QzdEMzFBMTcxMA==	\N	E5FD5ACD55C553A92738477ECB0465B9	\N
+49C8683059F38F7B681FF2730585F9A6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=37	37	37	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTo0OUM4NjgzMDU5RjM4RjdCNjgxRkYyNzMwNTg1RjlBNg==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+D3A0FDDC22E129C2EB7B0A5E7808CB7E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=38	38	38	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTpEM0EwRkREQzIyRTEyOUMyRUI3QjBBNUU3ODA4Q0I3RQ==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+EADFD2FF3B24BBA15103F3126C4E295D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=39	39	39	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTpFQURGRDJGRjNCMjRCQkExNTEwM0YzMTI2QzRFMjk1RA==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+72D427F5AFE7E0AB659128B4231319B4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=40	40	40	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTo3MkQ0MjdGNUFGRTdFMEFCNjU5MTI4QjQyMzEzMTlCNA==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+DE349A28FFB8BECC3957977273562130	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=41	41	41	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTpERTM0OUEyOEZGQjhCRUNDMzk1Nzk3NzI3MzU2MjEzMA==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+9A85559FD10DE19E39A83039C0AF12CD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=42	42	42	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTo5QTg1NTU5RkQxMERFMTlFMzlBODMwMzlDMEFGMTJDRA==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+476681437D680D90CF3B78E7114F7F21	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=43	43	43	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTo0NzY2ODE0MzdENjgwRDkwQ0YzQjc4RTcxMTRGN0YyMQ==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+1EF356E23A0069D6A97AD89E0D6C05F9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=44	44	44	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVToxRUYzNTZFMjNBMDA2OUQ2QTk3QUQ4OUUwRDZDMDVGOQ==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+60786DD5B89F405CA3F843E5DD2EACA6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=45	45	45	789	456	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUkNlbGxEVTo2MDc4NkRENUI4OUY0MDVDQTNGODQzRTVERDJFQUNBNg==	\N	25E690E22BDA90B9C4FEE1F083CBA597	\N
+F0F4E7335E15540F2784665D1A49AA6B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=46	46	46	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTpGMEY0RTczMzVFMTU1NDBGMjc4NDY2NUQxQTQ5QUE2Qg==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+58D99C6CAD0E027632C5CC2FA5C38DB4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=47	47	47	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTo1OEQ5OUM2Q0FEMEUwMjc2MzJDNUNDMkZBNUMzOERCNA==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+ECEC664641994704CE6A4222AA30EE78	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=48	48	48	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTpFQ0VDNjY0NjQxOTk0NzA0Q0U2QTQyMjJBQTMwRUU3OA==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+61C9A3B5E24424F3C21E7E702F81CC92	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=49	49	49	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTo2MUM5QTNCNUUyNDQyNEYzQzIxRTdFNzAyRjgxQ0M5Mg==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+340F170071D78ACA3F4E53ACEE1F2F49	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=50	50	50	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTozNDBGMTcwMDcxRDc4QUNBM0Y0RTUzQUNFRTFGMkY0OQ==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+32521953AA2555BCCF671FC6544F458A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=51	51	51	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTozMjUyMTk1M0FBMjU1NUJDQ0Y2NzFGQzY1NDRGNDU4QQ==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+7D6A4D058B4D77DA39FCDC2FC9A1B78A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=52	52	52	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTo3RDZBNEQwNThCNEQ3N0RBMzlGQ0RDMkZDOUExQjc4QQ==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+27F7577BCF08CE3B4F1A4011FCEE693C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=53	53	53	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVToyN0Y3NTc3QkNGMDhDRTNCNEYxQTQwMTFGQ0VFNjkzQw==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+0327C7F2BFB386B9C91C8F93C70F4B0F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=54	54	54	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUkNlbGxEVTowMzI3QzdGMkJGQjM4NkI5QzkxQzhGOTNDNzBGNEIwRg==	\N	5A3085C3400C3096E2ED2321452766B1	\N
+4279A85A76CBB256E0E4C2BBCB78FBCB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=55	55	55	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTo0Mjc5QTg1QTc2Q0JCMjU2RTBFNEMyQkJDQjc4RkJDQg==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+22CC2F77BC0D1758E4AC90D0844EB0FA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=56	56	56	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVToyMkNDMkY3N0JDMEQxNzU4RTRBQzkwRDA4NDRFQjBGQQ==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+EBAE96C402742B4BCBA0608ADC23251A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=57	57	57	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTpFQkFFOTZDNDAyNzQyQjRCQ0JBMDYwOEFEQzIzMjUxQQ==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+B04ED4054FF124E46081CE5968B17CB9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=58	58	58	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTpCMDRFRDQwNTRGRjEyNEU0NjA4MUNFNTk2OEIxN0NCOQ==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+8EC217D228BA9175A2E73358665B5D3E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=59	59	59	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTo4RUMyMTdEMjI4QkE5MTc1QTJFNzMzNTg2NjVCNUQzRQ==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+7C9707B1EAD31687D56DFA08A7656386	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=60	60	60	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTo3Qzk3MDdCMUVBRDMxNjg3RDU2REZBMDhBNzY1NjM4Ng==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+023FC45AF540AFCA3205D846D07C048B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=61	61	61	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTowMjNGQzQ1QUY1NDBBRkNBMzIwNUQ4NDZEMDdDMDQ4Qg==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+B46558EDB1CB27186BE31D3FA54856F0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=62	62	62	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTpCNDY1NThFREIxQ0IyNzE4NkJFMzFEM0ZBNTQ4NTZGMA==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+C5CD42EF608CB93F4AEF0E47329DF417	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=63	63	63	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUkNlbGxEVTpDNUNENDJFRjYwOENCOTNGNEFFRjBFNDczMjlERjQxNw==	\N	7F16F93D8816D9EBC76E52BB44A3CFF5	\N
+DA492DA1559FC7595D07DFF53ADD38AD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=64	64	64	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTpEQTQ5MkRBMTU1OUZDNzU5NUQwN0RGRjUzQUREMzhBRA==	\N	5A548EA9D166341776CA0695837E55D8	\N
+8E794C3E1EEE6EF8B69C268E06553C91	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=65	65	65	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTo4RTc5NEMzRTFFRUU2RUY4QjY5QzI2OEUwNjU1M0M5MQ==	\N	5A548EA9D166341776CA0695837E55D8	\N
+C2E0B9113CEAC91DF5E182B431D56788	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=66	66	66	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTpDMkUwQjkxMTNDRUFDOTFERjVFMTgyQjQzMUQ1Njc4OA==	\N	5A548EA9D166341776CA0695837E55D8	\N
+8EB7BACB085F1AAC02E18EBA694AD9D9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=67	67	67	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTo4RUI3QkFDQjA4NUYxQUFDMDJFMThFQkE2OTRBRDlEOQ==	\N	5A548EA9D166341776CA0695837E55D8	\N
+ECF0C7C7BDFFE39B32637C39924DA147	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=68	68	68	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTpFQ0YwQzdDN0JERkZFMzlCMzI2MzdDMzk5MjREQTE0Nw==	\N	5A548EA9D166341776CA0695837E55D8	\N
+E3816013E378E928377433098CC4C49F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=69	69	69	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTpFMzgxNjAxM0UzNzhFOTI4Mzc3NDMzMDk4Q0M0QzQ5Rg==	\N	5A548EA9D166341776CA0695837E55D8	\N
+CEC39AC620ED13978F78C8022E21CF9E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=70	70	70	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTpDRUMzOUFDNjIwRUQxMzk3OEY3OEM4MDIyRTIxQ0Y5RQ==	\N	5A548EA9D166341776CA0695837E55D8	\N
+373721F85AC9339C517C8895C29FF62A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=71	71	71	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTozNzM3MjFGODVBQzkzMzlDNTE3Qzg4OTVDMjlGRjYyQQ==	\N	5A548EA9D166341776CA0695837E55D8	\N
+07691B8D5DF7CB773B63599D118E3EFB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=72	72	72	789	456	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUkNlbGxEVTowNzY5MUI4RDVERjdDQjc3M0I2MzU5OUQxMThFM0VGQg==	\N	5A548EA9D166341776CA0695837E55D8	\N
+138CE3B21C8053675E0EBDC41C36E99D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=73	73	73	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVToxMzhDRTNCMjFDODA1MzY3NUUwRUJEQzQxQzM2RTk5RA==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+1F702800D1F7359958283DBCB45C0DD0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=74	74	74	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVToxRjcwMjgwMEQxRjczNTk5NTgyODNEQkNCNDVDMEREMA==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+0CE3320E6B41FC23B6B0FA4FD2103B2C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=75	75	75	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVTowQ0UzMzIwRTZCNDFGQzIzQjZCMEZBNEZEMjEwM0IyQw==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+92120D5EE5C0885D7E50860BD055A1EE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=76	76	76	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVTo5MjEyMEQ1RUU1QzA4ODVEN0U1MDg2MEJEMDU1QTFFRQ==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+D705554E98103411B005D2E3B4F42C87	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=77	77	77	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVTpENzA1NTU0RTk4MTAzNDExQjAwNUQyRTNCNEY0MkM4Nw==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+462EF46AA1C7641A8510C7C61D60C8B1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=78	78	78	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVTo0NjJFRjQ2QUExQzc2NDFBODUxMEM3QzYxRDYwQzhCMQ==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+26825D9CAA91BAC389DEBDF3572EF408	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=79	79	79	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVToyNjgyNUQ5Q0FBOTFCQUMzODlERUJERjM1NzJFRjQwOA==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+33F82DE9186F1539D2ED98818F41A0C2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=80	80	80	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVTozM0Y4MkRFOTE4NkYxNTM5RDJFRDk4ODE4RjQxQTBDMg==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+40175AF00A522213BA60537519A71978	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=81	81	81	789	456	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUkNlbGxEVTo0MDE3NUFGMDBBNTIyMjEzQkE2MDUzNzUxOUE3MTk3OA==	\N	7D80E5C6E0C9EC246370E86B7E524F8C	\N
+EA86088454B7491FB3BEFDDCA5FE097D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=82	82	82	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVTpFQTg2MDg4NDU0Qjc0OTFGQjNCRUZERENBNUZFMDk3RA==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+9BC6998B88BA4C1081CD5F211681C9CF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=83	83	83	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVTo5QkM2OTk4Qjg4QkE0QzEwODFDRDVGMjExNjgxQzlDRg==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+8377ECA137FF018C9716C0587F617182	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=84	84	84	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVTo4Mzc3RUNBMTM3RkYwMThDOTcxNkMwNTg3RjYxNzE4Mg==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+15890EF6D2196D9E21D70BDCE2AA3A77	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=85	85	85	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVToxNTg5MEVGNkQyMTk2RDlFMjFENzBCRENFMkFBM0E3Nw==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+F60F5BD54FA9842979790B4BBF80B8D9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=86	86	86	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVTpGNjBGNUJENTRGQTk4NDI5Nzk3OTBCNEJCRjgwQjhEOQ==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+2642586085120058DF59670F33FA5098	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=87	87	87	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVToyNjQyNTg2MDg1MTIwMDU4REY1OTY3MEYzM0ZBNTA5OA==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+A39C73D2879D86EF4184B605C0AE016F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=88	88	88	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVTpBMzlDNzNEMjg3OUQ4NkVGNDE4NEI2MDVDMEFFMDE2Rg==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+EEC85A7F76017260F9721B65A144D18E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=89	89	89	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVTpFRUM4NUE3Rjc2MDE3MjYwRjk3MjFCNjVBMTQ0RDE4RQ==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+1D825881F378E0735378D40BDECAC3EC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=90	90	90	789	456	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUkNlbGxEVToxRDgyNTg4MUYzNzhFMDczNTM3OEQ0MEJERUNBQzNFQw==	\N	BBB3C42A4F8AC94091B297DF708DD50B	\N
+76E9F605D4F37330BF0B505E94F64F11	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=91	91	91	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo3NkU5RjYwNUQ0RjM3MzMwQkYwQjUwNUU5NEY2NEYxMQ==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+67A1BDA10B5AF43028D07C7BE5CB1AE2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=92	92	92	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo2N0ExQkRBMTBCNUFGNDMwMjhEMDdDN0JFNUNCMUFFMg==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+B3B0A1939EFCA654A37005B6A7F24BD7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=93	93	93	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpCM0IwQTE5MzlFRkNBNjU0QTM3MDA1QjZBN0YyNEJENw==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+F26F279E91D0941DB4F646E707EA403A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=94	94	94	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpGMjZGMjc5RTkxRDA5NDFEQjRGNjQ2RTcwN0VBNDAzQQ==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+24379146FE349FBF04BA3B3018077214	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=95	95	95	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVToyNDM3OTE0NkZFMzQ5RkJGMDRCQTNCMzAxODA3NzIxNA==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+5E7EA1D6380C21D2C024524C2A198A5A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=96	96	96	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo1RTdFQTFENjM4MEMyMUQyQzAyNDUyNEMyQTE5OEE1QQ==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+5DC3A11A69D8CDB175FC9D49D9E0E720	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=97	97	97	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo1REMzQTExQTY5RDhDREIxNzVGQzlENDlEOUUwRTcyMA==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+9840AC1566774545CBD7FD44015EFFA5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=98	98	98	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo5ODQwQUMxNTY2Nzc0NTQ1Q0JEN0ZENDQwMTVFRkZBNQ==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+F4531C31205F28BC8830CAD7A7C2FDA1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=99	99	99	789	456	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpGNDUzMUMzMTIwNUYyOEJDODgzMENBRDdBN0MyRkRBMQ==	\N	4CFF136200A2DE36205A13559C55DB2A	\N
+\.
+
+COPY ties_data."LTESectorCarrier" (id, fdn, "essScLocalId", "sectorCarrierType", "REL_EUTRANCELL_USES_LTESECTORCARRIER_EIID", "REL_LTESECTORCARRIER_USES_ANTENNACAPABILITY_EIID", "REL_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER_EIID", "REL_EUTRANCELL_USES_LTESECTORCARRIER", "REL_LTESECTORCARRIER_USES_ANTENNACAPABILITY", "REL_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER") FROM stdin;
+6A71D2FA97A7798E13AE68DF144C18D2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=1	1	MO	urn:base64:RVV0cmFuQ2VsbDoxMkFFM0FBQjMzMkI3Q0JBNzVGNUI2MUEzRTExRDlENzpVU0VTOkxURVNlY3RvckNhcnJpZXI6NkE3MUQyRkE5N0E3Nzk4RTEzQUU2OERGMTQ0QzE4RDI=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo2QTcxRDJGQTk3QTc3OThFMTNBRTY4REYxNDRDMThEMjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjA0MjczRkM2NDQzNkRBNTIzODY1Q0Y4NDlFNUY3Q0M5	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo2QTcxRDJGQTk3QTc3OThFMTNBRTY4REYxNDRDMThEMg==	12AE3AAB332B7CBA75F5B61A3E11D9D7	04273FC64436DA523865CF849E5F7CC9	8EFAD2F305499DCD360040BD6F57B54E
+96FEEADB8F638A1D4BE56258CBC7F670	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=2	2	MO	urn:base64:RVV0cmFuQ2VsbDoyMTIxMkI1MjI0NkE4N0Y5MjIzMzc2NTk0OTE0MjRFMjpVU0VTOkxURVNlY3RvckNhcnJpZXI6OTZGRUVBREI4RjYzOEExRDRCRTU2MjU4Q0JDN0Y2NzA=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5NkZFRUFEQjhGNjM4QTFENEJFNTYyNThDQkM3RjY3MDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkQ1QjkwOTBFM0I2QTEwREJEQzI0M0VEMTRFRjI5NEJG	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5NkZFRUFEQjhGNjM4QTFENEJFNTYyNThDQkM3RjY3MA==	21212B52246A87F922337659491424E2	D5B9090E3B6A10DBDC243ED14EF294BF	8EFAD2F305499DCD360040BD6F57B54E
+78C2DACF26B995F7F6E14A1224A3814E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=3	3	MO	urn:base64:RVV0cmFuQ2VsbDpDOURENzMzQTE4QkM5Q0E2NkVBRTBBQTU2ODhFRTY4NTpVU0VTOkxURVNlY3RvckNhcnJpZXI6NzhDMkRBQ0YyNkI5OTVGN0Y2RTE0QTEyMjRBMzgxNEU=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3OEMyREFDRjI2Qjk5NUY3RjZFMTRBMTIyNEEzODE0RTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjAyNDQzREUwODA3RDgwMUQ2NjE0OTVEOUVGQjhEODM2	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3OEMyREFDRjI2Qjk5NUY3RjZFMTRBMTIyNEEzODE0RQ==	C9DD733A18BC9CA66EAE0AA5688EE685	02443DE0807D801D661495D9EFB8D836	8EFAD2F305499DCD360040BD6F57B54E
+936106877FE31C47ACF2782952735A99	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=4	4	MO	urn:base64:RVV0cmFuQ2VsbDo2M0U4ODkzNTc0NEQ2QzNFQjU5RUZFMDJDREFCQzA2MzpVU0VTOkxURVNlY3RvckNhcnJpZXI6OTM2MTA2ODc3RkUzMUM0N0FDRjI3ODI5NTI3MzVBOTk=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5MzYxMDY4NzdGRTMxQzQ3QUNGMjc4Mjk1MjczNUE5OTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkM2ODIzRDJCN0FGQTA2NENFNzc0Nzk1RTAxRDYyMjhC	urn:base64:RU5vZGVCRnVuY3Rpb246OEVGQUQyRjMwNTQ5OURDRDM2MDA0MEJENkY1N0I1NEU6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5MzYxMDY4NzdGRTMxQzQ3QUNGMjc4Mjk1MjczNUE5OQ==	63E88935744D6C3EB59EFE02CDABC063	C6823D2B7AFA064CE774795E01D6228B	8EFAD2F305499DCD360040BD6F57B54E
+ED4FCDD3318288DDB2614193E2EDFE63	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=5	5	MO	urn:base64:RVV0cmFuQ2VsbDo1OUEyMjA0OTI0QzRDMTYwMUExOUFDODg0N0QzMDJFODpVU0VTOkxURVNlY3RvckNhcnJpZXI6RUQ0RkNERDMzMTgyODhEREIyNjE0MTkzRTJFREZFNjM=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpFRDRGQ0REMzMxODI4OEREQjI2MTQxOTNFMkVERkU2MzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkRGMjZBRTQ0MjExMERCMDI4MURBRDQ1NDU0MzZCNzIw	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpFRDRGQ0REMzMxODI4OEREQjI2MTQxOTNFMkVERkU2Mw==	59A2204924C4C1601A19AC8847D302E8	DF26AE442110DB0281DAD4545436B720	C6694F03768AF9EE83DC293C10473076
+BED58D11C363D2CB5FD962657C57B202	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=6	6	MO	urn:base64:RVV0cmFuQ2VsbDo4OTI2NjkxNTk5ODkyNzYxQzlGRjhDRjNGMzI1MDY4RTpVU0VTOkxURVNlY3RvckNhcnJpZXI6QkVENThEMTFDMzYzRDJDQjVGRDk2MjY1N0M1N0IyMDI=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpCRUQ1OEQxMUMzNjNEMkNCNUZEOTYyNjU3QzU3QjIwMjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjdBMUM2RkU5MzUxMDA4QjNENTM5MTY2RDk0MjIyNzYy	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpCRUQ1OEQxMUMzNjNEMkNCNUZEOTYyNjU3QzU3QjIwMg==	8926691599892761C9FF8CF3F325068E	7A1C6FE9351008B3D539166D94222762	C6694F03768AF9EE83DC293C10473076
+D3C3BA1DB89377D7662B27F6F9D2C882	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=7	7	MO	urn:base64:RVV0cmFuQ2VsbDo2ODlCNkJCRkRENUI0MjZGRURBNkIxQ0U0NkY4Qjg5MzpVU0VTOkxURVNlY3RvckNhcnJpZXI6RDNDM0JBMURCODkzNzdENzY2MkIyN0Y2RjlEMkM4ODI=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpEM0MzQkExREI4OTM3N0Q3NjYyQjI3RjZGOUQyQzg4MjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjcwQTFGMTI5RTEwRUU3RDMxREZFMUUxQUE2Qzc0MzdE	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpEM0MzQkExREI4OTM3N0Q3NjYyQjI3RjZGOUQyQzg4Mg==	689B6BBFDD5B426FEDA6B1CE46F8B893	70A1F129E10EE7D31DFE1E1AA6C7437D	C6694F03768AF9EE83DC293C10473076
+422374EAB41474FDE8CFB932B2422802	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=8	8	MO	urn:base64:RVV0cmFuQ2VsbDpBMjc1RDE3MDY1MzZBNzdEN0FCQTZCQTJBM0M1NkRGRTpVU0VTOkxURVNlY3RvckNhcnJpZXI6NDIyMzc0RUFCNDE0NzRGREU4Q0ZCOTMyQjI0MjI4MDI=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo0MjIzNzRFQUI0MTQ3NEZERThDRkI5MzJCMjQyMjgwMjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjdERTkxQzc4RjhEQ0U0MjkyRjJGMEMzQjM0REVBQ0FC	urn:base64:RU5vZGVCRnVuY3Rpb246QzY2OTRGMDM3NjhBRjlFRTgzREMyOTNDMTA0NzMwNzY6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo0MjIzNzRFQUI0MTQ3NEZERThDRkI5MzJCMjQyMjgwMg==	A275D1706536A77D7ABA6BA2A3C56DFE	7DE91C78F8DCE4292F2F0C3B34DEACAB	C6694F03768AF9EE83DC293C10473076
+DDB43D4A95BA11C5FDF3D19514F628BD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=9	9	MO	urn:base64:RVV0cmFuQ2VsbDowOEFCQzczRDg2QzVCODM4MEJCQzVCNTI0Q0NFQzg2MjpVU0VTOkxURVNlY3RvckNhcnJpZXI6RERCNDNENEE5NUJBMTFDNUZERjNEMTk1MTRGNjI4QkQ=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpEREI0M0Q0QTk1QkExMUM1RkRGM0QxOTUxNEY2MjhCRDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjE0NUExQkY1NjFEQjI5N0YyNUZEM0YxMjQxN0QyQTUw	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpEREI0M0Q0QTk1QkExMUM1RkRGM0QxOTUxNEY2MjhCRA==	08ABC73D86C5B8380BBC5B524CCEC862	145A1BF561DB297F25FD3F12417D2A50	54D62577A2B3ED373FA47BBD89A67473
+BE8FD2B159EE7D5D47EFE8A2FD4313C8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=10	10	MO	urn:base64:RVV0cmFuQ2VsbDpCNjExRjYzREU3N0ZDNUMzMzNBMTdFQzA0N0U1RUY0MzpVU0VTOkxURVNlY3RvckNhcnJpZXI6QkU4RkQyQjE1OUVFN0Q1RDQ3RUZFOEEyRkQ0MzEzQzg=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpCRThGRDJCMTU5RUU3RDVENDdFRkU4QTJGRDQzMTNDODpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjkxODhEOTc1RDgzN0ExRTAzOTcxNjdBMjNFNzIxQjBD	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpCRThGRDJCMTU5RUU3RDVENDdFRkU4QTJGRDQzMTNDOA==	B611F63DE77FC5C333A17EC047E5EF43	9188D975D837A1E0397167A23E721B0C	54D62577A2B3ED373FA47BBD89A67473
+BAE5942A7A4B6C49AB04C0ABC064EB28	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=11	11	MO	urn:base64:RVV0cmFuQ2VsbDpDRjgzNDRGNzk1QjEzMzUwMDUwRTUyQzgzQjk3RENCOTpVU0VTOkxURVNlY3RvckNhcnJpZXI6QkFFNTk0MkE3QTRCNkM0OUFCMDRDMEFCQzA2NEVCMjg=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpCQUU1OTQyQTdBNEI2QzQ5QUIwNEMwQUJDMDY0RUIyODpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkQzMTREQURBRkEzRDg5NjQ0NUU3OEVCQ0MxNUExNkY3	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpCQUU1OTQyQTdBNEI2QzQ5QUIwNEMwQUJDMDY0RUIyOA==	CF8344F795B13350050E52C83B97DCB9	D314DADAFA3D896445E78EBCC15A16F7	54D62577A2B3ED373FA47BBD89A67473
+7D75F65DCEE7745E5E89EA5CBC8A477D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=12	12	MO	urn:base64:RVV0cmFuQ2VsbDo1OUEyRTdFODUwNDEyNUVCOERGMzc2NUZBRUJBQTUzQjpVU0VTOkxURVNlY3RvckNhcnJpZXI6N0Q3NUY2NURDRUU3NzQ1RTVFODlFQTVDQkM4QTQ3N0Q=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3RDc1RjY1RENFRTc3NDVFNUU4OUVBNUNCQzhBNDc3RDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjI4QUQzRUU4NDQ3NjZERjUwOEY2Mjg3Q0QxQ0UxOEE0	urn:base64:RU5vZGVCRnVuY3Rpb246NTRENjI1NzdBMkIzRUQzNzNGQTQ3QkJEODlBNjc0NzM6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3RDc1RjY1RENFRTc3NDVFNUU4OUVBNUNCQzhBNDc3RA==	59A2E7E8504125EB8DF3765FAEBAA53B	28AD3EE844766DF508F6287CD1CE18A4	54D62577A2B3ED373FA47BBD89A67473
+E8BF5D975B6ECED3AC3C1E7DFAF569D6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=13	13	MO	urn:base64:RVV0cmFuQ2VsbDpEQkE4MzIzMEMwRkE3MTk5M0Y4RkREODM2MzU0MjIzRTpVU0VTOkxURVNlY3RvckNhcnJpZXI6RThCRjVEOTc1QjZFQ0VEM0FDM0MxRTdERkFGNTY5RDY=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpFOEJGNUQ5NzVCNkVDRUQzQUMzQzFFN0RGQUY1NjlENjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkMzOThENkM2NzMyNjdBMDgxQzc4MUQ4NDQzOEY0Qjc0	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpFOEJGNUQ5NzVCNkVDRUQzQUMzQzFFN0RGQUY1NjlENg==	DBA83230C0FA71993F8FDD836354223E	C398D6C673267A081C781D84438F4B74	3B603CD3E74F0F9053DEF063EFAF2012
+72AF5544AF527B2DADD2BCE04BF7504C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=14	14	MO	urn:base64:RVV0cmFuQ2VsbDpFMEZFQ0I2QjUxQzY5OTMyNTYyQjZDMTk0MzYyQ0M4RTpVU0VTOkxURVNlY3RvckNhcnJpZXI6NzJBRjU1NDRBRjUyN0IyREFERDJCQ0UwNEJGNzUwNEM=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3MkFGNTU0NEFGNTI3QjJEQUREMkJDRTA0QkY3NTA0QzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjBCREFENUREQzE5QTY5NjI0NDUzNjQyMUU2RDI2RkUz	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3MkFGNTU0NEFGNTI3QjJEQUREMkJDRTA0QkY3NTA0Qw==	E0FECB6B51C69932562B6C194362CC8E	0BDAD5DDC19A696244536421E6D26FE3	3B603CD3E74F0F9053DEF063EFAF2012
+7A84CA220F5912B668B9902A82422847	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=15	15	MO	urn:base64:RVV0cmFuQ2VsbDoyMjdFQzU4QkU5Mjc3QTk5OUI2NkI1M0U2QzYxNkNGODpVU0VTOkxURVNlY3RvckNhcnJpZXI6N0E4NENBMjIwRjU5MTJCNjY4Qjk5MDJBODI0MjI4NDc=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3QTg0Q0EyMjBGNTkxMkI2NjhCOTkwMkE4MjQyMjg0NzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjQ5MjA1ODgxQzkxMjFGMjA4QkQ3OTE0OUZBNzk5ODc3	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3QTg0Q0EyMjBGNTkxMkI2NjhCOTkwMkE4MjQyMjg0Nw==	227EC58BE9277A999B66B53E6C616CF8	49205881C9121F208BD79149FA799877	3B603CD3E74F0F9053DEF063EFAF2012
+11DE95BBE63D51804C165BE428C562FC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=16	16	MO	urn:base64:RVV0cmFuQ2VsbDpBNUQyMjBCMURGRUE5MjhDMTdCOEJCOTJERjEyNjQ4ODpVU0VTOkxURVNlY3RvckNhcnJpZXI6MTFERTk1QkJFNjNENTE4MDRDMTY1QkU0MjhDNTYyRkM=	urn:base64:TFRFU2VjdG9yQ2FycmllcjoxMURFOTVCQkU2M0Q1MTgwNEMxNjVCRTQyOEM1NjJGQzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkEzMkRCOUUyNzhGQzFERTQxRkI0QTNCNTBGODAyNjUw	urn:base64:RU5vZGVCRnVuY3Rpb246M0I2MDNDRDNFNzRGMEY5MDUzREVGMDYzRUZBRjIwMTI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjoxMURFOTVCQkU2M0Q1MTgwNEMxNjVCRTQyOEM1NjJGQw==	A5D220B1DFEA928C17B8BB92DF126488	A32DB9E278FC1DE41FB4A3B50F802650	3B603CD3E74F0F9053DEF063EFAF2012
+40B28B706B0288149A3366C8EA774C41	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=17	17	MO	urn:base64:RVV0cmFuQ2VsbDo2N0ZGQzdGNzVBMkVGMENBQUM4Q0U3MEFBRjcyQjEwNTpVU0VTOkxURVNlY3RvckNhcnJpZXI6NDBCMjhCNzA2QjAyODgxNDlBMzM2NkM4RUE3NzRDNDE=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo0MEIyOEI3MDZCMDI4ODE0OUEzMzY2QzhFQTc3NEM0MTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkJERTM4MUJBQ0M2NzI5MEU0NDdCQzAxNzdFMDM4QUVC	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo0MEIyOEI3MDZCMDI4ODE0OUEzMzY2QzhFQTc3NEM0MQ==	67FFC7F75A2EF0CAAC8CE70AAF72B105	BDE381BACC67290E447BC0177E038AEB	1D9917590E5F75F44DF7EF626592C2C7
+CA4AFE762559AE791A12FDC893E9AE9C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=18	18	MO	urn:base64:RVV0cmFuQ2VsbDpCQjE4NDNEMjYwMUFFNzA1RjM0QkYxMkQyQTQyMjAzMzpVU0VTOkxURVNlY3RvckNhcnJpZXI6Q0E0QUZFNzYyNTU5QUU3OTFBMTJGREM4OTNFOUFFOUM=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpDQTRBRkU3NjI1NTlBRTc5MUExMkZEQzg5M0U5QUU5QzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkI0QkM0RDFCMTNFQjY1MTY5MEYzMTk1RTYyMkNDNEJE	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpDQTRBRkU3NjI1NTlBRTc5MUExMkZEQzg5M0U5QUU5Qw==	BB1843D2601AE705F34BF12D2A422033	B4BC4D1B13EB651690F3195E622CC4BD	1D9917590E5F75F44DF7EF626592C2C7
+7F10AA7C396CDE4F86B47D48B2E13D72	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=19	19	MO	urn:base64:RVV0cmFuQ2VsbDo4RjZFMjMwQ0YyNjVGOEM1QTE0NzkyQzA5QTY2ODY5MDpVU0VTOkxURVNlY3RvckNhcnJpZXI6N0YxMEFBN0MzOTZDREU0Rjg2QjQ3RDQ4QjJFMTNENzI=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3RjEwQUE3QzM5NkNERTRGODZCNDdENDhCMkUxM0Q3MjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjMyRUUzODVFQUNEMjZBMDA0NkJBRDVDQzg0OTA1RUNC	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3RjEwQUE3QzM5NkNERTRGODZCNDdENDhCMkUxM0Q3Mg==	8F6E230CF265F8C5A14792C09A668690	32EE385EACD26A0046BAD5CC84905ECB	1D9917590E5F75F44DF7EF626592C2C7
+88572A3196793B103445E4ACE68AEA49	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=20	20	MO	urn:base64:RVV0cmFuQ2VsbDo2NUE3QkI3MkFCQzM0RTdEMkM5RDIwQkQyMkIwM0Y2MDpVU0VTOkxURVNlY3RvckNhcnJpZXI6ODg1NzJBMzE5Njc5M0IxMDM0NDVFNEFDRTY4QUVBNDk=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo4ODU3MkEzMTk2NzkzQjEwMzQ0NUU0QUNFNjhBRUE0OTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjQzQjYzMTA2QjI3RkIwNUM2MTg0MDBFRTVBRTkxNjM3	urn:base64:RU5vZGVCRnVuY3Rpb246MUQ5OTE3NTkwRTVGNzVGNDRERjdFRjYyNjU5MkMyQzc6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo4ODU3MkEzMTk2NzkzQjEwMzQ0NUU0QUNFNjhBRUE0OQ==	65A7BB72ABC34E7D2C9D20BD22B03F60	43B63106B27FB05C618400EE5AE91637	1D9917590E5F75F44DF7EF626592C2C7
+CEE3234BB6A7A468B503C964448FD72B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=21	21	MO	urn:base64:RVV0cmFuQ2VsbDo0NzUxODc3NTM5OUNFOUY3NEJBMjk5RkM3QzAzMzczMjpVU0VTOkxURVNlY3RvckNhcnJpZXI6Q0VFMzIzNEJCNkE3QTQ2OEI1MDNDOTY0NDQ4RkQ3MkI=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpDRUUzMjM0QkI2QTdBNDY4QjUwM0M5NjQ0NDhGRDcyQjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkM4MTNFMTg2NTdDMkM1ODM3QTNGMjM3QkFENTU3OTQ0	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpDRUUzMjM0QkI2QTdBNDY4QjUwM0M5NjQ0NDhGRDcyQg==	47518775399CE9F74BA299FC7C033732	C813E18657C2C5837A3F237BAD557944	B3B3845E7D8910D6906B5EB41A8E0696
+77671BA896E46F12644F64A3696AACED	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=22	22	MO	urn:base64:RVV0cmFuQ2VsbDpGNEM3RDM0ODI0MEI5RTJBRTFDMzBEQkE4QTgyMjVGQzpVU0VTOkxURVNlY3RvckNhcnJpZXI6Nzc2NzFCQTg5NkU0NkYxMjY0NEY2NEEzNjk2QUFDRUQ=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3NzY3MUJBODk2RTQ2RjEyNjQ0RjY0QTM2OTZBQUNFRDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjQ2MkRDQ0RFQTVBMjg5MkI4Qzg2MzA3MjQ2NzlCNjc2	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3NzY3MUJBODk2RTQ2RjEyNjQ0RjY0QTM2OTZBQUNFRA==	F4C7D348240B9E2AE1C30DBA8A8225FC	462DCCDEA5A2892B8C8630724679B676	B3B3845E7D8910D6906B5EB41A8E0696
+D5ECCA0DC8E6539EEF5E3E80F2440FF8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=23	23	MO	urn:base64:RVV0cmFuQ2VsbDowMTU3MDU2QUFEN0Q3MDBBQjc0NjQ5QUQyM0FCMzUxNjpVU0VTOkxURVNlY3RvckNhcnJpZXI6RDVFQ0NBMERDOEU2NTM5RUVGNUUzRTgwRjI0NDBGRjg=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpENUVDQ0EwREM4RTY1MzlFRUY1RTNFODBGMjQ0MEZGODpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkY2RDBGRjIwNjlGMDM4RkY2NEQwNzJDODE4REQ5QkZE	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpENUVDQ0EwREM4RTY1MzlFRUY1RTNFODBGMjQ0MEZGOA==	0157056AAD7D700AB74649AD23AB3516	F6D0FF2069F038FF64D072C818DD9BFD	B3B3845E7D8910D6906B5EB41A8E0696
+F909E803B0F36A260820BDB8F9DED641	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=24	24	MO	urn:base64:RVV0cmFuQ2VsbDpCNDA2NkU3NDNEQ0Y0OEYwMjQzM0EzMDA0NUIyQkQ2NzpVU0VTOkxURVNlY3RvckNhcnJpZXI6RjkwOUU4MDNCMEYzNkEyNjA4MjBCREI4RjlERUQ2NDE=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpGOTA5RTgwM0IwRjM2QTI2MDgyMEJEQjhGOURFRDY0MTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkM1QzU5ODUxMUM3NTE0MDYxRTg2REEyNEY4REIzNTlE	urn:base64:RU5vZGVCRnVuY3Rpb246QjNCMzg0NUU3RDg5MTBENjkwNkI1RUI0MUE4RTA2OTY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpGOTA5RTgwM0IwRjM2QTI2MDgyMEJEQjhGOURFRDY0MQ==	B4066E743DCF48F02433A30045B2BD67	C5C598511C7514061E86DA24F8DB359D	B3B3845E7D8910D6906B5EB41A8E0696
+7B6CED12C445EBC5402060C76AABD35E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=25	25	MO	urn:base64:RVV0cmFuQ2VsbDo5NDgxRkU1RUU3MDI3RThGRkM1RjZDNTA1NEUwNDU4RDpVU0VTOkxURVNlY3RvckNhcnJpZXI6N0I2Q0VEMTJDNDQ1RUJDNTQwMjA2MEM3NkFBQkQzNUU=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3QjZDRUQxMkM0NDVFQkM1NDAyMDYwQzc2QUFCRDM1RTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjEzODc2RkVDRUVERjQ1QUU0RENBOEMzOTNFNDc4MjM3	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3QjZDRUQxMkM0NDVFQkM1NDAyMDYwQzc2QUFCRDM1RQ==	9481FE5EE7027E8FFC5F6C5054E0458D	13876FECEEDF45AE4DCA8C393E478237	4C8B24AC011A734A5FEBF321C77289AB
+A7755961EE174E532DDBEA5572858CDA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=26	26	MO	urn:base64:RVV0cmFuQ2VsbDo2NDJFMUJCRTg3MjNBQzlDNDU5MEY2NzAzRURDNDRGMTpVU0VTOkxURVNlY3RvckNhcnJpZXI6QTc3NTU5NjFFRTE3NEU1MzJEREJFQTU1NzI4NThDREE=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpBNzc1NTk2MUVFMTc0RTUzMkREQkVBNTU3Mjg1OENEQTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjAwODMzOTAzODkxRDA3RDA2MjhFMDNGRjQ0NjNBMTRB	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpBNzc1NTk2MUVFMTc0RTUzMkREQkVBNTU3Mjg1OENEQQ==	642E1BBE8723AC9C4590F6703EDC44F1	00833903891D07D0628E03FF4463A14A	4C8B24AC011A734A5FEBF321C77289AB
+F4A7A456CCCA0DEF8CB045E219B5AE17	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=27	27	MO	urn:base64:RVV0cmFuQ2VsbDoxMjMzNDVERkQ3NDU2MjdFNTFGOEUxNDA5OTMzMjlCMTpVU0VTOkxURVNlY3RvckNhcnJpZXI6RjRBN0E0NTZDQ0NBMERFRjhDQjA0NUUyMTlCNUFFMTc=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpGNEE3QTQ1NkNDQ0EwREVGOENCMDQ1RTIxOUI1QUUxNzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkM0QTI4M0VFRkQ1RjE0NjNCN0VFMENBNzgyNDA5REZC	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpGNEE3QTQ1NkNDQ0EwREVGOENCMDQ1RTIxOUI1QUUxNw==	123345DFD745627E51F8E140993329B1	C4A283EEFD5F1463B7EE0CA782409DFB	4C8B24AC011A734A5FEBF321C77289AB
+186269ADB75707F93FD6960BB47E8B52	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=28	28	MO	urn:base64:RVV0cmFuQ2VsbDoyMDREQTU0MDlGRjgwRTk3NTg2NDhEQjc1QTYzOUZCMzpVU0VTOkxURVNlY3RvckNhcnJpZXI6MTg2MjY5QURCNzU3MDdGOTNGRDY5NjBCQjQ3RThCNTI=	urn:base64:TFRFU2VjdG9yQ2FycmllcjoxODYyNjlBREI3NTcwN0Y5M0ZENjk2MEJCNDdFOEI1MjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkFGRkVBRjFEMEYyRDMwNTI0QzQ5QkE4NkQ1MkYzOUVF	urn:base64:RU5vZGVCRnVuY3Rpb246NEM4QjI0QUMwMTFBNzM0QTVGRUJGMzIxQzc3Mjg5QUI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjoxODYyNjlBREI3NTcwN0Y5M0ZENjk2MEJCNDdFOEI1Mg==	204DA5409FF80E9758648DB75A639FB3	AFFEAF1D0F2D30524C49BA86D52F39EE	4C8B24AC011A734A5FEBF321C77289AB
+51FACE199A356B553FD949E28EA80899	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=29	29	MO	urn:base64:RVV0cmFuQ2VsbDowMkQ2MjdFRTY5MzU0QzMyNDRDRjNDRTg4N0JFNTBGMzpVU0VTOkxURVNlY3RvckNhcnJpZXI6NTFGQUNFMTk5QTM1NkI1NTNGRDk0OUUyOEVBODA4OTk=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo1MUZBQ0UxOTlBMzU2QjU1M0ZEOTQ5RTI4RUE4MDg5OTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkUyQTEzQ0Y1NkMwRTE4N0M2MkZGOTcxNkJCMEZDRUQ2	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo1MUZBQ0UxOTlBMzU2QjU1M0ZEOTQ5RTI4RUE4MDg5OQ==	02D627EE69354C3244CF3CE887BE50F3	E2A13CF56C0E187C62FF9716BB0FCED6	96220B64D4A4C6F6B17DF30B12B841D3
+0A70F059568E5C79D8476781A019354F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=30	30	MO	urn:base64:RVV0cmFuQ2VsbDpFNzk3MEFBODA2ODg2REQzREQyMjhEOUFEOTM5RThCNTpVU0VTOkxURVNlY3RvckNhcnJpZXI6MEE3MEYwNTk1NjhFNUM3OUQ4NDc2NzgxQTAxOTM1NEY=	urn:base64:TFRFU2VjdG9yQ2FycmllcjowQTcwRjA1OTU2OEU1Qzc5RDg0NzY3ODFBMDE5MzU0RjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkUzRTFGQjMxRkI1RjRGQjFDQTgwODAzNjQ3NEJERDk1	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjowQTcwRjA1OTU2OEU1Qzc5RDg0NzY3ODFBMDE5MzU0Rg==	E7970AA806886DD3DD228D9AD939E8B5	E3E1FB31FB5F4FB1CA808036474BDD95	96220B64D4A4C6F6B17DF30B12B841D3
+D9DF1EDA6D0EB2BED37D785171CB5BBA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=31	31	MO	urn:base64:RVV0cmFuQ2VsbDpDNjc3MDU0QjJBQTgzMzlFMDBCQ0QyMzBFMzc4NURBMzpVU0VTOkxURVNlY3RvckNhcnJpZXI6RDlERjFFREE2RDBFQjJCRUQzN0Q3ODUxNzFDQjVCQkE=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpEOURGMUVEQTZEMEVCMkJFRDM3RDc4NTE3MUNCNUJCQTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjU3NjlDMDI2RDc5OTNDNjY2QzQ1NTM1RUREOEMzRUFE	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpEOURGMUVEQTZEMEVCMkJFRDM3RDc4NTE3MUNCNUJCQQ==	C677054B2AA8339E00BCD230E3785DA3	5769C026D7993C666C45535EDD8C3EAD	96220B64D4A4C6F6B17DF30B12B841D3
+9E8083A413565C5DE5B5535AA31B085C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=32	32	MO	urn:base64:RVV0cmFuQ2VsbDo3RkFFNTFGNTJFQ0FDNzkxQjI0MDdCREI2OEI1QTdGNzpVU0VTOkxURVNlY3RvckNhcnJpZXI6OUU4MDgzQTQxMzU2NUM1REU1QjU1MzVBQTMxQjA4NUM=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5RTgwODNBNDEzNTY1QzVERTVCNTUzNUFBMzFCMDg1QzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjJBMzI0NzVFRjRGNEFCNDE5MDRCNUFBQUE4RkYyQ0Ex	urn:base64:RU5vZGVCRnVuY3Rpb246OTYyMjBCNjRENEE0QzZGNkIxN0RGMzBCMTJCODQxRDM6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5RTgwODNBNDEzNTY1QzVERTVCNTUzNUFBMzFCMDg1Qw==	7FAE51F52ECAC791B2407BDB68B5A7F7	2A32475EF4F4AB41904B5AAAA8FF2CA1	96220B64D4A4C6F6B17DF30B12B841D3
+6B521DED56A52F90CFF76052044EC486	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=33	33	MO	urn:base64:RVV0cmFuQ2VsbDo2N0QyMDBEMENDMjE2MDYzMTI5QzdBOUU4NDRCRjBGMDpVU0VTOkxURVNlY3RvckNhcnJpZXI6NkI1MjFERUQ1NkE1MkY5MENGRjc2MDUyMDQ0RUM0ODY=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo2QjUyMURFRDU2QTUyRjkwQ0ZGNzYwNTIwNDRFQzQ4NjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkVCMTMwMUJBMjJFMDY5MTExNEEyMzQ0NTMyM0I2NDlC	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo2QjUyMURFRDU2QTUyRjkwQ0ZGNzYwNTIwNDRFQzQ4Ng==	67D200D0CC216063129C7A9E844BF0F0	EB1301BA22E0691114A23445323B649B	4FBA45FB12D28F9106A09E045DE90254
+97BEC990400A914D9032932447582A39	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=34	34	MO	urn:base64:RVV0cmFuQ2VsbDozMEIzMDNDMTlDMEM4RjA1N0ExRDIzOTcxMDVEMzQ2RTpVU0VTOkxURVNlY3RvckNhcnJpZXI6OTdCRUM5OTA0MDBBOTE0RDkwMzI5MzI0NDc1ODJBMzk=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5N0JFQzk5MDQwMEE5MTREOTAzMjkzMjQ0NzU4MkEzOTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjI4NUE3NTkwQ0VDMEJDNDZGMEMxQThBM0QxQUEyQkE1	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5N0JFQzk5MDQwMEE5MTREOTAzMjkzMjQ0NzU4MkEzOQ==	30B303C19C0C8F057A1D2397105D346E	285A7590CEC0BC46F0C1A8A3D1AA2BA5	4FBA45FB12D28F9106A09E045DE90254
+EB4BBFA85B1D9A9EE8F7D406FC8BD444	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=35	35	MO	urn:base64:RVV0cmFuQ2VsbDo5ODAzNzc2OUJBODVFQkU5NDI1MjJENUM0QzZDQjAyRjpVU0VTOkxURVNlY3RvckNhcnJpZXI6RUI0QkJGQTg1QjFEOUE5RUU4RjdENDA2RkM4QkQ0NDQ=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpFQjRCQkZBODVCMUQ5QTlFRThGN0Q0MDZGQzhCRDQ0NDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkM2MDZBRjFBMUFDNUE5NkE0M0IwQjhFQkZDMUIwNDdD	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpFQjRCQkZBODVCMUQ5QTlFRThGN0Q0MDZGQzhCRDQ0NA==	98037769BA85EBE942522D5C4C6CB02F	C606AF1A1AC5A96A43B0B8EBFC1B047C	4FBA45FB12D28F9106A09E045DE90254
+7C0D0AF440C912BE5BD10DE4F5587270	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=36	36	MO	urn:base64:RVV0cmFuQ2VsbDpCMkMzNTE2ODg3MTQ0RjY2RUYzRjMxRjY0MTczN0RBMDpVU0VTOkxURVNlY3RvckNhcnJpZXI6N0MwRDBBRjQ0MEM5MTJCRTVCRDEwREU0RjU1ODcyNzA=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3QzBEMEFGNDQwQzkxMkJFNUJEMTBERTRGNTU4NzI3MDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjQwRkI1NDgxNDAyRENFOEFENkIzQjAzNTdCMDBDRjgy	urn:base64:RU5vZGVCRnVuY3Rpb246NEZCQTQ1RkIxMkQyOEY5MTA2QTA5RTA0NURFOTAyNTQ6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3QzBEMEFGNDQwQzkxMkJFNUJEMTBERTRGNTU4NzI3MA==	B2C3516887144F66EF3F31F641737DA0	40FB5481402DCE8AD6B3B0357B00CF82	4FBA45FB12D28F9106A09E045DE90254
+E024800BB0240D7DB418E03DAF763FC9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=37	37	MO	urn:base64:RVV0cmFuQ2VsbDpFMzEyNDI2RTNDRUE4MzgyM0QzNDNCMjY1QjM4ODE4QTpVU0VTOkxURVNlY3RvckNhcnJpZXI6RTAyNDgwMEJCMDI0MEQ3REI0MThFMDNEQUY3NjNGQzk=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpFMDI0ODAwQkIwMjQwRDdEQjQxOEUwM0RBRjc2M0ZDOTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkZEOEYzREU4QjhBRjJGRDEwMkYzOUQwRUQ4OUIzNzE0	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpFMDI0ODAwQkIwMjQwRDdEQjQxOEUwM0RBRjc2M0ZDOQ==	E312426E3CEA83823D343B265B38818A	FD8F3DE8B8AF2FD102F39D0ED89B3714	222B3B5942A23115B9C1AC2B94AF8548
+3D9825BBFDDA56F41FA800A56C052E2E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=38	38	MO	urn:base64:RVV0cmFuQ2VsbDpBNzkyNUU4NTc1MDA5RDBGMTZEMTg1RTI1Nzg3OTc3MDpVU0VTOkxURVNlY3RvckNhcnJpZXI6M0Q5ODI1QkJGRERBNTZGNDFGQTgwMEE1NkMwNTJFMkU=	urn:base64:TFRFU2VjdG9yQ2FycmllcjozRDk4MjVCQkZEREE1NkY0MUZBODAwQTU2QzA1MkUyRTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjVDRUEyNDcwRDk5QThBMkJCM0VEOTBCQzE1REIxMTQw	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozRDk4MjVCQkZEREE1NkY0MUZBODAwQTU2QzA1MkUyRQ==	A7925E8575009D0F16D185E257879770	5CEA2470D99A8A2BB3ED90BC15DB1140	222B3B5942A23115B9C1AC2B94AF8548
+8B44859EE12633357CA3E9A5C8395FF0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=39	39	MO	urn:base64:RVV0cmFuQ2VsbDo3MkJDMjVCNTYxM0I5QkM1MzA4MjA5NThGMzkzRTkwQzpVU0VTOkxURVNlY3RvckNhcnJpZXI6OEI0NDg1OUVFMTI2MzMzNTdDQTNFOUE1QzgzOTVGRjA=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo4QjQ0ODU5RUUxMjYzMzM1N0NBM0U5QTVDODM5NUZGMDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjZBMjNBOEI4QjVBQ0VBNzc1RDZFOThCQUMxNTM0Mzcz	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo4QjQ0ODU5RUUxMjYzMzM1N0NBM0U5QTVDODM5NUZGMA==	72BC25B5613B9BC530820958F393E90C	6A23A8B8B5ACEA775D6E98BAC1534373	222B3B5942A23115B9C1AC2B94AF8548
+B73523501090D7CE4D8EF71252D4F52D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=40	40	MO	urn:base64:RVV0cmFuQ2VsbDpBQUY2M0I1QzVDRTgwQjMxOEY0NDUyNTYwQzlCNUU1QjpVU0VTOkxURVNlY3RvckNhcnJpZXI6QjczNTIzNTAxMDkwRDdDRTREOEVGNzEyNTJENEY1MkQ=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpCNzM1MjM1MDEwOTBEN0NFNEQ4RUY3MTI1MkQ0RjUyRDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjFEMjczRkRENDU2MThDQkQ0MzhEMDA4Mzg3MzMxNEQ1	urn:base64:RU5vZGVCRnVuY3Rpb246MjIyQjNCNTk0MkEyMzExNUI5QzFBQzJCOTRBRjg1NDg6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpCNzM1MjM1MDEwOTBEN0NFNEQ4RUY3MTI1MkQ0RjUyRA==	AAF63B5C5CE80B318F4452560C9B5E5B	1D273FDD45618CBD438D0083873314D5	222B3B5942A23115B9C1AC2B94AF8548
+FE5BB2828B02BDC7FC82D2F0738F5CE5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=41	41	MO	urn:base64:RVV0cmFuQ2VsbDpFMEY2ODZCNDFBQkU1MUNGNUMwMDk2MDhBMUJCOTg0RjpVU0VTOkxURVNlY3RvckNhcnJpZXI6RkU1QkIyODI4QjAyQkRDN0ZDODJEMkYwNzM4RjVDRTU=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpGRTVCQjI4MjhCMDJCREM3RkM4MkQyRjA3MzhGNUNFNTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkUwN0Y3NkVFRkEzRjZEMUE1MDgzQzk5RjNEMjAyQ0NE	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpGRTVCQjI4MjhCMDJCREM3RkM4MkQyRjA3MzhGNUNFNQ==	E0F686B41ABE51CF5C009608A1BB984F	E07F76EEFA3F6D1A5083C99F3D202CCD	FDB1D1C7AC573BA174781DD2DD7359FE
+0D019FB9076AA61D73956DAF4D98913F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=42	42	MO	urn:base64:RVV0cmFuQ2VsbDowQUIwQzQyNUU5MzdFRTRFN0I3OTg3OTg1MjBGMUNBMzpVU0VTOkxURVNlY3RvckNhcnJpZXI6MEQwMTlGQjkwNzZBQTYxRDczOTU2REFGNEQ5ODkxM0Y=	urn:base64:TFRFU2VjdG9yQ2FycmllcjowRDAxOUZCOTA3NkFBNjFENzM5NTZEQUY0RDk4OTEzRjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjE3MzM4ODc4NUNCNDc2MUIxNTRGNDQ4QUU2MzcyQURD	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjowRDAxOUZCOTA3NkFBNjFENzM5NTZEQUY0RDk4OTEzRg==	0AB0C425E937EE4E7B798798520F1CA3	173388785CB4761B154F448AE6372ADC	FDB1D1C7AC573BA174781DD2DD7359FE
+DAA8B97101D41F3E9D8BF8977250625D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=43	43	MO	urn:base64:RVV0cmFuQ2VsbDpBQkFDMUEzNEQ3MUVBRTE4RTcxOTg3QzE1REVEMUQ3MTpVU0VTOkxURVNlY3RvckNhcnJpZXI6REFBOEI5NzEwMUQ0MUYzRTlEOEJGODk3NzI1MDYyNUQ=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpEQUE4Qjk3MTAxRDQxRjNFOUQ4QkY4OTc3MjUwNjI1RDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkFBMTdDRTE1MDRDRDQ1MTIxMjEyNjdDMjIwMzQ2MjBB	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpEQUE4Qjk3MTAxRDQxRjNFOUQ4QkY4OTc3MjUwNjI1RA==	ABAC1A34D71EAE18E71987C15DED1D71	AA17CE1504CD4512121267C22034620A	FDB1D1C7AC573BA174781DD2DD7359FE
+1A777650C4E9B8075977354FDE860824	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=44	44	MO	urn:base64:RVV0cmFuQ2VsbDpCQjQ3Qjg1Njk5Q0EyQ0FDRkY5RjIwMTFGQTJENkNDMjpVU0VTOkxURVNlY3RvckNhcnJpZXI6MUE3Nzc2NTBDNEU5QjgwNzU5NzczNTRGREU4NjA4MjQ=	urn:base64:TFRFU2VjdG9yQ2FycmllcjoxQTc3NzY1MEM0RTlCODA3NTk3NzM1NEZERTg2MDgyNDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjU0MkQ1NjJFNzJDODAyNURENTYwRDcxOEZGREUxRDQ1	urn:base64:RU5vZGVCRnVuY3Rpb246RkRCMUQxQzdBQzU3M0JBMTc0NzgxREQyREQ3MzU5RkU6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjoxQTc3NzY1MEM0RTlCODA3NTk3NzM1NEZERTg2MDgyNA==	BB47B85699CA2CACFF9F2011FA2D6CC2	542D562E72C8025DD560D718FFDE1D45	FDB1D1C7AC573BA174781DD2DD7359FE
+CA63AD754710B31CCE770A71BBAFA823	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=45	45	MO	urn:base64:RVV0cmFuQ2VsbDpGQjZDQkIwQ0JCQzZGMTE4NjhCOTRFRDk3NzE1NjY3NzpVU0VTOkxURVNlY3RvckNhcnJpZXI6Q0E2M0FENzU0NzEwQjMxQ0NFNzcwQTcxQkJBRkE4MjM=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpDQTYzQUQ3NTQ3MTBCMzFDQ0U3NzBBNzFCQkFGQTgyMzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkUzQzk2QkE1RDdDMDc1NUEzMDExRDEyQTMyOTcxQkEx	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpDQTYzQUQ3NTQ3MTBCMzFDQ0U3NzBBNzFCQkFGQTgyMw==	FB6CBB0CBBC6F11868B94ED977156677	E3C96BA5D7C0755A3011D12A32971BA1	FE3075645E2303A67B9D0BAD3CCB29BC
+D686F8AE6CC4C8A588400AB752322CCA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=46	46	MO	urn:base64:RVV0cmFuQ2VsbDowNDI4OEE5QTk1MTg4RDFGMURENTlDOTBBNDlEMjY0OTpVU0VTOkxURVNlY3RvckNhcnJpZXI6RDY4NkY4QUU2Q0M0QzhBNTg4NDAwQUI3NTIzMjJDQ0E=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpENjg2RjhBRTZDQzRDOEE1ODg0MDBBQjc1MjMyMkNDQTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkI0QzMzM0VDRDkyQTczNTFBMzhFRTNCQzUxMEI1REE3	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpENjg2RjhBRTZDQzRDOEE1ODg0MDBBQjc1MjMyMkNDQQ==	04288A9A95188D1F1DD59C90A49D2649	B4C333ECD92A7351A38EE3BC510B5DA7	FE3075645E2303A67B9D0BAD3CCB29BC
+DFE953449C7E184AC614BB9B2625997F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=47	47	MO	urn:base64:RVV0cmFuQ2VsbDoyQTYwNTRDQ0NENzE3OUYwOUJDMTE4QjI4MThCMUFERTpVU0VTOkxURVNlY3RvckNhcnJpZXI6REZFOTUzNDQ5QzdFMTg0QUM2MTRCQjlCMjYyNTk5N0Y=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpERkU5NTM0NDlDN0UxODRBQzYxNEJCOUIyNjI1OTk3RjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjZGNzUxMTZCQjI4OUVDRDhFQjFBOTYyNTJGRDhGN0Mw	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpERkU5NTM0NDlDN0UxODRBQzYxNEJCOUIyNjI1OTk3Rg==	2A6054CCCD7179F09BC118B2818B1ADE	6F75116BB289ECD8EB1A96252FD8F7C0	FE3075645E2303A67B9D0BAD3CCB29BC
+89E516889722A65325C1E5428EEC167C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=48	48	MO	urn:base64:RVV0cmFuQ2VsbDo1MUM1MDQ2ODk2NDYxQkE4OTc0NEY3NTM4NEFCREI5MzpVU0VTOkxURVNlY3RvckNhcnJpZXI6ODlFNTE2ODg5NzIyQTY1MzI1QzFFNTQyOEVFQzE2N0M=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo4OUU1MTY4ODk3MjJBNjUzMjVDMUU1NDI4RUVDMTY3QzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjE2Qjg3MDUxMUZBQUYxMTgzRkM5MkU2NDFCMkMzODA0	urn:base64:RU5vZGVCRnVuY3Rpb246RkUzMDc1NjQ1RTIzMDNBNjdCOUQwQkFEM0NDQjI5QkM6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo4OUU1MTY4ODk3MjJBNjUzMjVDMUU1NDI4RUVDMTY3Qw==	51C5046896461BA89744F75384ABDB93	16B870511FAAF1183FC92E641B2C3804	FE3075645E2303A67B9D0BAD3CCB29BC
+A7650696F038E8A8D20654C1E88BF765	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=49	49	MO	urn:base64:RVV0cmFuQ2VsbDo3QzlEMjQ1OTM2NUNDODBCQ0VDODRFNERCOTcxMzEyMDpVU0VTOkxURVNlY3RvckNhcnJpZXI6QTc2NTA2OTZGMDM4RThBOEQyMDY1NEMxRTg4QkY3NjU=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpBNzY1MDY5NkYwMzhFOEE4RDIwNjU0QzFFODhCRjc2NTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjJDN0FBODA5Q0QxQTkyRkQ3NEVDNDE1MUQ3QzE2QThE	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpBNzY1MDY5NkYwMzhFOEE4RDIwNjU0QzFFODhCRjc2NQ==	7C9D2459365CC80BCEC84E4DB9713120	2C7AA809CD1A92FD74EC4151D7C16A8D	CF6B05084CD85A8C0943B77317510652
+2AAB010B2406F422886BA8BD080DE1F3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=50	50	MO	urn:base64:RVV0cmFuQ2VsbDo5QzQzNThDQURDMDhFNTZBMTlFOEZFRTFDMDFBNzA2RjpVU0VTOkxURVNlY3RvckNhcnJpZXI6MkFBQjAxMEIyNDA2RjQyMjg4NkJBOEJEMDgwREUxRjM=	urn:base64:TFRFU2VjdG9yQ2FycmllcjoyQUFCMDEwQjI0MDZGNDIyODg2QkE4QkQwODBERTFGMzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjJDMjFEMTA2OTQ2MEYzNUZGMzg5NTJGMTA1MERGN0ND	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjoyQUFCMDEwQjI0MDZGNDIyODg2QkE4QkQwODBERTFGMw==	9C4358CADC08E56A19E8FEE1C01A706F	2C21D1069460F35FF38952F1050DF7CC	CF6B05084CD85A8C0943B77317510652
+6AB2E20188362ADB23025E6F882690EC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=51	51	MO	urn:base64:RVV0cmFuQ2VsbDpGNDAyNDJCMEYwNzA4RTA5QkIwNzYzNUJDNzUwNTc3NjpVU0VTOkxURVNlY3RvckNhcnJpZXI6NkFCMkUyMDE4ODM2MkFEQjIzMDI1RTZGODgyNjkwRUM=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo2QUIyRTIwMTg4MzYyQURCMjMwMjVFNkY4ODI2OTBFQzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkFBM0VEMEM4MkE5RkU2RDc0MTJCN0M1NThBOTZDREE1	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo2QUIyRTIwMTg4MzYyQURCMjMwMjVFNkY4ODI2OTBFQw==	F40242B0F0708E09BB07635BC7505776	AA3ED0C82A9FE6D7412B7C558A96CDA5	CF6B05084CD85A8C0943B77317510652
+86CCA39D5D6AD1E1A8FB05ED06738695	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=52	52	MO	urn:base64:RVV0cmFuQ2VsbDozNTNFNDQ1RUFGRTNGQTU4NkQ2NzY4RjcyQTI2MjNBNDpVU0VTOkxURVNlY3RvckNhcnJpZXI6ODZDQ0EzOUQ1RDZBRDFFMUE4RkIwNUVEMDY3Mzg2OTU=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo4NkNDQTM5RDVENkFEMUUxQThGQjA1RUQwNjczODY5NTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkI1RDM2OTA1Qzg3REE2MzY2MTFDMTM3MTU5NzI3Q0VF	urn:base64:RU5vZGVCRnVuY3Rpb246Q0Y2QjA1MDg0Q0Q4NUE4QzA5NDNCNzczMTc1MTA2NTI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo4NkNDQTM5RDVENkFEMUUxQThGQjA1RUQwNjczODY5NQ==	353E445EAFE3FA586D6768F72A2623A4	B5D36905C87DA636611C137159727CEE	CF6B05084CD85A8C0943B77317510652
+4FB92C02ABE546943360E18F5447919F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=53	53	MO	urn:base64:RVV0cmFuQ2VsbDo3REY5Mzc0RUFEQTY4ODVCRjNDRUYyMzE4ODk0NjA4QzpVU0VTOkxURVNlY3RvckNhcnJpZXI6NEZCOTJDMDJBQkU1NDY5NDMzNjBFMThGNTQ0NzkxOUY=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo0RkI5MkMwMkFCRTU0Njk0MzM2MEUxOEY1NDQ3OTE5RjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjNFRjRDNzEzNTRFQzUyN0FCMDMzQTNGQjgyMEY0OEU0	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo0RkI5MkMwMkFCRTU0Njk0MzM2MEUxOEY1NDQ3OTE5Rg==	7DF9374EADA6885BF3CEF2318894608C	3EF4C71354EC527AB033A3FB820F48E4	8094F5C9E30C346536F0A08A851338F6
+A35530885A44AFFD76DDA542C2F47228	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=54	54	MO	urn:base64:RVV0cmFuQ2VsbDozREEzNUQ0OUQxRDlDNTFBMjM0MDM1QUQzQTNGRDM3RTpVU0VTOkxURVNlY3RvckNhcnJpZXI6QTM1NTMwODg1QTQ0QUZGRDc2RERBNTQyQzJGNDcyMjg=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpBMzU1MzA4ODVBNDRBRkZENzZEREE1NDJDMkY0NzIyODpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjBCMzY4MUYxOTU1ODRFRjEwNTFCOTE0RUI2M0VCQkNC	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpBMzU1MzA4ODVBNDRBRkZENzZEREE1NDJDMkY0NzIyOA==	3DA35D49D1D9C51A234035AD3A3FD37E	0B3681F195584EF1051B914EB63EBBCB	8094F5C9E30C346536F0A08A851338F6
+5707466E24D325B597E24A3AB3A8A02E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=55	55	MO	urn:base64:RVV0cmFuQ2VsbDoyQTExMjM1M0VDNzVGOUFDMkJBNDNFRTcwODI5NkEwMTpVU0VTOkxURVNlY3RvckNhcnJpZXI6NTcwNzQ2NkUyNEQzMjVCNTk3RTI0QTNBQjNBOEEwMkU=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo1NzA3NDY2RTI0RDMyNUI1OTdFMjRBM0FCM0E4QTAyRTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjU5QTc3RkJCREM4RTE4MTk3NDFFNDcyODU5NkM0MzVD	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo1NzA3NDY2RTI0RDMyNUI1OTdFMjRBM0FCM0E4QTAyRQ==	2A112353EC75F9AC2BA43EE708296A01	59A77FBBDC8E1819741E4728596C435C	8094F5C9E30C346536F0A08A851338F6
+069EBFDB8A379462AC82DA1958706C4F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=56	56	MO	urn:base64:RVV0cmFuQ2VsbDoxMzlGMEFEMkQ2NDFEOTcxNzc3MDJGQkY1RUZGMzBGRTpVU0VTOkxURVNlY3RvckNhcnJpZXI6MDY5RUJGREI4QTM3OTQ2MkFDODJEQTE5NTg3MDZDNEY=	urn:base64:TFRFU2VjdG9yQ2FycmllcjowNjlFQkZEQjhBMzc5NDYyQUM4MkRBMTk1ODcwNkM0RjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkJEQzhFNEVBQzUzQzlDMzk4MDBCNEJEQzAzMDlDOEJC	urn:base64:RU5vZGVCRnVuY3Rpb246ODA5NEY1QzlFMzBDMzQ2NTM2RjBBMDhBODUxMzM4RjY6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjowNjlFQkZEQjhBMzc5NDYyQUM4MkRBMTk1ODcwNkM0Rg==	139F0AD2D641D97177702FBF5EFF30FE	BDC8E4EAC53C9C39800B4BDC0309C8BB	8094F5C9E30C346536F0A08A851338F6
+DDA0517CB1E49F2ED5D60534F073D8A6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=57	57	MO	urn:base64:RVV0cmFuQ2VsbDo4RkYwNjExREE4RjBDRDY4RTNBMjE1QUEwN0NCQjIwRDpVU0VTOkxURVNlY3RvckNhcnJpZXI6RERBMDUxN0NCMUU0OUYyRUQ1RDYwNTM0RjA3M0Q4QTY=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpEREEwNTE3Q0IxRTQ5RjJFRDVENjA1MzRGMDczRDhBNjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjM3MzMyMjk5QkUxMzk4MTkzRjdCNzQ1MkMxNjUyMUY4	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpEREEwNTE3Q0IxRTQ5RjJFRDVENjA1MzRGMDczRDhBNg==	8FF0611DA8F0CD68E3A215AA07CBB20D	37332299BE1398193F7B7452C16521F8	E87A72FDF835513E6BACBF730D5BA6C8
+95F1D3E029E2573B6506E0C492AE9494	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=58	58	MO	urn:base64:RVV0cmFuQ2VsbDo1Q0FDMzQ4N0E4NUREREQzMzZCMUY1ODBGRDVGNzJERDpVU0VTOkxURVNlY3RvckNhcnJpZXI6OTVGMUQzRTAyOUUyNTczQjY1MDZFMEM0OTJBRTk0OTQ=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5NUYxRDNFMDI5RTI1NzNCNjUwNkUwQzQ5MkFFOTQ5NDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjgzQjhGQzM0MDlFOUUzNEY4RDRCMjJDRDUxNENDMDc4	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5NUYxRDNFMDI5RTI1NzNCNjUwNkUwQzQ5MkFFOTQ5NA==	5CAC3487A85DDDD336B1F580FD5F72DD	83B8FC3409E9E34F8D4B22CD514CC078	E87A72FDF835513E6BACBF730D5BA6C8
+C897D4111ADAF80E4B37B1EE0B2C3E46	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=59	59	MO	urn:base64:RVV0cmFuQ2VsbDo3M0MwRUM3OEU5REFFRTUzNDdENDVGMTA1NzBFQzg1MTpVU0VTOkxURVNlY3RvckNhcnJpZXI6Qzg5N0Q0MTExQURBRjgwRTRCMzdCMUVFMEIyQzNFNDY=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpDODk3RDQxMTFBREFGODBFNEIzN0IxRUUwQjJDM0U0NjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjU4N0FEQkQ0NkZBMEE3NzBFMUMzQUJBMjEwREI1N0VE	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpDODk3RDQxMTFBREFGODBFNEIzN0IxRUUwQjJDM0U0Ng==	73C0EC78E9DAEE5347D45F10570EC851	587ADBD46FA0A770E1C3ABA210DB57ED	E87A72FDF835513E6BACBF730D5BA6C8
+9131BBD1EB82C0D91E0988B1C7C7F067	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=60	60	MO	urn:base64:RVV0cmFuQ2VsbDo5OEJEREE4QjU0QjdCODkyNzY3NUU3N0M5MjdEODI4MzpVU0VTOkxURVNlY3RvckNhcnJpZXI6OTEzMUJCRDFFQjgyQzBEOTFFMDk4OEIxQzdDN0YwNjc=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5MTMxQkJEMUVCODJDMEQ5MUUwOTg4QjFDN0M3RjA2NzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjYwNEEyMkJGQzcyQTk2MDExNUQ2QjIxQzNGMTg2ODQx	urn:base64:RU5vZGVCRnVuY3Rpb246RTg3QTcyRkRGODM1NTEzRTZCQUNCRjczMEQ1QkE2Qzg6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5MTMxQkJEMUVCODJDMEQ5MUUwOTg4QjFDN0M3RjA2Nw==	98BDDA8B54B7B8927675E77C927D8283	604A22BFC72A960115D6B21C3F186841	E87A72FDF835513E6BACBF730D5BA6C8
+6001993A468525D8F81744175E1DFD84	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=61	61	MO	urn:base64:RVV0cmFuQ2VsbDo3MTM1NkZDRTVDNjM1OERBRThGOEJGM0Y3QzlCRjAxNDpVU0VTOkxURVNlY3RvckNhcnJpZXI6NjAwMTk5M0E0Njg1MjVEOEY4MTc0NDE3NUUxREZEODQ=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo2MDAxOTkzQTQ2ODUyNUQ4RjgxNzQ0MTc1RTFERkQ4NDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjFENENCQzQzRDYyQTAxQjI3RkEwQzc0NDJGOUFEMEQ4	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo2MDAxOTkzQTQ2ODUyNUQ4RjgxNzQ0MTc1RTFERkQ4NA==	71356FCE5C6358DAE8F8BF3F7C9BF014	1D4CBC43D62A01B27FA0C7442F9AD0D8	8E99154C3A70826BBD373F06BC1C752B
+157FC984BC10AE290A8EF99151B03354	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=62	62	MO	urn:base64:RVV0cmFuQ2VsbDpFNTQ4OUU2RDZDQzA3ODkxRjU0MUJFNDFFRjM3QUE2MzpVU0VTOkxURVNlY3RvckNhcnJpZXI6MTU3RkM5ODRCQzEwQUUyOTBBOEVGOTkxNTFCMDMzNTQ=	urn:base64:TFRFU2VjdG9yQ2FycmllcjoxNTdGQzk4NEJDMTBBRTI5MEE4RUY5OTE1MUIwMzM1NDpVU0VTOkFudGVubmFDYXBhYmlsaXR5Ojg5MkJBRTBCNDU4NjVEM0Y0REM3NzY2NjJCQjM3NjU0	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjoxNTdGQzk4NEJDMTBBRTI5MEE4RUY5OTE1MUIwMzM1NA==	E5489E6D6CC07891F541BE41EF37AA63	892BAE0B45865D3F4DC776662BB37654	8E99154C3A70826BBD373F06BC1C752B
+BAED17ED9DE215B3A977B4A40C471498	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=63	63	MO	urn:base64:RVV0cmFuQ2VsbDpEMEVBNThCRTBBQzE2NzFCOTM2RjE1QzY3REVBODg5MjpVU0VTOkxURVNlY3RvckNhcnJpZXI6QkFFRDE3RUQ5REUyMTVCM0E5NzdCNEE0MEM0NzE0OTg=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpCQUVEMTdFRDlERTIxNUIzQTk3N0I0QTQwQzQ3MTQ5ODpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkVFMUVBQUZEQjg1MjA2MjU5QUE5RDlENEJBMDFCREEy	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpCQUVEMTdFRDlERTIxNUIzQTk3N0I0QTQwQzQ3MTQ5OA==	D0EA58BE0AC1671B936F15C67DEA8892	EE1EAAFDB85206259AA9D9D4BA01BDA2	8E99154C3A70826BBD373F06BC1C752B
+5A6A2B3D21767F1BF0F2405AC06D01B0	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=64	64	MO	urn:base64:RVV0cmFuQ2VsbDo5QTAzMEQ5RURDMEM4QjA0QTBDNUQyNEEzQTIyMzEzNzpVU0VTOkxURVNlY3RvckNhcnJpZXI6NUE2QTJCM0QyMTc2N0YxQkYwRjI0MDVBQzA2RDAxQjA=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo1QTZBMkIzRDIxNzY3RjFCRjBGMjQwNUFDMDZEMDFCMDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjExMUJEMTIzRENBMUI5MzdGMEUxNUU1QkVGREUwOEU5	urn:base64:RU5vZGVCRnVuY3Rpb246OEU5OTE1NEMzQTcwODI2QkJEMzczRjA2QkMxQzc1MkI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo1QTZBMkIzRDIxNzY3RjFCRjBGMjQwNUFDMDZEMDFCMA==	9A030D9EDC0C8B04A0C5D24A3A223137	111BD123DCA1B937F0E15E5BEFDE08E9	8E99154C3A70826BBD373F06BC1C752B
+5155EA305406300383C95C1D8F59C43C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=65	65	MO	urn:base64:RVV0cmFuQ2VsbDo1NjZCOTU2NkE0MEFCMENDRjE2ODRBOEM3NUQ2RThGMDpVU0VTOkxURVNlY3RvckNhcnJpZXI6NTE1NUVBMzA1NDA2MzAwMzgzQzk1QzFEOEY1OUM0M0M=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo1MTU1RUEzMDU0MDYzMDAzODNDOTVDMUQ4RjU5QzQzQzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkRGNzgzN0VFQUI2NUEwNjg1OTExMDM2NkU1RjQ1Mjk3	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo1MTU1RUEzMDU0MDYzMDAzODNDOTVDMUQ4RjU5QzQzQw==	566B9566A40AB0CCF1684A8C75D6E8F0	DF7837EEAB65A06859110366E5F45297	CEE5D7B02D903A316D0A017C50FC9993
+536765CD4046DCD78CF3933FB856E77C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=66	66	MO	urn:base64:RVV0cmFuQ2VsbDpBNTU4N0Q1MUREQjREMUFBRjg4MDc1RUZBRkQzRkYxQTpVU0VTOkxURVNlY3RvckNhcnJpZXI6NTM2NzY1Q0Q0MDQ2RENENzhDRjM5MzNGQjg1NkU3N0M=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo1MzY3NjVDRDQwNDZEQ0Q3OENGMzkzM0ZCODU2RTc3QzpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkQwQUFFOTYzMUFGMTU1NEI4RjM5MDkzMkUzNzdFQTE5	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo1MzY3NjVDRDQwNDZEQ0Q3OENGMzkzM0ZCODU2RTc3Qw==	A5587D51DDB4D1AAF88075EFAFD3FF1A	D0AAE9631AF1554B8F390932E377EA19	CEE5D7B02D903A316D0A017C50FC9993
+3C04934E350AF691DFD0E93E9C43B9AB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=67	67	MO	urn:base64:RVV0cmFuQ2VsbDo3OTJGQzE1RkEzRjU1NTYyMzczRkY1QjY3Qzg5NzlEOTpVU0VTOkxURVNlY3RvckNhcnJpZXI6M0MwNDkzNEUzNTBBRjY5MURGRDBFOTNFOUM0M0I5QUI=	urn:base64:TFRFU2VjdG9yQ2FycmllcjozQzA0OTM0RTM1MEFGNjkxREZEMEU5M0U5QzQzQjlBQjpVU0VTOkFudGVubmFDYXBhYmlsaXR5Ojg5QjlGRTVEMkQ0QTA3Q0NENTRFNzA1QkZFMkQxMEYw	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozQzA0OTM0RTM1MEFGNjkxREZEMEU5M0U5QzQzQjlBQg==	792FC15FA3F55562373FF5B67C8979D9	89B9FE5D2D4A07CCD54E705BFE2D10F0	CEE5D7B02D903A316D0A017C50FC9993
+6828F136D4173CB3409095959B5C8B8B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=68	68	MO	urn:base64:RVV0cmFuQ2VsbDo2RkFBQjUzNDczRjA4NERDODg2RDFFMDQyNjVFRUFEMTpVU0VTOkxURVNlY3RvckNhcnJpZXI6NjgyOEYxMzZENDE3M0NCMzQwOTA5NTk1OUI1QzhCOEI=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo2ODI4RjEzNkQ0MTczQ0IzNDA5MDk1OTU5QjVDOEI4QjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkE2RTk3QkEzMDgzMkMxQjdBQzM2RjRENzlERDM4Qjcx	urn:base64:RU5vZGVCRnVuY3Rpb246Q0VFNUQ3QjAyRDkwM0EzMTZEMEEwMTdDNTBGQzk5OTM6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo2ODI4RjEzNkQ0MTczQ0IzNDA5MDk1OTU5QjVDOEI4Qg==	6FAAB53473F084DC886D1E04265EEAD1	A6E97BA30832C1B7AC36F4D79DD38B71	CEE5D7B02D903A316D0A017C50FC9993
+9E6667504F7CBDD9D2AE117219A1F501	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=69	69	MO	urn:base64:RVV0cmFuQ2VsbDowN0IzNzExNjc3MDg1RTE2RjQ4QUVEOTlCRUE0MDk2NjpVU0VTOkxURVNlY3RvckNhcnJpZXI6OUU2NjY3NTA0RjdDQkREOUQyQUUxMTcyMTlBMUY1MDE=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5RTY2Njc1MDRGN0NCREQ5RDJBRTExNzIxOUExRjUwMTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkRGQTYyMDJGRjk2REQ0MThFQUQ0QzkzMEYyN0YwQzc4	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5RTY2Njc1MDRGN0NCREQ5RDJBRTExNzIxOUExRjUwMQ==	07B3711677085E16F48AED99BEA40966	DFA6202FF96DD418EAD4C930F27F0C78	E240B26BA8EE38087134B6D22E24BBDB
+A7C40C6432DB775E67780AA0060CA7DB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=70	70	MO	urn:base64:RVV0cmFuQ2VsbDpCOTVFQkU0MjQ1ODAxRDcxODVFMUQwNUU1QkJEQTNGMzpVU0VTOkxURVNlY3RvckNhcnJpZXI6QTdDNDBDNjQzMkRCNzc1RTY3NzgwQUEwMDYwQ0E3REI=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpBN0M0MEM2NDMyREI3NzVFNjc3ODBBQTAwNjBDQTdEQjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjAxOTQ1RDdCN0QyQUZCMEIzREZFMjM4MjJEMkM5Q0NC	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpBN0M0MEM2NDMyREI3NzVFNjc3ODBBQTAwNjBDQTdEQg==	B95EBE4245801D7185E1D05E5BBDA3F3	01945D7B7D2AFB0B3DFE23822D2C9CCB	E240B26BA8EE38087134B6D22E24BBDB
+CF0284C3C21BEFE7AB248D65680A80EA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=71	71	MO	urn:base64:RVV0cmFuQ2VsbDpBQkZCRTlFQTc2NzNBMTkxREI2QTUxNDM5RDU1MTVENTpVU0VTOkxURVNlY3RvckNhcnJpZXI6Q0YwMjg0QzNDMjFCRUZFN0FCMjQ4RDY1NjgwQTgwRUE=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpDRjAyODRDM0MyMUJFRkU3QUIyNDhENjU2ODBBODBFQTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkJFNTBBQzU3QUIxRkFFNzM1MzFBREQxODEzMjQwNjdG	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpDRjAyODRDM0MyMUJFRkU3QUIyNDhENjU2ODBBODBFQQ==	ABFBE9EA7673A191DB6A51439D5515D5	BE50AC57AB1FAE73531ADD181324067F	E240B26BA8EE38087134B6D22E24BBDB
+15DF19B0C1FAE1610E970C154A10B219	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=72	72	MO	urn:base64:RVV0cmFuQ2VsbDo2MkVEQzdENEQ2QTFEMzYxRTEyRkVCMjY4OEU0M0E4OTpVU0VTOkxURVNlY3RvckNhcnJpZXI6MTVERjE5QjBDMUZBRTE2MTBFOTcwQzE1NEExMEIyMTk=	urn:base64:TFRFU2VjdG9yQ2FycmllcjoxNURGMTlCMEMxRkFFMTYxMEU5NzBDMTU0QTEwQjIxOTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjgyRDA1NURFMTVCOTdDRDg2NkNGNDU0QTk2ODhGNERC	urn:base64:RU5vZGVCRnVuY3Rpb246RTI0MEIyNkJBOEVFMzgwODcxMzRCNkQyMkUyNEJCREI6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjoxNURGMTlCMEMxRkFFMTYxMEU5NzBDMTU0QTEwQjIxOQ==	62EDC7D4D6A1D361E12FEB2688E43A89	82D055DE15B97CD866CF454A9688F4DB	E240B26BA8EE38087134B6D22E24BBDB
+8D65835759F555E8B99E68767BB35ACA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=73	73	MO	urn:base64:RVV0cmFuQ2VsbDpFRTdCNUVCQUUyMTM0M0U2OEFDMTk3MTUwRkEyNjU1RTpVU0VTOkxURVNlY3RvckNhcnJpZXI6OEQ2NTgzNTc1OUY1NTVFOEI5OUU2ODc2N0JCMzVBQ0E=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo4RDY1ODM1NzU5RjU1NUU4Qjk5RTY4NzY3QkIzNUFDQTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjM2MkVDM0I3NzU4RDg3M0RGOThBRTJBOUVDMjQ3MkI1	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo4RDY1ODM1NzU5RjU1NUU4Qjk5RTY4NzY3QkIzNUFDQQ==	EE7B5EBAE21343E68AC197150FA2655E	362EC3B7758D873DF98AE2A9EC2472B5	FC195225D4CD060E249281C9BBDAF964
+22CC8313F3514E848D51B40B889B3752	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=74	74	MO	urn:base64:RVV0cmFuQ2VsbDo0NzhDQjE3MzFDNzFCRTg0OUIwRDgyRjMyMDhGNzBDRjpVU0VTOkxURVNlY3RvckNhcnJpZXI6MjJDQzgzMTNGMzUxNEU4NDhENTFCNDBCODg5QjM3NTI=	urn:base64:TFRFU2VjdG9yQ2FycmllcjoyMkNDODMxM0YzNTE0RTg0OEQ1MUI0MEI4ODlCMzc1MjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkRBNUQ4QTNEMUNEQzNENTU0NDdGN0M4NkVERDhGRTUw	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjoyMkNDODMxM0YzNTE0RTg0OEQ1MUI0MEI4ODlCMzc1Mg==	478CB1731C71BE849B0D82F3208F70CF	DA5D8A3D1CDC3D55447F7C86EDD8FE50	FC195225D4CD060E249281C9BBDAF964
+6031B371CA7E568237A3DFA04A80FE4B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=75	75	MO	urn:base64:RVV0cmFuQ2VsbDo1RDZGM0I0OTRGRUNFMEQ3QkM0NjczNUQ2M0VDQTUwQjpVU0VTOkxURVNlY3RvckNhcnJpZXI6NjAzMUIzNzFDQTdFNTY4MjM3QTNERkEwNEE4MEZFNEI=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo2MDMxQjM3MUNBN0U1NjgyMzdBM0RGQTA0QTgwRkU0QjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjZBMzlCMTUxQzUwRjczRjAyOUI1NzcyMjk5RENGMjg5	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo2MDMxQjM3MUNBN0U1NjgyMzdBM0RGQTA0QTgwRkU0Qg==	5D6F3B494FECE0D7BC46735D63ECA50B	6A39B151C50F73F029B5772299DCF289	FC195225D4CD060E249281C9BBDAF964
+BF6A9895F0DA4A0328FAA8E33F372D3F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=76	76	MO	urn:base64:RVV0cmFuQ2VsbDpGODE4QUEzNkI1RTE0NTZCMzJGQjNCOTAxNTdGMTVBRDpVU0VTOkxURVNlY3RvckNhcnJpZXI6QkY2QTk4OTVGMERBNEEwMzI4RkFBOEUzM0YzNzJEM0Y=	urn:base64:TFRFU2VjdG9yQ2FycmllcjpCRjZBOTg5NUYwREE0QTAzMjhGQUE4RTMzRjM3MkQzRjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkIwRkU4ODBERjk0NzRBQTI5QzdBNEJBQUE5NDZFNTVE	urn:base64:RU5vZGVCRnVuY3Rpb246RkMxOTUyMjVENENEMDYwRTI0OTI4MUM5QkJEQUY5NjQ6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjpCRjZBOTg5NUYwREE0QTAzMjhGQUE4RTMzRjM3MkQzRg==	F818AA36B5E1456B32FB3B90157F15AD	B0FE880DF9474AA29C7A4BAAA946E55D	FC195225D4CD060E249281C9BBDAF964
+7E4545AFAD3F792814FB8F010D5CF9FD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=77	77	MO	urn:base64:RVV0cmFuQ2VsbDo4RUFBQkJCMkM5RDQ5OTZDOEFEOTQxNTQ5MDMwNTJDQzpVU0VTOkxURVNlY3RvckNhcnJpZXI6N0U0NTQ1QUZBRDNGNzkyODE0RkI4RjAxMEQ1Q0Y5RkQ=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo3RTQ1NDVBRkFEM0Y3OTI4MTRGQjhGMDEwRDVDRjlGRDpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkMyM0Q5RDA4MDdFNDVFRjU1REM2QjdEMzVFRUIwOEIx	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo3RTQ1NDVBRkFEM0Y3OTI4MTRGQjhGMDEwRDVDRjlGRA==	8EAABBB2C9D4996C8AD94154903052CC	C23D9D0807E45EF55DC6B7D35EEB08B1	0C2651AB5D430123729B336E8635E0E0
+938CE5FDE447302290320C8C01424B05	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=78	78	MO	urn:base64:RVV0cmFuQ2VsbDpDQUM2RUY1Q0M5NTRGN0E3RjUyOTRBNjQzQ0Q3QTE2MDpVU0VTOkxURVNlY3RvckNhcnJpZXI6OTM4Q0U1RkRFNDQ3MzAyMjkwMzIwQzhDMDE0MjRCMDU=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo5MzhDRTVGREU0NDczMDIyOTAzMjBDOEMwMTQyNEIwNTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkNGOEVGNzIzQkI0NkM2MTcwREIwNDkwRDFGQTI2Qjg1	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo5MzhDRTVGREU0NDczMDIyOTAzMjBDOEMwMTQyNEIwNQ==	CAC6EF5CC954F7A7F5294A643CD7A160	CF8EF723BB46C6170DB0490D1FA26B85	0C2651AB5D430123729B336E8635E0E0
+329617C4BD9599181D6F7FE06C40C1FF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=79	79	MO	urn:base64:RVV0cmFuQ2VsbDoxMDUzQ0UyQUVCRUU2QjMyQzg0NkMzM0IwN0UwQjA0NzpVU0VTOkxURVNlY3RvckNhcnJpZXI6MzI5NjE3QzRCRDk1OTkxODFENkY3RkUwNkM0MEMxRkY=	urn:base64:TFRFU2VjdG9yQ2FycmllcjozMjk2MTdDNEJEOTU5OTE4MUQ2RjdGRTA2QzQwQzFGRjpVU0VTOkFudGVubmFDYXBhYmlsaXR5OkUxQzM0MERGMEZGQTUxMjExRERCNUY4MjlFMkEyN0VF	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6TFRFU2VjdG9yQ2FycmllcjozMjk2MTdDNEJEOTU5OTE4MUQ2RjdGRTA2QzQwQzFGRg==	1053CE2AEBEE6B32C846C33B07E0B047	E1C340DF0FFA51211DDB5F829E2A27EE	0C2651AB5D430123729B336E8635E0E0
+5C2B860A2AE8149A46531B69F2252301	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/LTESectorCarrier=80	80	MO	urn:base64:RVV0cmFuQ2VsbDo4MDMxMzJDOEFDMzdERUQ2MENCOUNCOTk4NkQ5QkMzRDpVU0VTOkxURVNlY3RvckNhcnJpZXI6NUMyQjg2MEEyQUU4MTQ5QTQ2NTMxQjY5RjIyNTIzMDE=	urn:base64:TFRFU2VjdG9yQ2Fycmllcjo1QzJCODYwQTJBRTgxNDlBNDY1MzFCNjlGMjI1MjMwMTpVU0VTOkFudGVubmFDYXBhYmlsaXR5OjU5RTM5QUVCMkNEOEVDMDAxODg1M0Q3RUY3NUU0RTc3	urn:base64:RU5vZGVCRnVuY3Rpb246MEMyNjUxQUI1RDQzMDEyMzcyOUIzMzZFODYzNUUwRTA6UFJPVklERVM6TFRFU2VjdG9yQ2Fycmllcjo1QzJCODYwQTJBRTgxNDlBNDY1MzFCNjlGMjI1MjMwMQ==	803132C8AC37DED60CB9CB9986D9BC3D	59E39AEB2CD8EC0018853D7EF75E4E77	0C2651AB5D430123729B336E8635E0E0
+\.
+
+COPY ties_data."NRSectorCarrier" (id, fdn, "arfcnDL", "arfcnUL", "essScLocalId", "frequencyDL", "frequencyUL", "REL_NRCELLDU_USES_NRSECTORCARRIER_EIID", "REL_NRSECTORCARRIER_USES_ANTENNACAPABILITY_EIID", "REL_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER_EIID", "REL_NRCELLDU_USES_NRSECTORCARRIER", "REL_NRSECTORCARRIER_USES_ANTENNACAPABILITY", "REL_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER") FROM stdin;
+280DC38868CEE3ED4A6BA9149ABE7A6C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=1	1000	20	1	20	20	urn:base64:TlJDZWxsRFU6OThDM0E0NTkxQTM3NzE4RTEzMzBGMDI5NEUyM0I2MkE6VVNFUzpOUlNlY3RvckNhcnJpZXI6MjgwREMzODg2OENFRTNFRDRBNkJBOTE0OUFCRTdBNkM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjI4MERDMzg4NjhDRUUzRUQ0QTZCQTkxNDlBQkU3QTZDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NTgzNUY3N0JFOUQ0RTEwMjMxNkJENTkxOTVGNjM3MEI=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MjgwREMzODg2OENFRTNFRDRBNkJBOTE0OUFCRTdBNkM=	98C3A4591A37718E1330F0294E23B62A	5835F77BE9D4E102316BD59195F6370B	D3215E08570BE58339C7463626B50E37
+5C5B83AAB9E669D3138091E9AAC19405	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=2	1000	20	2	20	20	urn:base64:TlJDZWxsRFU6Rjk1NDZFODIzMTNBQzFENUU2OTBEQ0Q3QkU1NTYwNkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6NUM1QjgzQUFCOUU2NjlEMzEzODA5MUU5QUFDMTk0MDU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjVDNUI4M0FBQjlFNjY5RDMxMzgwOTFFOUFBQzE5NDA1OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MDRGMzlFQkFCNzI0NTRFNEQzMzMxRDZDMzM2N0I0NUY=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NUM1QjgzQUFCOUU2NjlEMzEzODA5MUU5QUFDMTk0MDU=	F9546E82313AC1D5E690DCD7BE55606F	04F39EBAB72454E4D3331D6C3367B45F	D3215E08570BE58339C7463626B50E37
+E49D942C16E0364E1E0788138916D70C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=3	1000	20	3	20	20	urn:base64:TlJDZWxsRFU6QjQ4MDQyN0U4QTBDMEI4RDk5NEU0Mzc3ODRCQjM4MkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkU0OUQ5NDJDMTZFMDM2NEUxRTA3ODgxMzg5MTZENzBDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QTc3QjIzN0E1NDFCMkQzMjI1QjRCNjFEMzA5OEU0QUE=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM=	B480427E8A0C0B8D994E437784BB382F	A77B237A541B2D3225B4B61D3098E4AA	D3215E08570BE58339C7463626B50E37
+2A6FF9967B960E0238CD1C402A352ADF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=4	1000	20	4	20	20	urn:base64:TlJDZWxsRFU6NDg0QjM0MTMxMEEzNjIxNTE1NTEyMkRFNzRFQUUxNkE6VVNFUzpOUlNlY3RvckNhcnJpZXI6MkE2RkY5OTY3Qjk2MEUwMjM4Q0QxQzQwMkEzNTJBREY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjJBNkZGOTk2N0I5NjBFMDIzOENEMUM0MDJBMzUyQURGOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzMwOTgxQTQ4OUE0NUJFNEJGNzA2NjdGQzY2OTkyQ0Y=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MkE2RkY5OTY3Qjk2MEUwMjM4Q0QxQzQwMkEzNTJBREY=	484B341310A36215155122DE74EAE16A	C30981A489A45BE4BF70667FC66992CF	D3215E08570BE58339C7463626B50E37
+7E0CE0F2BA06341920140FB7DF29CF6A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=5	1000	20	5	20	20	urn:base64:TlJDZWxsRFU6Mzc3QUE5NkI0QjNBOEZFMTA2QzlCQUY2M0ZFODQ2MEI6VVNFUzpOUlNlY3RvckNhcnJpZXI6N0UwQ0UwRjJCQTA2MzQxOTIwMTQwRkI3REYyOUNGNkE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjdFMENFMEYyQkEwNjM0MTkyMDE0MEZCN0RGMjlDRjZBOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NEE4NTBGOTlFQkEwOTM1QjdDREU2RUY0NDZDMDQ5OUM=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6N0UwQ0UwRjJCQTA2MzQxOTIwMTQwRkI3REYyOUNGNkE=	377AA96B4B3A8FE106C9BAF63FE8460B	4A850F99EBA0935B7CDE6EF446C0499C	D3215E08570BE58339C7463626B50E37
+B4EDE862A525DCA5BC9ED5B22CC3721B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=6	1000	20	6	20	20	urn:base64:TlJDZWxsRFU6M0FGMjIwOEE1OTU2RjA3NjQ0RDhGM0VEN0M2MkJEQ0Y6VVNFUzpOUlNlY3RvckNhcnJpZXI6QjRFREU4NjJBNTI1RENBNUJDOUVENUIyMkNDMzcyMUI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkI0RURFODYyQTUyNURDQTVCQzlFRDVCMjJDQzM3MjFCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzgzRTA4QTUzNDM4RUY5Njc4RDUxNUU3M0RCNjY3Rjc=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QjRFREU4NjJBNTI1RENBNUJDOUVENUIyMkNDMzcyMUI=	3AF2208A5956F07644D8F3ED7C62BDCF	C83E08A53438EF9678D515E73DB667F7	D3215E08570BE58339C7463626B50E37
+D89136FB5F8E6E485B94C21660C259A8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=7	1000	20	7	20	20	urn:base64:TlJDZWxsRFU6NDRBQkFFRTJBNzdBNUZDMkM4MTIxQjk1RkZBNTYyNkQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6RDg5MTM2RkI1RjhFNkU0ODVCOTRDMjE2NjBDMjU5QTg=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkQ4OTEzNkZCNUY4RTZFNDg1Qjk0QzIxNjYwQzI1OUE4OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NUUxQzYzQTNGMzJBODYyNUE1RjI4MjcyN0QzNkIwQzg=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RDg5MTM2RkI1RjhFNkU0ODVCOTRDMjE2NjBDMjU5QTg=	44ABAEE2A77A5FC2C8121B95FFA5626D	5E1C63A3F32A8625A5F282727D36B0C8	D3215E08570BE58339C7463626B50E37
+3F31CBFD6B09D4DA17907FEB840F4AE4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=8	1000	20	8	20	20	urn:base64:TlJDZWxsRFU6NEU0MEI0Q0I1MThEN0Y2QzRCMDI4OEE5MERCODEzNDc6VVNFUzpOUlNlY3RvckNhcnJpZXI6M0YzMUNCRkQ2QjA5RDREQTE3OTA3RkVCODQwRjRBRTQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjNGMzFDQkZENkIwOUQ0REExNzkwN0ZFQjg0MEY0QUU0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MUIzMzhGNDc4MDg3RjkzQzkxRTAyODdDQzg3Q0RDNTY=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6M0YzMUNCRkQ2QjA5RDREQTE3OTA3RkVCODQwRjRBRTQ=	4E40B4CB518D7F6C4B0288A90DB81347	1B338F478087F93C91E0287CC87CDC56	D3215E08570BE58339C7463626B50E37
+0D8E5CF2A936251A352A26590109C2C7	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=9	1000	20	9	20	20	urn:base64:TlJDZWxsRFU6Q0Y3MjlBMEJCQzM5RTUwNzdDQjU2NzQyMDZBNjczNTk6VVNFUzpOUlNlY3RvckNhcnJpZXI6MEQ4RTVDRjJBOTM2MjUxQTM1MkEyNjU5MDEwOUMyQzc=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjBEOEU1Q0YyQTkzNjI1MUEzNTJBMjY1OTAxMDlDMkM3OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NTk5MzEzQ0REMzVGNDk4RUU4OTlDRjUxQzlBMDlCRjU=	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MEQ4RTVDRjJBOTM2MjUxQTM1MkEyNjU5MDEwOUMyQzc=	CF729A0BBC39E5077CB5674206A67359	599313CDD35F498EE899CF51C9A09BF5	D3215E08570BE58339C7463626B50E37
+EFD2B059FAA79B1CFAA94D5A06AC952D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=10	1000	20	10	20	20	urn:base64:TlJDZWxsRFU6RkI3QTkyRUQ0OTVGRTVCMDhFQTFFMzIzNTNGNjc2MDg6VVNFUzpOUlNlY3RvckNhcnJpZXI6RUZEMkIwNTlGQUE3OUIxQ0ZBQTk0RDVBMDZBQzk1MkQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkVGRDJCMDU5RkFBNzlCMUNGQUE5NEQ1QTA2QUM5NTJEOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QjA0RTIyMzMzN0YyNzVDMEJGNTlCNDU5QTA2RUU2QzM=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RUZEMkIwNTlGQUE3OUIxQ0ZBQTk0RDVBMDZBQzk1MkQ=	FB7A92ED495FE5B08EA1E32353F67608	B04E223337F275C0BF59B459A06EE6C3	1050570EBB1315E1AE7A9FD5E1400A00
+C9FB21B897B6308924C000940A6B6256	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=11	1000	20	11	20	20	urn:base64:TlJDZWxsRFU6RTgwNjU2NDQ3MTdFRDE1RjM1MDRCNUVFNzFCQjA4OTQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6QzlGQjIxQjg5N0I2MzA4OTI0QzAwMDk0MEE2QjYyNTY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkM5RkIyMUI4OTdCNjMwODkyNEMwMDA5NDBBNkI2MjU2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MkQ3MUY2Q0RDQzVERkQxRDcxMkQ5QUIwMUJBQTQ3MDY=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QzlGQjIxQjg5N0I2MzA4OTI0QzAwMDk0MEE2QjYyNTY=	E8065644717ED15F3504B5EE71BB0894	2D71F6CDCC5DFD1D712D9AB01BAA4706	1050570EBB1315E1AE7A9FD5E1400A00
+95970B1B7C1EF775A24D900B84653AD1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=12	1000	20	12	20	20	urn:base64:TlJDZWxsRFU6NDQ2M0MzRDJGN0IzODgzMjNBODIxMDVFODU0QUVBMUM6VVNFUzpOUlNlY3RvckNhcnJpZXI6OTU5NzBCMUI3QzFFRjc3NUEyNEQ5MDBCODQ2NTNBRDE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjk1OTcwQjFCN0MxRUY3NzVBMjREOTAwQjg0NjUzQUQxOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RDc0MTcyMzU4QUQ0QkE0MThFMjQyM0EzRDU0MTUxRUQ=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OTU5NzBCMUI3QzFFRjc3NUEyNEQ5MDBCODQ2NTNBRDE=	4463C3D2F7B388323A82105E854AEA1C	D74172358AD4BA418E2423A3D54151ED	1050570EBB1315E1AE7A9FD5E1400A00
+B77E2DCF02094E0D4F400FFB1F915CA6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=13	1000	20	13	20	20	urn:base64:TlJDZWxsRFU6ODk3QzU2MkE1RDhFRTIyNzQ2QUM0RDQ4MDQ1MDVCNjk6VVNFUzpOUlNlY3RvckNhcnJpZXI6Qjc3RTJEQ0YwMjA5NEUwRDRGNDAwRkZCMUY5MTVDQTY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkI3N0UyRENGMDIwOTRFMEQ0RjQwMEZGQjFGOTE1Q0E2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MTE0QkQ3QkQ0NkQyRUE2QkY4NTEyNTEyODdGMkNGOTU=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6Qjc3RTJEQ0YwMjA5NEUwRDRGNDAwRkZCMUY5MTVDQTY=	897C562A5D8EE22746AC4D4804505B69	114BD7BD46D2EA6BF851251287F2CF95	1050570EBB1315E1AE7A9FD5E1400A00
+82D362D75CFF3D3222298BC197EBBECD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=14	1000	20	14	20	20	urn:base64:TlJDZWxsRFU6ODRFNzE1NURBRDY3OTNBNUVCRkZFNzI0NDlGNzc0OUI6VVNFUzpOUlNlY3RvckNhcnJpZXI6ODJEMzYyRDc1Q0ZGM0QzMjIyMjk4QkMxOTdFQkJFQ0Q=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjgyRDM2MkQ3NUNGRjNEMzIyMjI5OEJDMTk3RUJCRUNEOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QjAwNjk5QjVFQTMzQzg2N0VFRTdFMDQ0RUU4NDREMzQ=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6ODJEMzYyRDc1Q0ZGM0QzMjIyMjk4QkMxOTdFQkJFQ0Q=	84E7155DAD6793A5EBFFE72449F7749B	B00699B5EA33C867EEE7E044EE844D34	1050570EBB1315E1AE7A9FD5E1400A00
+529F6B2AC76DE9E8775BAEBA97890201	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=15	1000	20	15	20	20	urn:base64:TlJDZWxsRFU6MDY0NkE0MUEzMDE1MUI1OUJDMUQ5MTA3M0MxNjIyNTc6VVNFUzpOUlNlY3RvckNhcnJpZXI6NTI5RjZCMkFDNzZERTlFODc3NUJBRUJBOTc4OTAyMDE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjUyOUY2QjJBQzc2REU5RTg3NzVCQUVCQTk3ODkwMjAxOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QTUzN0Q3QTlFRkRFRTBDNDdCM0ZCNENGM0IxRjA2QTc=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NTI5RjZCMkFDNzZERTlFODc3NUJBRUJBOTc4OTAyMDE=	0646A41A30151B59BC1D91073C162257	A537D7A9EFDEE0C47B3FB4CF3B1F06A7	1050570EBB1315E1AE7A9FD5E1400A00
+62B1A8C49EC219C2F0F3D56F495EC4CC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=16	1000	20	16	20	20	urn:base64:TlJDZWxsRFU6NDU2MjdENjM2RDdBNDUzNTdGNkYyMzY2MUJBNzdDODU6VVNFUzpOUlNlY3RvckNhcnJpZXI6NjJCMUE4QzQ5RUMyMTlDMkYwRjNENTZGNDk1RUM0Q0M=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjYyQjFBOEM0OUVDMjE5QzJGMEYzRDU2RjQ5NUVDNENDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RTFDM0U5NTk0NDk0MkY0QUQxODMxNzE5MjAzQTE2NzI=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NjJCMUE4QzQ5RUMyMTlDMkYwRjNENTZGNDk1RUM0Q0M=	45627D636D7A45357F6F23661BA77C85	E1C3E95944942F4AD1831719203A1672	1050570EBB1315E1AE7A9FD5E1400A00
+DC88BC70E9A8DC86D8315C794215E2AD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=17	1000	20	17	20	20	urn:base64:TlJDZWxsRFU6RDIxQ0RGNzA0NzYwRUU2NkNDNjdBQzhDNTU4NUM0RkM6VVNFUzpOUlNlY3RvckNhcnJpZXI6REM4OEJDNzBFOUE4REM4NkQ4MzE1Qzc5NDIxNUUyQUQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkRDODhCQzcwRTlBOERDODZEODMxNUM3OTQyMTVFMkFEOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6OTI1MkUzQ0NBODhBRTU1OUJDQjFDODM4RkZEQTFDMjc=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6REM4OEJDNzBFOUE4REM4NkQ4MzE1Qzc5NDIxNUUyQUQ=	D21CDF704760EE66CC67AC8C5585C4FC	9252E3CCA88AE559BCB1C838FFDA1C27	1050570EBB1315E1AE7A9FD5E1400A00
+5BDCDFC664C467684309134FD386F182	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=18	1000	20	18	20	20	urn:base64:TlJDZWxsRFU6ODIxOUNBOEM0NjQxMzc2QjA2RkU0MDY3RkVFOENEQjQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6NUJEQ0RGQzY2NEM0Njc2ODQzMDkxMzRGRDM4NkYxODI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjVCRENERkM2NjRDNDY3Njg0MzA5MTM0RkQzODZGMTgyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RjI4M0YxOUY0RjA4NDJFNzI0QkE3MkU5NzE4RUE1Q0I=	urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NUJEQ0RGQzY2NEM0Njc2ODQzMDkxMzRGRDM4NkYxODI=	8219CA8C4641376B06FE4067FEE8CDB4	F283F19F4F0842E724BA72E9718EA5CB	1050570EBB1315E1AE7A9FD5E1400A00
+969DF432ED7F9A9E6607D475D11E6863	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=19	1000	20	19	20	20	urn:base64:TlJDZWxsRFU6NUIzQ0M4MUIzMjg0RDNGNjY1RjAzQTQ3NzQzOUZBOTg6VVNFUzpOUlNlY3RvckNhcnJpZXI6OTY5REY0MzJFRDdGOUE5RTY2MDdENDc1RDExRTY4NjM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjk2OURGNDMyRUQ3RjlBOUU2NjA3RDQ3NUQxMUU2ODYzOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6Qjc0Qjg5Mjk1NEU5NzExMkRENEI0RTVBRjlEM0E0Rjc=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OTY5REY0MzJFRDdGOUE5RTY2MDdENDc1RDExRTY4NjM=	5B3CC81B3284D3F665F03A477439FA98	B74B892954E97112DD4B4E5AF9D3A4F7	B6A6DE7D0965F02D48ECA86706A4454F
+8242C20440EEE441ABA2DE3F143845DE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=20	1000	20	20	20	20	urn:base64:TlJDZWxsRFU6QzE5NDRBMjYyMDgxRjgyQTk4Q0YwNTBGRUU0MUI4RkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6ODI0MkMyMDQ0MEVFRTQ0MUFCQTJERTNGMTQzODQ1REU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjgyNDJDMjA0NDBFRUU0NDFBQkEyREUzRjE0Mzg0NURFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6ODdDQzRFN0Y3NDI5MkZFODUzNDBGMjgwQTMyRUVCMkQ=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6ODI0MkMyMDQ0MEVFRTQ0MUFCQTJERTNGMTQzODQ1REU=	C1944A262081F82A98CF050FEE41B8FF	87CC4E7F74292FE85340F280A32EEB2D	B6A6DE7D0965F02D48ECA86706A4454F
+725257083C17CB17DF38C4961FC55C54	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=21	1000	20	21	20	20	urn:base64:TlJDZWxsRFU6NEJBNzk5QzMzQ0RBQTJDOUYzODYwNjA2MzFFMkZEMkE6VVNFUzpOUlNlY3RvckNhcnJpZXI6NzI1MjU3MDgzQzE3Q0IxN0RGMzhDNDk2MUZDNTVDNTQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjcyNTI1NzA4M0MxN0NCMTdERjM4QzQ5NjFGQzU1QzU0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MDQyNzNGQzY0NDM2REE1MjM4NjVDRjg0OUU1RjdDQzk=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NzI1MjU3MDgzQzE3Q0IxN0RGMzhDNDk2MUZDNTVDNTQ=	4BA799C33CDAA2C9F386060631E2FD2A	04273FC64436DA523865CF849E5F7CC9	B6A6DE7D0965F02D48ECA86706A4454F
+92000BD14FF2FCAABF9F4565B22488A5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=22	1000	20	22	20	20	urn:base64:TlJDZWxsRFU6RjczQUFDRjJCQTQzMkI2ODdERkQ2MkM0N0M5REZGMUE6VVNFUzpOUlNlY3RvckNhcnJpZXI6OTIwMDBCRDE0RkYyRkNBQUJGOUY0NTY1QjIyNDg4QTU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjkyMDAwQkQxNEZGMkZDQUFCRjlGNDU2NUIyMjQ4OEE1OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RDVCOTA5MEUzQjZBMTBEQkRDMjQzRUQxNEVGMjk0QkY=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OTIwMDBCRDE0RkYyRkNBQUJGOUY0NTY1QjIyNDg4QTU=	F73AACF2BA432B687DFD62C47C9DFF1A	D5B9090E3B6A10DBDC243ED14EF294BF	B6A6DE7D0965F02D48ECA86706A4454F
+3A79CB3F5B4CCD179A08DC196CC2FC91	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=23	1000	20	23	20	20	urn:base64:TlJDZWxsRFU6NTFENDk5MjJDQTZDQ0QyQ0U0NTFEOTZCQTIyNDAxMUY6VVNFUzpOUlNlY3RvckNhcnJpZXI6M0E3OUNCM0Y1QjRDQ0QxNzlBMDhEQzE5NkNDMkZDOTE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjNBNzlDQjNGNUI0Q0NEMTc5QTA4REMxOTZDQzJGQzkxOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MDI0NDNERTA4MDdEODAxRDY2MTQ5NUQ5RUZCOEQ4MzY=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6M0E3OUNCM0Y1QjRDQ0QxNzlBMDhEQzE5NkNDMkZDOTE=	51D49922CA6CCD2CE451D96BA224011F	02443DE0807D801D661495D9EFB8D836	B6A6DE7D0965F02D48ECA86706A4454F
+0BFA280C5BA850500084E30B612A3753	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=24	1000	20	24	20	20	urn:base64:TlJDZWxsRFU6RDA0MkRFMkQzOEY4RkZFNzBENzM4NzAyMDIxNUIyNTQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6MEJGQTI4MEM1QkE4NTA1MDAwODRFMzBCNjEyQTM3NTM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjBCRkEyODBDNUJBODUwNTAwMDg0RTMwQjYxMkEzNzUzOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzY4MjNEMkI3QUZBMDY0Q0U3NzQ3OTVFMDFENjIyOEI=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MEJGQTI4MEM1QkE4NTA1MDAwODRFMzBCNjEyQTM3NTM=	D042DE2D38F8FFE70D7387020215B254	C6823D2B7AFA064CE774795E01D6228B	B6A6DE7D0965F02D48ECA86706A4454F
+04186460C606475B2535287BC9CD5EDA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=25	1000	20	25	20	20	urn:base64:TlJDZWxsRFU6MTVFOTFDMzNCQTk5MzU0RURGMEE2NjdCNUNBRjgxQTU6VVNFUzpOUlNlY3RvckNhcnJpZXI6MDQxODY0NjBDNjA2NDc1QjI1MzUyODdCQzlDRDVFREE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjA0MTg2NDYwQzYwNjQ3NUIyNTM1Mjg3QkM5Q0Q1RURBOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6REYyNkFFNDQyMTEwREIwMjgxREFENDU0NTQzNkI3MjA=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MDQxODY0NjBDNjA2NDc1QjI1MzUyODdCQzlDRDVFREE=	15E91C33BA99354EDF0A667B5CAF81A5	DF26AE442110DB0281DAD4545436B720	B6A6DE7D0965F02D48ECA86706A4454F
+640837A9312B9168202E457BDA67E3AB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=26	1000	20	26	20	20	urn:base64:TlJDZWxsRFU6OUVEMDEwQjI5QkQ5NzM3OUI0NzM5QjZDMEYzMTg4NzQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6NjQwODM3QTkzMTJCOTE2ODIwMkU0NTdCREE2N0UzQUI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjY0MDgzN0E5MzEyQjkxNjgyMDJFNDU3QkRBNjdFM0FCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6N0ExQzZGRTkzNTEwMDhCM0Q1MzkxNjZEOTQyMjI3NjI=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NjQwODM3QTkzMTJCOTE2ODIwMkU0NTdCREE2N0UzQUI=	9ED010B29BD97379B4739B6C0F318874	7A1C6FE9351008B3D539166D94222762	B6A6DE7D0965F02D48ECA86706A4454F
+CC7F67B0939882240419A867FB75BD5B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=27	1000	20	27	20	20	urn:base64:TlJDZWxsRFU6NEQwRjVDQzM2MUYyMTg3REZCQTRFMjQzRjQ4OUVDMEU6VVNFUzpOUlNlY3RvckNhcnJpZXI6Q0M3RjY3QjA5Mzk4ODIyNDA0MTlBODY3RkI3NUJENUI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkNDN0Y2N0IwOTM5ODgyMjQwNDE5QTg2N0ZCNzVCRDVCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NzBBMUYxMjlFMTBFRTdEMzFERkUxRTFBQTZDNzQzN0Q=	urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6Q0M3RjY3QjA5Mzk4ODIyNDA0MTlBODY3RkI3NUJENUI=	4D0F5CC361F2187DFBA4E243F489EC0E	70A1F129E10EE7D31DFE1E1AA6C7437D	B6A6DE7D0965F02D48ECA86706A4454F
+9C1FC1BA3A08D95288448538CABB2FED	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=28	1000	20	28	20	20	urn:base64:TlJDZWxsRFU6MzZDMjUxRkIyM0E1NzBBNjdDNDk5RDI4Rjg3REE5NEY6VVNFUzpOUlNlY3RvckNhcnJpZXI6OUMxRkMxQkEzQTA4RDk1Mjg4NDQ4NTM4Q0FCQjJGRUQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjlDMUZDMUJBM0EwOEQ5NTI4ODQ0ODUzOENBQkIyRkVEOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6N0RFOTFDNzhGOERDRTQyOTJGMkYwQzNCMzRERUFDQUI=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OUMxRkMxQkEzQTA4RDk1Mjg4NDQ4NTM4Q0FCQjJGRUQ=	36C251FB23A570A67C499D28F87DA94F	7DE91C78F8DCE4292F2F0C3B34DEACAB	E5FD5ACD55C553A92738477ECB0465B9
+1636D2C97404CC1951A26B242280992E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=29	1000	20	29	20	20	urn:base64:TlJDZWxsRFU6RUM3ODZBNzIxQTA2NEZBMjZCRTQwQkUxNzNGQjkyRTE6VVNFUzpOUlNlY3RvckNhcnJpZXI6MTYzNkQyQzk3NDA0Q0MxOTUxQTI2QjI0MjI4MDk5MkU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjE2MzZEMkM5NzQwNENDMTk1MUEyNkIyNDIyODA5OTJFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MTQ1QTFCRjU2MURCMjk3RjI1RkQzRjEyNDE3RDJBNTA=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MTYzNkQyQzk3NDA0Q0MxOTUxQTI2QjI0MjI4MDk5MkU=	EC786A721A064FA26BE40BE173FB92E1	145A1BF561DB297F25FD3F12417D2A50	E5FD5ACD55C553A92738477ECB0465B9
+E2BE0197590AA8391179A2A78F8B7B3E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=30	1000	20	30	20	20	urn:base64:TlJDZWxsRFU6Q0M2RUQ2REZENDJBRUJERThBMUY4MDVEMzA3NjIyQTk6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTJCRTAxOTc1OTBBQTgzOTExNzlBMkE3OEY4QjdCM0U=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkUyQkUwMTk3NTkwQUE4MzkxMTc5QTJBNzhGOEI3QjNFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6OTE4OEQ5NzVEODM3QTFFMDM5NzE2N0EyM0U3MjFCMEM=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RTJCRTAxOTc1OTBBQTgzOTExNzlBMkE3OEY4QjdCM0U=	CC6ED6DFD42AEBDE8A1F805D307622A9	9188D975D837A1E0397167A23E721B0C	E5FD5ACD55C553A92738477ECB0465B9
+8BB9FC8DC8AF2821CF0AFF8E31520862	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=31	1000	20	31	20	20	urn:base64:TlJDZWxsRFU6QzM1RjRBNDZFREU5NUQxQkM1NzkxOUMxQUJBMEExNTA6VVNFUzpOUlNlY3RvckNhcnJpZXI6OEJCOUZDOERDOEFGMjgyMUNGMEFGRjhFMzE1MjA4NjI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjhCQjlGQzhEQzhBRjI4MjFDRjBBRkY4RTMxNTIwODYyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RDMxNERBREFGQTNEODk2NDQ1RTc4RUJDQzE1QTE2Rjc=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OEJCOUZDOERDOEFGMjgyMUNGMEFGRjhFMzE1MjA4NjI=	C35F4A46EDE95D1BC57919C1ABA0A150	D314DADAFA3D896445E78EBCC15A16F7	E5FD5ACD55C553A92738477ECB0465B9
+C0FE68D810F57154B913E056BC1B4305	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=32	1000	20	32	20	20	urn:base64:TlJDZWxsRFU6QkM2MjQwNDM5MkQ5NjhBRUVBRkEyOTBCNkUwMjk1OTY6VVNFUzpOUlNlY3RvckNhcnJpZXI6QzBGRTY4RDgxMEY1NzE1NEI5MTNFMDU2QkMxQjQzMDU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkMwRkU2OEQ4MTBGNTcxNTRCOTEzRTA1NkJDMUI0MzA1OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MjhBRDNFRTg0NDc2NkRGNTA4RjYyODdDRDFDRTE4QTQ=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QzBGRTY4RDgxMEY1NzE1NEI5MTNFMDU2QkMxQjQzMDU=	BC62404392D968AEEAFA290B6E029596	28AD3EE844766DF508F6287CD1CE18A4	E5FD5ACD55C553A92738477ECB0465B9
+2548E12457EDEFCD4119460CFD302977	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=33	1000	20	33	20	20	urn:base64:TlJDZWxsRFU6NTQ5QUU5NEE1RThCNzRDRDc0NUFFRjU2NDhCOEM1MjQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6MjU0OEUxMjQ1N0VERUZDRDQxMTk0NjBDRkQzMDI5Nzc=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjI1NDhFMTI0NTdFREVGQ0Q0MTE5NDYwQ0ZEMzAyOTc3OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzM5OEQ2QzY3MzI2N0EwODFDNzgxRDg0NDM4RjRCNzQ=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MjU0OEUxMjQ1N0VERUZDRDQxMTk0NjBDRkQzMDI5Nzc=	549AE94A5E8B74CD745AEF5648B8C524	C398D6C673267A081C781D84438F4B74	E5FD5ACD55C553A92738477ECB0465B9
+6DF1BB3C1B04A2AFF8FCFAE6B9E6C059	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=34	1000	20	34	20	20	urn:base64:TlJDZWxsRFU6MTQ4RUI5MkQ4ODAyRTk1M0ZGMjZDRkQxNzRCNkQ4MDQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6NkRGMUJCM0MxQjA0QTJBRkY4RkNGQUU2QjlFNkMwNTk=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjZERjFCQjNDMUIwNEEyQUZGOEZDRkFFNkI5RTZDMDU5OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MEJEQUQ1RERDMTlBNjk2MjQ0NTM2NDIxRTZEMjZGRTM=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NkRGMUJCM0MxQjA0QTJBRkY4RkNGQUU2QjlFNkMwNTk=	148EB92D8802E953FF26CFD174B6D804	0BDAD5DDC19A696244536421E6D26FE3	E5FD5ACD55C553A92738477ECB0465B9
+49C7F3D0A74534A1DD284353BA721340	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=35	1000	20	35	20	20	urn:base64:TlJDZWxsRFU6NEIxRUU3M0VCRDQ2ODAxNTgyQjJGRkE1MjEzMDUyNEY6VVNFUzpOUlNlY3RvckNhcnJpZXI6NDlDN0YzRDBBNzQ1MzRBMUREMjg0MzUzQkE3MjEzNDA=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjQ5QzdGM0QwQTc0NTM0QTFERDI4NDM1M0JBNzIxMzQwOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NDkyMDU4ODFDOTEyMUYyMDhCRDc5MTQ5RkE3OTk4Nzc=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NDlDN0YzRDBBNzQ1MzRBMUREMjg0MzUzQkE3MjEzNDA=	4B1EE73EBD46801582B2FFA52130524F	49205881C9121F208BD79149FA799877	E5FD5ACD55C553A92738477ECB0465B9
+AA66002C42C823375606A6793855D3FC	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=36	1000	20	36	20	20	urn:base64:TlJDZWxsRFU6NzQ2N0NFRjJBQzA4MDhGMzU5NTQ0NEM3RDMxQTE3MTA6VVNFUzpOUlNlY3RvckNhcnJpZXI6QUE2NjAwMkM0MkM4MjMzNzU2MDZBNjc5Mzg1NUQzRkM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkFBNjYwMDJDNDJDODIzMzc1NjA2QTY3OTM4NTVEM0ZDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QTMyREI5RTI3OEZDMURFNDFGQjRBM0I1MEY4MDI2NTA=	urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QUE2NjAwMkM0MkM4MjMzNzU2MDZBNjc5Mzg1NUQzRkM=	7467CEF2AC0808F3595444C7D31A1710	A32DB9E278FC1DE41FB4A3B50F802650	E5FD5ACD55C553A92738477ECB0465B9
+1C8C22D9065F1139C7CCA45EEF8C61EF	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=37	1000	20	37	20	20	urn:base64:TlJDZWxsRFU6NDlDODY4MzA1OUYzOEY3QjY4MUZGMjczMDU4NUY5QTY6VVNFUzpOUlNlY3RvckNhcnJpZXI6MUM4QzIyRDkwNjVGMTEzOUM3Q0NBNDVFRUY4QzYxRUY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjFDOEMyMkQ5MDY1RjExMzlDN0NDQTQ1RUVGOEM2MUVGOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QkRFMzgxQkFDQzY3MjkwRTQ0N0JDMDE3N0UwMzhBRUI=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MUM4QzIyRDkwNjVGMTEzOUM3Q0NBNDVFRUY4QzYxRUY=	49C8683059F38F7B681FF2730585F9A6	BDE381BACC67290E447BC0177E038AEB	25E690E22BDA90B9C4FEE1F083CBA597
+D266E324A64EC29530E026DD07A50720	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=38	1000	20	38	20	20	urn:base64:TlJDZWxsRFU6RDNBMEZEREMyMkUxMjlDMkVCN0IwQTVFNzgwOENCN0U6VVNFUzpOUlNlY3RvckNhcnJpZXI6RDI2NkUzMjRBNjRFQzI5NTMwRTAyNkREMDdBNTA3MjA=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkQyNjZFMzI0QTY0RUMyOTUzMEUwMjZERDA3QTUwNzIwOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QjRCQzREMUIxM0VCNjUxNjkwRjMxOTVFNjIyQ0M0QkQ=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RDI2NkUzMjRBNjRFQzI5NTMwRTAyNkREMDdBNTA3MjA=	D3A0FDDC22E129C2EB7B0A5E7808CB7E	B4BC4D1B13EB651690F3195E622CC4BD	25E690E22BDA90B9C4FEE1F083CBA597
+875DAAED20D2AC563357371DFFCDC86D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=39	1000	20	39	20	20	urn:base64:TlJDZWxsRFU6RUFERkQyRkYzQjI0QkJBMTUxMDNGMzEyNkM0RTI5NUQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6ODc1REFBRUQyMEQyQUM1NjMzNTczNzFERkZDREM4NkQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjg3NURBQUVEMjBEMkFDNTYzMzU3MzcxREZGQ0RDODZEOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MzJFRTM4NUVBQ0QyNkEwMDQ2QkFENUNDODQ5MDVFQ0I=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6ODc1REFBRUQyMEQyQUM1NjMzNTczNzFERkZDREM4NkQ=	EADFD2FF3B24BBA15103F3126C4E295D	32EE385EACD26A0046BAD5CC84905ECB	25E690E22BDA90B9C4FEE1F083CBA597
+E073BB0603BCA819D7537384AB62B902	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=40	1000	20	40	20	20	urn:base64:TlJDZWxsRFU6NzJENDI3RjVBRkU3RTBBQjY1OTEyOEI0MjMxMzE5QjQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTA3M0JCMDYwM0JDQTgxOUQ3NTM3Mzg0QUI2MkI5MDI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkUwNzNCQjA2MDNCQ0E4MTlENzUzNzM4NEFCNjJCOTAyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NDNCNjMxMDZCMjdGQjA1QzYxODQwMEVFNUFFOTE2Mzc=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RTA3M0JCMDYwM0JDQTgxOUQ3NTM3Mzg0QUI2MkI5MDI=	72D427F5AFE7E0AB659128B4231319B4	43B63106B27FB05C618400EE5AE91637	25E690E22BDA90B9C4FEE1F083CBA597
+F0C1F478850C438AE4A55B916706D319	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=41	1000	20	41	20	20	urn:base64:TlJDZWxsRFU6REUzNDlBMjhGRkI4QkVDQzM5NTc5NzcyNzM1NjIxMzA6VVNFUzpOUlNlY3RvckNhcnJpZXI6RjBDMUY0Nzg4NTBDNDM4QUU0QTU1QjkxNjcwNkQzMTk=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkYwQzFGNDc4ODUwQzQzOEFFNEE1NUI5MTY3MDZEMzE5OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzgxM0UxODY1N0MyQzU4MzdBM0YyMzdCQUQ1NTc5NDQ=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RjBDMUY0Nzg4NTBDNDM4QUU0QTU1QjkxNjcwNkQzMTk=	DE349A28FFB8BECC3957977273562130	C813E18657C2C5837A3F237BAD557944	25E690E22BDA90B9C4FEE1F083CBA597
+6459BBB9E31E42DD1BA64F183EE6D4D1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=42	1000	20	42	20	20	urn:base64:TlJDZWxsRFU6OUE4NTU1OUZEMTBERTE5RTM5QTgzMDM5QzBBRjEyQ0Q6VVNFUzpOUlNlY3RvckNhcnJpZXI6NjQ1OUJCQjlFMzFFNDJERDFCQTY0RjE4M0VFNkQ0RDE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjY0NTlCQkI5RTMxRTQyREQxQkE2NEYxODNFRTZENEQxOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NDYyRENDREVBNUEyODkyQjhDODYzMDcyNDY3OUI2NzY=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NjQ1OUJCQjlFMzFFNDJERDFCQTY0RjE4M0VFNkQ0RDE=	9A85559FD10DE19E39A83039C0AF12CD	462DCCDEA5A2892B8C8630724679B676	25E690E22BDA90B9C4FEE1F083CBA597
+B0A6F73C534723853CBDF21B0CFA2642	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=43	1000	20	43	20	20	urn:base64:TlJDZWxsRFU6NDc2NjgxNDM3RDY4MEQ5MENGM0I3OEU3MTE0RjdGMjE6VVNFUzpOUlNlY3RvckNhcnJpZXI6QjBBNkY3M0M1MzQ3MjM4NTNDQkRGMjFCMENGQTI2NDI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkIwQTZGNzNDNTM0NzIzODUzQ0JERjIxQjBDRkEyNjQyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RjZEMEZGMjA2OUYwMzhGRjY0RDA3MkM4MThERDlCRkQ=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QjBBNkY3M0M1MzQ3MjM4NTNDQkRGMjFCMENGQTI2NDI=	476681437D680D90CF3B78E7114F7F21	F6D0FF2069F038FF64D072C818DD9BFD	25E690E22BDA90B9C4FEE1F083CBA597
+BCC9DC05304B61096FEDEB9C0FCDBF32	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=44	1000	20	44	20	20	urn:base64:TlJDZWxsRFU6MUVGMzU2RTIzQTAwNjlENkE5N0FEODlFMEQ2QzA1Rjk6VVNFUzpOUlNlY3RvckNhcnJpZXI6QkNDOURDMDUzMDRCNjEwOTZGRURFQjlDMEZDREJGMzI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkJDQzlEQzA1MzA0QjYxMDk2RkVERUI5QzBGQ0RCRjMyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzVDNTk4NTExQzc1MTQwNjFFODZEQTI0RjhEQjM1OUQ=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QkNDOURDMDUzMDRCNjEwOTZGRURFQjlDMEZDREJGMzI=	1EF356E23A0069D6A97AD89E0D6C05F9	C5C598511C7514061E86DA24F8DB359D	25E690E22BDA90B9C4FEE1F083CBA597
+85207C734C32180D07026CD931FDB7F6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=45	1000	20	45	20	20	urn:base64:TlJDZWxsRFU6NjA3ODZERDVCODlGNDA1Q0EzRjg0M0U1REQyRUFDQTY6VVNFUzpOUlNlY3RvckNhcnJpZXI6ODUyMDdDNzM0QzMyMTgwRDA3MDI2Q0Q5MzFGREI3RjY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjg1MjA3QzczNEMzMjE4MEQwNzAyNkNEOTMxRkRCN0Y2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MTM4NzZGRUNFRURGNDVBRTREQ0E4QzM5M0U0NzgyMzc=	urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6ODUyMDdDNzM0QzMyMTgwRDA3MDI2Q0Q5MzFGREI3RjY=	60786DD5B89F405CA3F843E5DD2EACA6	13876FECEEDF45AE4DCA8C393E478237	25E690E22BDA90B9C4FEE1F083CBA597
+038A46775C277265E4EACF0E7790F7B4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=46	1000	20	46	20	20	urn:base64:TlJDZWxsRFU6RjBGNEU3MzM1RTE1NTQwRjI3ODQ2NjVEMUE0OUFBNkI6VVNFUzpOUlNlY3RvckNhcnJpZXI6MDM4QTQ2Nzc1QzI3NzI2NUU0RUFDRjBFNzc5MEY3QjQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjAzOEE0Njc3NUMyNzcyNjVFNEVBQ0YwRTc3OTBGN0I0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MDA4MzM5MDM4OTFEMDdEMDYyOEUwM0ZGNDQ2M0ExNEE=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MDM4QTQ2Nzc1QzI3NzI2NUU0RUFDRjBFNzc5MEY3QjQ=	F0F4E7335E15540F2784665D1A49AA6B	00833903891D07D0628E03FF4463A14A	5A3085C3400C3096E2ED2321452766B1
+C28615FC40FD89A29BC257C53846EC1B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=47	1000	20	47	20	20	urn:base64:TlJDZWxsRFU6NThEOTlDNkNBRDBFMDI3NjMyQzVDQzJGQTVDMzhEQjQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6QzI4NjE1RkM0MEZEODlBMjlCQzI1N0M1Mzg0NkVDMUI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkMyODYxNUZDNDBGRDg5QTI5QkMyNTdDNTM4NDZFQzFCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzRBMjgzRUVGRDVGMTQ2M0I3RUUwQ0E3ODI0MDlERkI=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QzI4NjE1RkM0MEZEODlBMjlCQzI1N0M1Mzg0NkVDMUI=	58D99C6CAD0E027632C5CC2FA5C38DB4	C4A283EEFD5F1463B7EE0CA782409DFB	5A3085C3400C3096E2ED2321452766B1
+BF3233CB2F106EC2E4C25BDCFB30D7EE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=48	1000	20	48	20	20	urn:base64:TlJDZWxsRFU6RUNFQzY2NDY0MTk5NDcwNENFNkE0MjIyQUEzMEVFNzg6VVNFUzpOUlNlY3RvckNhcnJpZXI6QkYzMjMzQ0IyRjEwNkVDMkU0QzI1QkRDRkIzMEQ3RUU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkJGMzIzM0NCMkYxMDZFQzJFNEMyNUJEQ0ZCMzBEN0VFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QUZGRUFGMUQwRjJEMzA1MjRDNDlCQTg2RDUyRjM5RUU=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QkYzMjMzQ0IyRjEwNkVDMkU0QzI1QkRDRkIzMEQ3RUU=	ECEC664641994704CE6A4222AA30EE78	AFFEAF1D0F2D30524C49BA86D52F39EE	5A3085C3400C3096E2ED2321452766B1
+22361310BFA331208A86E1F995A14DA8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=49	1000	20	49	20	20	urn:base64:TlJDZWxsRFU6NjFDOUEzQjVFMjQ0MjRGM0MyMUU3RTcwMkY4MUNDOTI6VVNFUzpOUlNlY3RvckNhcnJpZXI6MjIzNjEzMTBCRkEzMzEyMDhBODZFMUY5OTVBMTREQTg=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjIyMzYxMzEwQkZBMzMxMjA4QTg2RTFGOTk1QTE0REE4OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RTJBMTNDRjU2QzBFMTg3QzYyRkY5NzE2QkIwRkNFRDY=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MjIzNjEzMTBCRkEzMzEyMDhBODZFMUY5OTVBMTREQTg=	61C9A3B5E24424F3C21E7E702F81CC92	E2A13CF56C0E187C62FF9716BB0FCED6	5A3085C3400C3096E2ED2321452766B1
+93F359E5525EC94925936A3E372E7D9B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=50	1000	20	50	20	20	urn:base64:TlJDZWxsRFU6MzQwRjE3MDA3MUQ3OEFDQTNGNEU1M0FDRUUxRjJGNDk6VVNFUzpOUlNlY3RvckNhcnJpZXI6OTNGMzU5RTU1MjVFQzk0OTI1OTM2QTNFMzcyRTdEOUI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjkzRjM1OUU1NTI1RUM5NDkyNTkzNkEzRTM3MkU3RDlCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RTNFMUZCMzFGQjVGNEZCMUNBODA4MDM2NDc0QkREOTU=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OTNGMzU5RTU1MjVFQzk0OTI1OTM2QTNFMzcyRTdEOUI=	340F170071D78ACA3F4E53ACEE1F2F49	E3E1FB31FB5F4FB1CA808036474BDD95	5A3085C3400C3096E2ED2321452766B1
+95C1DFA87C196F8C4DD47D0F3EFF53CA	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=51	1000	20	51	20	20	urn:base64:TlJDZWxsRFU6MzI1MjE5NTNBQTI1NTVCQ0NGNjcxRkM2NTQ0RjQ1OEE6VVNFUzpOUlNlY3RvckNhcnJpZXI6OTVDMURGQTg3QzE5NkY4QzRERDQ3RDBGM0VGRjUzQ0E=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjk1QzFERkE4N0MxOTZGOEM0REQ0N0QwRjNFRkY1M0NBOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NTc2OUMwMjZENzk5M0M2NjZDNDU1MzVFREQ4QzNFQUQ=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OTVDMURGQTg3QzE5NkY4QzRERDQ3RDBGM0VGRjUzQ0E=	32521953AA2555BCCF671FC6544F458A	5769C026D7993C666C45535EDD8C3EAD	5A3085C3400C3096E2ED2321452766B1
+3FF49FD0BB880CA73E8C9116E3B61EE6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=52	1000	20	52	20	20	urn:base64:TlJDZWxsRFU6N0Q2QTREMDU4QjRENzdEQTM5RkNEQzJGQzlBMUI3OEE6VVNFUzpOUlNlY3RvckNhcnJpZXI6M0ZGNDlGRDBCQjg4MENBNzNFOEM5MTE2RTNCNjFFRTY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjNGRjQ5RkQwQkI4ODBDQTczRThDOTExNkUzQjYxRUU2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MkEzMjQ3NUVGNEY0QUI0MTkwNEI1QUFBQThGRjJDQTE=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6M0ZGNDlGRDBCQjg4MENBNzNFOEM5MTE2RTNCNjFFRTY=	7D6A4D058B4D77DA39FCDC2FC9A1B78A	2A32475EF4F4AB41904B5AAAA8FF2CA1	5A3085C3400C3096E2ED2321452766B1
+762BE1E7378F160158F6FF5D7052BAB4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=53	1000	20	53	20	20	urn:base64:TlJDZWxsRFU6MjdGNzU3N0JDRjA4Q0UzQjRGMUE0MDExRkNFRTY5M0M6VVNFUzpOUlNlY3RvckNhcnJpZXI6NzYyQkUxRTczNzhGMTYwMTU4RjZGRjVENzA1MkJBQjQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjc2MkJFMUU3Mzc4RjE2MDE1OEY2RkY1RDcwNTJCQUI0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RUIxMzAxQkEyMkUwNjkxMTE0QTIzNDQ1MzIzQjY0OUI=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NzYyQkUxRTczNzhGMTYwMTU4RjZGRjVENzA1MkJBQjQ=	27F7577BCF08CE3B4F1A4011FCEE693C	EB1301BA22E0691114A23445323B649B	5A3085C3400C3096E2ED2321452766B1
+60B08A9ECA8793B724689C58B535A512	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=54	1000	20	54	20	20	urn:base64:TlJDZWxsRFU6MDMyN0M3RjJCRkIzODZCOUM5MUM4RjkzQzcwRjRCMEY6VVNFUzpOUlNlY3RvckNhcnJpZXI6NjBCMDhBOUVDQTg3OTNCNzI0Njg5QzU4QjUzNUE1MTI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjYwQjA4QTlFQ0E4NzkzQjcyNDY4OUM1OEI1MzVBNTEyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6Mjg1QTc1OTBDRUMwQkM0NkYwQzFBOEEzRDFBQTJCQTU=	urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NjBCMDhBOUVDQTg3OTNCNzI0Njg5QzU4QjUzNUE1MTI=	0327C7F2BFB386B9C91C8F93C70F4B0F	285A7590CEC0BC46F0C1A8A3D1AA2BA5	5A3085C3400C3096E2ED2321452766B1
+9EBF76D73DA1DBD1A03B2767260AFB68	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=55	1000	20	55	20	20	urn:base64:TlJDZWxsRFU6NDI3OUE4NUE3NkNCQjI1NkUwRTRDMkJCQ0I3OEZCQ0I6VVNFUzpOUlNlY3RvckNhcnJpZXI6OUVCRjc2RDczREExREJEMUEwM0IyNzY3MjYwQUZCNjg=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjlFQkY3NkQ3M0RBMURCRDFBMDNCMjc2NzI2MEFGQjY4OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzYwNkFGMUExQUM1QTk2QTQzQjBCOEVCRkMxQjA0N0M=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OUVCRjc2RDczREExREJEMUEwM0IyNzY3MjYwQUZCNjg=	4279A85A76CBB256E0E4C2BBCB78FBCB	C606AF1A1AC5A96A43B0B8EBFC1B047C	7F16F93D8816D9EBC76E52BB44A3CFF5
+C8642E19317492BB0B99A217414605BE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=56	1000	20	56	20	20	urn:base64:TlJDZWxsRFU6MjJDQzJGNzdCQzBEMTc1OEU0QUM5MEQwODQ0RUIwRkE6VVNFUzpOUlNlY3RvckNhcnJpZXI6Qzg2NDJFMTkzMTc0OTJCQjBCOTlBMjE3NDE0NjA1QkU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkM4NjQyRTE5MzE3NDkyQkIwQjk5QTIxNzQxNDYwNUJFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NDBGQjU0ODE0MDJEQ0U4QUQ2QjNCMDM1N0IwMENGODI=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6Qzg2NDJFMTkzMTc0OTJCQjBCOTlBMjE3NDE0NjA1QkU=	22CC2F77BC0D1758E4AC90D0844EB0FA	40FB5481402DCE8AD6B3B0357B00CF82	7F16F93D8816D9EBC76E52BB44A3CFF5
+002FF41FF01735718EFB3F7171B39D81	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=57	1000	20	57	20	20	urn:base64:TlJDZWxsRFU6RUJBRTk2QzQwMjc0MkI0QkNCQTA2MDhBREMyMzI1MUE6VVNFUzpOUlNlY3RvckNhcnJpZXI6MDAyRkY0MUZGMDE3MzU3MThFRkIzRjcxNzFCMzlEODE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjAwMkZGNDFGRjAxNzM1NzE4RUZCM0Y3MTcxQjM5RDgxOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RkQ4RjNERThCOEFGMkZEMTAyRjM5RDBFRDg5QjM3MTQ=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MDAyRkY0MUZGMDE3MzU3MThFRkIzRjcxNzFCMzlEODE=	EBAE96C402742B4BCBA0608ADC23251A	FD8F3DE8B8AF2FD102F39D0ED89B3714	7F16F93D8816D9EBC76E52BB44A3CFF5
+CB9E427C06705864073AA7D78A7A3B02	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=58	1000	20	58	20	20	urn:base64:TlJDZWxsRFU6QjA0RUQ0MDU0RkYxMjRFNDYwODFDRTU5NjhCMTdDQjk6VVNFUzpOUlNlY3RvckNhcnJpZXI6Q0I5RTQyN0MwNjcwNTg2NDA3M0FBN0Q3OEE3QTNCMDI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkNCOUU0MjdDMDY3MDU4NjQwNzNBQTdENzhBN0EzQjAyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NUNFQTI0NzBEOTlBOEEyQkIzRUQ5MEJDMTVEQjExNDA=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6Q0I5RTQyN0MwNjcwNTg2NDA3M0FBN0Q3OEE3QTNCMDI=	B04ED4054FF124E46081CE5968B17CB9	5CEA2470D99A8A2BB3ED90BC15DB1140	7F16F93D8816D9EBC76E52BB44A3CFF5
+60EA4CECF73A4A866DDD77235AA9D79C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=59	1000	20	59	20	20	urn:base64:TlJDZWxsRFU6OEVDMjE3RDIyOEJBOTE3NUEyRTczMzU4NjY1QjVEM0U6VVNFUzpOUlNlY3RvckNhcnJpZXI6NjBFQTRDRUNGNzNBNEE4NjZEREQ3NzIzNUFBOUQ3OUM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjYwRUE0Q0VDRjczQTRBODY2RERENzcyMzVBQTlENzlDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NkEyM0E4QjhCNUFDRUE3NzVENkU5OEJBQzE1MzQzNzM=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NjBFQTRDRUNGNzNBNEE4NjZEREQ3NzIzNUFBOUQ3OUM=	8EC217D228BA9175A2E73358665B5D3E	6A23A8B8B5ACEA775D6E98BAC1534373	7F16F93D8816D9EBC76E52BB44A3CFF5
+D79B52CD8D1C0534158B2DF8C68D25D4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=60	1000	20	60	20	20	urn:base64:TlJDZWxsRFU6N0M5NzA3QjFFQUQzMTY4N0Q1NkRGQTA4QTc2NTYzODY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RDc5QjUyQ0Q4RDFDMDUzNDE1OEIyREY4QzY4RDI1RDQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkQ3OUI1MkNEOEQxQzA1MzQxNThCMkRGOEM2OEQyNUQ0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MUQyNzNGREQ0NTYxOENCRDQzOEQwMDgzODczMzE0RDU=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RDc5QjUyQ0Q4RDFDMDUzNDE1OEIyREY4QzY4RDI1RDQ=	7C9707B1EAD31687D56DFA08A7656386	1D273FDD45618CBD438D0083873314D5	7F16F93D8816D9EBC76E52BB44A3CFF5
+9504ECC61014E4CC3B7D59B2419EC7F5	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=61	1000	20	61	20	20	urn:base64:TlJDZWxsRFU6MDIzRkM0NUFGNTQwQUZDQTMyMDVEODQ2RDA3QzA0OEI6VVNFUzpOUlNlY3RvckNhcnJpZXI6OTUwNEVDQzYxMDE0RTRDQzNCN0Q1OUIyNDE5RUM3RjU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjk1MDRFQ0M2MTAxNEU0Q0MzQjdENTlCMjQxOUVDN0Y1OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RTA3Rjc2RUVGQTNGNkQxQTUwODNDOTlGM0QyMDJDQ0Q=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OTUwNEVDQzYxMDE0RTRDQzNCN0Q1OUIyNDE5RUM3RjU=	023FC45AF540AFCA3205D846D07C048B	E07F76EEFA3F6D1A5083C99F3D202CCD	7F16F93D8816D9EBC76E52BB44A3CFF5
+C118C7F37F4D6DD5269518496F58278B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=62	1000	20	62	20	20	urn:base64:TlJDZWxsRFU6QjQ2NTU4RURCMUNCMjcxODZCRTMxRDNGQTU0ODU2RjA6VVNFUzpOUlNlY3RvckNhcnJpZXI6QzExOEM3RjM3RjRENkRENTI2OTUxODQ5NkY1ODI3OEI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkMxMThDN0YzN0Y0RDZERDUyNjk1MTg0OTZGNTgyNzhCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MTczMzg4Nzg1Q0I0NzYxQjE1NEY0NDhBRTYzNzJBREM=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QzExOEM3RjM3RjRENkRENTI2OTUxODQ5NkY1ODI3OEI=	B46558EDB1CB27186BE31D3FA54856F0	173388785CB4761B154F448AE6372ADC	7F16F93D8816D9EBC76E52BB44A3CFF5
+F50176FD7602FBD61BB1783C39F32337	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=63	1000	20	63	20	20	urn:base64:TlJDZWxsRFU6QzVDRDQyRUY2MDhDQjkzRjRBRUYwRTQ3MzI5REY0MTc6VVNFUzpOUlNlY3RvckNhcnJpZXI6RjUwMTc2RkQ3NjAyRkJENjFCQjE3ODNDMzlGMzIzMzc=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkY1MDE3NkZENzYwMkZCRDYxQkIxNzgzQzM5RjMyMzM3OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QUExN0NFMTUwNENENDUxMjEyMTI2N0MyMjAzNDYyMEE=	urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RjUwMTc2RkQ3NjAyRkJENjFCQjE3ODNDMzlGMzIzMzc=	C5CD42EF608CB93F4AEF0E47329DF417	AA17CE1504CD4512121267C22034620A	7F16F93D8816D9EBC76E52BB44A3CFF5
+5A4EEB021CBB4A07BBE87E795CF81B7A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=64	1000	20	64	20	20	urn:base64:TlJDZWxsRFU6REE0OTJEQTE1NTlGQzc1OTVEMDdERkY1M0FERDM4QUQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6NUE0RUVCMDIxQ0JCNEEwN0JCRTg3RTc5NUNGODFCN0E=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjVBNEVFQjAyMUNCQjRBMDdCQkU4N0U3OTVDRjgxQjdBOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NTQyRDU2MkU3MkM4MDI1REQ1NjBENzE4RkZERTFENDU=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NUE0RUVCMDIxQ0JCNEEwN0JCRTg3RTc5NUNGODFCN0E=	DA492DA1559FC7595D07DFF53ADD38AD	542D562E72C8025DD560D718FFDE1D45	5A548EA9D166341776CA0695837E55D8
+E27E9E45BDB39E54A28C868A0A5ACD09	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=65	1000	20	65	20	20	urn:base64:TlJDZWxsRFU6OEU3OTRDM0UxRUVFNkVGOEI2OUMyNjhFMDY1NTNDOTE6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTI3RTlFNDVCREIzOUU1NEEyOEM4NjhBMEE1QUNEMDk=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkUyN0U5RTQ1QkRCMzlFNTRBMjhDODY4QTBBNUFDRDA5OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RTNDOTZCQTVEN0MwNzU1QTMwMTFEMTJBMzI5NzFCQTE=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RTI3RTlFNDVCREIzOUU1NEEyOEM4NjhBMEE1QUNEMDk=	8E794C3E1EEE6EF8B69C268E06553C91	E3C96BA5D7C0755A3011D12A32971BA1	5A548EA9D166341776CA0695837E55D8
+115E21696AADCAA2F2B2E30861861796	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=66	1000	20	66	20	20	urn:base64:TlJDZWxsRFU6QzJFMEI5MTEzQ0VBQzkxREY1RTE4MkI0MzFENTY3ODg6VVNFUzpOUlNlY3RvckNhcnJpZXI6MTE1RTIxNjk2QUFEQ0FBMkYyQjJFMzA4NjE4NjE3OTY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjExNUUyMTY5NkFBRENBQTJGMkIyRTMwODYxODYxNzk2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QjRDMzMzRUNEOTJBNzM1MUEzOEVFM0JDNTEwQjVEQTc=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MTE1RTIxNjk2QUFEQ0FBMkYyQjJFMzA4NjE4NjE3OTY=	C2E0B9113CEAC91DF5E182B431D56788	B4C333ECD92A7351A38EE3BC510B5DA7	5A548EA9D166341776CA0695837E55D8
+8D48BFDE1001B30AE5DBD567A0977E28	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=67	1000	20	67	20	20	urn:base64:TlJDZWxsRFU6OEVCN0JBQ0IwODVGMUFBQzAyRTE4RUJBNjk0QUQ5RDk6VVNFUzpOUlNlY3RvckNhcnJpZXI6OEQ0OEJGREUxMDAxQjMwQUU1REJENTY3QTA5NzdFMjg=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjhENDhCRkRFMTAwMUIzMEFFNURCRDU2N0EwOTc3RTI4OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NkY3NTExNkJCMjg5RUNEOEVCMUE5NjI1MkZEOEY3QzA=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OEQ0OEJGREUxMDAxQjMwQUU1REJENTY3QTA5NzdFMjg=	8EB7BACB085F1AAC02E18EBA694AD9D9	6F75116BB289ECD8EB1A96252FD8F7C0	5A548EA9D166341776CA0695837E55D8
+1C1B57F8771B4B4ABA9BB6AE99D3432A	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=68	1000	20	68	20	20	urn:base64:TlJDZWxsRFU6RUNGMEM3QzdCREZGRTM5QjMyNjM3QzM5OTI0REExNDc6VVNFUzpOUlNlY3RvckNhcnJpZXI6MUMxQjU3Rjg3NzFCNEI0QUJBOUJCNkFFOTlEMzQzMkE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjFDMUI1N0Y4NzcxQjRCNEFCQTlCQjZBRTk5RDM0MzJBOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MTZCODcwNTExRkFBRjExODNGQzkyRTY0MUIyQzM4MDQ=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MUMxQjU3Rjg3NzFCNEI0QUJBOUJCNkFFOTlEMzQzMkE=	ECF0C7C7BDFFE39B32637C39924DA147	16B870511FAAF1183FC92E641B2C3804	5A548EA9D166341776CA0695837E55D8
+EE48951D6D57E40EF435A9768D332F90	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=69	1000	20	69	20	20	urn:base64:TlJDZWxsRFU6RTM4MTYwMTNFMzc4RTkyODM3NzQzMzA5OENDNEM0OUY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RUU0ODk1MUQ2RDU3RTQwRUY0MzVBOTc2OEQzMzJGOTA=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkVFNDg5NTFENkQ1N0U0MEVGNDM1QTk3NjhEMzMyRjkwOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MkM3QUE4MDlDRDFBOTJGRDc0RUM0MTUxRDdDMTZBOEQ=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RUU0ODk1MUQ2RDU3RTQwRUY0MzVBOTc2OEQzMzJGOTA=	E3816013E378E928377433098CC4C49F	2C7AA809CD1A92FD74EC4151D7C16A8D	5A548EA9D166341776CA0695837E55D8
+C28F7CEE3CB0BBFBF0C6F719FEC211BB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=70	1000	20	70	20	20	urn:base64:TlJDZWxsRFU6Q0VDMzlBQzYyMEVEMTM5NzhGNzhDODAyMkUyMUNGOUU6VVNFUzpOUlNlY3RvckNhcnJpZXI6QzI4RjdDRUUzQ0IwQkJGQkYwQzZGNzE5RkVDMjExQkI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkMyOEY3Q0VFM0NCMEJCRkJGMEM2RjcxOUZFQzIxMUJCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MkMyMUQxMDY5NDYwRjM1RkYzODk1MkYxMDUwREY3Q0M=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QzI4RjdDRUUzQ0IwQkJGQkYwQzZGNzE5RkVDMjExQkI=	CEC39AC620ED13978F78C8022E21CF9E	2C21D1069460F35FF38952F1050DF7CC	5A548EA9D166341776CA0695837E55D8
+C5CF3C623988E715923D7886CB2466A6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=71	1000	20	71	20	20	urn:base64:TlJDZWxsRFU6MzczNzIxRjg1QUM5MzM5QzUxN0M4ODk1QzI5RkY2MkE6VVNFUzpOUlNlY3RvckNhcnJpZXI6QzVDRjNDNjIzOTg4RTcxNTkyM0Q3ODg2Q0IyNDY2QTY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkM1Q0YzQzYyMzk4OEU3MTU5MjNENzg4NkNCMjQ2NkE2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QUEzRUQwQzgyQTlGRTZENzQxMkI3QzU1OEE5NkNEQTU=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QzVDRjNDNjIzOTg4RTcxNTkyM0Q3ODg2Q0IyNDY2QTY=	373721F85AC9339C517C8895C29FF62A	AA3ED0C82A9FE6D7412B7C558A96CDA5	5A548EA9D166341776CA0695837E55D8
+6F3BF87603496381A0AA401D9AC6B915	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=72	1000	20	72	20	20	urn:base64:TlJDZWxsRFU6MDc2OTFCOEQ1REY3Q0I3NzNCNjM1OTlEMTE4RTNFRkI6VVNFUzpOUlNlY3RvckNhcnJpZXI6NkYzQkY4NzYwMzQ5NjM4MUEwQUE0MDFEOUFDNkI5MTU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjZGM0JGODc2MDM0OTYzODFBMEFBNDAxRDlBQzZCOTE1OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QjVEMzY5MDVDODdEQTYzNjYxMUMxMzcxNTk3MjdDRUU=	urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NkYzQkY4NzYwMzQ5NjM4MUEwQUE0MDFEOUFDNkI5MTU=	07691B8D5DF7CB773B63599D118E3EFB	B5D36905C87DA636611C137159727CEE	5A548EA9D166341776CA0695837E55D8
+5ECA43F7689D63684649BD90D40B79DD	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=73	1000	20	73	20	20	urn:base64:TlJDZWxsRFU6MTM4Q0UzQjIxQzgwNTM2NzVFMEVCREM0MUMzNkU5OUQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6NUVDQTQzRjc2ODlENjM2ODQ2NDlCRDkwRDQwQjc5REQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjVFQ0E0M0Y3Njg5RDYzNjg0NjQ5QkQ5MEQ0MEI3OUREOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6M0VGNEM3MTM1NEVDNTI3QUIwMzNBM0ZCODIwRjQ4RTQ=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NUVDQTQzRjc2ODlENjM2ODQ2NDlCRDkwRDQwQjc5REQ=	138CE3B21C8053675E0EBDC41C36E99D	3EF4C71354EC527AB033A3FB820F48E4	7D80E5C6E0C9EC246370E86B7E524F8C
+FF661FEC250A16BBE36D49880E4C2429	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=74	1000	20	74	20	20	urn:base64:TlJDZWxsRFU6MUY3MDI4MDBEMUY3MzU5OTU4MjgzREJDQjQ1QzBERDA6VVNFUzpOUlNlY3RvckNhcnJpZXI6RkY2NjFGRUMyNTBBMTZCQkUzNkQ0OTg4MEU0QzI0Mjk=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkZGNjYxRkVDMjUwQTE2QkJFMzZENDk4ODBFNEMyNDI5OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MEIzNjgxRjE5NTU4NEVGMTA1MUI5MTRFQjYzRUJCQ0I=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RkY2NjFGRUMyNTBBMTZCQkUzNkQ0OTg4MEU0QzI0Mjk=	1F702800D1F7359958283DBCB45C0DD0	0B3681F195584EF1051B914EB63EBBCB	7D80E5C6E0C9EC246370E86B7E524F8C
+B6372CE9CE6325BA1ADBDD0500C73B8E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=75	1000	20	75	20	20	urn:base64:TlJDZWxsRFU6MENFMzMyMEU2QjQxRkMyM0I2QjBGQTRGRDIxMDNCMkM6VVNFUzpOUlNlY3RvckNhcnJpZXI6QjYzNzJDRTlDRTYzMjVCQTFBREJERDA1MDBDNzNCOEU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkI2MzcyQ0U5Q0U2MzI1QkExQURCREQwNTAwQzczQjhFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NTlBNzdGQkJEQzhFMTgxOTc0MUU0NzI4NTk2QzQzNUM=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QjYzNzJDRTlDRTYzMjVCQTFBREJERDA1MDBDNzNCOEU=	0CE3320E6B41FC23B6B0FA4FD2103B2C	59A77FBBDC8E1819741E4728596C435C	7D80E5C6E0C9EC246370E86B7E524F8C
+7F4FDA4338069682CC88AD745CB6C63D	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=76	1000	20	76	20	20	urn:base64:TlJDZWxsRFU6OTIxMjBENUVFNUMwODg1RDdFNTA4NjBCRDA1NUExRUU6VVNFUzpOUlNlY3RvckNhcnJpZXI6N0Y0RkRBNDMzODA2OTY4MkNDODhBRDc0NUNCNkM2M0Q=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjdGNEZEQTQzMzgwNjk2ODJDQzg4QUQ3NDVDQjZDNjNEOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QkRDOEU0RUFDNTNDOUMzOTgwMEI0QkRDMDMwOUM4QkI=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6N0Y0RkRBNDMzODA2OTY4MkNDODhBRDc0NUNCNkM2M0Q=	92120D5EE5C0885D7E50860BD055A1EE	BDC8E4EAC53C9C39800B4BDC0309C8BB	7D80E5C6E0C9EC246370E86B7E524F8C
+E9D5351FA08CF470205691591A57971C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=77	1000	20	77	20	20	urn:base64:TlJDZWxsRFU6RDcwNTU1NEU5ODEwMzQxMUIwMDVEMkUzQjRGNDJDODc6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTlENTM1MUZBMDhDRjQ3MDIwNTY5MTU5MUE1Nzk3MUM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkU5RDUzNTFGQTA4Q0Y0NzAyMDU2OTE1OTFBNTc5NzFDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MzczMzIyOTlCRTEzOTgxOTNGN0I3NDUyQzE2NTIxRjg=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RTlENTM1MUZBMDhDRjQ3MDIwNTY5MTU5MUE1Nzk3MUM=	D705554E98103411B005D2E3B4F42C87	37332299BE1398193F7B7452C16521F8	7D80E5C6E0C9EC246370E86B7E524F8C
+84C3806E28DDA395FB657466730E553F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=78	1000	20	78	20	20	urn:base64:TlJDZWxsRFU6NDYyRUY0NkFBMUM3NjQxQTg1MTBDN0M2MUQ2MEM4QjE6VVNFUzpOUlNlY3RvckNhcnJpZXI6ODRDMzgwNkUyOEREQTM5NUZCNjU3NDY2NzMwRTU1M0Y=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjg0QzM4MDZFMjhEREEzOTVGQjY1NzQ2NjczMEU1NTNGOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6ODNCOEZDMzQwOUU5RTM0RjhENEIyMkNENTE0Q0MwNzg=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6ODRDMzgwNkUyOEREQTM5NUZCNjU3NDY2NzMwRTU1M0Y=	462EF46AA1C7641A8510C7C61D60C8B1	83B8FC3409E9E34F8D4B22CD514CC078	7D80E5C6E0C9EC246370E86B7E524F8C
+245B2FAC3BB11B00FAE447CABE698904	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=79	1000	20	79	20	20	urn:base64:TlJDZWxsRFU6MjY4MjVEOUNBQTkxQkFDMzg5REVCREYzNTcyRUY0MDg6VVNFUzpOUlNlY3RvckNhcnJpZXI6MjQ1QjJGQUMzQkIxMUIwMEZBRTQ0N0NBQkU2OTg5MDQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjI0NUIyRkFDM0JCMTFCMDBGQUU0NDdDQUJFNjk4OTA0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NTg3QURCRDQ2RkEwQTc3MEUxQzNBQkEyMTBEQjU3RUQ=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MjQ1QjJGQUMzQkIxMUIwMEZBRTQ0N0NBQkU2OTg5MDQ=	26825D9CAA91BAC389DEBDF3572EF408	587ADBD46FA0A770E1C3ABA210DB57ED	7D80E5C6E0C9EC246370E86B7E524F8C
+42855D46C847C3A8495357891130264E	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=80	1000	20	80	20	20	urn:base64:TlJDZWxsRFU6MzNGODJERTkxODZGMTUzOUQyRUQ5ODgxOEY0MUEwQzI6VVNFUzpOUlNlY3RvckNhcnJpZXI6NDI4NTVENDZDODQ3QzNBODQ5NTM1Nzg5MTEzMDI2NEU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjQyODU1RDQ2Qzg0N0MzQTg0OTUzNTc4OTExMzAyNjRFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NjA0QTIyQkZDNzJBOTYwMTE1RDZCMjFDM0YxODY4NDE=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NDI4NTVENDZDODQ3QzNBODQ5NTM1Nzg5MTEzMDI2NEU=	33F82DE9186F1539D2ED98818F41A0C2	604A22BFC72A960115D6B21C3F186841	7D80E5C6E0C9EC246370E86B7E524F8C
+03A4F1EB4E6F1981AA02DCD9A8433C93	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=81	1000	20	81	20	20	urn:base64:TlJDZWxsRFU6NDAxNzVBRjAwQTUyMjIxM0JBNjA1Mzc1MTlBNzE5Nzg6VVNFUzpOUlNlY3RvckNhcnJpZXI6MDNBNEYxRUI0RTZGMTk4MUFBMDJEQ0Q5QTg0MzNDOTM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjAzQTRGMUVCNEU2RjE5ODFBQTAyRENEOUE4NDMzQzkzOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MUQ0Q0JDNDNENjJBMDFCMjdGQTBDNzQ0MkY5QUQwRDg=	urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MDNBNEYxRUI0RTZGMTk4MUFBMDJEQ0Q5QTg0MzNDOTM=	40175AF00A522213BA60537519A71978	1D4CBC43D62A01B27FA0C7442F9AD0D8	7D80E5C6E0C9EC246370E86B7E524F8C
+BF8B10BD381DFC02FF35CAEF21FF8BF9	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=82	1000	20	82	20	20	urn:base64:TlJDZWxsRFU6RUE4NjA4ODQ1NEI3NDkxRkIzQkVGRERDQTVGRTA5N0Q6VVNFUzpOUlNlY3RvckNhcnJpZXI6QkY4QjEwQkQzODFERkMwMkZGMzVDQUVGMjFGRjhCRjk=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkJGOEIxMEJEMzgxREZDMDJGRjM1Q0FFRjIxRkY4QkY5OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6ODkyQkFFMEI0NTg2NUQzRjREQzc3NjY2MkJCMzc2NTQ=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QkY4QjEwQkQzODFERkMwMkZGMzVDQUVGMjFGRjhCRjk=	EA86088454B7491FB3BEFDDCA5FE097D	892BAE0B45865D3F4DC776662BB37654	BBB3C42A4F8AC94091B297DF708DD50B
+6D969214659F2A2CA9650AC208FBF457	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=83	1000	20	83	20	20	urn:base64:TlJDZWxsRFU6OUJDNjk5OEI4OEJBNEMxMDgxQ0Q1RjIxMTY4MUM5Q0Y6VVNFUzpOUlNlY3RvckNhcnJpZXI6NkQ5NjkyMTQ2NTlGMkEyQ0E5NjUwQUMyMDhGQkY0NTc=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjZEOTY5MjE0NjU5RjJBMkNBOTY1MEFDMjA4RkJGNDU3OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RUUxRUFBRkRCODUyMDYyNTlBQTlEOUQ0QkEwMUJEQTI=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NkQ5NjkyMTQ2NTlGMkEyQ0E5NjUwQUMyMDhGQkY0NTc=	9BC6998B88BA4C1081CD5F211681C9CF	EE1EAAFDB85206259AA9D9D4BA01BDA2	BBB3C42A4F8AC94091B297DF708DD50B
+365071A0DFF5B78304D2FA88D0843FBB	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=84	1000	20	84	20	20	urn:base64:TlJDZWxsRFU6ODM3N0VDQTEzN0ZGMDE4Qzk3MTZDMDU4N0Y2MTcxODI6VVNFUzpOUlNlY3RvckNhcnJpZXI6MzY1MDcxQTBERkY1Qjc4MzA0RDJGQTg4RDA4NDNGQkI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjM2NTA3MUEwREZGNUI3ODMwNEQyRkE4OEQwODQzRkJCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MTExQkQxMjNEQ0ExQjkzN0YwRTE1RTVCRUZERTA4RTk=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MzY1MDcxQTBERkY1Qjc4MzA0RDJGQTg4RDA4NDNGQkI=	8377ECA137FF018C9716C0587F617182	111BD123DCA1B937F0E15E5BEFDE08E9	BBB3C42A4F8AC94091B297DF708DD50B
+8307402BF7B31AF8574188E04561D3C8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=85	1000	20	85	20	20	urn:base64:TlJDZWxsRFU6MTU4OTBFRjZEMjE5NkQ5RTIxRDcwQkRDRTJBQTNBNzc6VVNFUzpOUlNlY3RvckNhcnJpZXI6ODMwNzQwMkJGN0IzMUFGODU3NDE4OEUwNDU2MUQzQzg=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjgzMDc0MDJCRjdCMzFBRjg1NzQxODhFMDQ1NjFEM0M4OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6REY3ODM3RUVBQjY1QTA2ODU5MTEwMzY2RTVGNDUyOTc=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6ODMwNzQwMkJGN0IzMUFGODU3NDE4OEUwNDU2MUQzQzg=	15890EF6D2196D9E21D70BDCE2AA3A77	DF7837EEAB65A06859110366E5F45297	BBB3C42A4F8AC94091B297DF708DD50B
+9815C219A506825B396777C746C32CE8	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=86	1000	20	86	20	20	urn:base64:TlJDZWxsRFU6RjYwRjVCRDU0RkE5ODQyOTc5NzkwQjRCQkY4MEI4RDk6VVNFUzpOUlNlY3RvckNhcnJpZXI6OTgxNUMyMTlBNTA2ODI1QjM5Njc3N0M3NDZDMzJDRTg=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjk4MTVDMjE5QTUwNjgyNUIzOTY3NzdDNzQ2QzMyQ0U4OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RDBBQUU5NjMxQUYxNTU0QjhGMzkwOTMyRTM3N0VBMTk=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6OTgxNUMyMTlBNTA2ODI1QjM5Njc3N0M3NDZDMzJDRTg=	F60F5BD54FA9842979790B4BBF80B8D9	D0AAE9631AF1554B8F390932E377EA19	BBB3C42A4F8AC94091B297DF708DD50B
+E04502AA9180D9BFE2BF1D3C7A9BC168	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=87	1000	20	87	20	20	urn:base64:TlJDZWxsRFU6MjY0MjU4NjA4NTEyMDA1OERGNTk2NzBGMzNGQTUwOTg6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTA0NTAyQUE5MTgwRDlCRkUyQkYxRDNDN0E5QkMxNjg=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkUwNDUwMkFBOTE4MEQ5QkZFMkJGMUQzQzdBOUJDMTY4OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6ODlCOUZFNUQyRDRBMDdDQ0Q1NEU3MDVCRkUyRDEwRjA=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RTA0NTAyQUE5MTgwRDlCRkUyQkYxRDNDN0E5QkMxNjg=	2642586085120058DF59670F33FA5098	89B9FE5D2D4A07CCD54E705BFE2D10F0	BBB3C42A4F8AC94091B297DF708DD50B
+102AB1BB98BDBA7E7ED16D3D3CFFB6D4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=88	1000	20	88	20	20	urn:base64:TlJDZWxsRFU6QTM5QzczRDI4NzlEODZFRjQxODRCNjA1QzBBRTAxNkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6MTAyQUIxQkI5OEJEQkE3RTdFRDE2RDNEM0NGRkI2RDQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjEwMkFCMUJCOThCREJBN0U3RUQxNkQzRDNDRkZCNkQ0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QTZFOTdCQTMwODMyQzFCN0FDMzZGNEQ3OUREMzhCNzE=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MTAyQUIxQkI5OEJEQkE3RTdFRDE2RDNEM0NGRkI2RDQ=	A39C73D2879D86EF4184B605C0AE016F	A6E97BA30832C1B7AC36F4D79DD38B71	BBB3C42A4F8AC94091B297DF708DD50B
+DB5F86A12F44A382347C1FB4893ED9A6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=89	1000	20	89	20	20	urn:base64:TlJDZWxsRFU6RUVDODVBN0Y3NjAxNzI2MEY5NzIxQjY1QTE0NEQxOEU6VVNFUzpOUlNlY3RvckNhcnJpZXI6REI1Rjg2QTEyRjQ0QTM4MjM0N0MxRkI0ODkzRUQ5QTY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkRCNUY4NkExMkY0NEEzODIzNDdDMUZCNDg5M0VEOUE2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6REZBNjIwMkZGOTZERDQxOEVBRDRDOTMwRjI3RjBDNzg=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6REI1Rjg2QTEyRjQ0QTM4MjM0N0MxRkI0ODkzRUQ5QTY=	EEC85A7F76017260F9721B65A144D18E	DFA6202FF96DD418EAD4C930F27F0C78	BBB3C42A4F8AC94091B297DF708DD50B
+5C2AD66A4AB041C406D723CBAE50A132	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=90	1000	20	90	20	20	urn:base64:TlJDZWxsRFU6MUQ4MjU4ODFGMzc4RTA3MzUzNzhENDBCREVDQUMzRUM6VVNFUzpOUlNlY3RvckNhcnJpZXI6NUMyQUQ2NkE0QUIwNDFDNDA2RDcyM0NCQUU1MEExMzI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjVDMkFENjZBNEFCMDQxQzQwNkQ3MjNDQkFFNTBBMTMyOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MDE5NDVEN0I3RDJBRkIwQjNERkUyMzgyMkQyQzlDQ0I=	urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NUMyQUQ2NkE0QUIwNDFDNDA2RDcyM0NCQUU1MEExMzI=	1D825881F378E0735378D40BDECAC3EC	01945D7B7D2AFB0B3DFE23822D2C9CCB	BBB3C42A4F8AC94091B297DF708DD50B
+A93CCC56481697761027BCDE211E1C60	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=91	1000	20	91	20	20	urn:base64:TlJDZWxsRFU6NzZFOUY2MDVENEYzNzMzMEJGMEI1MDVFOTRGNjRGMTE6VVNFUzpOUlNlY3RvckNhcnJpZXI6QTkzQ0NDNTY0ODE2OTc3NjEwMjdCQ0RFMjExRTFDNjA=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkE5M0NDQzU2NDgxNjk3NzYxMDI3QkNERTIxMUUxQzYwOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QkU1MEFDNTdBQjFGQUU3MzUzMUFERDE4MTMyNDA2N0Y=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QTkzQ0NDNTY0ODE2OTc3NjEwMjdCQ0RFMjExRTFDNjA=	76E9F605D4F37330BF0B505E94F64F11	BE50AC57AB1FAE73531ADD181324067F	4CFF136200A2DE36205A13559C55DB2A
+0BF78ED8A5CC93E9A94D0C26EE06E82C	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=92	1000	20	92	20	20	urn:base64:TlJDZWxsRFU6NjdBMUJEQTEwQjVBRjQzMDI4RDA3QzdCRTVDQjFBRTI6VVNFUzpOUlNlY3RvckNhcnJpZXI6MEJGNzhFRDhBNUNDOTNFOUE5NEQwQzI2RUUwNkU4MkM=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjBCRjc4RUQ4QTVDQzkzRTlBOTREMEMyNkVFMDZFODJDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6ODJEMDU1REUxNUI5N0NEODY2Q0Y0NTRBOTY4OEY0REI=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MEJGNzhFRDhBNUNDOTNFOUE5NEQwQzI2RUUwNkU4MkM=	67A1BDA10B5AF43028D07C7BE5CB1AE2	82D055DE15B97CD866CF454A9688F4DB	4CFF136200A2DE36205A13559C55DB2A
+3A03407819295DB521A1E8B0FBCCE4A6	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=93	1000	20	93	20	20	urn:base64:TlJDZWxsRFU6QjNCMEExOTM5RUZDQTY1NEEzNzAwNUI2QTdGMjRCRDc6VVNFUzpOUlNlY3RvckNhcnJpZXI6M0EwMzQwNzgxOTI5NURCNTIxQTFFOEIwRkJDQ0U0QTY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjNBMDM0MDc4MTkyOTVEQjUyMUExRThCMEZCQ0NFNEE2OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6MzYyRUMzQjc3NThEODczREY5OEFFMkE5RUMyNDcyQjU=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6M0EwMzQwNzgxOTI5NURCNTIxQTFFOEIwRkJDQ0U0QTY=	B3B0A1939EFCA654A37005B6A7F24BD7	362EC3B7758D873DF98AE2A9EC2472B5	4CFF136200A2DE36205A13559C55DB2A
+50CD521E55D12209A175020974A24AB4	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=94	1000	20	94	20	20	urn:base64:TlJDZWxsRFU6RjI2RjI3OUU5MUQwOTQxREI0RjY0NkU3MDdFQTQwM0E6VVNFUzpOUlNlY3RvckNhcnJpZXI6NTBDRDUyMUU1NUQxMjIwOUExNzUwMjA5NzRBMjRBQjQ=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjUwQ0Q1MjFFNTVEMTIyMDlBMTc1MDIwOTc0QTI0QUI0OlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6REE1RDhBM0QxQ0RDM0Q1NTQ0N0Y3Qzg2RUREOEZFNTA=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6NTBDRDUyMUU1NUQxMjIwOUExNzUwMjA5NzRBMjRBQjQ=	F26F279E91D0941DB4F646E707EA403A	DA5D8A3D1CDC3D55447F7C86EDD8FE50	4CFF136200A2DE36205A13559C55DB2A
+EBF6DFD0DE8908C4CF01E834A5B7EFB1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=95	1000	20	95	20	20	urn:base64:TlJDZWxsRFU6MjQzNzkxNDZGRTM0OUZCRjA0QkEzQjMwMTgwNzcyMTQ6VVNFUzpOUlNlY3RvckNhcnJpZXI6RUJGNkRGRDBERTg5MDhDNENGMDFFODM0QTVCN0VGQjE=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkVCRjZERkQwREU4OTA4QzRDRjAxRTgzNEE1QjdFRkIxOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6NkEzOUIxNTFDNTBGNzNGMDI5QjU3NzIyOTlEQ0YyODk=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RUJGNkRGRDBERTg5MDhDNENGMDFFODM0QTVCN0VGQjE=	24379146FE349FBF04BA3B3018077214	6A39B151C50F73F029B5772299DCF289	4CFF136200A2DE36205A13559C55DB2A
+DA2FC8B45D346CFD1C9BB7F074CCA32F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=96	1000	20	96	20	20	urn:base64:TlJDZWxsRFU6NUU3RUExRDYzODBDMjFEMkMwMjQ1MjRDMkExOThBNUE6VVNFUzpOUlNlY3RvckNhcnJpZXI6REEyRkM4QjQ1RDM0NkNGRDFDOUJCN0YwNzRDQ0EzMkY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkRBMkZDOEI0NUQzNDZDRkQxQzlCQjdGMDc0Q0NBMzJGOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QjBGRTg4MERGOTQ3NEFBMjlDN0E0QkFBQTk0NkU1NUQ=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6REEyRkM4QjQ1RDM0NkNGRDFDOUJCN0YwNzRDQ0EzMkY=	5E7EA1D6380C21D2C024524C2A198A5A	B0FE880DF9474AA29C7A4BAAA946E55D	4CFF136200A2DE36205A13559C55DB2A
+1E0B268A6D8C40331AACEBED444FCC1F	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=97	1000	20	97	20	20	urn:base64:TlJDZWxsRFU6NURDM0ExMUE2OUQ4Q0RCMTc1RkM5RDQ5RDlFMEU3MjA6VVNFUzpOUlNlY3RvckNhcnJpZXI6MUUwQjI2OEE2RDhDNDAzMzFBQUNFQkVENDQ0RkNDMUY=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjFFMEIyNjhBNkQ4QzQwMzMxQUFDRUJFRDQ0NEZDQzFGOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QzIzRDlEMDgwN0U0NUVGNTVEQzZCN0QzNUVFQjA4QjE=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6MUUwQjI2OEE2RDhDNDAzMzFBQUNFQkVENDQ0RkNDMUY=	5DC3A11A69D8CDB175FC9D49D9E0E720	C23D9D0807E45EF55DC6B7D35EEB08B1	4CFF136200A2DE36205A13559C55DB2A
+87670506C58610E1888B5BEBE2C9B21B	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=98	1000	20	98	20	20	urn:base64:TlJDZWxsRFU6OTg0MEFDMTU2Njc3NDU0NUNCRDdGRDQ0MDE1RUZGQTU6VVNFUzpOUlNlY3RvckNhcnJpZXI6ODc2NzA1MDZDNTg2MTBFMTg4OEI1QkVCRTJDOUIyMUI=	urn:base64:TlJTZWN0b3JDYXJyaWVyOjg3NjcwNTA2QzU4NjEwRTE4ODhCNUJFQkUyQzlCMjFCOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6Q0Y4RUY3MjNCQjQ2QzYxNzBEQjA0OTBEMUZBMjZCODU=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6ODc2NzA1MDZDNTg2MTBFMTg4OEI1QkVCRTJDOUIyMUI=	9840AC1566774545CBD7FD44015EFFA5	CF8EF723BB46C6170DB0490D1FA26B85	4CFF136200A2DE36205A13559C55DB2A
+A00B93EACEE32A938CD9A83446E1B3AE	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=99	1000	20	99	20	20	urn:base64:TlJDZWxsRFU6RjQ1MzFDMzEyMDVGMjhCQzg4MzBDQUQ3QTdDMkZEQTE6VVNFUzpOUlNlY3RvckNhcnJpZXI6QTAwQjkzRUFDRUUzMkE5MzhDRDlBODM0NDZFMUIzQUU=	urn:base64:TlJTZWN0b3JDYXJyaWVyOkEwMEI5M0VBQ0VFMzJBOTM4Q0Q5QTgzNDQ2RTFCM0FFOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6RTFDMzQwREYwRkZBNTEyMTFEREI1RjgyOUUyQTI3RUU=	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6QTAwQjkzRUFDRUUzMkE5MzhDRDlBODM0NDZFMUIzQUU=	F4531C31205F28BC8830CAD7A7C2FDA1	E1C340DF0FFA51211DDB5F829E2A27EE	4CFF136200A2DE36205A13559C55DB2A
+\.
+
+COPY ties_data."GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" (id, "GNBCUCPFunction", "CloudNativeApplication") FROM stdin;
+urn:base64:R05CQ1VDUEZ1bmN0aW9uOjA1MjU5MzAyNDkzMDJCOTY0OUZDOEYyMDFFQzRGN0ZDOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246MzI1NjEyMEU3M0FERDQwMjZBNDNBOTcxRENFNUMxNTE=	0525930249302B9649FC8F201EC4F7FC	3256120E73ADD4026A43A971DCE5C151
+\.
+
+COPY ties_data."GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" (id, "GNBCUUPFunction", "CloudNativeApplication") FROM stdin;
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOkJGRUVBQzJDRTYwMjczQ0IwQTc4MzE5Q0MyMDFBN0ZFOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246QUQ0MkQ5MDQ5N0U5M0QyNzYyMTVERjZEM0I4OTlFMTc=	BFEEAC2CE60273CB0A78319CC201A7FE	AD42D90497E93D276215DF6D3B899E17
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOkYxQzMyQjlERUNBMjIzMEQ5NzY1QkUyRjU0RjFFREZFOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246OTgwMEQ4MUM3NDNCRjQyNDZGRUI5NTA2M0Q2QjBGNkI=	F1C32B9DECA2230D9765BE2F54F1EDFE	9800D81C743BF4246FEB95063D6B0F6B
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOkExOEYzNDUyQzkxOEU4RjJDNTRFNjAwRjQyMDA1REJEOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246Mzk4REQxOUE1RkQ5MDJDOTgxRTRENTlGNDRFMjdGMDc=	A18F3452C918E8F2C54E600F42005DBD	398DD19A5FD902C981E4D59F44E27F07
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOjZCM0U1NkI2Qzk5MUY0RTU2OTExNURFNTYzM0IwQUEwOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246RTVFOEExMTQxOUUwOTk2NjYwNEMxNEZERTVFMDlERjU=	6B3E56B6C991F4E569115DE5633B0AA0	E5E8A11419E09966604C14FDE5E09DF5
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOjk5QkJBM0VDNjRCRTU5NjQwMEIzOEZFQkQ5Njc3RkM2OlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246NDEyMzREQkQzQ0NFQzAxMEUyRTkyNTg1MjcyMjk5NTA=	99BBA3EC64BE596400B38FEBD9677FC6	41234DBD3CCEC010E2E9258527229950
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOjk4MDZBQkUyOTg1QkRENEZFNkJEMkIzODU0OUM5NzNDOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246QzRFMjg5MzIzNTdGQTAwNzZDQTk2Q0Y3RkYyQzUxQkQ=	9806ABE2985BDD4FE6BD2B38549C973C	C4E28932357FA0076CA96CF7FF2C51BD
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOjlCMDA3ODgxQTFCOERFMzNEMUQzMDYzQkU2MDFENEI2OlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246RUUyRDRBREExMEZGNjg3RkY2QTg2NUNDOUU1NkE0MzY=	9B007881A1B8DE33D1D3063BE601D4B6	EE2D4ADA10FF687FF6A865CC9E56A436
+\.
+
+COPY ties_data."GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" (id, "GNBDUFunction", "CloudNativeApplication") FROM stdin;
+urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE	4CFF136200A2DE36205A13559C55DB2A	C549905CF3CC890CE5746C5E10ACF00D
+urn:base64:R05CRFVGdW5jdGlvbjpCQkIzQzQyQTRGOEFDOTQwOTFCMjk3REY3MDhERDUwQjpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjlFMDI5MTY4OTQzNTIwMEFFMTMzMkZCQkI5OTJDMTUx	BBB3C42A4F8AC94091B297DF708DD50B	9E0291689435200AE1332FBBB992C151
+urn:base64:R05CRFVGdW5jdGlvbjo3RDgwRTVDNkUwQzlFQzI0NjM3MEU4NkI3RTUyNEY4QzpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjZCNjU1OTcxNTY0QzAyRjFGQjdFNUQ3RTg0RjlEREFG	7D80E5C6E0C9EC246370E86B7E524F8C	6B655971564C02F1FB7E5D7E84F9DDAF
+urn:base64:R05CRFVGdW5jdGlvbjo1QTU0OEVBOUQxNjYzNDE3NzZDQTA2OTU4MzdFNTVEODpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkUxMjhDMzBEN0UyQURCN0RFRjkwNENFN0U5MzZBNTg2	5A548EA9D166341776CA0695837E55D8	E128C30D7E2ADB7DEF904CE7E936A586
+urn:base64:R05CRFVGdW5jdGlvbjo3RjE2RjkzRDg4MTZEOUVCQzc2RTUyQkI0NEEzQ0ZGNTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjBEQkRBRjM1N0E2OUMzNzNGQzJBOThCNjg0ODVEREUz	7F16F93D8816D9EBC76E52BB44A3CFF5	0DBDAF357A69C373FC2A98B68485DDE3
+urn:base64:R05CRFVGdW5jdGlvbjo1QTMwODVDMzQwMEMzMDk2RTJFRDIzMjE0NTI3NjZCMTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjNGMjU4MEU5RjQ2OUY5QTNDRDk3QjlGQ0Y2Q0Y0RkI3	5A3085C3400C3096E2ED2321452766B1	3F2580E9F469F9A3CD97B9FCF6CF4FB7
+urn:base64:R05CRFVGdW5jdGlvbjoyNUU2OTBFMjJCREE5MEI5QzRGRUUxRjA4M0NCQTU5NzpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkQ4MEUwOTI0MzJFQTY3M0U2RDI2RjgzM0ZENDU2REFC	25E690E22BDA90B9C4FEE1F083CBA597	D80E092432EA673E6D26F833FD456DAB
+urn:base64:R05CRFVGdW5jdGlvbjpFNUZENUFDRDU1QzU1M0E5MjczODQ3N0VDQjA0NjVCOTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjYwRTY4NUM1M0Y0QTFENzAwQUExMjQ5OUI4NTEzNzAw	E5FD5ACD55C553A92738477ECB0465B9	60E685C53F4A1D700AA12499B8513700
+urn:base64:R05CRFVGdW5jdGlvbjpCNkE2REU3RDA5NjVGMDJENDhFQ0E4NjcwNkE0NDU0RjpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjA3MjU0OUI2RjU1MjEwRUE5NjdENjZGQjM4REY0RDAy	B6A6DE7D0965F02D48ECA86706A4454F	072549B6F55210EA967D66FB38DF4D02
+urn:base64:R05CRFVGdW5jdGlvbjoxMDUwNTcwRUJCMTMxNUUxQUU3QTlGRDVFMTQwMEEwMDpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjQxNkYzMUU2RUIwOTA1NTMyNjYyMUY0OTE5RDM1QkZG	1050570EBB1315E1AE7A9FD5E1400A00	416F31E6EB09055326621F4919D35BFF
+urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOjcxOUJENUM3Q0Q4QTkzOUQ3NkE4M0RBOTVEQTQ1QzAx	D3215E08570BE58339C7463626B50E37	719BD5C7CD8A939D76A83DA95DA45C01
+\.
+
+COPY ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE" (id, "AntennaCapability", "AntennaModule") FROM stdin;
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6QTMyREI5RTI3OEZDMURFNDFGQjRBM0I1MEY4MDI2NTA6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTo0MkI0RUVGMDlFOTczNzhCMEUzNjVGOUJBQUI1MEUxQg==	A32DB9E278FC1DE41FB4A3B50F802650	42B4EEF09E97378B0E365F9BAAB50E1B
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6NDkyMDU4ODFDOTEyMUYyMDhCRDc5MTQ5RkE3OTk4Nzc6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpBRjM4ODYxOUY4NTE3Q0JFQUYyM0QwNkI0RDM3NDRGRg==	49205881C9121F208BD79149FA799877	AF388619F8517CBEAF23D06B4D3744FF
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6MEJEQUQ1RERDMTlBNjk2MjQ0NTM2NDIxRTZEMjZGRTM6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTo0RUNBMDIxNjUyNzVGQTE3QkU2MEFGMUQyN0FBQjUyOQ==	0BDAD5DDC19A696244536421E6D26FE3	4ECA02165275FA17BE60AF1D27AAB529
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6QzM5OEQ2QzY3MzI2N0EwODFDNzgxRDg0NDM4RjRCNzQ6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTo0QzRFOTk5OERBRTMwQzk1NEE5M0Q3ODk1OUZENTExQg==	C398D6C673267A081C781D84438F4B74	4C4E9998DAE30C954A93D78959FD511B
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6MjhBRDNFRTg0NDc2NkRGNTA4RjYyODdDRDFDRTE4QTQ6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpBRDJERDE1QUM0RTFERTA1MDY4NDM4ODdCNDdDNTFBMw==	28AD3EE844766DF508F6287CD1CE18A4	AD2DD15AC4E1DE0506843887B47C51A3
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6RDMxNERBREFGQTNEODk2NDQ1RTc4RUJDQzE1QTE2Rjc6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTo3MkM3NkMwM0VEMEI0MkZBM0ZFNEY5RDIyQzRBRjlFMQ==	D314DADAFA3D896445E78EBCC15A16F7	72C76C03ED0B42FA3FE4F9D22C4AF9E1
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6OTE4OEQ5NzVEODM3QTFFMDM5NzE2N0EyM0U3MjFCMEM6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpCNDEyNUVGQjc5RDQ2QkY5ODk1NzA5Rjk4NUM5MkU5OQ==	9188D975D837A1E0397167A23E721B0C	B4125EFB79D46BF9895709F985C92E99
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6MTQ1QTFCRjU2MURCMjk3RjI1RkQzRjEyNDE3RDJBNTA6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpCRDBFMTBCQzU1QjcyODZGNjk5REIzNDAwNDUwNTNDQQ==	145A1BF561DB297F25FD3F12417D2A50	BD0E10BC55B7286F699DB340045053CA
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6N0RFOTFDNzhGOERDRTQyOTJGMkYwQzNCMzRERUFDQUI6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZToxMzE5RURDMEE5NTYwOTA4NDY4MkIzMzFGMEEwNUU4Mg==	7DE91C78F8DCE4292F2F0C3B34DEACAB	1319EDC0A95609084682B331F0A05E82
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6NzBBMUYxMjlFMTBFRTdEMzFERkUxRTFBQTZDNzQzN0Q6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpCRUIwMUI5MEFDMDA5OUNBN0M3MzBENTRDNkE5OUY1Ng==	70A1F129E10EE7D31DFE1E1AA6C7437D	BEB01B90AC0099CA7C730D54C6A99F56
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6N0ExQzZGRTkzNTEwMDhCM0Q1MzkxNjZEOTQyMjI3NjI6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTowMDJCMDIxOUI3MzlCODhDOEE4MTM1NTJFRjFFODk0Mg==	7A1C6FE9351008B3D539166D94222762	002B0219B739B88C8A813552EF1E8942
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6REYyNkFFNDQyMTEwREIwMjgxREFENDU0NTQzNkI3MjA6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpGRjIxRTIyNjZCMzZFOTJGM0MyOThDOUMzNDk3QkRBRA==	DF26AE442110DB0281DAD4545436B720	FF21E2266B36E92F3C298C9C3497BDAD
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6QzY4MjNEMkI3QUZBMDY0Q0U3NzQ3OTVFMDFENjIyOEI6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTowN0M2M0JBMDhCMEM0M0UxOENDOTY0RjBCNkY0RTI0RA==	C6823D2B7AFA064CE774795E01D6228B	07C63BA08B0C43E18CC964F0B6F4E24D
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6MDI0NDNERTA4MDdEODAxRDY2MTQ5NUQ5RUZCOEQ4MzY6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpBQTQ4OTk5MzAyREZDOEVDODg3OTU3MjYyM0MwMDg1QQ==	02443DE0807D801D661495D9EFB8D836	AA48999302DFC8EC8879572623C0085A
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6RDVCOTA5MEUzQjZBMTBEQkRDMjQzRUQxNEVGMjk0QkY6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTo3RUNFRDRCRThDRjQ3NjYxRDVEM0U4Njc0NTg2QTlCMQ==	D5B9090E3B6A10DBDC243ED14EF294BF	7ECED4BE8CF47661D5D3E8674586A9B1
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6MDQyNzNGQzY0NDM2REE1MjM4NjVDRjg0OUU1RjdDQzk6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpDQkFCNDBCRUYyNjQ2RDIwRjY2NTQyRTlEMTBEN0ZDQQ==	04273FC64436DA523865CF849E5F7CC9	CBAB40BEF2646D20F66542E9D10D7FCA
+urn:base64:QW50ZW5uYUNhcGFiaWxpdHk6NTgzNUY3N0JFOUQ0RTEwMjMxNkJENTkxOTVGNjM3MEI6UkVBTElTRURfQlk6QW50ZW5uYU1vZHVsZTpDQkFCNDBCRUYyNjQ2RDIwRjY2NTQyRTlEMTBEN0ZDQQ==	5835F77BE9D4E102316BD59195F6370B	CBAB40BEF2646D20F66542E9D10D7FCA
+\.
+
diff --git a/teiv/src/test/resources/data/data.sql b/teiv/src/test/resources/data/data.sql
new file mode 100644
index 0000000..a9dd18a
--- /dev/null
+++ b/teiv/src/test/resources/data/data.sql
@@ -0,0 +1,217 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+COPY ties_data."CloudNativeSystem" ("id", "name", "REL_FK_deployed-managedElement" )  FROM stdin;
+\.
+
+COPY ties_data."003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F" ("id", "name", "REL_FK_C2F5EC33C0760F653CE7263A49C0B697FCA2D542" )  FROM stdin;
+C4E311A55666726FD9FE25CA572AFAF9	Example Cloud Native System/1	\N
+\.
+
+COPY ties_data."ManagedElement" ("id", "cmId", "fdn", "REL_FK_deployed-as-cloudNativeSystem", "REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM" )  FROM stdin;
+DA1039E77700A9EEFFA280049ECE9227	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=9	\N	\N
+6F02817AFE4D53237DB235EBE5378613	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=10	\N	\N
+27500EB447000209EE6E3CA1B31FBA92	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=13	\N	\N
+06222D277EE209CD8DCA1FE61CE752E6	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=14	\N	\N
+DC86CA7724113F4C0DF42BFEAA17FD53	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=16	\N	\N
+8D51EFC759166044DACBCA63C4EDFC51	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=19	\N	\N
+E64371CD4D12ED0CED200DD3A7591784	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=28	\N	\N
+\.
+
+COPY ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" ("id", "cmId", "fdn", "REL_FK_26958E3A529C4C8B68A29FDA906F8CD290F66078", "REL_ID_B7945BFD83380F3E12CF99F2B0F838F364027F92" )  FROM stdin;
+45EF31D8A1FD624D7276390A1215BFC3	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=1	C4E311A55666726FD9FE25CA572AFAF9	urn:base64:TWFuYWdlZEVsZW1lbnQ6NDVFRjMxRDhBMUZENjI0RDcyNzYzOTBBMTIxNUJGQzM6REVQTE9ZRURfQVM6Q2xvdWROYXRpdmVTeXN0ZW06QzRFMzExQTU1NjY2NzI2RkQ5RkUyNUNBNTcyQUZBRjk=
+DA1039E77700A9EEFFA280049ECE9227	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=9	\N	\N
+6F02817AFE4D53237DB235EBE5378613	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=10	\N	\N
+27500EB447000209EE6E3CA1B31FBA92	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=13	\N	\N
+06222D277EE209CD8DCA1FE61CE752E6	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=14	\N	\N
+DC86CA7724113F4C0DF42BFEAA17FD53	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=16	\N	\N
+8D51EFC759166044DACBCA63C4EDFC51	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=19	\N	\N
+E64371CD4D12ED0CED200DD3A7591784	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/ManagedElement=28	\N	\N
+\.
+
+COPY ties_data."CloudSite" ("id", "geo-location", "name" )  FROM stdin;
+16EE17AE89DF11B69E94B3F6827C2C0E	POINT(59.4019881 17.9419888)	ORAN
+\.
+
+COPY ties_data."NodeCluster" ("id", "name", "REL_FK_located-at-cloudSite", "REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE" )  FROM stdin;
+015C2DDBD7AC722B34ED6A20EDEEB9C3	Example NodeCluster/45	16EE17AE89DF11B69E94B3F6827C2C0E	urn:base64:Tm9kZUNsdXN0ZXI6MDE1QzJEREJEN0FDNzIyQjM0RUQ2QTIwRURFRUI5QzM6TE9DQVRFRF9BVDpDbG91ZFNpdGU6MTZFRTE3QUU4OURGMTFCNjlFOTRCM0Y2ODI3QzJDMEU=
+\.
+
+COPY ties_data."Namespace" ("id", "name", "REL_FK_deployed-on-nodeCluster", "REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER" )  FROM stdin;
+1C02E96B2AAE036C7AE404BC38C308E0	Example Namespace/1	\N	\N
+\.
+
+COPY ties_data."78682DB1FFA2533BA45F8E4FAA5596E1A98479FC" ("id", "name" )  FROM stdin;
+1C02E96B2AAE036C7AE404BC38C308E0	Example Namespace/1
+\.
+
+COPY ties_data."CloudNativeApplication" ("id", "name", "REL_FK_realised-managedElement", "REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION", "REL_FK_comprised-by-cloudNativeSystem", "REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION", "REL_FK_deployed-on-namespace", "REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE" )  FROM stdin;
+AD42D90497E93D276215DF6D3B899E17	Cloud Native CUUPApp/8	\N	\N	\N	\N	\N	\N
+719BD5C7CD8A939D76A83DA95DA45C01	Example Cloud App/9	\N	\N	\N	\N	1C02E96B2AAE036C7AE404BC38C308E0	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6MUMwMkU5NkIyQUFFMDM2QzdBRTQwNEJDMzhDMzA4RTA=
+416F31E6EB09055326621F4919D35BFF	Example Cloud App/10	\N	\N	\N	\N	\N	\N
+C549905CF3CC890CE5746C5E10ACF00D	Example Cloud App/19	\N	\N	\N	\N	\N	\N
+\.
+
+COPY ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ("id", "name", "REL_FK_AB87B417CCD05C332DDD0C60F0C6AB41D38B05E5", "REL_ID_FC2F6A5A12917357B548C83F4B0C1AD58FA61413", "REL_FK_8C98B70070BBD11F90F192DDA3ECF6302390E956", "REL_ID_AFBF10D23507AD3B6408947D2A9AF8465BA7B08C" )  FROM stdin;
+AD42D90497E93D276215DF6D3B899E17	Cloud Native CUUPApp/8	\N	\N	\N	\N
+719BD5C7CD8A939D76A83DA95DA45C01	Example Cloud App/9	\N	\N	1C02E96B2AAE036C7AE404BC38C308E0	urn:base64:Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo3MTlCRDVDN0NEOEE5MzlENzZBODNEQTk1REE0NUMwMTpERVBMT1lFRF9PTjpOYW1lc3BhY2U6MUMwMkU5NkIyQUFFMDM2QzdBRTQwNEJDMzhDMzA4RTA=
+416F31E6EB09055326621F4919D35BFF	Example Cloud App/10	6F02817AFE4D53237DB235EBE5378613	urn:base64:TWFuYWdlZEVsZW1lbnQ6NkYwMjgxN0FGRTRENTMyMzdEQjIzNUVCRTUzNzg2MTM6UkVBTElTRURfQlk6Q2xvdWROYXRpdmVBcHBsaWNhdGlvbjo0MTZGMzFFNkVCMDkwNTUzMjY2MjFGNDkxOUQzNUJGRg==	\N	\N
+C549905CF3CC890CE5746C5E10ACF00D	Example Cloud App/19	\N	\N	\N	\N
+\.
+
+COPY ties_data."Sector" ("id", "geo-location", "sectorId", "azimuth" )  FROM stdin;
+2F445AA5744FA3D230FD6838531F1407	POINT(59.4019881 17.9419888)	1	1
+F5128C172A70C4FCD4739650B06DE9E2	POINT(59.4019881 17.9419888)	2	2
+ADB1BAAC878C0BEEFE3175C60F44BB1D	POINT(59.4019881 17.9419888)	4	3
+\.
+
+COPY ties_data."GNBCUCPFunction" ("id", "pLMNId", "cmId", "fdn", "gNBCUName", "gNBIdLength", "gNBId", "REL_FK_managed-by-managedElement", "REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION" )  FROM stdin;
+\.
+
+COPY ties_data."GNBCUUPFunction" ("id", "cmId", "fdn", "gNBIdLength", "gNBId", "REL_FK_managed-by-managedElement", "REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION" )  FROM stdin;
+BFEEAC2CE60273CB0A78319CC201A7FE	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBCUUPFunction=8	1	8	E64371CD4D12ED0CED200DD3A7591784	urn:base64:TWFuYWdlZEVsZW1lbnQ6RTY0MzcxQ0Q0RDEyRUQwQ0VEMjAwREQzQTc1OTE3ODQ6TUFOQUdFUzpHTkJDVVVQRnVuY3Rpb246QkZFRUFDMkNFNjAyNzNDQjBBNzgzMTlDQzIwMUE3RkU=
+\.
+
+COPY ties_data."GNBDUFunction" ("id", "gNBDUId", "cmId", "fdn", "dUpLMNId", "gNBIdLength", "gNBId", "REL_FK_managed-by-managedElement", "REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION", "CD_sourceIds" )  FROM stdin;
+D3215E08570BE58339C7463626B50E37	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=9	{"mcc":"456","mnc":"82"}	1	9	DA1039E77700A9EEFFA280049ECE9227	urn:base64:TWFuYWdlZEVsZW1lbnQ6REExMDM5RTc3NzAwQTlFRUZGQTI4MDA0OUVDRTkyMjc6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOkQzMjE1RTA4NTcwQkU1ODMzOUM3NDYzNjI2QjUwRTM3	[]
+1050570EBB1315E1AE7A9FD5E1400A00	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=10	{"mcc":"456","mnc":"82"}	2	10	6F02817AFE4D53237DB235EBE5378613	urn:base64:TWFuYWdlZEVsZW1lbnQ6NkYwMjgxN0FGRTRENTMyMzdEQjIzNUVCRTUzNzg2MTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjEwNTA1NzBFQkIxMzE1RTFBRTdBOUZENUUxNDAwQTAw	[]
+25E690E22BDA90B9C4FEE1F083CBA597	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=13	{"mcc":"456","mnc":"82"}	2	13	27500EB447000209EE6E3CA1B31FBA92	urn:base64:TWFuYWdlZEVsZW1lbnQ6Mjc1MDBFQjQ0NzAwMDIwOUVFNkUzQ0ExQjMxRkJBOTI6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjI1RTY5MEUyMkJEQTkwQjlDNEZFRTFGMDgzQ0JBNTk3	[]
+5A3085C3400C3096E2ED2321452766B1	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=14	{"mcc":"456","mnc":"82"}	2	14	06222D277EE209CD8DCA1FE61CE752E6	urn:base64:TWFuYWdlZEVsZW1lbnQ6MDYyMjJEMjc3RUUyMDlDRDhEQ0ExRkU2MUNFNzUyRTY6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjVBMzA4NUMzNDAwQzMwOTZFMkVEMjMyMTQ1Mjc2NkIx	[]
+5A548EA9D166341776CA0695837E55D8	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=16	{"mcc":"456","mnc":"82"}	2	16	DC86CA7724113F4C0DF42BFEAA17FD53	urn:base64:TWFuYWdlZEVsZW1lbnQ6REM4NkNBNzcyNDExM0Y0QzBERjQyQkZFQUExN0ZENTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjVBNTQ4RUE5RDE2NjM0MTc3NkNBMDY5NTgzN0U1NUQ4	["urn:3gpp:dn:/SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=16","urn:cmHandle:/395221E080CCF0FD1924103B15873814"]
+4CFF136200A2DE36205A13559C55DB2A	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=19	{"mcc":"456","mnc":"82"}	2	19	8D51EFC759166044DACBCA63C4EDFC51	urn:base64:TWFuYWdlZEVsZW1lbnQ6OEQ1MUVGQzc1OTE2NjA0NERBQ0JDQTYzQzRFREZDNTE6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjRDRkYxMzYyMDBBMkRFMzYyMDVBMTM1NTlDNTVEQjJB	[]
+\.
+
+COPY ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" ("id", "gNBDUId", "cmId", "3786A6CA64C9422F9E7FC35B7B039F345BBDDA65", "dUpLMNId", "gNBIdLength", "gNBId", "REL_FK_48B14FA5B787C6398AD1DE5EE670AD0D2A2CB36F", "REL_ID_BDE0B6C74D14AC109D29A08D80E92D4D0DCAEB0B" )  FROM stdin;
+D3215E08570BE58339C7463626B50E37	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=9	{"mcc":"456","mnc":"82"}	1	9	DA1039E77700A9EEFFA280049ECE9227	urn:base64:TWFuYWdlZEVsZW1lbnQ6REExMDM5RTc3NzAwQTlFRUZGQTI4MDA0OUVDRTkyMjc6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOkQzMjE1RTA4NTcwQkU1ODMzOUM3NDYzNjI2QjUwRTM3
+1050570EBB1315E1AE7A9FD5E1400A00	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=10	{"mcc":"456","mnc":"82"}	2	10	6F02817AFE4D53237DB235EBE5378613	urn:base64:TWFuYWdlZEVsZW1lbnQ6NkYwMjgxN0FGRTRENTMyMzdEQjIzNUVCRTUzNzg2MTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjEwNTA1NzBFQkIxMzE1RTFBRTdBOUZENUUxNDAwQTAw
+25E690E22BDA90B9C4FEE1F083CBA597	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=13	{"mcc":"456","mnc":"82"}	2	13	27500EB447000209EE6E3CA1B31FBA92	urn:base64:TWFuYWdlZEVsZW1lbnQ6Mjc1MDBFQjQ0NzAwMDIwOUVFNkUzQ0ExQjMxRkJBOTI6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjI1RTY5MEUyMkJEQTkwQjlDNEZFRTFGMDgzQ0JBNTk3
+5A3085C3400C3096E2ED2321452766B1	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=14	{"mcc":"456","mnc":"82"}	2	14	06222D277EE209CD8DCA1FE61CE752E6	urn:base64:TWFuYWdlZEVsZW1lbnQ6MDYyMjJEMjc3RUUyMDlDRDhEQ0ExRkU2MUNFNzUyRTY6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjVBMzA4NUMzNDAwQzMwOTZFMkVEMjMyMTQ1Mjc2NkIx
+5A548EA9D166341776CA0695837E55D8	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=16	{"mcc":"456","mnc":"82"}	2	16	DC86CA7724113F4C0DF42BFEAA17FD53	urn:base64:TWFuYWdlZEVsZW1lbnQ6REM4NkNBNzcyNDExM0Y0QzBERjQyQkZFQUExN0ZENTM6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjVBNTQ4RUE5RDE2NjM0MTc3NkNBMDY5NTgzN0U1NUQ4
+4CFF136200A2DE36205A13559C55DB2A	\N	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/GNBDUFunction=19	{"mcc":"456","mnc":"82"}	2	19	8D51EFC759166044DACBCA63C4EDFC51	urn:base64:TWFuYWdlZEVsZW1lbnQ6OEQ1MUVGQzc1OTE2NjA0NERBQ0JDQTYzQzRFREZDNTE6TUFOQUdFUzpHTkJEVUZ1bmN0aW9uOjRDRkYxMzYyMDBBMkRFMzYyMDVBMTM1NTlDNTVEQjJB
+\.
+
+COPY ties_data."AntennaCapability" ("id", "nRFqBands", "eUtranFqBands", "cmId", "fdn", "geranFqBands", "REL_FK_used-by-lteSectorCarrier" )  FROM stdin;
+5835F77BE9D4E102316BD59195F6370B	["123","456","789"]	["123","4564","789"]	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=1	["123","456","789"]	\N
+A77B237A541B2D3225B4B61D3098E4AA	["123","456","789"]	["123","4564","789"]	\N	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaCapability=3	["123","456","789"]	\N
+\.
+
+COPY ties_data."NRCellDU" ("id", "nRPCI", "cmId", "cellLocalId", "fdn", "nCI", "nRTAC", "REL_FK_grouped-by-sector", "REL_ID_SECTOR_GROUPS_NRCELLDU", "REL_FK_provided-by-gnbduFunction", "REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU" )  FROM stdin;
+98C3A4591A37718E1330F0294E23B62A	789	\N	1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=1	1	456	F5128C172A70C4FCD4739650B06DE9E2	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==	D3215E08570BE58339C7463626B50E37	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==
+F9546E82313AC1D5E690DCD7BE55606F	789	\N	2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=2	2	456	F5128C172A70C4FCD4739650B06DE9E2	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpGOTU0NkU4MjMxM0FDMUQ1RTY5MERDRDdCRTU1NjA2Rg==	D3215E08570BE58339C7463626B50E37	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpGOTU0NkU4MjMxM0FDMUQ1RTY5MERDRDdCRTU1NjA2Rg==
+B480427E8A0C0B8D994E437784BB382F	789	\N	3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=3	3	456	F5128C172A70C4FCD4739650B06DE9E2	urn:base64:U2VjdG9yOkY1MTI4QzE3MkE3MEM0RkNENDczOTY1MEIwNkRFOUUyOkdST1VQUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==	D3215E08570BE58339C7463626B50E37	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==
+76E9F605D4F37330BF0B505E94F64F11	789	\N	91	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=91	91	456	\N	\N	4CFF136200A2DE36205A13559C55DB2A	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo3NkU5RjYwNUQ0RjM3MzMwQkYwQjUwNUU5NEY2NEYxMQ==
+67A1BDA10B5AF43028D07C7BE5CB1AE2	789	\N	92	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=92	92	456	\N	\N	4CFF136200A2DE36205A13559C55DB2A	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo2N0ExQkRBMTBCNUFGNDMwMjhEMDdDN0JFNUNCMUFFMg==
+B3B0A1939EFCA654A37005B6A7F24BD7	789	\N	93	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=93	93	456	\N	\N	4CFF136200A2DE36205A13559C55DB2A	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpCM0IwQTE5MzlFRkNBNjU0QTM3MDA1QjZBN0YyNEJENw==
+\.
+
+COPY ties_data."50AC08AB775076E74FC4891954F1D99D3D293ACC" ("id", "nRPCI", "cmId", "020335B0F627C169E24167748C38FE756FB34AE2", "fdn", "nCI", "nRTAC", "REL_FK_609963BFEE15FF824280FBE201313C3CDACDDDCE", "REL_ID_040FC8B06B420BA5708AF4798102D1E65FB4DC61" )  FROM stdin;
+98C3A4591A37718E1330F0294E23B62A	789	\N	1	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=1	1	456	D3215E08570BE58339C7463626B50E37	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTo5OEMzQTQ1OTFBMzc3MThFMTMzMEYwMjk0RTIzQjYyQQ==
+F9546E82313AC1D5E690DCD7BE55606F	789	\N	2	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=2	2	456	D3215E08570BE58339C7463626B50E37	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpGOTU0NkU4MjMxM0FDMUQ1RTY5MERDRDdCRTU1NjA2Rg==
+B480427E8A0C0B8D994E437784BB382F	789	\N	3	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=3	3	456	D3215E08570BE58339C7463626B50E37	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUkNlbGxEVTpCNDgwNDI3RThBMEMwQjhEOTk0RTQzNzc4NEJCMzgyRg==
+76E9F605D4F37330BF0B505E94F64F11	789	\N	91	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=91	91	456	4CFF136200A2DE36205A13559C55DB2A	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo3NkU5RjYwNUQ0RjM3MzMwQkYwQjUwNUU5NEY2NEYxMQ==
+67A1BDA10B5AF43028D07C7BE5CB1AE2	789	\N	92	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=92	92	456	4CFF136200A2DE36205A13559C55DB2A	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTo2N0ExQkRBMTBCNUFGNDMwMjhEMDdDN0JFNUNCMUFFMg==
+B3B0A1939EFCA654A37005B6A7F24BD7	789	\N	93	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=93	93	456	4CFF136200A2DE36205A13559C55DB2A	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpCM0IwQTE5MzlFRkNBNjU0QTM3MDA1QjZBN0YyNEJENw==
+F26F279E91D0941DB4F646E707EA403A	789	\N	94	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRCellDU=94	94	456	4CFF136200A2DE36205A13559C55DB2A	urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpQUk9WSURFUzpOUkNlbGxEVTpGMjZGMjc5RTkxRDA5NDFEQjRGNjQ2RTcwN0VBNDAzQQ==
+\.
+
+COPY ties_data."NRSectorCarrier" ("id", "fdn", "frequencyUL", "cmId", "essScLocalId", "arfcnUL", "frequencyDL", "arfcnDL", "REL_FK_used-by-nrCellDu", "REL_ID_NRCELLDU_USES_NRSECTORCARRIER", "REL_FK_provided-by-gnbduFunction", "REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER", "REL_FK_used-antennaCapability", "REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY" )  FROM stdin;
+E49D942C16E0364E1E0788138916D70C	SubNetwork=SolarSyst3em/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/NRSectorCarrier=3	20	\N	20	3	20	20	B480427E8A0C0B8D994E437784BB382F	urn:base64:TlJDZWxsRFU6QjQ4MDQyN0U4QTBDMEI4RDk5NEU0Mzc3ODRCQjM4MkY6VVNFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM=	D3215E08570BE58339C7463626B50E37	urn:base64:R05CRFVGdW5jdGlvbjpEMzIxNUUwODU3MEJFNTgzMzlDNzQ2MzYyNkI1MEUzNzpQUk9WSURFUzpOUlNlY3RvckNhcnJpZXI6RTQ5RDk0MkMxNkUwMzY0RTFFMDc4ODEzODkxNkQ3MEM=	A77B237A541B2D3225B4B61D3098E4AA	urn:base64:TlJTZWN0b3JDYXJyaWVyOkU0OUQ5NDJDMTZFMDM2NEUxRTA3ODgxMzg5MTZENzBDOlVTRVM6QW50ZW5uYUNhcGFiaWxpdHk6QTc3QjIzN0E1NDFCMkQzMjI1QjRCNjFEMzA5OEU0QUE=
+\.
+
+COPY ties_data."AntennaModule" ("id", "mechanicalAntennaTilt", "fdn", "cmId", "antennaModelNumber", "totalTilt", "mechanicalAntennaBearing", "positionWithinSector", "electricalAntennaTilt", "REL_FK_grouped-by-sector", "REL_ID_SECTOR_GROUPS_ANTENNAMODULE", "REL_FK_installed-at-site", "REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE" )  FROM stdin;
+278A05C67D47D117C2DC5BDF5E00AE70	123	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=1	\N	['123-abc']	45	123	['123', '456', '789']	1	ADB1BAAC878C0BEEFE3175C60F44BB1D	urn:base64:U2VjdG9yOkFEQjFCQUFDODc4QzBCRUVGRTMxNzVDNjBGNDRCQjFEOkdST1VQUzpBbnRlbm5hTW9kdWxlOjI3OEEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcw	\N	\N
+279A05C67D47D117C2DC5BDF5E00AE70	456	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModule=2	\N	['123-xyz']	45	123	['123', '456', '789']	1	\N	\N	\N	\N
+\.
+
+COPY ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" ("id", "fdn" )  FROM stdin;
+378A05C67D47D117C2DC5BDF5E00AE70	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=11
+379A05C67D47D117C2DC5BDF5E00AE70	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=12
+478A05C67D47D117C2DC5BDF5E00AE70	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=21
+479A05C67D47D117C2DC5BDF5E00AE70	SubNetwork=SolarSystem/SubNetwork=Earth/SubNetwork=Europe/SubNetwork=Hungary/AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee=22
+\.
+
+COPY ties_data."ENodeBFunction" ("id", "eNBId", "cmId", "eNodeBPlmnId", "fdn", "REL_FK_managed-by-managedElement", "REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION", "REL_FK_realised-by-physicalNetworkAppliance", "REL_ID_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE" )  FROM stdin;
+\.
+
+COPY ties_data."EUtranCell" ("id", "cellId", "cmId", "earfcn", "duplexType", "tac", "fdn", "earfcndl", "earfcnul", "REL_FK_grouped-by-sector", "REL_ID_SECTOR_GROUPS_EUTRANCELL", "REL_FK_provided-by-enodebFunction", "REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL" )  FROM stdin;
+\.
+
+COPY ties_data."LTESectorCarrier" ("id", "fdn", "cmId", "sectorCarrierType", "essScLocalId", "REL_FK_provided-by-enodebFunction", "REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER", "REL_FK_used-antennaCapability", "REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY", "REL_FK_used-by-euTranCell", "REL_ID_EUTRANCELL_USES_LTESECTORCARRIER" )  FROM stdin;
+\.
+
+COPY ties_data."NRCellCU" ("id", "fdn", "cmId", "plmnId", "nCI", "cellLocalId", "nRTAC", "REL_FK_provided-by-gnbcucpFunction", "REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU" )  FROM stdin;
+\.
+
+COPY ties_data."PhysicalNetworkAppliance" ("id", "geo-location", "cmId", "name", "type", "REL_FK_installed-at-site", "REL_ID_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE" )  FROM stdin;
+\.
+
+COPY ties_data."Site" ("id", "geo-location", "cmId", "name" )  FROM stdin;
+\.
+
+COPY ties_data."GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ("id", "aSide_GNBCUCPFunction", "bSide_CloudNativeApplication" )  FROM stdin;
+\.
+
+COPY ties_data."GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ("id", "aSide_GNBCUUPFunction", "bSide_CloudNativeApplication" )  FROM stdin;
+urn:base64:R05CQ1VVUEZ1bmN0aW9uOkJGRUVBQzJDRTYwMjczQ0IwQTc4MzE5Q0MyMDFBN0ZFOlJFQUxJU0VEX0JZOkNsb3VkTmF0aXZlQXBwbGljYXRpb246QUQ0MkQ5MDQ5N0U5M0QyNzYyMTVERjZEM0I4OTlFMTc=	BFEEAC2CE60273CB0A78319CC201A7FE	AD42D90497E93D276215DF6D3B899E17
+\.
+
+COPY ties_data."GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ("id", "aSide_GNBDUFunction", "bSide_CloudNativeApplication" )  FROM stdin;
+urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE	4CFF136200A2DE36205A13559C55DB2A	C549905CF3CC890CE5746C5E10ACF00D
+\.
+
+COPY ties_data."AC201B3A42917A9A983A1E3683B67C38C50630FC" ("id", "aSide_B0FD0521695A211BFF76F413A31F28CBA32E57ED", "bSide_84EF1134719BB6FCF33A94FF770311FC722BCF41" )  FROM stdin;
+urn:base64:R05CRFVGdW5jdGlvbjo0Q0ZGMTM2MjAwQTJERTM2MjA1QTEzNTU5QzU1REIyQTpSRUFMSVNFRF9CWTpDbG91ZE5hdGl2ZUFwcGxpY2F0aW9uOkM1NDk5MDVDRjNDQzg5MENFNTc0NkM1RTEwQUNGMDBE	4CFF136200A2DE36205A13559C55DB2A	C549905CF3CC890CE5746C5E10ACF00D
+\.
+
+COPY ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE" ("id", "aSide_AntennaCapability", "bSide_AntennaModule" )  FROM stdin;
+\.
+
+COPY ties_data."ANTENNAMODULE_REALISED_BY_ANTENNAMODULE" ("id", "aSide_AntennaModule", "bSide_AntennaModule" )  FROM stdin;
+urn:base64:QW50ZW5uYU1vZHVsZToyNzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpSRUFMSVNFRF9CWTpBbnRlbm5hTW9kdWxlOjI3OEEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==	278A05C67D47D117C2DC5BDF5E00AE70	279A05C67D47D117C2DC5BDF5E00AE70
+\.
+
+COPY ties_data."B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6" ("id", "aSide_2A2D3374BF907674FA1905478E30ACB8882DC03C", "bSide_EE6DD4A2CFD743779BBCBFC18FC296EF6D72EB1E" )  FROM stdin;
+urn:base64:QW50ZW5uYU1vZHVsZTozNzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpSRUFMSVNFRF9CWTpBbnRlbm5hTW9kdWxlOjM3OUEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==	378A05C67D47D117C2DC5BDF5E00AE70	379A05C67D47D117C2DC5BDF5E00AE70
+\.
+
+COPY ties_data."C35AE10CFF62DEDC5E3FC3C40E47373B10800818" ("id", "aSide_2A2D3374BF907674FA1905478E30ACB8882DC03C", "bSide_EE6DD4A2CFD743779BBCBFC18FC296EF6D72EB1E" )  FROM stdin;
+urn:base64:QW50ZW5uYU1vZHVsZTo0NzhBMDVDNjdENDdEMTE3QzJEQzVCREY1RTAwQUU3MDpERVBMT1lFRF9CWTpBbnRlbm5hTW9kdWxlOjQ3OUEwNUM2N0Q0N0QxMTdDMkRDNUJERjVFMDBBRTcwCg==	478A05C67D47D117C2DC5BDF5E00AE70	479A05C67D47D117C2DC5BDF5E00AE70
+\.
+
+COPY ties_model.module_reference("name", "includedModules", "content", "ownerAppId", "status") FROM stdin;
+gnbdu-function-model	[]	Z25kYnUtZnVuY3Rpb24tbW9kZWwgeWFuZyBtb2RlbCBmaWxlCg==	ADDITIONAL_MODULE	IN_USAGE
+gnbcucp-gnbcuup-model	[]	Z25iY3VjcC1nbmJjdXVwLW1vZGVsIHlhbmcgbW9kZWwgZmlsZQo=	ADDITIONAL_MODULE	IN_USAGE
+gnbcucp-gnbcuup-old-model	[]	Z25iY3VjcC1nbmJjdXVwLW1vZGVsIHlhbmcgbW9kZWwgZmlsZQo=	ADDITIONAL_MODULE	DEPRECATED
+\.
+
+COPY ties_model.decorators ("name", "dataType", "moduleReferenceName" )  FROM stdin;
+gnbdu-function-model:location	TEXT	gnbdu-function-model
+gnbcucp-gnbcuup-model:metadata	JSONB	gnbcucp-gnbcuup-model
+gnbcucp-gnbcuup-old-model:metadata	JSONB	gnbcucp-gnbcuup-old-model
+\.
+
+COPY ties_model.classifiers ("name", "moduleReferenceName" )  FROM stdin;
+gnbdu-function-model:Rural	gnbdu-function-model
+gnbcucp-gnbcuup-model:Weekend	gnbcucp-gnbcuup-model
+gnbcucp-gnbcuup-old-model:Weekend	gnbcucp-gnbcuup-old-model
+\.
+
+;
\ No newline at end of file
diff --git a/teiv/src/test/resources/pgsqlschema/00_init-oran-smo-teiv-data.sql b/teiv/src/test/resources/pgsqlschema/00_init-oran-smo-teiv-data.sql
new file mode 100644
index 0000000..094be5e
--- /dev/null
+++ b/teiv/src/test/resources/pgsqlschema/00_init-oran-smo-teiv-data.sql
@@ -0,0 +1,1354 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+CREATE EXTENSION IF NOT EXISTS postgis;
+CREATE EXTENSION IF NOT EXISTS postgis_topology;
+
+GRANT USAGE ON SCHEMA topology to :pguser;
+GRANT SELECT ON ALL SEQUENCES IN SCHEMA topology TO :pguser;
+GRANT SELECT ON ALL TABLES IN SCHEMA topology TO :pguser;
+
+CREATE SCHEMA IF NOT EXISTS ties_data;
+ALTER SCHEMA ties_data OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+-- Function to create CONSTRAINT only if it does not exists
+CREATE OR REPLACE FUNCTION ties_data.create_constraint_if_not_exists (
+	t_name TEXT, c_name TEXT, constraint_sql TEXT
+)
+RETURNS void AS
+$$
+BEGIN
+	IF NOT EXISTS (SELECT constraint_name FROM information_schema.table_constraints WHERE table_name = t_name AND constraint_name = c_name) THEN
+		EXECUTE constraint_sql;
+	END IF;
+END;
+$$ language 'plpgsql';
+
+CREATE TABLE IF NOT EXISTS ties_data."003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"name"			TEXT,
+	"REL_FK_C2F5EC33C0760F653CE7263A49C0B697FCA2D542"			VARCHAR(511)
+);
+
+ALTER TABLE ONLY ties_data."003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"fdn"			TEXT,
+	"cmId"			jsonb,
+	"REL_FK_26958E3A529C4C8B68A29FDA906F8CD290F66078"			VARCHAR(511),
+	"REL_ID_B7945BFD83380F3E12CF99F2B0F838F364027F92"			VARCHAR(511),
+	"REL_CD_B7945BFD83380F3E12CF99F2B0F838F364027F92"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" ALTER COLUMN "REL_CD_B7945BFD83380F3E12CF99F2B0F838F364027F92" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"name"			TEXT,
+	"REL_FK_AB87B417CCD05C332DDD0C60F0C6AB41D38B05E5"			VARCHAR(511),
+	"REL_ID_FC2F6A5A12917357B548C83F4B0C1AD58FA61413"			VARCHAR(511),
+	"REL_CD_CEAD4CCE5250E7D3C64801C8FDDC21F1D87BEC0C"			jsonb,
+	"REL_FK_8C98B70070BBD11F90F192DDA3ECF6302390E956"			VARCHAR(511),
+	"REL_ID_AFBF10D23507AD3B6408947D2A9AF8465BA7B08C"			VARCHAR(511),
+	"REL_CD_F7E43E0D0F76D6EFED9AB684B84A69E177F591D2"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ALTER COLUMN "REL_CD_CEAD4CCE5250E7D3C64801C8FDDC21F1D87BEC0C" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ALTER COLUMN "REL_CD_F7E43E0D0F76D6EFED9AB684B84A69E177F591D2" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."50AC08AB775076E74FC4891954F1D99D3D293ACC" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"020335B0F627C169E24167748C38FE756FB34AE2"			BIGINT,
+	"nRTAC"			BIGINT,
+	"nRPCI"			BIGINT,
+	"cmId"			jsonb,
+	"fdn"			TEXT,
+	"nCI"			BIGINT,
+	"REL_FK_609963BFEE15FF824280FBE201313C3CDACDDDCE"			VARCHAR(511),
+	"REL_ID_040FC8B06B420BA5708AF4798102D1E65FB4DC61"			VARCHAR(511),
+	"REL_CD_040FC8B06B420BA5708AF4798102D1E65FB4DC61"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."50AC08AB775076E74FC4891954F1D99D3D293ACC" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."50AC08AB775076E74FC4891954F1D99D3D293ACC" ALTER COLUMN "REL_CD_040FC8B06B420BA5708AF4798102D1E65FB4DC61" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."78682DB1FFA2533BA45F8E4FAA5596E1A98479FC" (
+	"id"			VARCHAR(511),
+	"name"			TEXT,
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."78682DB1FFA2533BA45F8E4FAA5596E1A98479FC" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"gNBDUId"			BIGINT,
+	"cmId"			jsonb,
+	"3786A6CA64C9422F9E7FC35B7B039F345BBDDA65"			TEXT,
+	"gNBIdLength"			BIGINT,
+	"dUpLMNId"			jsonb,
+	"gNBId"			BIGINT,
+	"REL_FK_48B14FA5B787C6398AD1DE5EE670AD0D2A2CB36F"			VARCHAR(511),
+	"REL_ID_BDE0B6C74D14AC109D29A08D80E92D4D0DCAEB0B"			VARCHAR(511),
+	"REL_CD_45E8E8693B1B8928376EAA8995D08AA7B1E483BD"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" ALTER COLUMN "REL_CD_45E8E8693B1B8928376EAA8995D08AA7B1E483BD" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."AC201B3A42917A9A983A1E3683B67C38C50630FC" (
+	"id"			VARCHAR(511),
+	"aSide_B0FD0521695A211BFF76F413A31F28CBA32E57ED"			VARCHAR(511),
+	"bSide_84EF1134719BB6FCF33A94FF770311FC722BCF41"			VARCHAR(511),
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."AC201B3A42917A9A983A1E3683B67C38C50630FC" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaCapability"			VARCHAR(511),
+	"bSide_AntennaModule"			VARCHAR(511),
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."AntennaCapability" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"eUtranFqBands"			jsonb,
+	"fdn"			TEXT,
+	"geranFqBands"			jsonb,
+	"nRFqBands"			jsonb,
+	"cmId"			jsonb,
+	"REL_FK_used-by-lteSectorCarrier"			VARCHAR(511)
+);
+
+ALTER TABLE ONLY ties_data."AntennaCapability" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."AntennaModule" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"totalTilt"			BIGINT,
+	"mechanicalAntennaBearing"			BIGINT,
+	"fdn"			TEXT,
+	"antennaModelNumber"			TEXT,
+	"mechanicalAntennaTilt"			BIGINT,
+	"positionWithinSector"			TEXT,
+	"cmId"			jsonb,
+	"electricalAntennaTilt"			BIGINT,
+	"REL_FK_grouped-by-sector"			VARCHAR(511),
+	"REL_ID_SECTOR_GROUPS_ANTENNAMODULE"			VARCHAR(511),
+	"REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE"			jsonb,
+	"REL_FK_installed-at-site"			VARCHAR(511),
+	"REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE"			VARCHAR(511),
+	"REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."AntennaModule" ALTER COLUMN "REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."ANTENNAMODULE_REALISED_BY_ANTENNAMODULE" (
+	"id"			VARCHAR(511),
+	"aSide_AntennaModule"			VARCHAR(511),
+	"bSide_AntennaModule"			VARCHAR(511),
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ANTENNAMODULE_REALISED_BY_ANTENNAMODULE" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6" (
+	"id"			VARCHAR(511),
+	"aSide_2A2D3374BF907674FA1905478E30ACB8882DC03C"			VARCHAR(511),
+	"bSide_EE6DD4A2CFD743779BBCBFC18FC296EF6D72EB1E"			VARCHAR(511),
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."C35AE10CFF62DEDC5E3FC3C40E47373B10800818" (
+	"id"			VARCHAR(511),
+	"aSide_2A2D3374BF907674FA1905478E30ACB8882DC03C"			VARCHAR(511),
+	"bSide_EE6DD4A2CFD743779BBCBFC18FC296EF6D72EB1E"			VARCHAR(511),
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."C35AE10CFF62DEDC5E3FC3C40E47373B10800818" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."CloudNativeApplication" (
+	"id"			VARCHAR(511),
+	"name"			TEXT,
+	"CD_sourceIds"			jsonb,
+	"REL_FK_realised-managedElement"			VARCHAR(511),
+	"REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION"			VARCHAR(511),
+	"REL_CD_8F561B5FB3CF928F2C4046CE1A7C37A8FE06B9A7"			jsonb,
+	"REL_FK_comprised-by-cloudNativeSystem"			VARCHAR(511),
+	"REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION"			VARCHAR(511),
+	"REL_CD_39262797D0119611B8459ECF46754A074711E485"			jsonb,
+	"REL_FK_deployed-on-namespace"			VARCHAR(511),
+	"REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE"			VARCHAR(511),
+	"REL_CD_sourceIds_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."CloudNativeApplication" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudNativeApplication" ALTER COLUMN "REL_CD_8F561B5FB3CF928F2C4046CE1A7C37A8FE06B9A7" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudNativeApplication" ALTER COLUMN "REL_CD_39262797D0119611B8459ECF46754A074711E485" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."CloudNativeApplication" ALTER COLUMN "REL_CD_sourceIds_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."CloudNativeSystem" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds" jsonb,
+	"name"			TEXT,
+	"REL_FK_deployed-managedElement"			VARCHAR(511)
+);
+
+ALTER TABLE ONLY ties_data."CloudNativeSystem" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."CloudSite" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds" jsonb,
+	"name"			TEXT,
+	"geo-location"			geography
+);
+
+ALTER TABLE ONLY ties_data."CloudSite" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."ENodeBFunction" (
+	"id"			VARCHAR(511),
+	"fdn"			TEXT,
+	"eNBId"			BIGINT,
+	"cmId"			jsonb,
+	"eNodeBPlmnId"			jsonb,
+	"CD_sourceIds"			jsonb,
+	"REL_FK_managed-by-managedElement"			VARCHAR(511),
+	"REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"			VARCHAR(511),
+	"REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION"			jsonb,
+	"REL_FK_realised-by-physicalNetworkAppliance"			VARCHAR(511),
+	"REL_ID_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE"			VARCHAR(511),
+	"REL_CD_556274C475BA56EE4DEFB691F9037C869223A124"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ENodeBFunction" ALTER COLUMN "REL_CD_556274C475BA56EE4DEFB691F9037C869223A124" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."EUtranCell" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"     jsonb,
+	"earfcn"			BIGINT,
+	"earfcndl"			BIGINT,
+	"duplexType"			TEXT,
+	"fdn"			TEXT,
+	"tac"			BIGINT,
+	"earfcnul"			BIGINT,
+	"cmId"			jsonb,
+	"cellId"			BIGINT,
+	"REL_FK_grouped-by-sector"			VARCHAR(511),
+	"REL_ID_SECTOR_GROUPS_EUTRANCELL"			VARCHAR(511),
+	"REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL"			jsonb,
+	"REL_FK_provided-by-enodebFunction"			VARCHAR(511),
+	"REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL"			VARCHAR(511),
+	"REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."EUtranCell" ALTER COLUMN "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" (
+	"id"			VARCHAR(511),
+	"aSide_GNBCUCPFunction"			VARCHAR(511),
+	"bSide_CloudNativeApplication"			VARCHAR(511),
+	"CD_sourceIds"         jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBCUCPFunction" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"     jsonb,
+	"fdn"			TEXT,
+	"pLMNId"			jsonb,
+	"gNBCUName"			TEXT,
+	"gNBId"			BIGINT,
+	"cmId"			jsonb,
+	"gNBIdLength"			BIGINT,
+	"REL_FK_managed-by-managedElement"			VARCHAR(511),
+	"REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION"			VARCHAR(511),
+	"REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUCPFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" (
+	"id"			VARCHAR(511),
+	"aSide_GNBCUUPFunction"			VARCHAR(511),
+	"bSide_CloudNativeApplication"			VARCHAR(511),
+	"CD_sourceIds"     jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBCUUPFunction" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"     jsonb,
+	"gNBId"			BIGINT,
+	"fdn"			TEXT,
+	"cmId"			jsonb,
+	"gNBIdLength"			BIGINT,
+	"REL_FK_managed-by-managedElement"			VARCHAR(511),
+	"REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION"			VARCHAR(511),
+	"REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBCUUPFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" (
+	"id"			VARCHAR(511),
+	"aSide_GNBDUFunction"			VARCHAR(511),
+	"bSide_CloudNativeApplication"			VARCHAR(511),
+	"CD_sourceIds"     jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."GNBDUFunction" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds" jsonb,
+	"fdn"			TEXT,
+	"gNBId"			BIGINT,
+	"dUpLMNId"			jsonb,
+	"gNBDUId"			BIGINT,
+	"cmId"			jsonb,
+	"gNBIdLength"			BIGINT,
+	"REL_FK_managed-by-managedElement"			VARCHAR(511),
+	"REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION"			VARCHAR(511),
+	"REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION"       jsonb
+);
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."GNBDUFunction" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."LTESectorCarrier" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"     jsonb,
+	"sectorCarrierType"			TEXT,
+	"essScLocalId"			BIGINT,
+	"fdn"			TEXT,
+	"cmId"			jsonb,
+	"REL_FK_provided-by-enodebFunction"			VARCHAR(511),
+	"REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"			VARCHAR(511),
+	"REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER"			jsonb,
+	"REL_FK_used-antennaCapability"			VARCHAR(511),
+	"REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY"			VARCHAR(511),
+	"REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY"			jsonb,
+	"REL_FK_used-by-euTranCell"			VARCHAR(511),
+	"REL_ID_EUTRANCELL_USES_LTESECTORCARRIER"			VARCHAR(511),
+	"REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."LTESectorCarrier" ALTER COLUMN "REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."ManagedElement" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"     jsonb,
+	"fdn"			TEXT,
+	"cmId"			jsonb,
+	"REL_FK_deployed-as-cloudNativeSystem"			VARCHAR(511),
+	"REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"			VARCHAR(511),
+	"REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."ManagedElement" ALTER COLUMN "REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."NRCellCU" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"nCI"			BIGINT,
+	"plmnId"			jsonb,
+	"fdn"			TEXT,
+	"nRTAC"			BIGINT,
+	"cellLocalId"			BIGINT,
+	"cmId"			jsonb,
+	"REL_FK_provided-by-gnbcucpFunction"			VARCHAR(511),
+	"REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU"			VARCHAR(511),
+	"REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellCU" ALTER COLUMN "REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."NRCellDU" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"nRTAC"			BIGINT,
+	"fdn"			TEXT,
+	"nRPCI"			BIGINT,
+	"nCI"			BIGINT,
+	"cellLocalId"			BIGINT,
+	"cmId"			jsonb,
+	"REL_FK_grouped-by-sector"			VARCHAR(511),
+	"REL_ID_SECTOR_GROUPS_NRCELLDU"			VARCHAR(511),
+	"REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU"			jsonb,
+	"REL_FK_provided-by-gnbduFunction"			VARCHAR(511),
+	"REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU"			VARCHAR(511),
+	"REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRCellDU" ALTER COLUMN "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."NRSectorCarrier" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"frequencyDL"			BIGINT,
+	"arfcnDL"			BIGINT,
+	"fdn"			TEXT,
+	"essScLocalId"			BIGINT,
+	"frequencyUL"			BIGINT,
+	"cmId"			jsonb,
+	"arfcnUL"			BIGINT,
+	"REL_FK_used-by-nrCellDu"			VARCHAR(511),
+	"REL_ID_NRCELLDU_USES_NRSECTORCARRIER"			VARCHAR(511),
+	"REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER"			jsonb,
+	"REL_FK_provided-by-gnbduFunction"			VARCHAR(511),
+	"REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER"			VARCHAR(511),
+	"REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER"			jsonb,
+	"REL_FK_used-antennaCapability"			VARCHAR(511),
+	"REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY"			VARCHAR(511),
+	"REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NRSectorCarrier" ALTER COLUMN "REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."Namespace" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"name"			TEXT,
+	"REL_FK_deployed-on-nodeCluster"			VARCHAR(511),
+	"REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER"			VARCHAR(511),
+	"REL_CD_sourceIds_NAMESPACE_DEPLOYED_ON_NODECLUSTER"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."Namespace" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."Namespace" ALTER COLUMN "REL_CD_sourceIds_NAMESPACE_DEPLOYED_ON_NODECLUSTER" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."NodeCluster" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"name"			TEXT,
+	"REL_FK_located-at-cloudSite"			VARCHAR(511),
+	"REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE"			VARCHAR(511),
+	"REL_CD_sourceIds_NODECLUSTER_LOCATED_AT_CLOUDSITE"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."NodeCluster" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."NodeCluster" ALTER COLUMN "REL_CD_sourceIds_NODECLUSTER_LOCATED_AT_CLOUDSITE" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."PhysicalNetworkAppliance" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"geo-location"			geography,
+	"name"			TEXT,
+	"cmId"			jsonb,
+	"type"			TEXT,
+	"REL_FK_installed-at-site"			VARCHAR(511),
+	"REL_ID_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE"			VARCHAR(511),
+	"REL_CD_sourceIds_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."PhysicalNetworkAppliance" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."PhysicalNetworkAppliance" ALTER COLUMN "REL_CD_sourceIds_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE" SET DEFAULT '[]';
+
+
+CREATE TABLE IF NOT EXISTS ties_data."Sector" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"azimuth"			DECIMAL,
+	"geo-location"			geography,
+	"sectorId"			BIGINT
+);
+
+ALTER TABLE ONLY ties_data."Sector" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."Site" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"name"			TEXT,
+	"geo-location"			geography,
+	"cmId"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."Site" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."TESTENTITYA_GROUPS_TESTENTITYB" (
+	"id"			VARCHAR(511),
+	"aSide_TestEntityA"			VARCHAR(511),
+	"bSide_TestEntityB"			VARCHAR(511),
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."TESTENTITYA_GROUPS_TESTENTITYB" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."TESTENTITYA_PROVIDES_TESTENTITYB" (
+	"id"			VARCHAR(511),
+	"aSide_TestEntityA"			VARCHAR(511),
+	"bSide_TestEntityB"			VARCHAR(511),
+	"CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."TESTENTITYA_PROVIDES_TESTENTITYB" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."TestEntityA" (
+	"id"			VARCHAR(511),
+	"CD_sourceIds"			jsonb,
+	"attribute1"			TEXT
+);
+
+ALTER TABLE ONLY ties_data."TestEntityA" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."TestEntityB" (
+	"id"			VARCHAR(511),
+    "CD_sourceIds"			jsonb,
+	"attribute1"			TEXT,
+	"REL_FK_used-by-testEntityA"			VARCHAR(511),
+	"REL_ID_TESTENTITYA_USES_TESTENTITYB"			VARCHAR(511),
+	"REL_CD_sourceIds_TESTENTITYA_USES_TESTENTITYB"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."TestEntityB" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+ALTER TABLE ONLY ties_data."TestEntityB" ALTER COLUMN "REL_CD_sourceIds_TESTENTITYA_USES_TESTENTITYB" SET DEFAULT '[]';
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TESTENTITYA_GROUPS_TESTENTITYB',
+ 'PK_TESTENTITYA_GROUPS_TESTENTITYB_id',
+ 'ALTER TABLE ties_data."TESTENTITYA_GROUPS_TESTENTITYB" ADD CONSTRAINT "PK_TESTENTITYA_GROUPS_TESTENTITYB_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TESTENTITYA_PROVIDES_TESTENTITYB',
+ 'PK_TESTENTITYA_PROVIDES_TESTENTITYB_id',
+ 'ALTER TABLE ties_data."TESTENTITYA_PROVIDES_TESTENTITYB" ADD CONSTRAINT "PK_TESTENTITYA_PROVIDES_TESTENTITYB_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TestEntityA',
+ 'PK_TestEntityA_id',
+ 'ALTER TABLE ties_data."TestEntityA" ADD CONSTRAINT "PK_TestEntityA_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TestEntityB',
+ 'PK_TestEntityB_id',
+ 'ALTER TABLE ties_data."TestEntityB" ADD CONSTRAINT "PK_TestEntityB_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TESTENTITYA_GROUPS_TESTENTITYB',
+ 'FK_TESTENTITYA_GROUPS_TESTENTITYB_aSide_TestEntityA',
+ 'ALTER TABLE ties_data."TESTENTITYA_GROUPS_TESTENTITYB" ADD CONSTRAINT "FK_TESTENTITYA_GROUPS_TESTENTITYB_aSide_TestEntityA" FOREIGN KEY ("aSide_TestEntityA") REFERENCES ties_data."TestEntityA" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TESTENTITYA_GROUPS_TESTENTITYB',
+ 'FK_TESTENTITYA_GROUPS_TESTENTITYB_bSide_TestEntityB',
+ 'ALTER TABLE ties_data."TESTENTITYA_GROUPS_TESTENTITYB" ADD CONSTRAINT "FK_TESTENTITYA_GROUPS_TESTENTITYB_bSide_TestEntityB" FOREIGN KEY ("bSide_TestEntityB") REFERENCES ties_data."TestEntityB" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TESTENTITYA_PROVIDES_TESTENTITYB',
+ 'FK_TESTENTITYA_PROVIDES_TESTENTITYB_aSide_TestEntityA',
+ 'ALTER TABLE ties_data."TESTENTITYA_PROVIDES_TESTENTITYB" ADD CONSTRAINT "FK_TESTENTITYA_PROVIDES_TESTENTITYB_aSide_TestEntityA" FOREIGN KEY ("aSide_TestEntityA") REFERENCES ties_data."TestEntityA" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TESTENTITYA_PROVIDES_TESTENTITYB',
+ 'FK_TESTENTITYA_PROVIDES_TESTENTITYB_bSide_TestEntityB',
+ 'ALTER TABLE ties_data."TESTENTITYA_PROVIDES_TESTENTITYB" ADD CONSTRAINT "FK_TESTENTITYA_PROVIDES_TESTENTITYB_bSide_TestEntityB" FOREIGN KEY ("bSide_TestEntityB") REFERENCES ties_data."TestEntityB" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TestEntityB',
+ 'FK_TestEntityB_REL_FK_used-by-testEntityA',
+ 'ALTER TABLE ties_data."TestEntityB" ADD CONSTRAINT "FK_TestEntityB_REL_FK_used-by-testEntityA" FOREIGN KEY ("REL_FK_used-by-testEntityA") REFERENCES ties_data."TestEntityA" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'TestEntityB',
+ 'UNIQUE_TestEntityB_REL_ID_TESTENTITYA_USES_TESTENTITYB',
+ 'ALTER TABLE ties_data."TestEntityB" ADD CONSTRAINT "UNIQUE_TestEntityB_REL_ID_TESTENTITYA_USES_TESTENTITYB" UNIQUE ("REL_ID_TESTENTITYA_USES_TESTENTITYB");'
+);
+
+ALTER TABLE ONLY ties_data."Site" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+CREATE TABLE IF NOT EXISTS ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" (
+	"id"			VARCHAR(511),
+	"fdn"			TEXT,
+    "CD_sourceIds"			jsonb
+);
+
+ALTER TABLE ONLY ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" ALTER COLUMN "CD_sourceIds" SET DEFAULT '[]';
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F',
+ 'PK_F568C5029499EE188A168886B2EF09C0D1FAAA9F',
+ 'ALTER TABLE ties_data."003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F" ADD CONSTRAINT "PK_F568C5029499EE188A168886B2EF09C0D1FAAA9F" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'1EF2A41C34A961CD8AE603E020B7B8B57345267F',
+ 'PK_19E2CBE3A8BBA12A7D9EC9923573BC0A65B1EC4A',
+ 'ALTER TABLE ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" ADD CONSTRAINT "PK_19E2CBE3A8BBA12A7D9EC9923573BC0A65B1EC4A" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'25978231183BE3B9ADD7DBE6C77F5E59696CDE5F',
+ 'PK_F52E445B46B712C0D9014D194AB039C205E69818',
+ 'ALTER TABLE ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ADD CONSTRAINT "PK_F52E445B46B712C0D9014D194AB039C205E69818" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'50AC08AB775076E74FC4891954F1D99D3D293ACC',
+ 'PK_CCB39BED50FEF60B1B1F86A7C938BE89B7D90D38',
+ 'ALTER TABLE ties_data."50AC08AB775076E74FC4891954F1D99D3D293ACC" ADD CONSTRAINT "PK_CCB39BED50FEF60B1B1F86A7C938BE89B7D90D38" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'78682DB1FFA2533BA45F8E4FAA5596E1A98479FC',
+ 'PK_77881E9D6F659316F836050DDC6E26FA4DE425EE',
+ 'ALTER TABLE ties_data."78682DB1FFA2533BA45F8E4FAA5596E1A98479FC" ADD CONSTRAINT "PK_77881E9D6F659316F836050DDC6E26FA4DE425EE" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'7D7AACEBB0E4E4732835BA4BFE708DDD3738962D',
+ 'PK_079D5D67E043B09F9C7CD4F6EA1DB12688D43F69',
+ 'ALTER TABLE ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" ADD CONSTRAINT "PK_079D5D67E043B09F9C7CD4F6EA1DB12688D43F69" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AC201B3A42917A9A983A1E3683B67C38C50630FC',
+ 'PK_5D1AC46C58E1FE44FB266F86CE79B3AEBE1D92B3',
+ 'ALTER TABLE ties_data."AC201B3A42917A9A983A1E3683B67C38C50630FC" ADD CONSTRAINT "PK_5D1AC46C58E1FE44FB266F86CE79B3AEBE1D92B3" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE',
+ 'PK_ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE_id',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE" ADD CONSTRAINT "PK_ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaCapability',
+ 'PK_AntennaCapability_id',
+ 'ALTER TABLE ties_data."AntennaCapability" ADD CONSTRAINT "PK_AntennaCapability_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaModule',
+ 'PK_AntennaModule_id',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "PK_AntennaModule_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeApplication',
+ 'PK_CloudNativeApplication_id',
+ 'ALTER TABLE ties_data."CloudNativeApplication" ADD CONSTRAINT "PK_CloudNativeApplication_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeSystem',
+ 'PK_CloudNativeSystem_id',
+ 'ALTER TABLE ties_data."CloudNativeSystem" ADD CONSTRAINT "PK_CloudNativeSystem_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudSite',
+ 'PK_CloudSite_id',
+ 'ALTER TABLE ties_data."CloudSite" ADD CONSTRAINT "PK_CloudSite_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ENodeBFunction',
+ 'PK_ENodeBFunction_id',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "PK_ENodeBFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'EUtranCell',
+ 'PK_EUtranCell_id',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "PK_EUtranCell_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'PK_GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id',
+ 'ALTER TABLE ties_data."GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "PK_GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUCPFunction',
+ 'PK_GNBCUCPFunction_id',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "PK_GNBCUCPFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'PK_GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id',
+ 'ALTER TABLE ties_data."GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "PK_GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUUPFunction',
+ 'PK_GNBCUUPFunction_id',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "PK_GNBCUUPFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'PK_GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id',
+ 'ALTER TABLE ties_data."GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "PK_GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBDUFunction',
+ 'PK_GNBDUFunction_id',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "PK_GNBDUFunction_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'PK_LTESectorCarrier_id',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "PK_LTESectorCarrier_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ManagedElement',
+ 'PK_ManagedElement_id',
+ 'ALTER TABLE ties_data."ManagedElement" ADD CONSTRAINT "PK_ManagedElement_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellCU',
+ 'PK_NRCellCU_id',
+ 'ALTER TABLE ties_data."NRCellCU" ADD CONSTRAINT "PK_NRCellCU_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellDU',
+ 'PK_NRCellDU_id',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "PK_NRCellDU_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'PK_NRSectorCarrier_id',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "PK_NRSectorCarrier_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'PK_Namespace_id',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "PK_Namespace_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NodeCluster',
+ 'PK_NodeCluster_id',
+ 'ALTER TABLE ties_data."NodeCluster" ADD CONSTRAINT "PK_NodeCluster_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'PhysicalNetworkAppliance',
+ 'PK_PhysicalNetworkAppliance_id',
+ 'ALTER TABLE ties_data."PhysicalNetworkAppliance" ADD CONSTRAINT "PK_PhysicalNetworkAppliance_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Sector',
+ 'PK_Sector_id',
+ 'ALTER TABLE ties_data."Sector" ADD CONSTRAINT "PK_Sector_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Site',
+ 'PK_Site_id',
+ 'ALTER TABLE ties_data."Site" ADD CONSTRAINT "PK_Site_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F',
+ 'FK_54FE608944AC8EFFFBE7E55744B8BA52F6B29ABB',
+ 'ALTER TABLE ties_data."003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F" ADD CONSTRAINT "FK_54FE608944AC8EFFFBE7E55744B8BA52F6B29ABB" FOREIGN KEY ("REL_FK_C2F5EC33C0760F653CE7263A49C0B697FCA2D542") REFERENCES ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'1EF2A41C34A961CD8AE603E020B7B8B57345267F',
+ 'FK_9C091709D40D51DEE4DC87A44695F6EBA2E965DE',
+ 'ALTER TABLE ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" ADD CONSTRAINT "FK_9C091709D40D51DEE4DC87A44695F6EBA2E965DE" FOREIGN KEY ("REL_FK_26958E3A529C4C8B68A29FDA906F8CD290F66078") REFERENCES ties_data."003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'1EF2A41C34A961CD8AE603E020B7B8B57345267F',
+ 'UNIQUE_9A721779BB5547778B9258ACD73261B9AABFF302',
+ 'ALTER TABLE ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" ADD CONSTRAINT "UNIQUE_9A721779BB5547778B9258ACD73261B9AABFF302" UNIQUE ("REL_ID_B7945BFD83380F3E12CF99F2B0F838F364027F92");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'25978231183BE3B9ADD7DBE6C77F5E59696CDE5F',
+ 'FK_899FCB466B0BBCC040E945A3E746F5DE53CCCB29',
+ 'ALTER TABLE ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ADD CONSTRAINT "FK_899FCB466B0BBCC040E945A3E746F5DE53CCCB29" FOREIGN KEY ("REL_FK_AB87B417CCD05C332DDD0C60F0C6AB41D38B05E5") REFERENCES ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'25978231183BE3B9ADD7DBE6C77F5E59696CDE5F',
+ 'UNIQUE_3DDA71C08F678AA7303FE0BD127CC27A80D1DDED',
+ 'ALTER TABLE ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ADD CONSTRAINT "UNIQUE_3DDA71C08F678AA7303FE0BD127CC27A80D1DDED" UNIQUE ("REL_ID_FC2F6A5A12917357B548C83F4B0C1AD58FA61413");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'25978231183BE3B9ADD7DBE6C77F5E59696CDE5F',
+ 'FK_E33FB71E6FAC69C92ADEEC55E63D401D21DF91AE',
+ 'ALTER TABLE ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ADD CONSTRAINT "FK_E33FB71E6FAC69C92ADEEC55E63D401D21DF91AE" FOREIGN KEY ("REL_FK_8C98B70070BBD11F90F192DDA3ECF6302390E956") REFERENCES ties_data."78682DB1FFA2533BA45F8E4FAA5596E1A98479FC" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'25978231183BE3B9ADD7DBE6C77F5E59696CDE5F',
+ 'UNIQUE_287E65679DC2108F55F43D62A4325F6DECF372E1',
+ 'ALTER TABLE ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" ADD CONSTRAINT "UNIQUE_287E65679DC2108F55F43D62A4325F6DECF372E1" UNIQUE ("REL_ID_AFBF10D23507AD3B6408947D2A9AF8465BA7B08C");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'50AC08AB775076E74FC4891954F1D99D3D293ACC',
+ 'FK_D43434F9F6FD1C14BE14A0EEDA4C9918B26E82F1',
+ 'ALTER TABLE ties_data."50AC08AB775076E74FC4891954F1D99D3D293ACC" ADD CONSTRAINT "FK_D43434F9F6FD1C14BE14A0EEDA4C9918B26E82F1" FOREIGN KEY ("REL_FK_609963BFEE15FF824280FBE201313C3CDACDDDCE") REFERENCES ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'50AC08AB775076E74FC4891954F1D99D3D293ACC',
+ 'UNIQUE_4E6028C8AF5DB6D082B612C5CBB5B32A943C0AAD',
+ 'ALTER TABLE ties_data."50AC08AB775076E74FC4891954F1D99D3D293ACC" ADD CONSTRAINT "UNIQUE_4E6028C8AF5DB6D082B612C5CBB5B32A943C0AAD" UNIQUE ("REL_ID_040FC8B06B420BA5708AF4798102D1E65FB4DC61");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'7D7AACEBB0E4E4732835BA4BFE708DDD3738962D',
+ 'FK_C5EB2FEB41FDD27A7CED04A3FD665B4BDEF994F5',
+ 'ALTER TABLE ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" ADD CONSTRAINT "FK_C5EB2FEB41FDD27A7CED04A3FD665B4BDEF994F5" FOREIGN KEY ("REL_FK_48B14FA5B787C6398AD1DE5EE670AD0D2A2CB36F") REFERENCES ties_data."1EF2A41C34A961CD8AE603E020B7B8B57345267F" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'7D7AACEBB0E4E4732835BA4BFE708DDD3738962D',
+ 'UNIQUE_176E72F1225D7EEFC222D87B6EC4D66DD968BD13',
+ 'ALTER TABLE ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" ADD CONSTRAINT "UNIQUE_176E72F1225D7EEFC222D87B6EC4D66DD968BD13" UNIQUE ("REL_ID_BDE0B6C74D14AC109D29A08D80E92D4D0DCAEB0B");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AC201B3A42917A9A983A1E3683B67C38C50630FC',
+ 'FK_BFC9C18D6DBCD1FFC021B021CF31444EAA1FEDCA',
+ 'ALTER TABLE ties_data."AC201B3A42917A9A983A1E3683B67C38C50630FC" ADD CONSTRAINT "FK_BFC9C18D6DBCD1FFC021B021CF31444EAA1FEDCA" FOREIGN KEY ("aSide_B0FD0521695A211BFF76F413A31F28CBA32E57ED") REFERENCES ties_data."7D7AACEBB0E4E4732835BA4BFE708DDD3738962D" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AC201B3A42917A9A983A1E3683B67C38C50630FC',
+ 'FK_EADC754A352728E72F7320F69D802725C71EDE3E',
+ 'ALTER TABLE ties_data."AC201B3A42917A9A983A1E3683B67C38C50630FC" ADD CONSTRAINT "FK_EADC754A352728E72F7320F69D802725C71EDE3E" FOREIGN KEY ("bSide_84EF1134719BB6FCF33A94FF770311FC722BCF41") REFERENCES ties_data."25978231183BE3B9ADD7DBE6C77F5E59696CDE5F" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE',
+ 'FK_03713853A2B7ACDC198858CAFBFF355026FEA0B3',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE" ADD CONSTRAINT "FK_03713853A2B7ACDC198858CAFBFF355026FEA0B3" FOREIGN KEY ("aSide_AntennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE',
+ 'FK_5059CE8D2FEE5A1FAD9E06F4FAAFC148BAEA70E3',
+ 'ALTER TABLE ties_data."ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE" ADD CONSTRAINT "FK_5059CE8D2FEE5A1FAD9E06F4FAAFC148BAEA70E3" FOREIGN KEY ("bSide_AntennaModule") REFERENCES ties_data."AntennaModule" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaCapability',
+ 'FK_AntennaCapability_REL_FK_used-by-lteSectorCarrier',
+ 'ALTER TABLE ties_data."AntennaCapability" ADD CONSTRAINT "FK_AntennaCapability_REL_FK_used-by-lteSectorCarrier" FOREIGN KEY ("REL_FK_used-by-lteSectorCarrier") REFERENCES ties_data."LTESectorCarrier" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaModule',
+ 'FK_AntennaModule_REL_FK_grouped-by-sector',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "FK_AntennaModule_REL_FK_grouped-by-sector" FOREIGN KEY ("REL_FK_grouped-by-sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaModule',
+ 'UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE" UNIQUE ("REL_ID_SECTOR_GROUPS_ANTENNAMODULE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaModule',
+ 'FK_AntennaModule_REL_FK_installed-at-site',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "FK_AntennaModule_REL_FK_installed-at-site" FOREIGN KEY ("REL_FK_installed-at-site") REFERENCES ties_data."Site" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'AntennaModule',
+ 'UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE',
+ 'ALTER TABLE ties_data."AntennaModule" ADD CONSTRAINT "UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE" UNIQUE ("REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeApplication',
+ 'FK_CloudNativeApplication_REL_FK_realised-managedElement',
+ 'ALTER TABLE ties_data."CloudNativeApplication" ADD CONSTRAINT "FK_CloudNativeApplication_REL_FK_realised-managedElement" FOREIGN KEY ("REL_FK_realised-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeApplication',
+ 'UNIQUE_DAB3C12479849DA6C222B812C2A8CD1535D0C186',
+ 'ALTER TABLE ties_data."CloudNativeApplication" ADD CONSTRAINT "UNIQUE_DAB3C12479849DA6C222B812C2A8CD1535D0C186" UNIQUE ("REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeApplication',
+ 'FK_CloudNativeApplication_REL_FK_comprised-by-cloudNativeSystem',
+ 'ALTER TABLE ties_data."CloudNativeApplication" ADD CONSTRAINT "FK_CloudNativeApplication_REL_FK_comprised-by-cloudNativeSystem" FOREIGN KEY ("REL_FK_comprised-by-cloudNativeSystem") REFERENCES ties_data."CloudNativeSystem" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeApplication',
+ 'UNIQUE_F2774BC0806E925ADA0B1CAA50B5A41DFB7BF79A',
+ 'ALTER TABLE ties_data."CloudNativeApplication" ADD CONSTRAINT "UNIQUE_F2774BC0806E925ADA0B1CAA50B5A41DFB7BF79A" UNIQUE ("REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeApplication',
+ 'FK_CloudNativeApplication_REL_FK_deployed-on-namespace',
+ 'ALTER TABLE ties_data."CloudNativeApplication" ADD CONSTRAINT "FK_CloudNativeApplication_REL_FK_deployed-on-namespace" FOREIGN KEY ("REL_FK_deployed-on-namespace") REFERENCES ties_data."Namespace" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeApplication',
+ 'UNIQUE_1A317D31DA93B0CF9A9F8A04077B0F60ABCFF49C',
+ 'ALTER TABLE ties_data."CloudNativeApplication" ADD CONSTRAINT "UNIQUE_1A317D31DA93B0CF9A9F8A04077B0F60ABCFF49C" UNIQUE ("REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'CloudNativeSystem',
+ 'FK_CloudNativeSystem_REL_FK_deployed-managedElement',
+ 'ALTER TABLE ties_data."CloudNativeSystem" ADD CONSTRAINT "FK_CloudNativeSystem_REL_FK_deployed-managedElement" FOREIGN KEY ("REL_FK_deployed-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ENodeBFunction',
+ 'FK_ENodeBFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "FK_ENodeBFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ENodeBFunction',
+ 'UNIQUE_F33037EE8037D0606D15FFB45EE8A27FD6DE30EE',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "UNIQUE_F33037EE8037D0606D15FFB45EE8A27FD6DE30EE" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ENodeBFunction',
+ 'FK_ENodeBFunction_REL_FK_realised-by-physicalNetworkAppliance',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "FK_ENodeBFunction_REL_FK_realised-by-physicalNetworkAppliance" FOREIGN KEY ("REL_FK_realised-by-physicalNetworkAppliance") REFERENCES ties_data."PhysicalNetworkAppliance" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ENodeBFunction',
+ 'UNIQUE_6964DA7D7CC1F79A3DB8B43E5F77E42DF8DFBF73',
+ 'ALTER TABLE ties_data."ENodeBFunction" ADD CONSTRAINT "UNIQUE_6964DA7D7CC1F79A3DB8B43E5F77E42DF8DFBF73" UNIQUE ("REL_ID_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'EUtranCell',
+ 'FK_EUtranCell_REL_FK_grouped-by-sector',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "FK_EUtranCell_REL_FK_grouped-by-sector" FOREIGN KEY ("REL_FK_grouped-by-sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'EUtranCell',
+ 'UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL" UNIQUE ("REL_ID_SECTOR_GROUPS_EUTRANCELL");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'EUtranCell',
+ 'FK_EUtranCell_REL_FK_provided-by-enodebFunction',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "FK_EUtranCell_REL_FK_provided-by-enodebFunction" FOREIGN KEY ("REL_FK_provided-by-enodebFunction") REFERENCES ties_data."ENodeBFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'EUtranCell',
+ 'UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL',
+ 'ALTER TABLE ties_data."EUtranCell" ADD CONSTRAINT "UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL" UNIQUE ("REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'FK_B2DDDC542E95DD31826EECEBBF67FD01DAF48833',
+ 'ALTER TABLE ties_data."GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "FK_B2DDDC542E95DD31826EECEBBF67FD01DAF48833" FOREIGN KEY ("aSide_GNBCUCPFunction") REFERENCES ties_data."GNBCUCPFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'FK_95C3AD1FCFBD310B9947B9B622CA8E0FC2135DC5',
+ 'ALTER TABLE ties_data."GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "FK_95C3AD1FCFBD310B9947B9B622CA8E0FC2135DC5" FOREIGN KEY ("bSide_CloudNativeApplication") REFERENCES ties_data."CloudNativeApplication" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUCPFunction',
+ 'FK_GNBCUCPFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "FK_GNBCUCPFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUCPFunction',
+ 'UNIQUE_249F73FF1F4316A56DEF4424FA43C2064FFBE4DD',
+ 'ALTER TABLE ties_data."GNBCUCPFunction" ADD CONSTRAINT "UNIQUE_249F73FF1F4316A56DEF4424FA43C2064FFBE4DD" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'FK_F3346189A1BB0DA705219A4136349DF50AE8AA33',
+ 'ALTER TABLE ties_data."GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "FK_F3346189A1BB0DA705219A4136349DF50AE8AA33" FOREIGN KEY ("aSide_GNBCUUPFunction") REFERENCES ties_data."GNBCUUPFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'FK_36215EA9FC5F31CC0F131E526A84A54CB006C66B',
+ 'ALTER TABLE ties_data."GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "FK_36215EA9FC5F31CC0F131E526A84A54CB006C66B" FOREIGN KEY ("bSide_CloudNativeApplication") REFERENCES ties_data."CloudNativeApplication" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUUPFunction',
+ 'FK_GNBCUUPFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "FK_GNBCUUPFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBCUUPFunction',
+ 'UNIQUE_BDB349CDF0C4055902881ECCB71F460AE1DD323E',
+ 'ALTER TABLE ties_data."GNBCUUPFunction" ADD CONSTRAINT "UNIQUE_BDB349CDF0C4055902881ECCB71F460AE1DD323E" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'FK_69C6800CC81731E475893CC85582971C7530C98E',
+ 'ALTER TABLE ties_data."GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "FK_69C6800CC81731E475893CC85582971C7530C98E" FOREIGN KEY ("aSide_GNBDUFunction") REFERENCES ties_data."GNBDUFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION',
+ 'FK_CA6721EE0944CBBB8E071CEA630162ABD7DFF2DA',
+ 'ALTER TABLE ties_data."GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION" ADD CONSTRAINT "FK_CA6721EE0944CBBB8E071CEA630162ABD7DFF2DA" FOREIGN KEY ("bSide_CloudNativeApplication") REFERENCES ties_data."CloudNativeApplication" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBDUFunction',
+ 'FK_GNBDUFunction_REL_FK_managed-by-managedElement',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "FK_GNBDUFunction_REL_FK_managed-by-managedElement" FOREIGN KEY ("REL_FK_managed-by-managedElement") REFERENCES ties_data."ManagedElement" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'GNBDUFunction',
+ 'UNIQUE_08DFEFAF56EDDE43CBDC336F459D28C6518D3E1D',
+ 'ALTER TABLE ties_data."GNBDUFunction" ADD CONSTRAINT "UNIQUE_08DFEFAF56EDDE43CBDC336F459D28C6518D3E1D" UNIQUE ("REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction" FOREIGN KEY ("REL_FK_provided-by-enodebFunction") REFERENCES ties_data."ENodeBFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9" UNIQUE ("REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_used-antennaCapability',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_used-antennaCapability" FOREIGN KEY ("REL_FK_used-antennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88" UNIQUE ("REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'FK_LTESectorCarrier_REL_FK_used-by-euTranCell',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "FK_LTESectorCarrier_REL_FK_used-by-euTranCell" FOREIGN KEY ("REL_FK_used-by-euTranCell") REFERENCES ties_data."EUtranCell" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'LTESectorCarrier',
+ 'UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER',
+ 'ALTER TABLE ties_data."LTESectorCarrier" ADD CONSTRAINT "UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER" UNIQUE ("REL_ID_EUTRANCELL_USES_LTESECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ManagedElement',
+ 'FK_ManagedElement_REL_FK_deployed-as-cloudNativeSystem',
+ 'ALTER TABLE ties_data."ManagedElement" ADD CONSTRAINT "FK_ManagedElement_REL_FK_deployed-as-cloudNativeSystem" FOREIGN KEY ("REL_FK_deployed-as-cloudNativeSystem") REFERENCES ties_data."CloudNativeSystem" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ManagedElement',
+ 'UNIQUE_ADD7C124AEF822CB0293FC75E39449DC1AD097E5',
+ 'ALTER TABLE ties_data."ManagedElement" ADD CONSTRAINT "UNIQUE_ADD7C124AEF822CB0293FC75E39449DC1AD097E5" UNIQUE ("REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellCU',
+ 'FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction',
+ 'ALTER TABLE ties_data."NRCellCU" ADD CONSTRAINT "FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction" FOREIGN KEY ("REL_FK_provided-by-gnbcucpFunction") REFERENCES ties_data."GNBCUCPFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellCU',
+ 'UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU',
+ 'ALTER TABLE ties_data."NRCellCU" ADD CONSTRAINT "UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU" UNIQUE ("REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellDU',
+ 'FK_NRCellDU_REL_FK_grouped-by-sector',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "FK_NRCellDU_REL_FK_grouped-by-sector" FOREIGN KEY ("REL_FK_grouped-by-sector") REFERENCES ties_data."Sector" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellDU',
+ 'UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU" UNIQUE ("REL_ID_SECTOR_GROUPS_NRCELLDU");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellDU',
+ 'FK_NRCellDU_REL_FK_provided-by-gnbduFunction',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "FK_NRCellDU_REL_FK_provided-by-gnbduFunction" FOREIGN KEY ("REL_FK_provided-by-gnbduFunction") REFERENCES ties_data."GNBDUFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRCellDU',
+ 'UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU',
+ 'ALTER TABLE ties_data."NRCellDU" ADD CONSTRAINT "UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU" UNIQUE ("REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'FK_NRSectorCarrier_REL_FK_used-by-nrCellDu',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "FK_NRSectorCarrier_REL_FK_used-by-nrCellDu" FOREIGN KEY ("REL_FK_used-by-nrCellDu") REFERENCES ties_data."NRCellDU" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER" UNIQUE ("REL_ID_NRCELLDU_USES_NRSECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction" FOREIGN KEY ("REL_FK_provided-by-gnbduFunction") REFERENCES ties_data."GNBDUFunction" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'UNIQUE_872BE05F1989443F2595D99A77BC03733B2D1E2F',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "UNIQUE_872BE05F1989443F2595D99A77BC03733B2D1E2F" UNIQUE ("REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'FK_NRSectorCarrier_REL_FK_used-antennaCapability',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "FK_NRSectorCarrier_REL_FK_used-antennaCapability" FOREIGN KEY ("REL_FK_used-antennaCapability") REFERENCES ties_data."AntennaCapability" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NRSectorCarrier',
+ 'UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991',
+ 'ALTER TABLE ties_data."NRSectorCarrier" ADD CONSTRAINT "UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991" UNIQUE ("REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'FK_Namespace_REL_FK_deployed-on-nodeCluster',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "FK_Namespace_REL_FK_deployed-on-nodeCluster" FOREIGN KEY ("REL_FK_deployed-on-nodeCluster") REFERENCES ties_data."NodeCluster" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'Namespace',
+ 'UNIQUE_Namespace_REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER',
+ 'ALTER TABLE ties_data."Namespace" ADD CONSTRAINT "UNIQUE_Namespace_REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER" UNIQUE ("REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NodeCluster',
+ 'FK_NodeCluster_REL_FK_located-at-cloudSite',
+ 'ALTER TABLE ties_data."NodeCluster" ADD CONSTRAINT "FK_NodeCluster_REL_FK_located-at-cloudSite" FOREIGN KEY ("REL_FK_located-at-cloudSite") REFERENCES ties_data."CloudSite" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'NodeCluster',
+ 'UNIQUE_NodeCluster_REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE',
+ 'ALTER TABLE ties_data."NodeCluster" ADD CONSTRAINT "UNIQUE_NodeCluster_REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE" UNIQUE ("REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'PhysicalNetworkAppliance',
+ 'FK_PhysicalNetworkAppliance_REL_FK_installed-at-site',
+ 'ALTER TABLE ties_data."PhysicalNetworkAppliance" ADD CONSTRAINT "FK_PhysicalNetworkAppliance_REL_FK_installed-at-site" FOREIGN KEY ("REL_FK_installed-at-site") REFERENCES ties_data."Site" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'PhysicalNetworkAppliance',
+ 'UNIQUE_A9110A77514C472452AC80053A8010FBAF481AD0',
+ 'ALTER TABLE ties_data."PhysicalNetworkAppliance" ADD CONSTRAINT "UNIQUE_A9110A77514C472452AC80053A8010FBAF481AD0" UNIQUE ("REL_ID_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_REALISED_BY_ANTENNAMODULE',
+ 'PK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_id',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_REALISED_BY_ANTENNAMODULE" ADD CONSTRAINT "PK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_id" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_REALISED_BY_ANTENNAMODULE',
+ 'FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_aSide_AntennaModule',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_REALISED_BY_ANTENNAMODULE" ADD CONSTRAINT "FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_aSide_AntennaModule" FOREIGN KEY ("aSide_AntennaModule") REFERENCES ties_data."AntennaModule" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'ANTENNAMODULE_REALISED_BY_ANTENNAMODULE',
+ 'FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_bSide_AntennaModule',
+ 'ALTER TABLE ties_data."ANTENNAMODULE_REALISED_BY_ANTENNAMODULE" ADD CONSTRAINT "FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_bSide_AntennaModule" FOREIGN KEY ("bSide_AntennaModule") REFERENCES ties_data."AntennaModule" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'B69D3E92CA22CE61B921AE61BD3CF031791CF714',
+ 'PK_2673E8FB17E57FD56D5E897DA13412B9165B90AA',
+ 'ALTER TABLE ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" ADD CONSTRAINT "PK_2673E8FB17E57FD56D5E897DA13412B9165B90AA" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6',
+ 'PK_E3722EAF721B41FACDCF065D2017267CE2C90BED',
+ 'ALTER TABLE ties_data."B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6" ADD CONSTRAINT "PK_E3722EAF721B41FACDCF065D2017267CE2C90BED" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6',
+ 'FK_00AE9B9921E38ACFEE934695787FA8794817A6ED',
+ 'ALTER TABLE ties_data."B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6" ADD CONSTRAINT "FK_00AE9B9921E38ACFEE934695787FA8794817A6ED" FOREIGN KEY ("aSide_2A2D3374BF907674FA1905478E30ACB8882DC03C") REFERENCES ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6',
+ 'FK_68EED3C83D2C93559F7A61E7D05B4363CDF1DB8F',
+ 'ALTER TABLE ties_data."B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6" ADD CONSTRAINT "FK_68EED3C83D2C93559F7A61E7D05B4363CDF1DB8F" FOREIGN KEY ("bSide_EE6DD4A2CFD743779BBCBFC18FC296EF6D72EB1E") REFERENCES ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'C35AE10CFF62DEDC5E3FC3C40E47373B10800818',
+ 'PK_F03D1DD176CD75707BD6217EF652705007C0F272',
+ 'ALTER TABLE ties_data."C35AE10CFF62DEDC5E3FC3C40E47373B10800818" ADD CONSTRAINT "PK_F03D1DD176CD75707BD6217EF652705007C0F272" PRIMARY KEY ("id");'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'C35AE10CFF62DEDC5E3FC3C40E47373B10800818',
+ 'FK_E19DA712FB443E0212578638DF62281CFD6BFA7A',
+ 'ALTER TABLE ties_data."C35AE10CFF62DEDC5E3FC3C40E47373B10800818" ADD CONSTRAINT "FK_E19DA712FB443E0212578638DF62281CFD6BFA7A" FOREIGN KEY ("aSide_2A2D3374BF907674FA1905478E30ACB8882DC03C") REFERENCES ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" (id) ON DELETE CASCADE;'
+);
+
+SELECT ties_data.create_constraint_if_not_exists(
+	'C35AE10CFF62DEDC5E3FC3C40E47373B10800818',
+ 'FK_7772B14325D2340707AF687BF0F70F32914F935D',
+ 'ALTER TABLE ties_data."C35AE10CFF62DEDC5E3FC3C40E47373B10800818" ADD CONSTRAINT "FK_7772B14325D2340707AF687BF0F70F32914F935D" FOREIGN KEY ("bSide_EE6DD4A2CFD743779BBCBFC18FC296EF6D72EB1E") REFERENCES ties_data."B69D3E92CA22CE61B921AE61BD3CF031791CF714" (id) ON DELETE CASCADE;'
+);
diff --git a/teiv/src/test/resources/pgsqlschema/01_init-oran-smo-teiv-model.sql b/teiv/src/test/resources/pgsqlschema/01_init-oran-smo-teiv-model.sql
new file mode 100644
index 0000000..e919b22
--- /dev/null
+++ b/teiv/src/test/resources/pgsqlschema/01_init-oran-smo-teiv-model.sql
@@ -0,0 +1,485 @@
+--
+-- ============LICENSE_START=======================================================
+-- Copyright (C) 2024 Ericsson
+-- Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+-- ================================================================================
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- SPDX-License-Identifier: Apache-2.0
+-- ============LICENSE_END=========================================================
+--
+
+DROP SCHEMA IF EXISTS ties_model cascade;
+CREATE SCHEMA IF NOT EXISTS ties_model;
+ALTER SCHEMA ties_model OWNER TO :pguser;
+SET default_tablespace = '';
+SET default_table_access_method = heap;
+
+SET ROLE :'pguser';
+
+CREATE TABLE IF NOT EXISTS ties_model.hash_info (
+    "name"                 VARCHAR(511) PRIMARY KEY,
+    "hashedValue"          VARCHAR(511),
+    "type"                 VARCHAR(511)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.module_reference (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "namespace"              VARCHAR(511),
+    "domain"             VARCHAR(511),
+    "includedModules"        jsonb,
+    "content"               TEXT,
+    "revision"            VARCHAR(511),
+    "ownerAppId"       VARCHAR(511),
+    "status"       VARCHAR(127)
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.entity_info (
+    "name"                   VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.decorators (
+    "name"     VARCHAR(511) PRIMARY KEY,
+    "dataType"      VARCHAR(511),
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.classifiers (
+    "name"    VARCHAR(511) PRIMARY KEY,
+    "moduleReferenceName"    VARCHAR(511),
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS ties_model.relationship_info (
+    "name"      VARCHAR(511) PRIMARY KEY,
+    "aSideAssociationName"    TEXT,
+    "aSideMOType"             TEXT,
+    "aSideMinCardinality"     BIGINT,
+    "aSideMaxCardinality"     BIGINT,
+    "bSideAssociationName"    TEXT,
+    "bSideMOType"             TEXT,
+    "bSideMinCardinality"     BIGINT,
+    "bSideMaxCardinality"     BIGINT,
+    "associationKind"    TEXT,
+    "relationshipDataLocation"          TEXT,
+    "connectSameEntity"       BOOLEAN,
+    "moduleReferenceName"     TEXT,
+    FOREIGN KEY ("moduleReferenceName") REFERENCES ties_model.module_reference ("name") ON DELETE CASCADE
+);
+
+COPY ties_model.hash_info("name", "hashedValue", "type") FROM stdin;
+PK_ENodeBFunction_id	PK_ENodeBFunction_id	CONSTRAINT
+FK_TestEntityB_REL_FK_used-by-testEntityA	FK_TestEntityB_REL_FK_used-by-testEntityA	CONSTRAINT
+frequencyDL	frequencyDL	COLUMN
+ANTENNAMODULE_REALISED_BY_ANTENNAMODULE	ANTENNAMODULE_REALISED_BY_ANTENNAMODULE	TABLE
+aSide_AntennaModule	aSide_AntennaModule	COLUMN
+bSide_AntennaModule	bSide_AntennaModule	COLUMN
+PK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_id	PK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_id	CONSTRAINT
+FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_aSide_AntennaModule	FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_aSide_AntennaModule	CONSTRAINT
+FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_bSide_AntennaModule	FK_ANTENNAMODULE_REALISED_BY_ANTENNAMODULE_bSide_AntennaModule	CONSTRAINT
+UNIQUE_GNBCUUPFunction_REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	UNIQUE_BDB349CDF0C4055902881ECCB71F460AE1DD323E	CONSTRAINT
+NRCellDU	NRCellDU	TABLE
+NRSectorCarrier	NRSectorCarrier	TABLE
+REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	COLUMN
+PK_ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE_id	PK_ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE_id	CONSTRAINT
+FK_GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_bSide_CloudNativeApplication	FK_CA6721EE0944CBBB8E071CEA630162ABD7DFF2DA	CONSTRAINT
+FK_LTESectorCarrier_REL_FK_used-by-euTranCell	FK_LTESectorCarrier_REL_FK_used-by-euTranCell	CONSTRAINT
+FK_GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN_bSide_CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	FK_EADC754A352728E72F7320F69D802725C71EDE3E	CONSTRAINT
+frequencyUL	frequencyUL	COLUMN
+FK_GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_aSide_GNBCUUPFunction	FK_F3346189A1BB0DA705219A4136349DF50AE8AA33	CONSTRAINT
+REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	COLUMN
+PK_Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_id	PK_77881E9D6F659316F836050DDC6E26FA4DE425EE	CONSTRAINT
+FK_Namespace_REL_FK_deployed-on-nodeCluster	FK_Namespace_REL_FK_deployed-on-nodeCluster	CONSTRAINT
+ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt	1EF2A41C34A961CD8AE603E020B7B8B57345267F	TABLE
+UNIQUE_TestEntityB_REL_ID_TESTENTITYA_USES_TESTENTITYB	UNIQUE_TestEntityB_REL_ID_TESTENTITYA_USES_TESTENTITYB	CONSTRAINT
+UNIQUE_ManagedElement_REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM	UNIQUE_ADD7C124AEF822CB0293FC75E39449DC1AD097E5	CONSTRAINT
+NRCellCU	NRCellCU	TABLE
+REL_FK_used-by-euTranCell	REL_FK_used-by-euTranCell	COLUMN
+UNIQUE_NRSectorCarrier_REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	UNIQUE_EDF7D5C78EF6505848B1679B714D7831F5863991	CONSTRAINT
+PK_TESTENTITYA_PROVIDES_TESTENTITYB_id	PK_TESTENTITYA_PROVIDES_TESTENTITYB_id	CONSTRAINT
+FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	FK_LTESectorCarrier_REL_FK_provided-by-enodebFunction	CONSTRAINT
+REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+bSide_CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	bSide_84EF1134719BB6FCF33A94FF770311FC722BCF41	COLUMN
+eNBId	eNBId	COLUMN
+PK_NodeCluster_id	PK_NodeCluster_id	CONSTRAINT
+FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction	FK_NRCellCU_REL_FK_provided-by-gnbcucpFunction	CONSTRAINT
+FK_CloudNativeSystem_REL_FK_deployed-managedElement	FK_CloudNativeSystem_REL_FK_deployed-managedElement	CONSTRAINT
+PK_Sector_id	PK_Sector_id	CONSTRAINT
+GNBCUCPFunction	GNBCUCPFunction	TABLE
+UNIQUE_CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_REL_ID_CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE	UNIQUE_287E65679DC2108F55F43D62A4325F6DECF372E1	CONSTRAINT
+REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+FK_NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU_REL_FK_provided-by-gnbduFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	FK_D43434F9F6FD1C14BE14A0EEDA4C9918B26E82F1	CONSTRAINT
+PK_ManagedElement_id	PK_ManagedElement_id	CONSTRAINT
+UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	UNIQUE_AntennaModule_REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	CONSTRAINT
+PK_GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN_id	PK_5D1AC46C58E1FE44FB266F86CE79B3AEBE1D92B3	CONSTRAINT
+REL_FK_provided-by-gnbcucpFunction	REL_FK_provided-by-gnbcucpFunction	COLUMN
+REL_FK_managed-by-managedElementttttttttttttttttttttttttttttttttttttttt	REL_FK_48B14FA5B787C6398AD1DE5EE670AD0D2A2CB36F	COLUMN
+FK_GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN_aSide_GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	FK_BFC9C18D6DBCD1FFC021B021CF31444EAA1FEDCA	CONSTRAINT
+ManagedElement	ManagedElement	TABLE
+PK_AntennaModule_id	PK_AntennaModule_id	CONSTRAINT
+FK_EUtranCell_REL_FK_provided-by-enodebFunction	FK_EUtranCell_REL_FK_provided-by-enodebFunction	CONSTRAINT
+FK_ENodeBFunction_REL_FK_managed-by-managedElement	FK_ENodeBFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+UNIQUE_GNBDUFunction_REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	UNIQUE_08DFEFAF56EDDE43CBDC336F459D28C6518D3E1D	CONSTRAINT
+PK_GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id	PK_GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id	CONSTRAINT
+FK_TESTENTITYA_PROVIDES_TESTENTITYB_bSide_TestEntityB	FK_TESTENTITYA_PROVIDES_TESTENTITYB_bSide_TestEntityB	CONSTRAINT
+FK_CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm_REL_FK_deployed-managedElementttttttttttttttttttttttttttttttttttttttttt	FK_54FE608944AC8EFFFBE7E55744B8BA52F6B29ABB	CONSTRAINT
+REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	COLUMN
+UNIQUE_CloudNativeApplication_REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE	UNIQUE_1A317D31DA93B0CF9A9F8A04077B0F60ABCFF49C	CONSTRAINT
+UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	UNIQUE_NRCellDU_REL_ID_GNBDUFUNCTION_PROVIDES_NRCELLDU	CONSTRAINT
+UNIQUE_Namespace_REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER	UNIQUE_Namespace_REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER	CONSTRAINT
+FK_GNBCUUPFunction_REL_FK_managed-by-managedElement	FK_GNBCUUPFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+aSide_GNBCUUPFunction	aSide_GNBCUUPFunction	COLUMN
+UNIQUE_CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_REL_ID_MANAGEDELEMENTTTTTTTTT_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNN	UNIQUE_3DDA71C08F678AA7303FE0BD127CC27A80D1DDED	CONSTRAINT
+eNodeBPlmnId	eNodeBPlmnId	COLUMN
+PK_NRSectorCarrier_id	PK_NRSectorCarrier_id	CONSTRAINT
+FK_GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_bSide_CloudNativeApplication	FK_36215EA9FC5F31CC0F131E526A84A54CB006C66B	CONSTRAINT
+mechanicalAntennaBearing	mechanicalAntennaBearing	COLUMN
+GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	TABLE
+ENodeBFunction	ENodeBFunction	TABLE
+nRPCI	nRPCI	COLUMN
+antennaModelNumber	antennaModelNumber	COLUMN
+REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION	REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION	COLUMN
+REL_FK_used-antennaCapability	REL_FK_used-antennaCapability	COLUMN
+PK_NRCellCU_id	PK_NRCellCU_id	CONSTRAINT
+REL_FK_deployed-as-cloudNativeSystem	REL_FK_deployed-as-cloudNativeSystem	COLUMN
+PK_NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU_id	PK_CCB39BED50FEF60B1B1F86A7C938BE89B7D90D38	CONSTRAINT
+cellId	cellId	COLUMN
+UNIQUE_NRSectorCarrier_REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	UNIQUE_872BE05F1989443F2595D99A77BC03733B2D1E2F	CONSTRAINT
+REL_FK_deployed-on-namespace	REL_FK_deployed-on-namespace	COLUMN
+PK_CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_id	PK_F52E445B46B712C0D9014D194AB039C205E69818	CONSTRAINT
+aSide_GNBCUCPFunction	aSide_GNBCUCPFunction	COLUMN
+FK_CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_REL_FK_deployed-on-namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	FK_E33FB71E6FAC69C92ADEEC55E63D401D21DF91AE	CONSTRAINT
+UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL	UNIQUE_EUtranCell_REL_ID_SECTOR_GROUPS_EUTRANCELL	CONSTRAINT
+PK_CloudNativeApplication_id	PK_CloudNativeApplication_id	CONSTRAINT
+PK_CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm_id	PK_F568C5029499EE188A168886B2EF09C0D1FAAA9F	CONSTRAINT
+UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	UNIQUE_EUtranCell_REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	CONSTRAINT
+name	name	COLUMN
+REL_FK_provided-by-gnbduFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	REL_FK_609963BFEE15FF824280FBE201313C3CDACDDDCE	COLUMN
+REL_FK_located-at-cloudSite	REL_FK_located-at-cloudSite	COLUMN
+REL_FK_realised-managedElementttttttttttttttttttttttttttttttttttttttttt	REL_FK_AB87B417CCD05C332DDD0C60F0C6AB41D38B05E5	COLUMN
+REL_ID_MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN	REL_ID_BDE0B6C74D14AC109D29A08D80E92D4D0DCAEB0B	COLUMN
+geranFqBands	geranFqBands	COLUMN
+REL_ID_MANAGEDELEMENTTTTTTTTT_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNN	REL_ID_FC2F6A5A12917357B548C83F4B0C1AD58FA61413	COLUMN
+FK_GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_aSide_GNBDUFunction	FK_69C6800CC81731E475893CC85582971C7530C98E	CONSTRAINT
+REL_FK_realised-by-physicalNetworkAppliance	REL_FK_realised-by-physicalNetworkAppliance	COLUMN
+PK_EUtranCell_id	PK_EUtranCell_id	CONSTRAINT
+REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE	REL_ID_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE	COLUMN
+FK_NRSectorCarrier_REL_FK_used-antennaCapability	FK_NRSectorCarrier_REL_FK_used-antennaCapability	CONSTRAINT
+REL_ID_GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU	REL_ID_040FC8B06B420BA5708AF4798102D1E65FB4DC61	COLUMN
+CloudNativeApplication	CloudNativeApplication	TABLE
+positionWithinSector	positionWithinSector	COLUMN
+PK_Namespace_id	PK_Namespace_id	CONSTRAINT
+GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	TABLE
+Sector	Sector	TABLE
+REL_ID_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE	REL_ID_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE	COLUMN
+FK_GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_bSide_CloudNativeApplication	FK_95C3AD1FCFBD310B9947B9B622CA8E0FC2135DC5	CONSTRAINT
+PhysicalNetworkAppliance	PhysicalNetworkAppliance	TABLE
+PK_GNBCUCPFunction_id	PK_GNBCUCPFunction_id	CONSTRAINT
+REL_FK_deployed-on-nodeCluster	REL_FK_deployed-on-nodeCluster	COLUMN
+AntennaCapability	AntennaCapability	TABLE
+NodeCluster	NodeCluster	TABLE
+REL_ID_NRCELLDU_USES_NRSECTORCARRIER	REL_ID_NRCELLDU_USES_NRSECTORCARRIER	COLUMN
+PK_GNBCUUPFunction_id	PK_GNBCUUPFunction_id	CONSTRAINT
+UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	UNIQUE_LTESectorCarrier_REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	CONSTRAINT
+FK_ManagedElement_REL_FK_deployed-as-cloudNativeSystem	FK_ManagedElement_REL_FK_deployed-as-cloudNativeSystem	CONSTRAINT
+TestEntityA	TestEntityA	TABLE
+azimuth	azimuth	COLUMN
+TestEntityB	TestEntityB	TABLE
+REL_FK_deployed-managedElementttttttttttttttttttttttttttttttttttttttttt	REL_FK_C2F5EC33C0760F653CE7263A49C0B697FCA2D542	COLUMN
+FK_EUtranCell_REL_FK_grouped-by-sector	FK_EUtranCell_REL_FK_grouped-by-sector	CONSTRAINT
+cellLocalId	cellLocalId	COLUMN
+gNBCUName	gNBCUName	COLUMN
+FK_NRSectorCarrier_REL_FK_used-by-nrCellDu	FK_NRSectorCarrier_REL_FK_used-by-nrCellDu	CONSTRAINT
+electricalAntennaTilt	electricalAntennaTilt	COLUMN
+REL_FK_provided-by-enodebFunction	REL_FK_provided-by-enodebFunction	COLUMN
+aSide_GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	aSide_B0FD0521695A211BFF76F413A31F28CBA32E57ED	COLUMN
+GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	7D7AACEBB0E4E4732835BA4BFE708DDD3738962D	TABLE
+PK_PhysicalNetworkAppliance_id	PK_PhysicalNetworkAppliance_id	CONSTRAINT
+REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_ID_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+eUtranFqBands	eUtranFqBands	COLUMN
+FK_GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_aSide_GNBCUCPFunction	FK_B2DDDC542E95DD31826EECEBBF67FD01DAF48833	CONSTRAINT
+REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	REL_ID_EUTRANCELL_USES_LTESECTORCARRIER	COLUMN
+REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	COLUMN
+CloudSite	CloudSite	TABLE
+GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	TABLE
+UNIQUE_ENodeBFunction_REL_ID_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE	UNIQUE_6964DA7D7CC1F79A3DB8B43E5F77E42DF8DFBF73	CONSTRAINT
+FK_PhysicalNetworkAppliance_REL_FK_installed-at-site	FK_PhysicalNetworkAppliance_REL_FK_installed-at-site	CONSTRAINT
+CloudNativeSystem	CloudNativeSystem	TABLE
+UNIQUE_NodeCluster_REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE	UNIQUE_NodeCluster_REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE	CONSTRAINT
+REL_FK_used-by-lteSectorCarrier	REL_FK_used-by-lteSectorCarrier	COLUMN
+attribute1	attribute1	COLUMN
+PK_ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt_id	PK_19E2CBE3A8BBA12A7D9EC9923573BC0A65B1EC4A	CONSTRAINT
+FK_AntennaModule_REL_FK_grouped-by-sector	FK_AntennaModule_REL_FK_grouped-by-sector	CONSTRAINT
+FK_GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_REL_FK_managed-by-managedElementttttttttttttttttttttttttttttttttttttttt	FK_C5EB2FEB41FDD27A7CED04A3FD665B4BDEF994F5	CONSTRAINT
+REL_FK_used-by-nrCellDu	REL_FK_used-by-nrCellDu	COLUMN
+REL_FK_comprised-by-cloudNativeSystem	REL_FK_comprised-by-cloudNativeSystem	COLUMN
+FK_GNBDUFunction_REL_FK_managed-by-managedElement	FK_GNBDUFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+PK_LTESectorCarrier_id	PK_LTESectorCarrier_id	CONSTRAINT
+PK_AntennaCapability_id	PK_AntennaCapability_id	CONSTRAINT
+PK_CloudNativeSystem_id	PK_CloudNativeSystem_id	CONSTRAINT
+FK_TESTENTITYA_PROVIDES_TESTENTITYB_aSide_TestEntityA	FK_TESTENTITYA_PROVIDES_TESTENTITYB_aSide_TestEntityA	CONSTRAINT
+geo-location	geo-location	COLUMN
+REL_FK_grouped-by-sector	REL_FK_grouped-by-sector	COLUMN
+FK_ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE_aSide_AntennaCapability	FK_03713853A2B7ACDC198858CAFBFF355026FEA0B3	CONSTRAINT
+FK_ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE_bSide_AntennaModule	FK_5059CE8D2FEE5A1FAD9E06F4FAAFC148BAEA70E3	CONSTRAINT
+REL_FK_deployed-as-cloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm	REL_FK_26958E3A529C4C8B68A29FDA906F8CD290F66078	COLUMN
+id	id	COLUMN
+gNBId	gNBId	COLUMN
+REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION	REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION	COLUMN
+PK_NRCellDU_id	PK_NRCellDU_id	CONSTRAINT
+EUtranCell	EUtranCell	TABLE
+PK_Site_id	PK_Site_id	CONSTRAINT
+REL_FK_installed-at-site	REL_FK_installed-at-site	COLUMN
+REL_FK_used-by-testEntityA	REL_FK_used-by-testEntityA	COLUMN
+FK_AntennaCapability_REL_FK_used-by-lteSectorCarrier	FK_AntennaCapability_REL_FK_used-by-lteSectorCarrier	CONSTRAINT
+aSide_AntennaCapability	aSide_AntennaCapability	COLUMN
+nRTAC	nRTAC	COLUMN
+earfcndl	earfcndl	COLUMN
+FK_NodeCluster_REL_FK_located-at-cloudSite	FK_NodeCluster_REL_FK_located-at-cloudSite	CONSTRAINT
+aSide_GNBDUFunction	aSide_GNBDUFunction	COLUMN
+Namespace	Namespace	TABLE
+FK_AntennaModule_REL_FK_installed-at-site	FK_AntennaModule_REL_FK_installed-at-site	CONSTRAINT
+earfcnul	earfcnul	COLUMN
+PK_TestEntityB_id	PK_TestEntityB_id	CONSTRAINT
+FK_TESTENTITYA_GROUPS_TESTENTITYB_aSide_TestEntityA	FK_TESTENTITYA_GROUPS_TESTENTITYB_aSide_TestEntityA	CONSTRAINT
+fdnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	3786A6CA64C9422F9E7FC35B7B039F345BBDDA65	COLUMN
+UNIQUE_ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt_REL_ID_MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM	UNIQUE_9A721779BB5547778B9258ACD73261B9AABFF302	CONSTRAINT
+REL_FK_deployed-on-namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	REL_FK_8C98B70070BBD11F90F192DDA3ECF6302390E956	COLUMN
+FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction	FK_NRSectorCarrier_REL_FK_provided-by-gnbduFunction	CONSTRAINT
+PK_GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id	PK_GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id	CONSTRAINT
+cmId	cmId	COLUMN
+aSide_TestEntityA	aSide_TestEntityA	COLUMN
+type	type	COLUMN
+nCI	nCI	COLUMN
+ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE	ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE	TABLE
+REL_ID_TESTENTITYA_USES_TESTENTITYB	REL_ID_TESTENTITYA_USES_TESTENTITYB	COLUMN
+NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU	50AC08AB775076E74FC4891954F1D99D3D293ACC	TABLE
+REL_ID_MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM	REL_ID_B7945BFD83380F3E12CF99F2B0F838F364027F92	COLUMN
+REL_ID_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE	REL_ID_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE	COLUMN
+REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	COLUMN
+FK_NRCellDU_REL_FK_grouped-by-sector	FK_NRCellDU_REL_FK_grouped-by-sector	CONSTRAINT
+FK_CloudNativeApplication_REL_FK_realised-managedElement	FK_CloudNativeApplication_REL_FK_realised-managedElement	CONSTRAINT
+TESTENTITYA_GROUPS_TESTENTITYB	TESTENTITYA_GROUPS_TESTENTITYB	TABLE
+PK_GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_id	PK_079D5D67E043B09F9C7CD4F6EA1DB12688D43F69	CONSTRAINT
+UNIQUE_LTESectorCarrier_REL_ID_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	UNIQUE_B9770D6C26DDA0173DB9690F6E3B42C111AF26E9	CONSTRAINT
+duplexType	duplexType	COLUMN
+AntennaModule	AntennaModule	TABLE
+LTESectorCarrier	LTESectorCarrier	TABLE
+REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	REL_ID_ANTENNAMODULE_INSTALLED_AT_SITE	COLUMN
+FK_LTESectorCarrier_REL_FK_used-antennaCapability	FK_LTESectorCarrier_REL_FK_used-antennaCapability	CONSTRAINT
+REL_FK_managed-by-managedElement	REL_FK_managed-by-managedElement	COLUMN
+UNIQUE_NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU_REL_ID_GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU	UNIQUE_4E6028C8AF5DB6D082B612C5CBB5B32A943C0AAD	CONSTRAINT
+fdn	fdn	COLUMN
+dUpLMNId	dUpLMNId	COLUMN
+UNIQUE_GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_REL_ID_MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN	UNIQUE_176E72F1225D7EEFC222D87B6EC4D66DD968BD13	CONSTRAINT
+REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	REL_ID_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	COLUMN
+REL_ID_SECTOR_GROUPS_EUTRANCELL	REL_ID_SECTOR_GROUPS_EUTRANCELL	COLUMN
+Site	Site	TABLE
+REL_ID_SECTOR_GROUPS_NRCELLDU	REL_ID_SECTOR_GROUPS_NRCELLDU	COLUMN
+UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU	UNIQUE_NRCellDU_REL_ID_SECTOR_GROUPS_NRCELLDU	CONSTRAINT
+arfcnUL	arfcnUL	COLUMN
+PK_GNBDUFunction_id	PK_GNBDUFunction_id	CONSTRAINT
+Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	78682DB1FFA2533BA45F8E4FAA5596E1A98479FC	TABLE
+FK_ENodeBFunction_REL_FK_realised-by-physicalNetworkAppliance	FK_ENodeBFunction_REL_FK_realised-by-physicalNetworkAppliance	CONSTRAINT
+FK_GNBCUCPFunction_REL_FK_managed-by-managedElement	FK_GNBCUCPFunction_REL_FK_managed-by-managedElement	CONSTRAINT
+REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	REL_ID_ENODEBFUNCTION_PROVIDES_EUTRANCELL	COLUMN
+nRFqBands	nRFqBands	COLUMN
+CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm	003B7CAE0FA8C3C54BE1BAD8BB9A50985A2EA03F	TABLE
+tac	tac	COLUMN
+arfcnDL	arfcnDL	COLUMN
+REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER	REL_ID_NAMESPACE_DEPLOYED_ON_NODECLUSTER	COLUMN
+bSide_CloudNativeApplication	bSide_CloudNativeApplication	COLUMN
+PK_CloudSite_id	PK_CloudSite_id	CONSTRAINT
+CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	25978231183BE3B9ADD7DBE6C77F5E59696CDE5F	TABLE
+earfcn	earfcn	COLUMN
+GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN	AC201B3A42917A9A983A1E3683B67C38C50630FC	TABLE
+REL_ID_CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE	REL_ID_AFBF10D23507AD3B6408947D2A9AF8465BA7B08C	COLUMN
+sectorId	sectorId	COLUMN
+FK_CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn_REL_FK_realised-managedElementttttttttttttttttttttttttttttttttttttttttt	FK_899FCB466B0BBCC040E945A3E746F5DE53CCCB29	CONSTRAINT
+REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE	REL_ID_NODECLUSTER_LOCATED_AT_CLOUDSITE	COLUMN
+TESTENTITYA_PROVIDES_TESTENTITYB	TESTENTITYA_PROVIDES_TESTENTITYB	TABLE
+REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM	REL_ID_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM	COLUMN
+GNBCUUPFunction	GNBCUUPFunction	TABLE
+REL_FK_realised-managedElement	REL_FK_realised-managedElement	COLUMN
+UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE	UNIQUE_AntennaModule_REL_ID_SECTOR_GROUPS_ANTENNAMODULE	CONSTRAINT
+UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER	UNIQUE_NRSectorCarrier_REL_ID_NRCELLDU_USES_NRSECTORCARRIER	CONSTRAINT
+bSide_TestEntityB	bSide_TestEntityB	COLUMN
+REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	COLUMN
+totalTilt	totalTilt	COLUMN
+FK_ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt_REL_FK_deployed-as-cloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm	FK_9C091709D40D51DEE4DC87A44695F6EBA2E965DE	CONSTRAINT
+gNBIdLength	gNBIdLength	COLUMN
+UNIQUE_ENodeBFunction_REL_ID_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	UNIQUE_F33037EE8037D0606D15FFB45EE8A27FD6DE30EE	CONSTRAINT
+FK_NRCellDU_REL_FK_provided-by-gnbduFunction	FK_NRCellDU_REL_FK_provided-by-gnbduFunction	CONSTRAINT
+UNIQUE_GNBCUCPFunction_REL_ID_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	UNIQUE_249F73FF1F4316A56DEF4424FA43C2064FFBE4DD	CONSTRAINT
+FK_TESTENTITYA_GROUPS_TESTENTITYB_bSide_TestEntityB	FK_TESTENTITYA_GROUPS_TESTENTITYB_bSide_TestEntityB	CONSTRAINT
+cellLocalIdddddddddddddddddddddddddddddddddddddddddddddddddddddd	020335B0F627C169E24167748C38FE756FB34AE2	COLUMN
+REL_FK_deployed-managedElement	REL_FK_deployed-managedElement	COLUMN
+FK_CloudNativeApplication_REL_FK_comprised-by-cloudNativeSystem	FK_CloudNativeApplication_REL_FK_comprised-by-cloudNativeSystem	CONSTRAINT
+pLMNId	pLMNId	COLUMN
+PK_GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id	PK_GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION_id	CONSTRAINT
+UNIQUE_CloudNativeApplication_REL_ID_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION	UNIQUE_DAB3C12479849DA6C222B812C2A8CD1535D0C186	CONSTRAINT
+essScLocalId	essScLocalId	COLUMN
+REL_FK_provided-by-gnbduFunction	REL_FK_provided-by-gnbduFunction	COLUMN
+UNIQUE_LTESectorCarrier_REL_ID_LTESECTORCARRIER_USES_ANTENNACAPABILITY	UNIQUE_5D5FEB6B4B09D5D42A589753C684994CD0B96E88	CONSTRAINT
+sectorCarrierType	sectorCarrierType	COLUMN
+UNIQUE_PhysicalNetworkAppliance_REL_ID_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE	UNIQUE_A9110A77514C472452AC80053A8010FBAF481AD0	CONSTRAINT
+GNBDUFunction	GNBDUFunction	TABLE
+mechanicalAntennaTilt	mechanicalAntennaTilt	COLUMN
+UNIQUE_CloudNativeApplication_REL_ID_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION	UNIQUE_F2774BC0806E925ADA0B1CAA50B5A41DFB7BF79A	CONSTRAINT
+UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	UNIQUE_NRCellCU_REL_ID_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	CONSTRAINT
+plmnId	plmnId	COLUMN
+PK_TestEntityA_id	PK_TestEntityA_id	CONSTRAINT
+FK_CloudNativeApplication_REL_FK_deployed-on-namespace	FK_CloudNativeApplication_REL_FK_deployed-on-namespace	CONSTRAINT
+gNBDUId	gNBDUId	COLUMN
+CD_sourceIds	CD_sourceIds	COLUMN
+PK_TESTENTITYA_GROUPS_TESTENTITYB_id	PK_TESTENTITYA_GROUPS_TESTENTITYB_id	CONSTRAINT
+REL_ID_SECTOR_GROUPS_ANTENNAMODULE	REL_ID_SECTOR_GROUPS_ANTENNAMODULE	COLUMN
+AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	B69D3E92CA22CE61B921AE61BD3CF031791CF714	TABLE
+ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE	B9B76FD20FF23B2A41C82CB5EDF6FA25B6AC2BC6	TABLE
+PK_AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_id	PK_2673E8FB17E57FD56D5E897DA13412B9165B90AA	CONSTRAINT
+PK_ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE_id	PK_E3722EAF721B41FACDCF065D2017267CE2C90BED	CONSTRAINT
+FK_ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE_aSide_AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	FK_00AE9B9921E38ACFEE934695787FA8794817A6ED	CONSTRAINT
+FK_ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE_bSide_AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	FK_68EED3C83D2C93559F7A61E7D05B4363CDF1DB8F	CONSTRAINT
+ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE	C35AE10CFF62DEDC5E3FC3C40E47373B10800818	TABLE
+PK_ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE_id	PK_F03D1DD176CD75707BD6217EF652705007C0F272	CONSTRAINT
+FK_ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE_aSide_AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	FK_E19DA712FB443E0212578638DF62281CFD6BFA7A	CONSTRAINT
+FK_ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE_bSide_AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	FK_7772B14325D2340707AF687BF0F70F32914F935D	CONSTRAINT
+aSide_AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	aSide_2A2D3374BF907674FA1905478E30ACB8882DC03C	COLUMN
+bSide_AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	bSide_EE6DD4A2CFD743779BBCBFC18FC296EF6D72EB1E	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM	REL_CD_B7945BFD83380F3E12CF99F2B0F838F364027F92	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN	REL_CD_45E8E8693B1B8928376EAA8995D08AA7B1E483BD	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENTTTTTTTTT_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNN	REL_CD_CEAD4CCE5250E7D3C64801C8FDDC21F1D87BEC0C	COLUMN
+REL_CD_sourceIds_GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU	REL_CD_040FC8B06B420BA5708AF4798102D1E65FB4DC61	COLUMN
+REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE	REL_CD_sourceIds_SECTOR_GROUPS_ANTENNAMODULE	COLUMN
+REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE	REL_CD_sourceIds_ANTENNAMODULE_INSTALLED_AT_SITE	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	COLUMN
+REL_CD_sourceIds_ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE	REL_CD_556274C475BA56EE4DEFB691F9037C869223A124	COLUMN
+REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL	REL_CD_sourceIds_SECTOR_GROUPS_EUTRANCELL	COLUMN
+REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL	REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_EUTRANCELL	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	COLUMN
+REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	REL_CD_sourceIds_ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	COLUMN
+REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_sourceIds_LTESECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER	REL_CD_sourceIds_EUTRANCELL_USES_LTESECTORCARRIER	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM	REL_CD_sourceIds_MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM	COLUMN
+REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	REL_CD_sourceIds_GNBCUCPFUNCTION_PROVIDES_NRCELLCU	COLUMN
+REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU	REL_CD_sourceIds_SECTOR_GROUPS_NRCELLDU	COLUMN
+REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU	REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRCELLDU	COLUMN
+REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER	REL_CD_sourceIds_NRCELLDU_USES_NRSECTORCARRIER	COLUMN
+REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	REL_CD_sourceIds_GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	COLUMN
+REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY	REL_CD_sourceIds_NRSECTORCARRIER_USES_ANTENNACAPABILITY	COLUMN
+REL_CD_sourceIds_NAMESPACE_DEPLOYED_ON_NODECLUSTER	REL_CD_sourceIds_NAMESPACE_DEPLOYED_ON_NODECLUSTER	COLUMN
+REL_CD_sourceIds_NODECLUSTER_LOCATED_AT_CLOUDSITE	REL_CD_sourceIds_NODECLUSTER_LOCATED_AT_CLOUDSITE	COLUMN
+REL_CD_sourceIds_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE	REL_CD_sourceIds_PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION	REL_CD_8F561B5FB3CF928F2C4046CE1A7C37A8FE06B9A7	COLUMN
+REL_CD_sourceIds_CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION	REL_CD_39262797D0119611B8459ECF46754A074711E485	COLUMN
+REL_CD_sourceIds_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE	REL_CD_sourceIds_CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE	COLUMN
+REL_CD_sourceIds_CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE	REL_CD_F7E43E0D0F76D6EFED9AB684B84A69E177F591D2	COLUMN
+REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	REL_CD_sourceIds_MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	COLUMN
+REL_CD_sourceIds_TESTENTITYA_USES_TESTENTITYB	REL_CD_sourceIds_TESTENTITYA_USES_TESTENTITYB	COLUMN
+\.
+
+COPY ties_model.module_reference("name", "namespace", "domain", "includedModules", "revision", "content", "ownerAppId", "status") FROM stdin;
+o-ran-smo-teiv-common-yang-extensions	urn:o-ran:smo-teiv-common-yang-extensions	\N	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMgewoKICB5YW5nLXZlcnNpb24gMS4xOwogIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMiOwogIHByZWZpeCBvci10ZWl2LXlleHQ7CgogIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOwogIGRlc2NyaXB0aW9uCiAgIlRvcG9sb2d5IGFuZCBJbnZlbnRvcnkgWUFORyBleHRlbnNpb25zIG1vZGVsLgoKICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogIFRoaXMgbW9kZWwgY29udGFpbnMgZXh0ZW5zaW9ucyB0byB0aGUgWUFORyBsYW5ndWFnZSB0aGF0IHRvcG9sb2d5IGFuZAogIGludmVudG9yeSBtb2RlbHMgd2lsbCB1c2UgdG8gZGVmaW5lIGFuZCBhbm5vdGF0ZSB0eXBlcyBhbmQgcmVsYXRpb25zaGlwcy4iOwoKICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgewogICAgZGVzY3JpcHRpb24gIkluaXRpYWwgcmV2aXNpb24uIjsKICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICB9CgogIGV4dGVuc2lvbiBiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgewoKICAgIGRlc2NyaXB0aW9uCiAgICAgICJEZWZpbmVzIGEgYmktZGlyZWN0aW9uYWwgcmVsYXRpb25zaGlwIGluIHRoZSB0b3BvbG9neS4KCiAgICAgICBBIGJpLWRpcmVjdGlvbmFsLWFzc29jaWF0aW9uIChCREEpIGlzIGEgcmVsYXRpb25zaGlwIGNvbXByaXNpbmcgb2YgYW4KICAgICAgIEEtc2lkZSBhbmQgYSBCLXNpZGUuIFRoZSBBLXNpZGUgaXMgY29uc2lkZXJlZCB0aGUgb3JpZ2luYXRpbmcgc2lkZSBvZgogICAgICAgdGhlIHJlbGF0aW9uc2hpcDsgdGhlIEItc2lkZSBpcyBjb25zaWRlcmVkIHRoZSB0ZXJtaW5hdGluZyBzaWRlIG9mIHRoZQogICAgICAgcmVsYXRpb25zaGlwLiBUaGUgb3JkZXIgb2YgQS1zaWRlIGFuZCBCLXNpZGUgaXMgb2YgaW1wb3J0YW5jZSBhbmQgTVVTVAogICAgICAgTk9UIGJlIGNoYW5nZWQgb25jZSBkZWZpbmVkLgoKICAgICAgIEJvdGggQS1zaWRlIGFuZCBCLXNpZGUgYXJlIGRlZmluZWQgb24gYSB0eXBlLCBhbmQgYXJlIGdpdmVuIGEgcm9sZS4gQQogICAgICAgdHlwZSBtYXkgaGF2ZSBtdWx0aXBsZSBvcmlnaW5hdGluZyBhbmQvb3IgdGVybWluYXRpbmcgc2lkZXMgb2YgYQogICAgICAgcmVsYXRpb25zaGlwLCBhbGwgZGlzdGluZ3Vpc2hlZCBieSByb2xlIG5hbWUuCgogICAgICAgVGhlIHN0YXRlbWVudCBNVVNUIG9ubHkgYmUgYSBzdWJzdGF0ZW1lbnQgb2YgdGhlICdtb2R1bGUnIHN0YXRlbWVudC4KICAgICAgIE11bHRpcGxlICdiaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIHN0YXRlbWVudHMgYXJlIGFsbG93ZWQKICAgICAgIHBlciBwYXJlbnQgc3RhdGVtZW50LgoKICAgICAgIFN1YnN0YXRlbWVudHMgdG8gdGhlICdiaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIGRlZmluZSB0aGUKICAgICAgIEEtc2lkZSBhbmQgdGhlIEItc2lkZSwgcmVzcGVjdGl2ZWx5LCBhbmQgb3B0aW9uYWxseSBwcm9wZXJ0aWVzIG9mIHRoZQogICAgICAgcmVsYXRpb25zaGlwLiBEYXRhIG5vZGVzIG9mIHR5cGVzICdsZWFmJyBhbmQgJ2xlYWYtbGlzdCcgYXJlIHVzZWQgZm9yCiAgICAgICB0aGlzIHB1cnBvc2UuIE9uZSBvZiB0aGUgZGF0YSBub2RlcyBNVVNUIGJlIGFubm90YXRlZCB3aXRoIHRoZSAnYS1zaWRlJwogICAgICAgZXh0ZW5zaW9uOyBhbm90aGVyIGRhdGEgbm9kZSBNVVNUIGJlIGFubm90YXRlZCB3aXRoIHRoZSAnYi1zaWRlJwogICAgICAgZXh0ZW5zaW9uLiBPdGhlciBkYXRhIG5vZGVzIGRlZmluZSBwcm9wZXJ0aWVzIG9mIHRoZSByZWxhdGlvbnNoaXAuCgogICAgICAgVGhlIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSByZWxhdGlvbnNoaXAuIFRoZSByZWxhdGlvbnNoaXAgbmFtZSBpcwogICAgICAgc2NvcGVkIHRvIHRoZSBuYW1lc3BhY2Ugb2YgdGhlIGRlY2xhcmluZyBtb2R1bGUgYW5kIE1VU1QgYmUgdW5pcXVlCiAgICAgICB3aXRoaW4gdGhlIHNjb3BlLiI7CgogICAgYXJndW1lbnQgcmVsYXRpb25zaGlwTmFtZTsKICB9CgogIGV4dGVuc2lvbiBhU2lkZSB7CiAgICBkZXNjcmlwdGlvbgogICAgICAiRGVmaW5lcyB0aGUgQS1zaWRlIG9mIGEgcmVsYXRpb25zaGlwLgoKICAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIGEgJ2xlYWYnIG9yICdsZWFmLWxpc3QnCiAgICAgICBzdGF0ZW1lbnQsIHdoaWNoIGl0c2VsZiBtdXN0IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZQogICAgICAgJ3VuaS1kaXJlY3Rpb25hbC10b3BvbG9neS1yZWxhdGlvbnNoaXAnIHN0YXRlbWVudC4KCiAgICAgICBUaGUgZGF0YSB0eXBlIG9mIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIE1VU1QgYmUKICAgICAgICdpbnN0YW5jZS1pZGVudGlmaWVyJy4gQ29uc3RyYWludHMgTUFZIGJlIHVzZWQgYXMgcGFydCBvZiB0aGUgcGFyZW50CiAgICAgICAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgdG8gZW5mb3JjZSBjYXJkaW5hbGl0eS4KCiAgICAgICBUaGUgaWRlbnRpZmllciBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBpcyB1c2VkIGFzIG5hbWUgb2YKICAgICAgIHRoZSByb2xlIG9mIHRoZSBBLXNpZGUgb2YgdGhlIHJlbGF0aW9uc2hpcC4gVGhlIG5hbWUgb2YgdGhlIHJvbGUgaXMKICAgICAgIHNjb3BlZCB0byB0aGUgdHlwZSBvbiB3aGljaCB0aGUgQS1zaWRlIGlzIGRlZmluZWQgYW5kIE1VU1QgYmUgdW5pcXVlCiAgICAgICB3aXRoaW4gdGhlIHNjb3BlLgoKICAgICAgIFdoaWxlIHRoZSBwYXJlbnQgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIGRvZXMgbm90IHJlc3VsdCBpbiBhIHByb3BlcnR5IG9mCiAgICAgICB0aGUgcmVsYXRpb25zaGlwLCBpdCBpcyBSRUNPTU1FTkRFRCB0byBhdm9pZCB1c2luZyB0aGUgbmFtZSBvZiBhbgogICAgICAgZXhpc3RpbmcgdHlwZSBwcm9wZXJ0eSBhcyByb2xlIG5hbWUgdG8gYXZvaWQgcG90ZW50aWFsIGFtYmlndWl0aWVzCiAgICAgICBiZXR3ZWVuIHByb3BlcnRpZXMgb2YgYSB0eXBlLCBhbmQgcm9sZXMgb2YgYSByZWxhdGlvbnNoaXAgb24gdGhlIHR5cGUuCgogICAgICAgVGhlIGFyZ3VtZW50IGlzIHRoZSBuYW1lIG9mIHRoZSB0eXBlIG9uIHdoaWNoIHRoZSBBLXNpZGUgcmVzaWRlcy4gSWYgdGhlCiAgICAgICB0eXBlIGlzIGRlY2xhcmVkIGluIGFub3RoZXIgbW9kdWxlLCB0aGUgdHlwZSBtdXN0IGJlIHByZWZpeGVkLCBhbmQgYQogICAgICAgY29ycmVzcG9uZGluZyAnaW1wb3J0JyBzdGF0ZW1lbnQgYmUgdXNlZCB0byBkZWNsYXJlIHRoZSBwcmVmaXguIjsKCiAgICBhcmd1bWVudCBhU2lkZVR5cGU7CiAgfQoKICBleHRlbnNpb24gYlNpZGUgewogICAgZGVzY3JpcHRpb24gIkRlZmluZXMgdGhlIEItc2lkZSBvZiBhIHJlbGF0aW9uc2hpcC4KCiAgICAgICBUaGUgc3RhdGVtZW50IE1VU1Qgb25seSBiZSBhIHN1YnN0YXRlbWVudCBvZiBhICdsZWFmJyBvciAnbGVhZi1saXN0JwogICAgICAgc3RhdGVtZW50LCB3aGljaCBpdHNlbGYgbXVzdCBiZSBhIHN1YnN0YXRlbWVudCBvZiB0aGUKICAgICAgICd1bmktZGlyZWN0aW9uYWwtdG9wb2xvZ3ktcmVsYXRpb25zaGlwJyBzdGF0ZW1lbnQuCgogICAgICAgVGhlIGRhdGEgdHlwZSBvZiB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBNVVNUIGJlCiAgICAgICAnaW5zdGFuY2UtaWRlbnRpZmllcicuIENvbnN0cmFpbnRzIE1BWSBiZSB1c2VkIGFzIHBhcnQgb2YgdGhlIHBhcmVudAogICAgICAgJ2xlYWYnIG9yICdsZWFmLWxpc3QnIHRvIGVuZm9yY2UgY2FyZGluYWxpdHkuCgogICAgICAgVGhlIGlkZW50aWZpZXIgb2YgdGhlIHBhcmVudCAnbGVhZicgb3IgJ2xlYWYtbGlzdCcgaXMgdXNlZCBhcyBuYW1lIG9mCiAgICAgICB0aGUgcm9sZSBvZiB0aGUgQi1zaWRlIG9mIHRoZSByZWxhdGlvbnNoaXAuIFRoZSBuYW1lIG9mIHRoZSByb2xlIGlzCiAgICAgICBzY29wZWQgdG8gdGhlIHR5cGUgb24gd2hpY2ggdGhlIEItc2lkZSBpcyBkZWZpbmVkIGFuZCBNVVNUIGJlIHVuaXF1ZQogICAgICAgd2l0aGluIHRoZSBzY29wZS4KCiAgICAgICBXaGlsZSB0aGUgcGFyZW50ICdsZWFmJyBvciAnbGVhZi1saXN0JyBkb2VzIG5vdCByZXN1bHQgaW4gYSBwcm9wZXJ0eSBvZgogICAgICAgdGhlIHJlbGF0aW9uc2hpcCwgaXQgaXMgUkVDT01NRU5ERUQgdG8gYXZvaWQgdXNpbmcgdGhlIG5hbWUgb2YgYW4KICAgICAgIGV4aXN0aW5nIHR5cGUgcHJvcGVydHkgYXMgcm9sZSBuYW1lIHRvIGF2b2lkIHBvdGVudGlhbCBhbWJpZ3VpdGllcwogICAgICAgYmV0d2VlbiBwcm9wZXJ0aWVzIG9mIGEgdHlwZSwgYW5kIHJvbGVzIG9mIGEgcmVsYXRpb25zaGlwIG9uIHRoZSB0eXBlLgoKICAgICAgIFRoZSBhcmd1bWVudCBpcyB0aGUgbmFtZSBvZiB0aGUgdHlwZSBvbiB3aGljaCB0aGUgQi1zaWRlIHJlc2lkZXMuIElmIHRoZQogICAgICAgdHlwZSBpcyBkZWNsYXJlZCBpbiBhbm90aGVyIG1vZHVsZSwgdGhlIHR5cGUgbXVzdCBiZSBwcmVmaXhlZCwgYW5kIGEKICAgICAgIGNvcnJlc3BvbmRpbmcgJ2ltcG9ydCcgc3RhdGVtZW50IGJlIHVzZWQgdG8gZGVjbGFyZSB0aGUgcHJlZml4LiI7CgogICAgYXJndW1lbnQgYlNpZGVUeXBlOwogIH0KCiAgZXh0ZW5zaW9uIGRvbWFpbiB7CiAgICBkZXNjcmlwdGlvbiAiS2V5d29yZCB1c2VkIHRvIGNhcnJ5IGRvbWFpbiBpbmZvcm1hdGlvbi4iOwogICAgYXJndW1lbnQgZG9tYWluTmFtZTsKICB9CgogIGV4dGVuc2lvbiBsYWJlbCB7CiAgICBkZXNjcmlwdGlvbiAiVGhlIGxhYmVsIGNhbiBiZSB1c2VkIHRvIGdpdmUgbW9kdWxlcyBhbmQgc3VibW9kdWxlcyBhIHNlbWFudGljIHZlcnNpb24sIGluIGFkZGl0aW9uIHRvIHRoZWlyIHJldmlzaW9uLgoKICAgICAgVGhlIGZvcm1hdCBvZiB0aGUgbGFiZWwgaXMg4oCYeC55LnrigJkg4oCTIGV4cHJlc3NlZCBhcyBwYXR0ZXJuLCBpdCBpcyBbMC05XStcXC5bMC05XStcXC5bMC05XSsKCiAgICAgIFRoZSBzdGF0ZW1lbnQgTVVTVCBvbmx5IGJlIGEgc3Vic3RhdGVtZW50IG9mIHRoZSByZXZpc2lvbiBzdGF0ZW1lbnQuICBaZXJvIG9yIG9uZSByZXZpc2lvbiBsYWJlbCBzdGF0ZW1lbnRzCiAgICAgIHBlciBwYXJlbnQgc3RhdGVtZW50IGFyZSBhbGxvd2VkLgoKICAgICAgUmV2aXNpb24gbGFiZWxzIE1VU1QgYmUgdW5pcXVlIGFtb25nc3QgYWxsIHJldmlzaW9ucyBvZiBhIG1vZHVsZSBvciBzdWJtb2R1bGUuIjsKICAgICAgYXJndW1lbnQgc2VtdmVyc2lvbjsKICB9Cn0=	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-oam-to-cloud	urn:o-ran:smo-teiv-oam-to-cloud	OAM_TO_CLOUD	["o-ran-smo-teiv-oam", "o-ran-smo-teiv-cloud"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LW9hbS10by1jbG91ZCB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtb2FtLXRvLWNsb3VkIjsKICAgIHByZWZpeCBvci10ZWl2LW9hbXRvY2xvdWQ7CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHtwcmVmaXggb3ItdGVpdi10eXBlczsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LW9hbSB7cHJlZml4IG9yLXRlaXYtb2FtOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNsb3VkIHtwcmVmaXggb3ItdGVpdi1jbG91ZDsgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBPJk0gdG8gQ2xvdWQgdG9wb2xvZ3kgbW9kZWwuCgogICAgQ29weXJpZ2h0IChjKSAyMDIzIEVyaWNzc29uIEFCLiBBbGwgcmlnaHRzIHJlc2VydmVkLgoKICAgIFRoaXMgbW9kZWwgY29udGFpbnMgdGhlIFJBTiBPJk0gdG8gQ2xvdWQgdG9wb2xvZ3kgcmVsYXRpb25zIjsKCiAgICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgewogICAgICAgIGRlc2NyaXB0aW9uICJJbml0aWFsIHJldmlzaW9uLiI7CiAgICAgICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogICAgfQoKICAgIG9yLXRlaXYteWV4dDpkb21haW4gT0FNX1RPX0NMT1VEOwoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfREVQTE9ZRURfQVNfQ0xPVURJRklFRE5GIHsgIC8vIDAuLjEgdG8gMQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZiBkZXBsb3llZC1hcy1jbG91ZGlmaWVkTkYgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWFuYWdlZCBFbGVtZW50IGRlcGxveWVkIGFzIENsb3VkaWZpZWQgTkYuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtb2FtOk1hbmFnZWRFbGVtZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIGRlcGxveWVkLW1hbmFnZWRFbGVtZW50IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkNsb3VkaWZpZWQgTkYgZGVwbG95cyBNYW5hZ2VkIEVsZW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtY2xvdWQ6Q2xvdWRpZmllZE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1hbmRhdG9yeSB0cnVlOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfTUFOQUdFREVMRU1FTlQgeyAvLyAxLi5uIHRvIDEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgc2VydmljZWQtbWFuYWdlZEVsZW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWFuYWdlZCBFbGVtZW50IHNlcnZpY2VkIGJ5IHRoaXMgTkYgRGVwbG95bWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1jbG91ZDpORkRlcGxveW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3Qgc2VydmluZy1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCB0aGF0IHNlcnZlcyB0aGlzIE1hbmFnZWQgRWxlbWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1vYW06TWFuYWdlZEVsZW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWluLWVsZW1lbnRzIDE7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-common-yang-types	urn:o-ran:smo-teiv-common-yang-types	\N	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHsKCiAgeWFuZy12ZXJzaW9uIDEuMTsKICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyI7CiAgcHJlZml4IG9yLXRlaXYtdHlwZXM7CgogIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogIGltcG9ydCBfM2dwcC1jb21tb24teWFuZy10eXBlcyB7IHByZWZpeCB0eXBlczNncHA7IH0KCiAgb3JnYW5pemF0aW9uICJFcmljc3NvbiBBQiI7CiAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgZGVzY3JpcHRpb24KICAiVG9wb2xvZ3kgYW5kIEludmVudG9yeSBjb21tb24gdHlwZXMgbW9kZWwuCgogIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgVGhpcyBtb2RlbCBjb250YWlucyByZS11c2FibGUgZGF0YSB0eXBlcyB0aGF0IHRvcG9sb2d5IGFuZCBpbnZlbnRvcnkgbW9kZWxzCiAgd2lsbCBmcmVxdWVudGx5IHVzZSBhcyBwYXJ0IG9mIHR5cGVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CgogIHJldmlzaW9uICIyMDI0LTA1LTAyIiB7CiAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogIH0KCiAgZ3JvdXBpbmcgVG9wX0dycF9UeXBlIHsKCiAgICBkZXNjcmlwdGlvbiAiR3JvdXBpbmcgY29udGFpbmluZyB0aGUga2V5IGF0dHJpYnV0ZSBjb21tb24gdG8gYWxsIHR5cGVzLiBBbGwgdHlwZXMKICAgICAgICAgICAgICAgIE1VU1QgdXNlIHRoaXMgZ3JvdXBpbmcuIjsKCiAgICBsZWFmIGlkIHsKICAgICAgdHlwZSBzdHJpbmc7CiAgICAgIGRlc2NyaXB0aW9uICJVbmlxdWUgaWRlbnRpZmllciBvZiB0b3BvbG9neSBlbnRpdGllcy4gUmVwcmVzZW50cyB0aGUgRW50aXR5IEluc3RhbmNlIElkZW50aWZpZXIuIjsKICAgIH0KICB9CgogIGdyb3VwaW5nIENNX0lEIHsKCiAgICBkZXNjcmlwdGlvbiAiR3JvdXBpbmcgY29udGFpbmluZyB0aGUga2V5IGF0dHJpYnV0ZXMgdG8gbWFrZQogICAgICAgICAgICAgICAgdXNlIG9mIENvbmZpZ3VyYXRpb24gTWFuYWdlbWVudCAoQ00pLiI7CgogICAgbGVhZiBjbUhhbmRsZSB7CiAgICAgIHR5cGUgc3RyaW5nOwogICAgICBkZXNjcmlwdGlvbiAiVW5pcXVlIGlkZW50aWZpZXIgZm9yIG5ldHdvcmsgZW50aXRpZXMgaW4gQ00uIjsKICAgIH0KCiAgICBsZWFmIHJlc291cmNlSWRlbnRpZmllciB7CiAgICAgIHR5cGUgc3RyaW5nOwogICAgICBkZXNjcmlwdGlvbiAiVGhlIHhwYXRoIGV4cHJlc3Npb24gaWRlbnRpZnlpbmcgdGhlIHJlc291cmNlIGluIHRoZSBOb2RlIG1vZGVsIHlhbmcgdHJlZS4iOwogICAgfQogIH0KCiAgdHlwZWRlZiBfM0dQUF9GRE5fVHlwZSB7CiAgICB0eXBlIHR5cGVzM2dwcDpEaXN0aW5ndWlzaGVkTmFtZTsKICB9CgogIGNvbnRhaW5lciBjb25zdW1lci1kYXRhIHsKICAgIGRlc2NyaXB0aW9uICJUaGlzIGNvbnRhaW5lciBkZWZpbmVzIHRoZSBjb25zdW1lci1kYXRhLiBDb25zdW1lci1kYXRhIG1heSBiZSBhdHRhY2hlZCB0byBUb3BvbG9neSBFbnRpdHkgb3IKICAgICAgICAgICAgICAgIFRvcG9sb2d5IFJlbGF0aW9uIGluc3RhbmNlLCBvdXRzaWRlIG9mIHRoZSBkZWNsYXJlZCBUb3BvbG9neSBFbnRpdHkgb3IgVG9wb2xvZ3kgUmVsYXRpb25zaGlwJ3MgYXR0cmlidXRlcy4KICAgICAgICAgICAgICAgIFRoaXMgY29udGFpbmVyIGNhbm5vdCBiZSBpbnN0YW50aWF0ZWQsIGFuZCBpdCBNVVNUIE5PVCBiZSBhdWdtZW50ZWQgb3IgZGV2aWF0ZWQgaW4gYW55IHdheSwgdW5sZXNzIHN0YXRlZAogICAgICAgICAgICAgICAgb3RoZXJ3aXNlLiI7CgogICAgY29udGFpbmVyIGRlY29yYXRvcnMgewogICAgICBkZXNjcmlwdGlvbiAiVGhpcyBjb250YWluZXIgc2VydmVzIGFzIGV4dGVuc2lvbiBwb2ludCBmb3IgYXBwbGljYXRpb25zIHdpc2hpbmcgdG8gZGVmaW5lIHRoZWlyIG93biBkZWNvcmF0b3JzLgogICAgICAgICAgICAgICAgICBUaGlzIGlzIGRvbmUgdmlhIGF1Z21lbnRhdGlvbnMuIFRoZXkgY2FuIG9ubHkgYmUgZGVmaW5lZCBpbiBuYW1lIHZhbHVlIHBhaXIuIjsKICAgIH0KCiAgICBsZWFmLWxpc3QgY2xhc3NpZmllcnMgewogICAgICBkZXNjcmlwdGlvbiAiQ29uc3VtZXIgZGVmaW5lZCB0YWdzIHRvIHRvcG9sb2d5IGVudGl0aWVzIGFuZCByZWxhdGlvbnNoaXBzLiI7CiAgICAgIHR5cGUgaWRlbnRpdHlyZWYgeyBiYXNlIGNsYXNzaWZpZXI7IH0KICAgIH0KCiAgICBsZWFmLWxpc3Qgc291cmNlSWRzIHsKICAgICAgZGVzY3JpcHRpb24gIkFuIG9yZGVyZWQgbGlzdCBvZiBpZGVudGl0aWVzIHRoYXQgcmVwcmVzZW50IHRoZSBzZXQgb2YgbmF0aXZlIHNvdXJjZSBpZGVudGlmaWVycyBmb3IgcGFydGljaXBhdGluZwogICAgICAgICAgICAgICAgICBlbnRpdGllcy4iOwogICAgICB0eXBlIHN0cmluZzsKICAgICAgb3JkZXJlZC1ieSB1c2VyOwogICAgfQoKICAgIGNvbnRhaW5lciBtZXRhZGF0YSB7CiAgICAgIGRlc2NyaXB0aW9uICJUaGlzIGNvbnRhaW5lciBzZXJ2ZXMgYXMgZXh0ZW5zaW9uIHBvaW50IHRvIGRlZmluZSBtZXRhZGF0YS4gVGhleSBjYW4gb25seSBiZSBkZWZpbmVkIGluIG5hbWUgdmFsdWUKICAgICAgICAgICAgICAgICAgcGFpci4iOwogICAgfQogIH0KCiAgaWRlbnRpdHkgY2xhc3NpZmllcnsKICAgIGRlc2NyaXB0aW9uICAiVGhlIGNsYXNzaWZpZXIgaXMgdXNlZCBhcyBhIGJhc2UgdG8gcHJvdmlkZSBhbGwgY2xhc3NpZmllcnMgd2l0aCBpZGVudGl0eS4gIjsKICB9Cn0=	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-oam	urn:o-ran:smo-teiv-oam	OAM	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LW9hbSB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtb2FtIjsKICAgIHByZWZpeCBvci10ZWl2LW9hbTsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBvcmdhbml6YXRpb24gIkVyaWNzc29uIEFCIjsKICAgIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOwogICAgZGVzY3JpcHRpb24KICAgICJSQU4gTyZNIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIE8mTSBkb21haW4sIHdoaWNoIGFyZSBpbnRlbmRlZCB0byByZXByZXNlbnQgbWFuYWdlbWVudCBzeXN0ZW1zCiAgICBhbmQgbWFuYWdlbWVudCBpbnRlcmZhY2VzLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIE9BTTsKCiAgICBsaXN0IE1hbmFnZWRFbGVtZW50IHsKICAgICAgICBkZXNjcmlwdGlvbiAiQSBNYW5hZ2VkIEVsZW1lbnQgKE1FKSBpcyBhIG5vZGUgaW50byBhIHRlbGVjb21tdW5pY2F0aW9uIG5ldHdvcmsKICAgICAgICAgICAgICAgICAgICBwcm92aWRpbmcgc3VwcG9ydCBhbmQvb3Igc2VydmljZSB0byBzdWJzY3JpYmVycy4gQW4gTUUgY29tbXVuaWNhdGVzCiAgICAgICAgICAgICAgICAgICAgd2l0aCBhIG1hbmFnZXIgYXBwbGljYXRpb24gKGRpcmVjdGx5IG9yIGluZGlyZWN0bHkpIG92ZXIgb25lIG9yIG1vcmUKICAgICAgICAgICAgICAgICAgICBpbnRlcmZhY2VzIGZvciB0aGUgcHVycG9zZSBvZiBiZWluZyBtb25pdG9yZWQgYW5kL29yIGNvbnRyb2xsZWQuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBmZG4gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgRnVsbCBEaXN0aW5ndWlzaGVkIE5hbWUgKEZETikgaWRlbnRpZmllcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYW4gaW5zdGFuY2Ugb2YgdGhlIE1hbmFnZWRFbGVtZW50IE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTWFuYWdlZEVsZW1lbnQuIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-oam-to-ran	urn:o-ran:smo-teiv-oam-to-ran	OAM_TO_RAN	["o-ran-smo-teiv-oam", "o-ran-smo-teiv-ran"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LW9hbS10by1yYW4gewogICAgeWFuZy12ZXJzaW9uIDEuMTsKICAgIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LW9hbS10by1yYW4iOwogICAgcHJlZml4IG9yLXRlaXYtb2FtdG9yYW47CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHtwcmVmaXggb3ItdGVpdi10eXBlczsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LW9hbSB7cHJlZml4IG9yLXRlaXYtb2FtOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LXJhbiB7cHJlZml4IG9yLXRlaXYtcmFuOyB9CgogICAgb3JnYW5pemF0aW9uICJFcmljc3NvbiBBQiI7CiAgICBjb250YWN0ICJFcmljc3NvbiBmaXJzdCBsaW5lIHN1cHBvcnQgdmlhIGVtYWlsIjsKICAgIGRlc2NyaXB0aW9uCiAgICAiUkFOIE8mTSB0byBMb2dpY2FsIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSBSQU4gTyZNIHRvIExvZ2ljYWwgdG9wb2xvZ3kgcmVsYXRpb25zIjsKCiAgICByZXZpc2lvbiAiMjAyNC0wNS0wMiIgewogICAgICAgIGRlc2NyaXB0aW9uICJJbml0aWFsIHJldmlzaW9uLiI7CiAgICAgICAgb3ItdGVpdi15ZXh0OmxhYmVsIDAuMy4wOwogICAgfQoKICAgIG9yLXRlaXYteWV4dDpkb21haW4gT0FNX1RPX1JBTjsKCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE1BTkFHRURFTEVNRU5UX01BTkFHRVNfRU5PREVCRlVOQ1RJT04geyAgIC8vIDEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IG1hbmFnZWQtZW5vZGViRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWFuYWdlZCBFbGVtZW50IG1hbmFnZXMgZU5vZGVCIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBvci10ZWl2LW9hbTpNYW5hZ2VkRWxlbWVudDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBtYW5hZ2VkLWJ5LW1hbmFnZWRFbGVtZW50IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImVOb2RlQiBGdW5jdGlvbiBtYW5hZ2VkIGJ5IE1hbmFnZWQgRWxlbWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1yYW46RU5vZGVCRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfTUFOQUdFU19HTkJEVUZVTkNUSU9OIHsgICAgLy8gMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgbWFuYWdlZC1nbmJkdUZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk1hbmFnZWQgRWxlbWVudCBtYW5hZ2VzIGdOb2RlQi1EVSBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1vYW06TWFuYWdlZEVsZW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgbWFuYWdlZC1ieS1tYW5hZ2VkRWxlbWVudCB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUItRFUgRnVuY3Rpb24gbWFuYWdlZCBieSBNYW5hZ2VkIEVsZW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkRVRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfTUFOQUdFU19HTkJDVUNQRlVOQ1RJT04geyAgICAvLyAxIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBtYW5hZ2VkLWduYmN1Y3BGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJNYW5hZ2VkIEVsZW1lbnQgbWFuYWdlcyBnTm9kZUItQ1UtQ1AgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtb2FtOk1hbmFnZWRFbGVtZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIG1hbmFnZWQtYnktbWFuYWdlZEVsZW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVLUNQIEZ1bmN0aW9uIG1hbmFnZWQgYnkgTWFuYWdlZCBFbGVtZW50LiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBvci10ZWl2LXJhbjpHTkJDVUNQRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTUFOQUdFREVMRU1FTlRfTUFOQUdFU19HTkJDVVVQRlVOQ1RJT04geyAgICAvLyAxIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBtYW5hZ2VkLWduYmN1dXBGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJNYW5hZ2VkIEVsZW1lbnQgbWFuYWdlcyBnTm9kZUItQ1UtVVAgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtb2FtOk1hbmFnZWRFbGVtZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIG1hbmFnZWQtYnktbWFuYWdlZEVsZW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVLVVQIEZ1bmN0aW9uIG1hbmFnZWQgYnkgTWFuYWdlZCBFbGVtZW50LiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBvci10ZWl2LXJhbjpHTkJDVVVQRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-ran	urn:o-ran:smo-teiv-ran	RAN	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LXJhbiB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtcmFuIjsKICAgIHByZWZpeCBvci10ZWl2LXJhbjsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgXzNncHAtY29tbW9uLXlhbmctdHlwZXMgeyBwcmVmaXggdHlwZXMzZ3BwOyB9CgogICAgaW1wb3J0IGlldGYtZ2VvLWxvY2F0aW9uIHsKICAgICAgICBwcmVmaXggZ2VvOwogICAgICAgIHJlZmVyZW5jZSAiUkZDIDkxNzk6IEEgWUFORyBHcm91cGluZyBmb3IgR2VvZ3JhcGhpYyBMb2NhdGlvbnMiOwogICAgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBMb2dpY2FsIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIExvZ2ljYWwgZG9tYWluLCB3aGljaCByZXByZXNlbnRzIHRoZSBmdW5jdGlvbmFsIGNhcGFiaWxpdHkKICAgIG9mIHRoZSBkZXBsb3llZCBSQU4gdGhhdCBhcmUgcmVsZXZhbnQgdG8gckFwcHMgdXNlIGNhc2VzLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIFJBTjsKCiAgICBsaXN0IEdOQkRVRnVuY3Rpb24gewogICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUIgRGlzdHJpYnV0ZWQgVW5pdCAoZ05CLURVKS4KCiAgICAgICAgICAgICAgICAgICAgQSBnTkIgbWF5IGNvbnNpc3Qgb2YgYSBnTkItQ2VudHJhbGl6ZWQgVW5pdAogICAgICAgICAgICAgICAgICAgIChnTkItQ1UpIGFuZCBhIGdOQi1EVS4gVGhlIENVIHByb2Nlc3NlcyBub24tcmVhbAogICAgICAgICAgICAgICAgICAgIHRpbWUgcHJvdG9jb2xzIGFuZCBzZXJ2aWNlcywgYW5kIHRoZSBEVSBwcm9jZXNzZXMKICAgICAgICAgICAgICAgICAgICBQSFkgbGV2ZWwgcHJvdG9jb2wgYW5kIHJlYWwgdGltZSBzZXJ2aWNlcy4gVGhlCiAgICAgICAgICAgICAgICAgICAgZ05CLUNVIGFuZCB0aGUgZ05CLURVIHVuaXRzIGFyZSBjb25uZWN0ZWQgdmlhCiAgICAgICAgICAgICAgICAgICAgRjEgbG9naWNhbCBpbnRlcmZhY2UuCgogICAgICAgICAgICAgICAgICAgIFRoZSBmb2xsb3dpbmcgaXMgdHJ1ZSBmb3IgYSBnTkItRFU6CiAgICAgICAgICAgICAgICAgICAgSXMgY29ubmVjdGVkIHRvIHRoZSBnTkItQ1UtQ1AgdGhyb3VnaCB0aGUgRjEtQwogICAgICAgICAgICAgICAgICAgIGludGVyZmFjZS5JcyBjb25uZWN0ZWQgdG8gdGhlIGdOQi1DVS1VUCB0aHJvdWdoCiAgICAgICAgICAgICAgICAgICAgdGhlIEYxLVUgaW50ZXJmYWNlLiBPbmUgZ05CLURVIGlzIGNvbm5lY3RlZCB0byBvbmx5CiAgICAgICAgICAgICAgICAgICAgb25lIGdOQi1DVS1DUC4gT25lIGdOQi1EVSBjYW4gYmUgY29ubmVjdGVkIHRvCiAgICAgICAgICAgICAgICAgICAgbXVsdGlwbGUgZ05CLUNVLVVQcyB1bmRlciB0aGUgY29udHJvbCBvZiB0aGUgc2FtZQogICAgICAgICAgICAgICAgICAgIGdOQi1DVS1DUC4KICAgICAgICAgICAgICAgICAgICBOb3RlOiBBIGdOQiBtYXkgY29uc2lzdCBvZiBhIGdOQi1DVS1DUCwgbXVsdGlwbGUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtVVBzIGFuZCBtdWx0aXBsZSBnTkItRFVzLiBnTkItRFUgaXMgYSBjb25jcmV0ZQogICAgICAgICAgICAgICAgICAgIGNsYXNzIHRoYXQgZXh0ZW5kcyB0aGUgTkctUkFOIG5vZGUgb2JqZWN0LiBJbiBUb3BvbG9neSwgeW91CiAgICAgICAgICAgICAgICAgICAgY2FuIGNyZWF0ZSwgcmVhZCwgdXBkYXRlLCBhbmQgZGVsZXRlIHRoZSBnTkItRFUgb2JqZWN0LiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBHTkJEVUZ1bmN0aW9uIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgR05CRFVGdW5jdGlvbi4iOwogICAgICAgICAgICAgICAgdHlwZSBvci10ZWl2LXR5cGVzOl8zR1BQX0ZETl9UeXBlOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgZFVwTE1OSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlBMTU4gaWRlbnRpZmllciB1c2VkIGFzIHBhcnQgb2YgUE0gRXZlbnRzIGRhdGEiOwogICAgICAgICAgICAgICAgdXNlcyB0eXBlczNncHA6UExNTklkOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGdOQkRVSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgRFUgd2l0aGluIGEgZ05vZGVCIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGdOQklkIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJJZGVudGl0eSBvZiBnTm9kZUIgd2l0aGluIGEgUExNTiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJJZExlbmd0aCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTGVuZ3RoIG9mIGdOQklkIGJpdCBzdHJpbmcgcmVwcmVzZW50YXRpb24iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IEdOQkNVQ1BGdW5jdGlvbiB7CiAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQiBDZW50cmFsaXplZCBVbml0IENvbnRyb2wgUGxhbmUgKGdOQi1DVS1DUCkKCiAgICAgICAgICAgICAgICAgICAgVGhpcyBpcyBhIGxvZ2ljYWwgbm9kZSBob3N0aW5nIHRoZSBSYWRpbyBSZXNvdXJjZQogICAgICAgICAgICAgICAgICAgIENvbnRyb2wgKFJSQykgYW5kIHRoZSBjb250cm9sIHBsYW5lIHBhcnQgb2YgdGhlCiAgICAgICAgICAgICAgICAgICAgUGFja2V0IERhdGEgQ29udmVyZ2VuY2UgUHJvdG9jb2wgKFBEQ1ApIG9mIHRoZQogICAgICAgICAgICAgICAgICAgIGdOb2RlQiBDZW50cmFsaXplZCBVbml0IChnTkItQ1UpIGZvciBhbiBFLVVUUkFOIGdOb2RlQgogICAgICAgICAgICAgICAgICAgIChlbi1nTkIpIG9yIGEgZ05vZGVCIChnTkIpLiBUaGUgZ05CLUNVLUNQIHRlcm1pbmF0ZXMKICAgICAgICAgICAgICAgICAgICB0aGUgRTEgaW50ZXJmYWNlIGNvbm5lY3RlZCB3aXRoIHRoZSBnTkItQ1UtVVAgYW5kIHRoZQogICAgICAgICAgICAgICAgICAgIEYxLUMgaW50ZXJmYWNlIGNvbm5lY3RlZCB3aXRoIHRoZSBnTm9kZUIKICAgICAgICAgICAgICAgICAgICBEaXN0cmlidXRlZCBVbml0IChnTkItRFUpLgoKICAgICAgICAgICAgICAgICAgICBUaGUgZm9sbG93aW5nIGlzIHRydWUgZm9yIGEgZ05CLUNVLUNQOgogICAgICAgICAgICAgICAgICAgIElzIGNvbm5lY3RlZCB0byB0aGUgZ05CLURVIHRocm91Z2ggdGhlIEYxLUMgaW50ZXJmYWNlLgogICAgICAgICAgICAgICAgICAgIElzIGNvbm5lY3RlZCB0byB0aGUgZ05CLUNVLVVQIHRocm91Z2ggdGhlIEUxIGludGVyZmFjZS4KICAgICAgICAgICAgICAgICAgICBPbmx5IG9uZSBnTkItQ1UtQ1AgaXMgY29ubmVjdGVkIHRvIG9uZSBnTkItRFUuCiAgICAgICAgICAgICAgICAgICAgT25seSBvbmUgZ05CLUNVLUNQIGlzIGNvbm5lY3RlZCB0byBvbmUgZ05CLUNVLVVQLgogICAgICAgICAgICAgICAgICAgIE9uZSBnTkItRFUgY2FuIGJlIGNvbm5lY3RlZCB0byBtdWx0aXBsZSBnTkItQ1UtVVBzCiAgICAgICAgICAgICAgICAgICAgdW5kZXIgdGhlIGNvbnRyb2wgb2YgdGhlIHNhbWUgZ05CLUNVLUNQLk9uZSBnTkItQ1UtVVAKICAgICAgICAgICAgICAgICAgICBjYW4gYmUgY29ubmVjdGVkIHRvIG11bHRpcGxlIERVcyB1bmRlciB0aGUgY29udHJvbCBvZgogICAgICAgICAgICAgICAgICAgIHRoZSBzYW1lIGdOQi1DVS1DUC4KICAgICAgICAgICAgICAgICAgICBOb3RlOiBBIGdOQiBtYXkgY29uc2lzdCBvZiBhIGdOQi1DVS1DUCwgbXVsdGlwbGUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtVVBzIGFuZCBtdWx0aXBsZSBnTkItRFVzLiBBIGdOQi1DVS1DUCBpcyBhCiAgICAgICAgICAgICAgICAgICAgY29uY3JldGUgY2xhc3MgdGhhdCBleHRlbmRzIHRoZSBORy1SQU4gbm9kZSBvYmplY3QuCiAgICAgICAgICAgICAgICAgICAgSW4gVG9wb2xvZ3ksIHlvdSBjYW4gY3JlYXRlLCByZWFkLCB1cGRhdGUsIGFuZCBkZWxldGUKICAgICAgICAgICAgICAgICAgICB0aGUgZ05CLUNVLUNQIG9iamVjdC4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgR05CQ1VDUEZ1bmN0aW9uIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgR05CQ1VDUEZ1bmN0aW9uLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZ05CQ1VOYW1lIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOYW1lIG9mIGdOb2RlQi1DVSI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSWRlbnRpdHkgb2YgZ05vZGVCIHdpdGhpbiBhIFBMTU4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZ05CSWRMZW5ndGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxlbmd0aCBvZiBnTkJJZCBiaXQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgcExNTklkIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQTE1OIGlkZW50aWZpZXIgdG8gYmUgdXNlZCBhcyBwYXJ0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvZiBnbG9iYWwgUkFOIG5vZGUgaWRlbnRpdHkiOwogICAgICAgICAgICAgICAgdXNlcyB0eXBlczNncHA6UExNTklkOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgY21JZCB7CiAgICAgICAgICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6Q01fSUQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgbGlzdCBHTkJDVVVQRnVuY3Rpb24gewogICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUIgQ2VudHJhbGl6ZWQgVW5pdCBVc2VyIFBsYW5lIChnTkItQ1UtVVApCgogICAgICAgICAgICAgICAgICAgIEEgZ05CLUNVLVVQIGlzIGEgbG9naWNhbCBub2RlIGhvc3RpbmcgdGhlIFVzZXIKICAgICAgICAgICAgICAgICAgICBQbGFuZSBwYXJ0IG9mIHRoZSBQYWNrZXQgRGF0YSBDb252ZXJnZW5jZSwKICAgICAgICAgICAgICAgICAgICBQcm90b2NvbCAoUERDUCkgb2YgdGhlIGdOb2RlQiBDZW50cmFsaXplZCBVbml0CiAgICAgICAgICAgICAgICAgICAgKGdOQi1DVSkgZm9yIGFuIEUtVVRSQU4gZ05vZGVCIChlbi1nTkIpLCBhbmQgdGhlCiAgICAgICAgICAgICAgICAgICAgVXNlciBQbGFuZSBwYXJ0IG9mIHRoZSBQRENQIHByb3RvY29sIGFuZCB0aGUKICAgICAgICAgICAgICAgICAgICBTZXJ2aWNlIERhdGEgQWRhcHRhdGlvbiBQcm90b2NvbCAoU0RBUCkgb2YgdGhlCiAgICAgICAgICAgICAgICAgICAgZ05CLUNVIGZvciBhIGdOb2RlQiAoZ05CKS4gVGhlIGdOQi1DVS1VUCB0ZXJtaW5hdGVzCiAgICAgICAgICAgICAgICAgICAgdGhlIEUxIGludGVyZmFjZSBjb25uZWN0ZWQgd2l0aCB0aGUgZ05CLUNVLUNQIGFuZAogICAgICAgICAgICAgICAgICAgIHRoZSBGMS1VIGludGVyZmFjZSBjb25uZWN0ZWQgd2l0aCB0aGUgZ05vZGVCCiAgICAgICAgICAgICAgICAgICAgRGlzdHJpYnV0ZWQgVW5pdCAoZ05CLURVKS4KCiAgICAgICAgICAgICAgICAgICAgVGhlIGZvbGxvd2luZyBpcyB0cnVlIGZvciBhIGdOQi1DVS1VUDoKICAgICAgICAgICAgICAgICAgICBJcyBjb25uZWN0ZWQgdG8gdGhlIGdOQi1EVSB0aHJvdWdoIHRoZQogICAgICAgICAgICAgICAgICAgIEYxLVUgaW50ZXJmYWNlLiBJcyBjb25uZWN0ZWQgdG8gdGhlIGdOQi1DVS1DUCB0aHJvdWdoCiAgICAgICAgICAgICAgICAgICAgdGhlIEUxIGludGVyZmFjZS4gT25lIGdOQi1DVS1VUCBpcyBjb25uZWN0ZWQgdG8gb25seSBvbmUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtQ1AuIE9uZSBnTkItRFUgY2FuIGJlIGNvbm5lY3RlZCB0byBtdWx0aXBsZQogICAgICAgICAgICAgICAgICAgIGdOQi1DVS1VUHMgdW5kZXIgdGhlIGNvbnRyb2wgb2YgdGhlIHNhbWUgZ05CLUNVLUNQLiBPbmUKICAgICAgICAgICAgICAgICAgICBnTkItQ1UtVVAgY2FuIGJlIGNvbm5lY3RlZCB0byBtdWx0aXBsZSBEVXMgdW5kZXIgdGhlCiAgICAgICAgICAgICAgICAgICAgY29udHJvbCBvZiB0aGUgc2FtZSBnTkItQ1UtQ1AuCiAgICAgICAgICAgICAgICAgICAgTm90ZTogQSBnTkIgbWF5IGNvbnNpc3Qgb2YgYSBnTkItQ1UtQ1AsIG11bHRpcGxlIGdOQi1DVS1VUHMKICAgICAgICAgICAgICAgICAgICBhbmQgbXVsdGlwbGUgZ05CLURVcy4gQSBnTkItQ1UtVVAgaXMgYSBjb25jcmV0ZSBjbGFzcyB0aGF0CiAgICAgICAgICAgICAgICAgICAgZXh0ZW5kcyB0aGUgTkctUkFOIG5vZGUgb2JqZWN0LiBJbiBUb3BvbG9neSwgeW91IGNhbgogICAgICAgICAgICAgICAgICAgIGNyZWF0ZSwgcmVhZCwgdXBkYXRlLCBhbmQgZGVsZXRlIHRoZSBnTkItQ1UtVVAgb2JqZWN0LiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBHTkJDVVVQRnVuY3Rpb24gTU8uIEl0IGNvbnRhaW5zCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgZnVsbCBwYXRoIGZyb20gdGhlIFN1Ym5ldHdvcmsgdG8gdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHTkJDVVVQRnVuY3Rpb24uIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBnTkJJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSWRlbnRpdHkgb2YgZ05vZGVCIHdpdGhpbiBhIFBMTU4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZ05CSWRMZW5ndGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxlbmd0aCBvZiBnTkJJZCBiaXQgc3RyaW5nIHJlcHJlc2VudGF0aW9uIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb250YWluZXIgY21JZCB7CiAgICAgICAgICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6Q01fSUQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgbGlzdCBOUkNlbGxDVSB7CiAgICAgICAgZGVzY3JpcHRpb24gIlJlcHJlc2VudHMgYW4gTlIgQ2VsbCBpbiBnTm9kZUItQ1UuCgogICAgICAgICAgICAgICAgICAgIDVHIE5SIGlzIGEgbmV3IHJhZGlvIGFjY2VzcyB0ZWNobm9sb2d5IChSQVQpCiAgICAgICAgICAgICAgICAgICAgZGV2ZWxvcGVkIGJ5IDNHUFAgZm9yIHRoZSA1RyAoZmlmdGggZ2VuZXJhdGlvbikKICAgICAgICAgICAgICAgICAgICBtb2JpbGUgbmV0d29yay4gSXQgaXMgZGVzaWduZWQgdG8gYmUgdGhlIGdsb2JhbAogICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkIGZvciB0aGUgYWlyIGludGVyZmFjZSBvZiA1RyBuZXR3b3Jrcy4KCiAgICAgICAgICAgICAgICAgICAgNUcgTlIgaGFzIHN5bmNocm9uaXphdGlvbiBzaWduYWwgdGhhdCBpcyBrbm93biBhcwogICAgICAgICAgICAgICAgICAgIFByaW1hcnkgU3luY2hyb25pemF0aW9uIHNpZ25hbCAoUFNTKSBhbmQgU2Vjb25kYXJ5CiAgICAgICAgICAgICAgICAgICAgU3luY2hyb25pemF0aW9uIHNpZ25hbCAoU1NTKS4gVGhlc2Ugc2lnbmFscyBhcmUKICAgICAgICAgICAgICAgICAgICBzcGVjaWZpYyB0byBOUiBwaHlzaWNhbCBsYXllciBhbmQgcHJvdmlkZSB0aGUKICAgICAgICAgICAgICAgICAgICBmb2xsb3dpbmcgaW5mb3JtYXRpb24gcmVxdWlyZWQgYnkgVUUgZm9yIGRvd25saW5rCiAgICAgICAgICAgICAgICAgICAgc3luY2hyb25pemF0aW9uOiBQU1MgcHJvdmlkZXMgUmFkaW8gRnJhbWUgQm91bmRhcnkKICAgICAgICAgICAgICAgICAgICAoUG9zaXRpb24gb2YgMXN0IFN5bWJvbCBpbiBhIFJhZGlvIGZyYW1lKSBTU1MgcHJvdmlkZXMKICAgICAgICAgICAgICAgICAgICBTdWJmcmFtZSBCb3VuZGFyeSAoUG9zaXRpb24gb2YgMXN0IFN5bWJvbCBpbiBhIFN1YmZyYW1lKQogICAgICAgICAgICAgICAgICAgIFBoeXNpY2FsIExheWVyIENlbGwgSUQgKFBDSSkgaW5mb3JtYXRpb24gdXNpbmcgYm90aAogICAgICAgICAgICAgICAgICAgIFBTUyBhbmQgU1NTLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBOUkNlbGxDVSBNTy4gSXQgY29udGFpbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBmdWxsIHBhdGggZnJvbSB0aGUgU3VibmV0d29yayB0byB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5SQ2VsbENVLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgY2VsbExvY2FsSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlVzZWQgdG9nZXRoZXIgd2l0aCBnTm9kZUIgaWRlbnRpZmllciB0bwogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnRpZnkgTlIgY2VsbCBpbiBQTE1OLiBVc2VkIHRvZ2V0aGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aXRoIGdOQklkIHRvIGZvcm0gTkNJLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIHBsbW5JZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiUExNTiBJRCBmb3IgTlIgQ0dJLiBJZiBlbXB0eSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdOQkNVQ1BGdW5jdGlvbjo6cExNTklkIGlzIHVzZWQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciBQTE1OIElEIGluIE5SIENHSSI7CiAgICAgICAgICAgICAgICB1c2VzIHR5cGVzM2dwcDpQTE1OSWQ7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgbkNJIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBDZWxsIElkZW50aXR5IjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIG5SVEFDIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBUcmFja2luZyBBcmVhIENvZGUgKFRBQykiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IE5SQ2VsbERVIHsKICAgICAgICBkZXNjcmlwdGlvbiAiUmVwcmVzZW50cyBhbiBOUiBDZWxsIGluIGdOb2RlQi1EVS4KCiAgICAgICAgICAgICAgICAgICAgNUcgTlIgaXMgYSBuZXcgcmFkaW8gYWNjZXNzIHRlY2hub2xvZ3kgKFJBVCkKICAgICAgICAgICAgICAgICAgICBkZXZlbG9wZWQgYnkgM0dQUCBmb3IgdGhlIDVHIChmaWZ0aCBnZW5lcmF0aW9uKQogICAgICAgICAgICAgICAgICAgIG1vYmlsZSBuZXR3b3JrLiBJdCBpcyBkZXNpZ25lZCB0byBiZSB0aGUgZ2xvYmFsCiAgICAgICAgICAgICAgICAgICAgc3RhbmRhcmQgZm9yIHRoZSBhaXIgaW50ZXJmYWNlIG9mIDVHIG5ldHdvcmtzLgoKICAgICAgICAgICAgICAgICAgICA1RyBOUiBoYXMgc3luY2hyb25pemF0aW9uIHNpZ25hbCB0aGF0IGlzIGtub3duIGFzCiAgICAgICAgICAgICAgICAgICAgUHJpbWFyeSBTeW5jaHJvbml6YXRpb24gc2lnbmFsIChQU1MpIGFuZCBTZWNvbmRhcnkKICAgICAgICAgICAgICAgICAgICBTeW5jaHJvbml6YXRpb24gc2lnbmFsIChTU1MpLiBUaGVzZSBzaWduYWxzIGFyZQogICAgICAgICAgICAgICAgICAgIHNwZWNpZmljIHRvIE5SIHBoeXNpY2FsIGxheWVyIGFuZCBwcm92aWRlIHRoZQogICAgICAgICAgICAgICAgICAgIGZvbGxvd2luZyBpbmZvcm1hdGlvbiByZXF1aXJlZCBieSBVRSBmb3IgZG93bmxpbmsKICAgICAgICAgICAgICAgICAgICBzeW5jaHJvbml6YXRpb246IFBTUyBwcm92aWRlcyBSYWRpbyBGcmFtZSBCb3VuZGFyeQogICAgICAgICAgICAgICAgICAgIChQb3NpdGlvbiBvZiAxc3QgU3ltYm9sIGluIGEgUmFkaW8gZnJhbWUpIFNTUyBwcm92aWRlcwogICAgICAgICAgICAgICAgICAgIFN1YmZyYW1lIEJvdW5kYXJ5IChQb3NpdGlvbiBvZiAxc3QgU3ltYm9sIGluIGEgU3ViZnJhbWUpCiAgICAgICAgICAgICAgICAgICAgUGh5c2ljYWwgTGF5ZXIgQ2VsbCBJRCAoUENJKSBpbmZvcm1hdGlvbiB1c2luZyBib3RoCiAgICAgICAgICAgICAgICAgICAgUFNTIGFuZCBTU1MuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBmZG4gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgRnVsbCBEaXN0aW5ndWlzaGVkIE5hbWUgKEZETikgaWRlbnRpZmllcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYW4gaW5zdGFuY2Ugb2YgdGhlIE5SQ2VsbERVIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTlJDZWxsRFUuIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBjZWxsTG9jYWxJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVXNlZCB0b2dldGhlciB3aXRoIGdOb2RlQiBpZGVudGlmaWVyIHRvIGlkZW50aWZ5IE5SCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VsbCBpbiBQTE1OLiBVc2VkIHRvZ2V0aGVyIHdpdGggZ05CSWQgdG8gZm9ybSBOQ0kuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIG5DSSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQ2VsbCBJZGVudGl0eS4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgblJQQ0kgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBQaHlzaWNhbCBDZWxsIElkZW50aXR5IChQQ0kpIG9mIHRoZSBOUiBjZWxsLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBuUlRBQyB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgVHJhY2tpbmcgQXJlYSBDb2RlIChUQUMpLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgRU5vZGVCRnVuY3Rpb24gewogICAgICAgIGRlc2NyaXB0aW9uICJBbiBFdm9sdmVkIE5vZGUgQiAoZU5vZGVCKSBpcyB0aGUgb25seSBtYW5kYXRvcnkKICAgICAgICAgICAgICAgICAgICBub2RlIGluIHRoZSByYWRpbyBhY2Nlc3MgbmV0d29yayAoUkFOKSBvZiBMb25nLVRlcm0KICAgICAgICAgICAgICAgICAgICBFdm9sdXRpb24gKExURSkuIFRoZSBlTm9kZUIgaXMgYSBjb21wbGV4IGJhc2UKICAgICAgICAgICAgICAgICAgICBzdGF0aW9uIHRoYXQgaGFuZGxlcyByYWRpbyBjb21tdW5pY2F0aW9ucwogICAgICAgICAgICAgICAgICAgIGluIHRoZSBjZWxsIGFuZCBjYXJyaWVzIG91dCByYWRpbyByZXNvdXJjZQogICAgICAgICAgICAgICAgICAgIG1hbmFnZW1lbnQgYW5kIGhhbmRvdmVyIGRlY2lzaW9ucy4gVW5saWtlIDIvM0cKICAgICAgICAgICAgICAgICAgICB3aXJlbGVzcyBSQU4sIHRoZXJlIGlzIG5vIGNlbnRyYWxpemVkIHJhZGlvIG5ldHdvcmsKICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVyIGluIExURS4gSXQgaXMgdGhlIGhhcmR3YXJlIHRoYXQgaXMgY29ubmVjdGVkCiAgICAgICAgICAgICAgICAgICAgdG8gdGhlIG1vYmlsZSBwaG9uZSBuZXR3b3JrIHRoYXQgY29tbXVuaWNhdGVzCiAgICAgICAgICAgICAgICAgICAgZGlyZWN0bHkgd2l0aCBtb2JpbGUgaGFuZHNldHMgKFVzZXIgRXF1aXBtZW50KSwgbGlrZSBhIGJhc2UKICAgICAgICAgICAgICAgICAgICB0cmFuc2NlaXZlciBzdGF0aW9uIChCVFMpIGluIEdTTSBuZXR3b3Jrcy4gVGhpcyBzaW1wbGlmaWVzCiAgICAgICAgICAgICAgICAgICAgdGhlIGFyY2hpdGVjdHVyZSBhbmQgYWxsb3dzIGxvd2VyIHJlc3BvbnNlIHRpbWVzLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgZmRuIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIEZ1bGwgRGlzdGluZ3Vpc2hlZCBOYW1lIChGRE4pIGlkZW50aWZpZXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuIGluc3RhbmNlIG9mIHRoZSBFTm9kZUJGdW5jdGlvbiBNTy4gSXQgY29udGFpbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBmdWxsIHBhdGggZnJvbSB0aGUgU3VibmV0d29yayB0byB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVOb2RlQkZ1bmN0aW9uLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZU5CSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFTm9kZUIgSUQgdGhhdCBmb3JtcyBwYXJ0IG9mCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgQ2VsbCBHbG9iYWwgSWRlbnRpdHksIGFuZCBpcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxzbyB1c2VkIHRvIGlkZW50aWZ5IHRoZSBub2RlIG92ZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBTMSBpbnRlcmZhY2UiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBlTm9kZUJQbG1uSWQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFTm9kZUIgUHVibGljIExhbmQgTW9iaWxlIE5ldHdvcmsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIChQTE1OKSBJRCB0aGF0IGZvcm1zIHBhcnQgb2YgdGhlIEVOb2RlQgogICAgICAgICAgICAgICAgICAgICAgICAgICAgR2xvYmFsIElEIHVzZWQgdG8gaWRlbnRpZnkgdGhlIG5vZGUgb3ZlcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIFMxIGludGVyZmFjZS4gTm90ZTogVGhlIHZhbHVlIChNQ0M9MDAxLCBNTkM9MDEpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRpY2F0ZXMgdGhhdCB0aGUgUExNTiBpcyBub3QgaW5pdGlhdGVkLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgVGhlIHZhbHVlIGNhbiBub3QgYmUgdXNlZCBhcyBhIHZhbGlkIFBMTU4gSWRlbnRpdHkuIjsKCiAgICAgICAgICAgICAgICBsZWFmIG1jYyB7CiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBNQ0MgcGFydCBvZiBhIFBMTU4gaWRlbnRpdHkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VkIGluIHRoZSByYWRpbyBuZXR3b3JrLiI7CiAgICAgICAgICAgICAgICAgICAgdHlwZSBpbnQzMiB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlIDAuLjk5OTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBsZWFmIG1uYyB7CiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBNTkMgcGFydCBvZiBhIFBMTU4gaWRlbnRpdHkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VkIGluIHRoZSByYWRpbyBuZXR3b3JrLiI7CiAgICAgICAgICAgICAgICAgICAgdHlwZSBpbnQzMiB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlIDAuLjk5OTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBsZWFmIG1uY0xlbmd0aCB7CiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBsZW5ndGggb2YgdGhlIE1OQyBwYXJ0IG9mIGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQTE1OIGlkZW50aXR5IHVzZWQgaW4gdGhlIHJhZGlvIG5ldHdvcmsuIjsKICAgICAgICAgICAgICAgICAgICB0eXBlIGludDMyIHsKICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgMi4uMzsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IEVVdHJhbkNlbGwgewogICAgICAgIGRlc2NyaXB0aW9uICJSZXByZXNlbnRzIGFuIEZERCBvciBUREQgRVV0cmFuQ2VsbCBhbmQKICAgICAgICAgICAgICAgICAgICBjb250YWlucyBwYXJhbWV0ZXJzIG5lZWRlZCBieSB0aGUgY2VsbC4KICAgICAgICAgICAgICAgICAgICBJdCBhbHNvIGNvbnRhaW5zIHBhcmFtZXRlcnMgZm9yIHRoZQogICAgICAgICAgICAgICAgICAgIG1hbmRhdG9yeSBjb21tb24gY2hhbm5lbHMuIEFuIEVVVFJBTiBzdGFuZHMKICAgICAgICAgICAgICAgICAgICBmb3IgRXZvbHZlZCBVbml2ZXJzYWwgTW9iaWxlIFRlbGVjb21tdW5pY2F0aW9ucwogICAgICAgICAgICAgICAgICAgIFN5c3RlbSAoVU1UUykgVGVycmVzdHJpYWwgUmFkaW8gQWNjZXNzIE5ldHdvcmsKICAgICAgICAgICAgICAgICAgICB3aGljaCBjb250YWlucyBhbiBlTm9kZUIuIFRoZSBlTm9kZUIgY29uY3JldGUKICAgICAgICAgICAgICAgICAgICBjbGFzcyBpcyBleHRlbmRlZCBmcm9tIHRoZSBFVVRSQU4gTm9kZSBhYnN0cmFjdCBjbGFzcy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiBlaXRoZXIgdGhlIEVVdHJhbkNlbGxGREQgTU8gb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBFVXRyYW5DZWxsVEREIE1PLiBJdCBjb250YWlucyB0aGUgZnVsbAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZSBFVXRyYW5DZWxsRkREIG9yCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFVXRyYW5DZWxsVERELiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgY2VsbElkewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlJCUyBpbnRlcm5hbCBJRCBhdHRyaWJ1dGUgZm9yIEVVdHJhbkNlbGwuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBNdXN0IGJlIHVuaXF1ZSBpbiB0aGUgUkJTLiBUb2dldGhlciB3aXRoIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTm9kZSBJRCBhbmQgUHVibGljIExhbmQgTW9iaWxlIE5ldHdvcmsgKFBMTU4pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzIGlzIGEgdW5pdmVyc2FsbHkgdW5pcXVlIGNlbGwgSUQiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZWFyZmNuZGwgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBjaGFubmVsIG51bWJlciBmb3IgdGhlIGNlbnRyYWwgZG93bmxpbmsgZnJlcXVlbmN5LiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBlYXJmY251bCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2hhbm5lbCBudW1iZXIgZm9yIHRoZSBjZW50cmFsIHVwbGluayBmcmVxdWVuY3kiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZGxDaGFubmVsQmFuZHdpZHRoIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUaGUgZG93bmxpbmsgY2hhbm5lbCBiYW5kd2lkdGggaW4gdGhlIEZERCBjZWxsLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBlYXJmY24gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBFLVVUUkEgQWJzb2x1dGUgUmFkaW8gRnJlcXVlbmN5IENoYW5uZWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE51bWJlciAoRUFSRkNOKSBmb3IgdGhlIFRERCBjZWxsIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGNoYW5uZWxCYW5kd2lkdGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBjaGFubmVsIGJhbmR3aWR0aCBpbiB0aGUgVEREIGNlbGwuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIHRhYyB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVHJhY2tpbmcgQXJlYSBDb2RlIGZvciB0aGUgRVV0cmFuIENlbGwiOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZHVwbGV4VHlwZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSW5kaWNhdG9yIG9mIEVVdHJhbkNlbGwgdHlwZSwgRkREIG9yIFRERCI7CiAgICAgICAgICAgICAgICB0eXBlIGVudW1lcmF0aW9uIHsKICAgICAgICAgICAgICAgICAgICBlbnVtIGZkZCB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDA7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJGREQiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIHRkZCB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDE7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUREQiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgTlJTZWN0b3JDYXJyaWVyIHsKICAgICAgICBkZXNjcmlwdGlvbiAiVGhlIE5SIFNlY3RvciBDYXJyaWVyIG9iamVjdCBwcm92aWRlcwogICAgICAgICAgICAgICAgICAgIHRoZSBhdHRyaWJ1dGVzIGZvciBkZWZpbmluZyB0aGUgbG9naWNhbAogICAgICAgICAgICAgICAgICAgIGNoYXJhY3RlcmlzdGljcyBvZiBhIGNhcnJpZXIgKGNlbGwpIGluIGEKICAgICAgICAgICAgICAgICAgICBzZWN0b3IuIEEgc2VjdG9yIGlzIGEgY292ZXJhZ2UgYXJlYSBhc3NvY2lhdGVkCiAgICAgICAgICAgICAgICAgICAgd2l0aCBhIGJhc2Ugc3RhdGlvbiBoYXZpbmcgaXRzIG93biBhbnRlbm5hcywKICAgICAgICAgICAgICAgICAgICByYWRpbyBwb3J0cywgYW5kIGNvbnRyb2wgY2hhbm5lbHMuIFRoZSBjb25jZXB0CiAgICAgICAgICAgICAgICAgICAgb2Ygc2VjdG9ycyB3YXMgZGV2ZWxvcGVkIHRvIGltcHJvdmUgY28tY2hhbm5lbAogICAgICAgICAgICAgICAgICAgIGludGVyZmVyZW5jZSBpbiBjZWxsdWxhciBzeXN0ZW1zLCBhbmQgbW9zdCB3aXJlbGVzcwogICAgICAgICAgICAgICAgICAgIHN5c3RlbXMgdXNlIHRocmVlIHNlY3RvciBjZWxscy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgTlJTZWN0b3JDYXJyaWVyIE1PLiBJdCBjb250YWlucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrIHRvIHRoZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTlJTZWN0b3JDYXJyaWVyLiI7CiAgICAgICAgICAgICAgICB0eXBlIG9yLXRlaXYtdHlwZXM6XzNHUFBfRkROX1R5cGU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgYXJmY25ETCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQWJzb2x1dGUgUmFkaW8gRnJlcXVlbmN5IENoYW5uZWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIE51bWJlciAoTlItQVJGQ04pIGZvciBkb3dubGluayI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBhcmZjblVMIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBBYnNvbHV0ZSBSYWRpbyBmcmVxdWVuY3kgQ2hhbm5lbCBOdW1iZXIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIChOUi1BUkZDTikgZm9yIHVwbGluay4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgZnJlcXVlbmN5REwgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlJGIFJlZmVyZW5jZSBGcmVxdWVuY3kgb2YgZG93bmxpbmsgY2hhbm5lbCI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBmcmVxdWVuY3lVTCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiUkYgUmVmZXJlbmNlIEZyZXF1ZW5jeSBvZiB1cGxpbmsgY2hhbm5lbCI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBiU0NoYW5uZWxCd0RMIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJCUyBDaGFubmVsIGJhbmR3aWR0aCBpbiBNSHogZm9yIGRvd25saW5rLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgTFRFU2VjdG9yQ2FycmllciB7CiAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBMVEUgU2VjdG9yIENhcnJpZXIgb2JqZWN0IHByb3ZpZGVzIHRoZQogICAgICAgICAgICAgICAgICAgIGF0dHJpYnV0ZXMgZm9yIGRlZmluaW5nIHRoZSBsb2dpY2FsIGNoYXJhY3RlcmlzdGljcwogICAgICAgICAgICAgICAgICAgIG9mIGEgY2FycmllciAoY2VsbCkgaW4gYSBzZWN0b3IuIEEgc2VjdG9yIGlzIGEgY292ZXJhZ2UKICAgICAgICAgICAgICAgICAgICBhcmVhIGFzc29jaWF0ZWQgd2l0aCBhIGJhc2Ugc3RhdGlvbiBoYXZpbmcKICAgICAgICAgICAgICAgICAgICBpdHMgb3duIGFudGVubmFzLCByYWRpbyBwb3J0cywgYW5kIGNvbnRyb2wgY2hhbm5lbHMuCiAgICAgICAgICAgICAgICAgICAgVGhlIGNvbmNlcHQgb2Ygc2VjdG9ycyB3YXMgZGV2ZWxvcGVkIHRvIGltcHJvdmUgY28tY2hhbm5lbAogICAgICAgICAgICAgICAgICAgIGludGVyZmVyZW5jZSBpbiBjZWxsdWxhciBzeXN0ZW1zLCBhbmQgbW9zdCB3aXJlbGVzcyBzeXN0ZW1zCiAgICAgICAgICAgICAgICAgICAgdXNlIHRocmVlIHNlY3RvciBjZWxscy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgU2VjdG9yQ2FycmllciBNTy4gSXQgY29udGFpbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBmdWxsIHBhdGggZnJvbSB0aGUgU3VibmV0d29yayB0byB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNlY3RvckNhcnJpZXIuIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBzZWN0b3JDYXJyaWVyVHlwZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiSW5kaWNhdGVzIHdoZXRoZXIgb3Igbm90IHRoZSBzZWN0b3IgY2FycmllcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxsZWQgYnkgTU8gU2VjdG9yQ2FycmllciBpcyBhIGRpZ2l0YWwgc2VjdG9yLiI7CiAgICAgICAgICAgICAgICB0eXBlIGVudW1lcmF0aW9uIHsKICAgICAgICAgICAgICAgICAgICBlbnVtIG5vcm1hbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAwOwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTm90IGEgZGlnaXRhbCBzZWN0b3IiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIGxlZnRfZGlnaXRhbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSAxOwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTGVmdCBkaWdpdGFsIHNlY3RvciBmb3IgMkRTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSByaWdodF9kaWdpdGFsX3NlY3RvciB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDI7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSaWdodCBkaWdpdGFsIHNlY3RvciBmb3IgMkRTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSBsZWZ0X2RpZ2l0YWxfc2VjdG9yXzNkcyB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDM7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMZWZ0IGRpZ2l0YWwgc2VjdG9yIGZvciAzRFMiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBlbnVtIHJpZ2h0X2RpZ2l0YWxfc2VjdG9yXzNkcyB7CiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlIDQ7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJSaWdodCBkaWdpdGFsIHNlY3RvciBmb3IgM0RTIjsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZW51bSBtaWRkbGVfZGlnaXRhbF9zZWN0b3IgewogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA1OwogICAgICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTWlkZGxlIGRpZ2l0YWwgc2VjdG9yIGZvciAzRFMiOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgQW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgIGRlc2NyaXB0aW9uICJUaGlzIE1PIHNlcnZlcyBhcyBhIG1hcHBpbmcgYmV0d2VlbiB0aGUgY2VsbAogICAgICAgICAgICAgICAgICAgIGFuZCB0aGUgUkJTIGVxdWlwbWVudCB1c2VkIHRvIHByb3ZpZGUgY292ZXJhZ2UKICAgICAgICAgICAgICAgICAgICBpbiBhIGNlcnRhaW4gZ2VvZ3JhcGhpY2FsIGFyZWEuIFRoZSBNTyBhbHNvCiAgICAgICAgICAgICAgICAgICAgY29udHJvbHMgdGhlIG1heGltdW0gb3V0cHV0IHBvd2VyIG9mIHRoZSBzZWN0b3IuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBmZG4gewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoaXMgRnVsbCBEaXN0aW5ndWlzaGVkIE5hbWUgKEZETikgaWRlbnRpZmllcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYW4gaW5zdGFuY2Ugb2YgdGhlIFNlY3RvckVxdWlwbWVudEZ1bmN0aW9uIE1PLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgSXQgY29udGFpbnMgdGhlIGZ1bGwgcGF0aCBmcm9tIHRoZSBTdWJuZXR3b3JrCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byB0aGUgU2VjdG9yRXF1aXBtZW50RnVuY3Rpb24uIjsKICAgICAgICAgICAgICAgIHR5cGUgb3ItdGVpdi10eXBlczpfM0dQUF9GRE5fVHlwZTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZi1saXN0IGVVdHJhbkZxQmFuZHMgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkxpc3Qgb2YgTFRFIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdCBhc3NvY2lhdGVkIGhhcmR3YXJlIHN1cHBvcnRzIjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmLWxpc3QgZ2VyYW5GcUJhbmRzIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIEdFUkFOIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdCBhc3NvY2lhdGVkIGhhcmR3YXJlIHN1cHBvcnRzIjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmLWxpc3QgblJGcUJhbmRzIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMaXN0IG9mIE5SIGZyZXF1ZW5jeSBiYW5kcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzb2NpYXRlZCBoYXJkd2FyZSBzdXBwb3J0cyI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgU2VjdG9yIHsKICAgICAgICBkZXNjcmlwdGlvbiAiQSBncm91cCBvZiBjby1sb2NhdGVkIENlbGxzIHRoYXQKICAgICAgICAgICAgICAgICAgICBoYXZlIGEgc2hhcmVkIGNvdmVyYWdlIGFyZWEuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBzZWN0b3JJZCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVW5pdmVyc2FsbHkgdW5pcXVlIElEIGdlbmVyYXRlZCBieSB0aGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlY3RvcidzIGRpc2NvdmVyeSBtZWNoYW5pc20uIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDY0OwogICAgICAgICAgICB9CgogICAgICAgICAgICB1c2VzIGdlbzpnZW8tbG9jYXRpb247CgogICAgICAgICAgICBsZWFmIGF6aW11dGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIkF2ZXJhZ2UgdmFsdWUgb2YgdGhlIGF6aW11dGhzIG9mIHRoZSBjZWxscwogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcHJpc2luZyB0aGUgc2VjdG9yLCBkZXRlcm1pbmVkIGR1cmluZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VjdG9yIGRpc2NvdmVyeS4iOwogICAgICAgICAgICAgICAgdHlwZSBkZWNpbWFsNjR7CiAgICAgICAgICAgICAgICAgICAgZnJhY3Rpb24tZGlnaXRzIDY7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB1bml0cyAiZGVncmVlcyI7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgRU5PREVCRlVOQ1RJT05fUFJPVklERVNfRVVUUkFOQ0VMTCB7IC8vIDEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHByb3ZpZGVkLWV1VHJhbkNlbGwgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZU5vZGVCIEZ1bmN0aW9uIHByb3ZpZGVzIEVVVFJBTiBDZWxsLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBFTm9kZUJGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBwcm92aWRlZC1ieS1lbm9kZWJGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJFVVRSQU4gQ2VsbCBwcm92aWRlZCBieSBlTm9kZUIgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEVVdHJhbkNlbGw7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgRU5PREVCRlVOQ1RJT05fUFJPVklERVNfTFRFU0VDVE9SQ0FSUklFUiB7IC8vIDEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHByb3ZpZGVkLWx0ZVNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZU5vZGVCIEZ1bmN0aW9uIHByb3ZpZGVzIExURSBTZWN0b3IgQ2Fycmllci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgRU5vZGVCRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgcHJvdmlkZWQtYnktZW5vZGViRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTFRFIFNlY3RvciBDYXJyaWVyIHByb3ZpZGVkIGJ5IGVOb2RlQiBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTFRFU2VjdG9yQ2FycmllcjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtYW5kYXRvcnkgdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBHTkJEVUZVTkNUSU9OX1BST1ZJREVTX05SQ0VMTERVIHsgLy8gMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgcHJvdmlkZWQtbnJDZWxsRHUgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLURVIEZ1bmN0aW9uIHByb3ZpZGVzIE5SIENlbGwtRFUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIEdOQkRVRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgcHJvdmlkZWQtYnktZ25iZHVGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBDZWxsLURVIHByb3ZpZGVkIGJ5IGdOb2RlQi1EVSBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTlJDZWxsRFU7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgR05CRFVGVU5DVElPTl9QUk9WSURFU19OUlNFQ1RPUkNBUlJJRVIgeyAvLyAxIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBwcm92aWRlZC1uclNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLURVIEZ1bmN0aW9uIHByb3ZpZGVzIE5SIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBHTkJEVUZ1bmN0aW9uOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHByb3ZpZGVkLWJ5LWduYmR1RnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgU2VjdG9yIENhcnJpZXIgcHJvdmlkZWQgYnkgZ05vZGVCLURVIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBOUlNlY3RvckNhcnJpZXI7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgR05CQ1VDUEZVTkNUSU9OX1BST1ZJREVTX05SQ0VMTENVIHsgLy8gMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgcHJvdmlkZWQtbnJDZWxsQ3UgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVQ1AgRnVuY3Rpb24gcHJvdmlkZXMgTlIgQ2VsbC1DVS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgR05CQ1VDUEZ1bmN0aW9uOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHByb3ZpZGVkLWJ5LWduYmN1Y3BGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBDZWxsLUNVIHByb3ZpZGVkIGJ5IGdOb2RlQi1DVUNQIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBOUkNlbGxDVTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtYW5kYXRvcnkgdHJ1ZTsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBFVVRSQU5DRUxMX1VTRVNfTFRFU0VDVE9SQ0FSUklFUiB7IC8vIDAuLjEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHVzZWQtbHRlU2VjdG9yQ2FycmllciB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJFVVRSQU4gQ2VsbCB1c2VzIExURSBTZWN0b3IgQ2Fycmllci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgRVV0cmFuQ2VsbDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiB1c2VkLWJ5LWV1VHJhbkNlbGwgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTFRFIFNlY3RvciBDYXJyaWVyIHVzZWQgYnkgRVVUUkFOIENlbGwuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIExURVNlY3RvckNhcnJpZXI7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBMVEVTRUNUT1JDQVJSSUVSX1VTRVNfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyAwLi5uIHRvIDAuLjEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgdXNlZC1hbnRlbm5hQ2FwYWJpbGl0eSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJMVEUgU2VjdG9yIENhcnJpZXIgdXNlcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIExURVNlY3RvckNhcnJpZXI7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYtbGlzdCB1c2VkLWJ5LWx0ZVNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHVzZWQgYnkgTFRFIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBBbnRlbm5hQ2FwYWJpbGl0eTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5SQ0VMTERVX1VTRVNfTlJTRUNUT1JDQVJSSUVSIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgdXNlZC1uclNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQ2VsbC1EVSB1c2VzIE5SIFNlY3RvciBDYXJyaWVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBOUkNlbGxEVTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiB1c2VkLWJ5LW5yQ2VsbER1IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5SIFNlY3RvciBDYXJyaWVyIHVzZWQgYnkgTlIgQ2VsbC1EVS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTlJTZWN0b3JDYXJyaWVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTlJTRUNUT1JDQVJSSUVSX1VTRVNfQU5URU5OQUNBUEFCSUxJVFkgeyAvLyAwLi5uIHRvIDAuLjEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgdXNlZC1hbnRlbm5hQ2FwYWJpbGl0eSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOUiBTZWN0b3IgQ2FycmllciB1c2VzIEFudGVubmEgQ2FwYWJpbGl0eS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgTlJTZWN0b3JDYXJyaWVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3QgdXNlZC1ieS1uclNlY3RvckNhcnJpZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHVzZWQgYnkgTlIgU2VjdG9yIENhcnJpZXIuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIEFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgU0VDVE9SX0dST1VQU19OUkNFTExEVSB7IC8vIDAuLjEgdG8gMC4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IGdyb3VwZWQtbnJDZWxsRHUgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiU2VjdG9yIGdyb3VwcyBOUiBDZWxsLURVLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBTZWN0b3I7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CgogICAgICAgIGxlYWYgZ3JvdXBlZC1ieS1zZWN0b3IgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTlIgQ2VsbC1EVSBncm91cGVkIGJ5IFNlY3Rvci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgTlJDZWxsRFU7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBTRUNUT1JfR1JPVVBTX0VVVFJBTkNFTEwgeyAvLyAwLi4xIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBncm91cGVkLWV1VHJhbkNlbGwgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiU2VjdG9yIGdyb3VwcyBFVVRSQU4gQ2VsbC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgU2VjdG9yOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIGdyb3VwZWQtYnktc2VjdG9yIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkVVVFJBTiBDZWxsIGdyb3VwZWQgYnkgU2VjdG9yLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBFVXRyYW5DZWxsOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-equipment	urn:o-ran:smo-teiv-equipment	EQUIPMENT	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWVxdWlwbWVudCB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtZXF1aXBtZW50IjsKICAgIHByZWZpeCBvci10ZWl2LWVxdWlwOwoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy10eXBlcyB7cHJlZml4IG9yLXRlaXYtdHlwZXM7IH0KCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctZXh0ZW5zaW9ucyB7cHJlZml4IG9yLXRlaXYteWV4dDsgfQoKICAgIGltcG9ydCBpZXRmLWdlby1sb2NhdGlvbiB7CiAgICAgICAgcHJlZml4IGdlbzsKICAgICAgICByZWZlcmVuY2UgIlJGQyA5MTc5OiBBIFlBTkcgR3JvdXBpbmcgZm9yIEdlb2dyYXBoaWMgTG9jYXRpb25zIjsKICAgIH0KCiAgICBvcmdhbml6YXRpb24gIkVyaWNzc29uIEFCIjsKICAgIGNvbnRhY3QgIkVyaWNzc29uIGZpcnN0IGxpbmUgc3VwcG9ydCB2aWEgZW1haWwiOwogICAgZGVzY3JpcHRpb24KICAgICJSQU4gRXF1aXBtZW50IHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIEVxdWlwbWVudCBkb21haW4sIHdoaWNoIGlzIG1vZGVsbGVkIHRvIHVuZGVyc3RhbmQgdGhlIHBoeXNpY2FsCiAgICBsb2NhdGlvbiBvZiBlcXVpcG1lbnQgc3VjaCBhcyBhbnRlbm5hcyBhc3NvY2lhdGVkIHdpdGggYSBjZWxsL2NhcnJpZXIKICAgIGFuZCB0aGVpciByZWxldmFudCBwcm9wZXJ0aWVzIGUuZy4gdGlsdCwgbWF4IHBvd2VyIGV0Yy4iOwoKICAgIHJldmlzaW9uICIyMDI0LTA1LTAyIiB7CiAgICAgICAgZGVzY3JpcHRpb24gIkluaXRpYWwgcmV2aXNpb24uIjsKICAgICAgICBvci10ZWl2LXlleHQ6bGFiZWwgMC4zLjA7CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmRvbWFpbiBFUVVJUE1FTlQ7CgogICAgbGlzdCBBbnRlbm5hTW9kdWxlIHsKICAgICAgICBkZXNjcmlwdGlvbiAiQW4gQW50ZW5uYSBNb2R1bGUgcmVwcmVzZW50cyB0aGUKICAgICAgICAgICAgICAgICAgICBwaHlzaWNhbCBhc3BlY3Qgb2YgYW4gYW50ZW5uYS4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIGZkbiB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVGhpcyBGdWxsIERpc3Rpbmd1aXNoZWQgTmFtZSAoRkROKSBpZGVudGlmaWVzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbiBpbnN0YW5jZSBvZiB0aGUgQW50ZW5uYVN1YlVuaXQgTU8uIEl0IGNvbnRhaW5zCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgZnVsbCBwYXRoIGZyb20gdGhlIFN1Ym5ldHdvcmsgdG8gdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBbnRlbm5hU3ViVW5pdC4iOwogICAgICAgICAgICAgICAgdHlwZSBvci10ZWl2LXR5cGVzOl8zR1BQX0ZETl9UeXBlOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGFudGVubmFNb2RlbE51bWJlciB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiVmVuZG9yLXNwZWNpZmljIGFudGVubmEgbW9kZWwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkZW50aWZpZXIuIFRoaXMgYXR0cmlidXRlIGlzIHBhcnQgb2YKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFJU0cgdjMgQURCIFN0YW5kYXJkIGFuZCBoYXMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vIG9wZXJhdGlvbmFsIGltcGFjdC4iOwogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgbWVjaGFuaWNhbEFudGVubmFCZWFyaW5nIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIGJlYXJpbmcgb24gYW50ZW5uYSBzdWJ1bml0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGVyZSBhbnRlbm5hIHVuaXQgaXMgaW5zdGFsbGVkLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBtZWNoYW5pY2FsQW50ZW5uYVRpbHQgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBmaXhlZCBhbnRlbm5hIHRpbHQgb2YgdGhlIGluc3RhbGxhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmluZWQgYXMgdGhlIGluY2xpbmF0aW9uIG9mIHRoZSBhbnRlbm5hCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtZW50IHJlc3BlY3QgdG8gdGhlIHZlcnRpY2FsIHBsYW5lLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgSXQgaXMgYSBzaWduZWQgdmFsdWUuIFBvc2l0aXZlIGluZGljYXRlcwogICAgICAgICAgICAgICAgICAgICAgICAgICAgZG93bnRpbHQsIGFuZCBuZWdhdGl2ZSBpbmRpY2F0ZXMgdXB0aWx0LiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiBwb3NpdGlvbldpdGhpblNlY3RvciB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSB1bml0IHBvc2l0aW9uIHdpdGhpbiBzZWN0b3IuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaGlzIGF0dHJpYnV0ZSBpcyBwYXJ0IG9mIEFJU0cgdjMgQURCCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFuZGFyZCBhbmQgaGFzIG5vIG9wZXJhdGlvbmFsIGltcGFjdC4iOwogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGxlYWYgdG90YWxUaWx0IHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUb3RhbCBhbnRlbm5hIGVsZXZhdGlvbiBpbmNsdWRpbmcgdGhlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnN0YWxsZWQgdGlsdCBhbmQgdGhlIHRpbHQgYXBwbGllZCBieQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlIFJlbW90ZSBFbGVjdHJpY2FsIFRpbHQgKFJFVCkuIjsKICAgICAgICAgICAgICAgIHR5cGUgdWludDMyOwogICAgICAgICAgICB9CgogICAgICAgICAgICBsZWFmIGVsZWN0cmljYWxBbnRlbm5hVGlsdCB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiRWxlY3RyaWNhbGx5LWNvbnRyb2xsZWQgdGlsdCBvZiBtYWluIGJlYW0gbWF4aW11bQogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2l0aCByZXNwZWN0IHRvIGRpcmVjdGlvbiBvcnRob2dvbmFsIHRvIGFudGVubmEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQgYXhpcyAoc2VlIDNHUFAgVFMgMjUuNDY2KS4gVmFsdWUgaXMgc2lnbmVkOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlsdCBkb3duIGlzIHBvc2l0aXZlLCB0aWx0IHVwIGlzIG5lZ2F0aXZlLiI7CiAgICAgICAgICAgICAgICB0eXBlIHVpbnQzMjsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZi1saXN0IGFudGVubmFCZWFtV2lkdGggewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBhbmd1bGFyIHNwYW4gb2YgdGhlIG1haW4gbG9iZSBvZiB0aGUgYW50ZW5uYSByYWRpYXRpb24KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiBpbiB0aGUgaG9yaXpvbnRhbCBwbGFuZS4gTWVhc3VyZWQgaW4gZGVncmVlcy4iOwogICAgICAgICAgICAgICAgdHlwZSB1aW50MzI7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHVzZXMgZ2VvOmdlby1sb2NhdGlvbjsKCiAgICAgICAgICAgIGNvbnRhaW5lciBjbUlkIHsKICAgICAgICAgICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpDTV9JRDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IFNpdGUgewogICAgICAgIGRlc2NyaXB0aW9uICJBIHNpdGUgaXMgYSBwaHlzaWNhbCBsb2NhdGlvbiB3aGVyZSBhbiBBbnRlbm5hIG9yCiAgICAgICAgICAgICAgICAgICAgUGh5c2ljYWwgTkYgY2FuIGJlIGluc3RhbGxlZC4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIG5hbWUgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5hbWUgb2YgU2l0ZSI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgdXNlcyBnZW86Z2VvLWxvY2F0aW9uOwoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgUGh5c2ljYWxORiB7CiAgICAgICAgZGVzY3JpcHRpb24gIlJlcHJlc2VudHMgYSBQaHlzaWNhbCBORiwKICAgICAgICAgICAgICAgICAgICB3aGljaCBpcyB1c2VkIHRvIHJlYWxpc2UgTmV0d29yayBGdW5jdGlvbnMuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBuYW1lIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOYW1lIG9mIFBoeXNpY2FsIE5GLiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgbGVhZiB0eXBlIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJUeXBlIG9mIFBoeXNpY2FsIE5GLiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgdXNlcyBnZW86Z2VvLWxvY2F0aW9uOwoKICAgICAgICAgICAgY29udGFpbmVyIGNtSWQgewogICAgICAgICAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOkNNX0lEOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgQU5URU5OQU1PRFVMRV9JTlNUQUxMRURfQVRfU0lURSB7IC8vIDAuLm4gdG8gMC4uMQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZiBpbnN0YWxsZWQtYXQtc2l0ZSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIE1vZHVsZSBpbnN0YWxsZWQgYXQgU2l0ZS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQW50ZW5uYU1vZHVsZTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IGluc3RhbGxlZC1hbnRlbm5hTW9kdWxlIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIlNpdGUgd2hlcmUgQW50ZW5uYSBNb2R1bGUgaXMgaW5zdGFsbGVkLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBTaXRlOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgUEhZU0lDQUxORl9JTlNUQUxMRURfQVRfU0lURSB7IC8vIDEuLm4gdG8gMC4uMQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZiBpbnN0YWxsZWQtYXQtc2l0ZSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQaHlzaWNhbCBORiBpbnN0YWxsZWQgYXQgU2l0ZS4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgUGh5c2ljYWxORjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IGluc3RhbGxlZC1waHlzaWNhbE5GIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIlNpdGUgd2hlcmUgUGh5c2ljYWwgTkYgaXMgaW5zdGFsbGVkLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBTaXRlOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1pbi1lbGVtZW50cyAxOwogICAgICAgIH0KICAgIH0KfQ==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-cloud-to-ran	urn:o-ran:smo-teiv-cloud-to-ran	CLOUD_TO_RAN	["o-ran-smo-teiv-cloud", "o-ran-smo-teiv-ran"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNsb3VkLXRvLXJhbiB7CiAgICB5YW5nLXZlcnNpb24gMS4xOwogICAgbmFtZXNwYWNlICJ1cm46by1yYW46c21vLXRlaXYtY2xvdWQtdG8tcmFuIjsKICAgIHByZWZpeCBvci10ZWl2LWNsb3VkdG9yYW47CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLXR5cGVzIHtwcmVmaXggb3ItdGVpdi10eXBlczsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1jb21tb24teWFuZy1leHRlbnNpb25zIHtwcmVmaXggb3ItdGVpdi15ZXh0OyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNsb3VkIHtwcmVmaXggb3ItdGVpdi1jbG91ZDsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1yYW4ge3ByZWZpeCBvci10ZWl2LXJhbjsgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBDbG91ZCB0byBSQU4gTG9naWNhbCB0b3BvbG9neSBtb2RlbC4KCiAgICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgVGhpcyBtb2RlbCBjb250YWlucyB0aGUgUkFOIENsb3VkIHRvIFJBTiBMb2dpY2FsIHRvcG9sb2d5IHJlbGF0aW9ucyI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIENMT1VEX1RPX1JBTjsKCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfR05CRFVGVU5DVElPTiB7IC8vIDAuLm4gdG8gMC4ubQoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IHNlcnZpY2VkLWduYmR1RnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCRFUgRnVuY3Rpb24gc2VydmljZWQgYnkgdGhpcyBORiBEZXBsb3ltZW50LiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDphU2lkZSBvci10ZWl2LWNsb3VkOk5GRGVwbG95bWVudDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IHNlcnZpbmctbkZEZXBsb3ltZW50IHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5GIERlcGxveW1lbnQgdGhhdCBzZXJ2ZXMgdGhpcyBnTm9kZUJEVSBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1yYW46R05CRFVGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfR05CQ1VDUEZVTkNUSU9OIHsgLy8gMC4ubiB0byAwLi5tCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iY3VjcEZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQi1DVS1DUCBGdW5jdGlvbiBzZXJ2aWNlZCBieSB0aGlzIE5GIERlcGxveW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtY2xvdWQ6TkZEZXBsb3ltZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3Qgc2VydmluZy1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCB0aGF0IHNlcnZlcyB0aGlzIGdOb2RlQkNVQ1AgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkNVQ1BGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIE5GREVQTE9ZTUVOVF9TRVJWRVNfR05CQ1VVUEZVTkNUSU9OIHsgLy8gMC4ubiB0byAwLi5tCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iY3V1cEZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQi1DVS1VUCBGdW5jdGlvbiBzZXJ2aWNlZCBieSB0aGlzIE5GIERlcGxveW1lbnQuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtY2xvdWQ6TkZEZXBsb3ltZW50OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3Qgc2VydmluZy1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCB0aGF0IHNlcnZlcyB0aGlzIGdOb2RlQkNVVVAgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkNVVVBGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KfQ==	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-cloud	urn:o-ran:smo-teiv-cloud	CLOUD	[]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWNsb3VkIHsKICAgIHlhbmctdmVyc2lvbiAxLjE7CiAgICBuYW1lc3BhY2UgInVybjpvLXJhbjpzbW8tdGVpdi1jbG91ZCI7CiAgICBwcmVmaXggb3ItdGVpdi1jbG91ZDsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgaWV0Zi1nZW8tbG9jYXRpb24gewogICAgICAgIHByZWZpeCBnZW87CiAgICAgICAgcmVmZXJlbmNlICJSRkMgOTE3OTogQSBZQU5HIEdyb3VwaW5nIGZvciBHZW9ncmFwaGljIExvY2F0aW9ucyI7CiAgICB9CgogICAgb3JnYW5pemF0aW9uICJFcmljc3NvbiBBQiI7CiAgICBjb250YWN0ICJFcmljc3NvbiBmaXJzdCBsaW5lIHN1cHBvcnQgdmlhIGVtYWlsIjsKICAgIGRlc2NyaXB0aW9uCiAgICAiUkFOIENsb3VkIHRvcG9sb2d5IG1vZGVsLgoKICAgIENvcHlyaWdodCAoYykgMjAyMyBFcmljc3NvbiBBQi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgICBUaGlzIG1vZGVsIGNvbnRhaW5zIHRoZSB0b3BvbG9neSBlbnRpdGllcyBhbmQgcmVsYXRpb25zIGluIHRoZQogICAgUkFOIENMT1VEIGRvbWFpbiwgd2hpY2ggY29tcHJpc2VzIGNsb3VkIGluZnJhc3RydWN0dXJlIGFuZAogICAgZGVwbG95bWVudCBhc3BlY3RzIHRoYXQgY2FuIGJlIHVzZWQgaW4gdGhlIHRvcG9sb2d5IG1vZGVsLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIENMT1VEOwoKICAgIGxpc3QgQ2xvdWRpZmllZE5GIHsKICAgICAgICBkZXNjcmlwdGlvbiAiQSBSQU4gTmV0d29yayBGdW5jdGlvbiBzb2Z0d2FyZSB0aGF0IGlzIGRlcGxveWVkIGluIHRoZSBPLUNsb3VkIHZpYSBvbmUgb3IgbW9yZSBORiBEZXBsb3ltZW50cy4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIG5hbWUgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5hbWUgb2YgQ2xvdWRpZmllZCBORiI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IE5GRGVwbG95bWVudCB7CiAgICAgICAgZGVzY3JpcHRpb24gIkEgc29mdHdhcmUgZGVwbG95bWVudCBvbiBPLUNsb3VkIHJlc291cmNlcyB0aGF0IHJlYWxpemVzLCBhbGwgb3IgcGFydCBvZiwgYSBDbG91ZGlmaWVkIE5GLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgbmFtZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTmFtZSBvZiBORiBEZXBsb3ltZW50IjsKICAgICAgICAgICAgICAgIHR5cGUgc3RyaW5nOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGxpc3QgQ2xvdWROYW1lc3BhY2UgewogICAgICAgIGRlc2NyaXB0aW9uICJDbG91ZE5hbWVzcGFjZSBwcm92aWRlIGEgbWVjaGFuaXNtIGZvciBpc29sYXRpbmcKICAgICAgICAgICAgICAgICAgICBncm91cHMgb2YgcmVzb3VyY2VzIHdpdGhpbiBhIHNpbmdsZSBjbHVzdGVyLiI7CgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBjb250YWluZXIgYXR0cmlidXRlcyB7CiAgICAgICAgICAgIGxlYWYgbmFtZSB7CiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiAiTmFtZSBvZiBDbG91ZCBOYW1lc3BhY2UiOwogICAgICAgICAgICAgICAgdHlwZSBzdHJpbmc7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgbGlzdCBOb2RlQ2x1c3RlciB7CiAgICAgICAgZGVzY3JpcHRpb24gIkEgTm9kZUNsdXN0ZXIgbWFuYWdlcyBhIGNvbGxlY3Rpb24gb2YgTm9kZXMuIjsKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGNvbnRhaW5lciBhdHRyaWJ1dGVzIHsKICAgICAgICAgICAgbGVhZiBuYW1lIHsKICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uICJOYW1lIG9mIE5vZGUgQ2x1c3RlciI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBsaXN0IENsb3VkU2l0ZSB7CiAgICAgICAgZGVzY3JpcHRpb24gIlJlcHJlc2VudHMgdGhlIGluZnJhc3RydWN0dXJlIHRoYXQKICAgICAgICAgICAgICAgICAgICBob3N0cyB0aGUgTkYgRGVwbG95bWVudC4iOwoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgY29udGFpbmVyIGF0dHJpYnV0ZXMgewogICAgICAgICAgICBsZWFmIG5hbWUgewogICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5hbWUgb2YgQ2xvdWQgU2l0ZSI7CiAgICAgICAgICAgICAgICB0eXBlIHN0cmluZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgdXNlcyBnZW86Z2VvLWxvY2F0aW9uOwogICAgICAgIH0KICAgIH0KCgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBDTE9VRElGSUVETkZfQ09NUFJJU0VTX05GREVQTE9ZTUVOVCB7IC8vIDEgdG8gMS4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IGNvbXByaXNlZC1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2xvdWRpZmllZCBORiBjb21wcmlzZXMgb2YgdGhlc2UgTkYgRGVwbG95bWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQ2xvdWRpZmllZE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1pbi1lbGVtZW50cyAxOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBjb21wcmlzZWQtYnktY2xvdWRpZmllZE5GIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5GIERlcGxveW1lbnQgcGFydCBvZiBDbG91ZGlmaWVkIE5GLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBORkRlcGxveW1lbnQ7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgTkZERVBMT1lNRU5UX0RFUExPWUVEX09OX0NMT1VETkFNRVNQQUNFIHsgLy8gMS4ubiB0byAxLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgZGVwbG95ZWQtb24tY2xvdWROYW1lc3BhY2UgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTkYgRGVwbG95bWVudCBkZXBsb3llZCBvbiBDbG91ZCBOYW1lc3BhY2UuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIE5GRGVwbG95bWVudDsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtaW4tZWxlbWVudHMgMTsKICAgICAgICB9CgogICAgICAgIGxlYWYtbGlzdCBkZXBsb3llZC1uRkRlcGxveW1lbnQgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2xvdWQgTmFtZXNwYWNlIGRlcGxveXMgTkYgRGVwbG95bWVudC4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgQ2xvdWROYW1lc3BhY2U7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWluLWVsZW1lbnRzIDE7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgQ0xPVUROQU1FU1BBQ0VfREVQTE9ZRURfT05fTk9ERUNMVVNURVIgeyAvLyAxLi5uIHRvIDEKCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYgZGVwbG95ZWQtb24tbm9kZUNsdXN0ZXIgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQ2xvdWQgTmFtZXNwYWNlIGRlcGxveWVkIG9uIE5vZGUgQ2x1c3Rlci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgQ2xvdWROYW1lc3BhY2U7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWFuZGF0b3J5IHRydWU7CiAgICAgICAgfQoKICAgICAgICBsZWFmLWxpc3QgZGVwbG95ZWQtY2xvdWROYW1lc3BhY2UgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiTm9kZSBDbHVzdGVyIGRlcGxveXMgQ2xvdWQgTmFtZXNwYWNlLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBOb2RlQ2x1c3RlcjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgICAgICBtaW4tZWxlbWVudHMgMTsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBOT0RFQ0xVU1RFUl9MT0NBVEVEX0FUX0NMT1VEU0lURSB7IC8vIDEuLm4gdG8gMS4ubgoKICAgICAgICB1c2VzIG9yLXRlaXYtdHlwZXM6VG9wX0dycF9UeXBlOwogICAgICAgIGtleSBpZDsKCiAgICAgICAgbGVhZi1saXN0IGxvY2F0ZWQtYXQtY2xvdWRTaXRlIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIk5vZGUgQ2x1c3RlciBsb2NhdGVkIGF0IENsb3VkIFNpdGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIE5vZGVDbHVzdGVyOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgICAgIG1pbi1lbGVtZW50cyAxOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IGxvY2F0aW9uLW9mLW5vZGVDbHVzdGVyIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIkNsb3VkIFNpdGUgaXMgbG9jYXRpb24gb2YgTm9kZSBDbHVzdGVyLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBDbG91ZFNpdGU7CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICAgICAgbWluLWVsZW1lbnRzIDE7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+o-ran-smo-teiv-equipment-to-ran	urn:o-ran:smo-teiv-equipment-to-ran	EQUIPMENT_TO_RAN	["o-ran-smo-teiv-equipment", "o-ran-smo-teiv-ran"]	2024-05-02	bW9kdWxlIG8tcmFuLXNtby10ZWl2LWVxdWlwbWVudC10by1yYW4gewogICAgeWFuZy12ZXJzaW9uIDEuMTsKICAgIG5hbWVzcGFjZSAidXJuOm8tcmFuOnNtby10ZWl2LWVxdWlwbWVudC10by1yYW4iOwogICAgcHJlZml4IG9yLXRlaXYtZXF1aXB0b3JhbjsKCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtY29tbW9uLXlhbmctdHlwZXMge3ByZWZpeCBvci10ZWl2LXR5cGVzOyB9CgogICAgaW1wb3J0IG8tcmFuLXNtby10ZWl2LWNvbW1vbi15YW5nLWV4dGVuc2lvbnMge3ByZWZpeCBvci10ZWl2LXlleHQ7IH0KCiAgICBpbXBvcnQgby1yYW4tc21vLXRlaXYtZXF1aXBtZW50IHtwcmVmaXggb3ItdGVpdi1lcXVpcDsgfQoKICAgIGltcG9ydCBvLXJhbi1zbW8tdGVpdi1yYW4ge3ByZWZpeCBvci10ZWl2LXJhbjsgfQoKICAgIG9yZ2FuaXphdGlvbiAiRXJpY3Nzb24gQUIiOwogICAgY29udGFjdCAiRXJpY3Nzb24gZmlyc3QgbGluZSBzdXBwb3J0IHZpYSBlbWFpbCI7CiAgICBkZXNjcmlwdGlvbgogICAgIlJBTiBFcXVpcG1lbnQgdG8gTG9naWNhbCB0b3BvbG9neSBtb2RlbC4KCiAgICBDb3B5cmlnaHQgKGMpIDIwMjMgRXJpY3Nzb24gQUIuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgVGhpcyBtb2RlbCBjb250YWlucyB0aGUgUkFOIEVxdWlwbWVudCB0byBMb2dpY2FsIHRvcG9sb2d5CiAgICBlbnRpdGllcyBhbmQgcmVsYXRpb25zLiI7CgogICAgcmV2aXNpb24gIjIwMjQtMDUtMDIiIHsKICAgICAgICBkZXNjcmlwdGlvbiAiSW5pdGlhbCByZXZpc2lvbi4iOwogICAgICAgIG9yLXRlaXYteWV4dDpsYWJlbCAwLjMuMDsKICAgIH0KCiAgICBvci10ZWl2LXlleHQ6ZG9tYWluIEVRVUlQTUVOVF9UT19SQU47CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBQSFlTSUNBTE5GX1NFUlZFU19HTkJEVUZVTkNUSU9OIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iZHVGdW5jdGlvbiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJnTm9kZUItRFUgRnVuY3Rpb24gc2VydmljZWQgYnkgdGhpcyBQaHlzaWNhbCBORi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1lcXVpcDpQaHlzaWNhbE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHNlcnZpbmctcGh5c2ljYWxORiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQaHlzaWNhbCBORiBzZXJ2ZXMgdGhpcyBnTm9kZUItRFUgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkRVRnVuY3Rpb247CiAgICAgICAgICAgIHR5cGUgaW5zdGFuY2UtaWRlbnRpZmllcjsKICAgICAgICB9CiAgICB9CgogICAgb3ItdGVpdi15ZXh0OmJpRGlyZWN0aW9uYWxUb3BvbG9neVJlbGF0aW9uc2hpcCBQSFlTSUNBTE5GX1NFUlZFU19HTkJDVUNQRlVOQ1RJT04geyAvLyAwLi4xIHRvIDAuLm4KCiAgICAgICAgdXNlcyBvci10ZWl2LXR5cGVzOlRvcF9HcnBfVHlwZTsKICAgICAgICBrZXkgaWQ7CgogICAgICAgIGxlYWYtbGlzdCBzZXJ2aWNlZC1nbmJjdWNwRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZ05vZGVCLUNVQ1AgRnVuY3Rpb24gc2VydmljZWQgYnkgdGhpcyBQaHlzaWNhbCBORi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YVNpZGUgb3ItdGVpdi1lcXVpcDpQaHlzaWNhbE5GOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQoKICAgICAgICBsZWFmIHNlcnZpbmctcGh5c2ljYWxORiB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJQaHlzaWNhbCBORiBzZXJ2ZXMgdGhpcyBnTm9kZUItQ1VDUCBGdW5jdGlvbi4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1yYW46R05CQ1VDUEZ1bmN0aW9uOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgUEhZU0lDQUxORl9TRVJWRVNfR05CQ1VVUEZVTkNUSU9OIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZ25iY3V1cEZ1bmN0aW9uIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gImdOb2RlQi1DVVVQIEZ1bmN0aW9uIHNlcnZpY2VkIGJ5IHRoaXMgUGh5c2ljYWwgTkYuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtZXF1aXA6UGh5c2ljYWxORjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBzZXJ2aW5nLXBoeXNpY2FsTkYgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiUGh5c2ljYWwgTkYgc2VydmVzIHRoaXMgZ05vZGVCLUNVVVAgRnVuY3Rpb24uIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkdOQkNVVVBGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIFBIWVNJQ0FMTkZfU0VSVkVTX0VOT0RFQkZVTkNUSU9OIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtZW5vZGViRnVuY3Rpb24gewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiZU5vZGVCIEZ1bmN0aW9uIHNlcnZpY2VkIGJ5IHRoaXMgUGh5c2ljYWwgTkYuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtZXF1aXA6UGh5c2ljYWxORjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBzZXJ2aW5nLXBoeXNpY2FsTkYgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiUGh5c2ljYWwgTkYgc2VydmVzIHRoaXMgZU5vZGVCIEZ1bmN0aW9uLiI7CiAgICAgICAgICAgIG9yLXRlaXYteWV4dDpiU2lkZSBvci10ZWl2LXJhbjpFTm9kZUJGdW5jdGlvbjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KICAgIH0KCiAgICBvci10ZWl2LXlleHQ6YmlEaXJlY3Rpb25hbFRvcG9sb2d5UmVsYXRpb25zaGlwIEFOVEVOTkFNT0RVTEVfU0VSVkVTX0FOVEVOTkFDQVBBQklMSVRZIHsgLy8gMC4ubiB0byAwLi5tCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3Qgc2VydmljZWQtYW50ZW5uYUNhcGFiaWxpdHkgewogICAgICAgICAgICBkZXNjcmlwdGlvbiAiQW50ZW5uYSBDYXBhYmlsaXR5IHNlcnZpY2VkIGJ5IHRoaXMgQW50ZW5uYSBNb2R1bGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtZXF1aXA6QW50ZW5uYU1vZHVsZTsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZi1saXN0IHNlcnZpbmctYW50ZW5uYU1vZHVsZSB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIE1vZHVsZSBzZXJ2ZXMgdGhpcyBBbnRlbm5hIENhcGFiaWxpdHkuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmJTaWRlIG9yLXRlaXYtcmFuOkFudGVubmFDYXBhYmlsaXR5OwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQoKICAgIG9yLXRlaXYteWV4dDpiaURpcmVjdGlvbmFsVG9wb2xvZ3lSZWxhdGlvbnNoaXAgU0VDVE9SX0dST1VQU19BTlRFTk5BTU9EVUxFIHsgLy8gMC4uMSB0byAwLi5uCgogICAgICAgIHVzZXMgb3ItdGVpdi10eXBlczpUb3BfR3JwX1R5cGU7CiAgICAgICAga2V5IGlkOwoKICAgICAgICBsZWFmLWxpc3QgZ3JvdXBlZC1hbnRlbm5hTW9kdWxlIHsKICAgICAgICAgICAgZGVzY3JpcHRpb24gIlNlY3RvciBncm91cHMgQW50ZW5uYSBNb2R1bGUuIjsKICAgICAgICAgICAgb3ItdGVpdi15ZXh0OmFTaWRlIG9yLXRlaXYtcmFuOlNlY3RvcjsKICAgICAgICAgICAgdHlwZSBpbnN0YW5jZS1pZGVudGlmaWVyOwogICAgICAgIH0KCiAgICAgICAgbGVhZiBncm91cGVkLWJ5LXNlY3RvciB7CiAgICAgICAgICAgIGRlc2NyaXB0aW9uICJBbnRlbm5hIE1vZHVsZSBncm91cGVkIGJ5IFNlY3Rvci4iOwogICAgICAgICAgICBvci10ZWl2LXlleHQ6YlNpZGUgb3ItdGVpdi1lcXVpcDpBbnRlbm5hTW9kdWxlOwogICAgICAgICAgICB0eXBlIGluc3RhbmNlLWlkZW50aWZpZXI7CiAgICAgICAgfQogICAgfQp9	BUILT_IN_MODULE	IN_USAGE
+\.
+
+COPY ties_model.entity_info("name", "moduleReferenceName") FROM stdin;
+ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt	o-ran-smo-teiv-oam
+ManagedElement	o-ran-smo-teiv-oam
+NodeCluster	o-ran-smo-teiv-cloud
+CloudNativeSystem	o-ran-smo-teiv-cloud
+CloudNativeApplication	o-ran-smo-teiv-cloud
+CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm	o-ran-smo-teiv-cloud
+CloudSite	o-ran-smo-teiv-cloud
+Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	o-ran-smo-teiv-cloud
+CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	o-ran-smo-teiv-cloud
+Namespace	o-ran-smo-teiv-cloud
+Sector	o-ran-smo-teiv-ran
+GNBCUUPFunction	o-ran-smo-teiv-ran
+ENodeBFunction	o-ran-smo-teiv-ran
+NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU	o-ran-smo-teiv-ran
+NRCellDU	o-ran-smo-teiv-ran
+LTESectorCarrier	o-ran-smo-teiv-ran
+GNBDUFunction	o-ran-smo-teiv-ran
+NRCellCU	o-ran-smo-teiv-ran
+GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	o-ran-smo-teiv-ran
+AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	o-ran-smo-teiv-equipment
+ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE	o-ran-smo-teiv-equipment
+EUtranCell	o-ran-smo-teiv-ran
+GNBCUCPFunction	o-ran-smo-teiv-ran
+NRSectorCarrier	o-ran-smo-teiv-ran
+AntennaCapability	o-ran-smo-teiv-ran
+TestEntityB	o-ran-smo-teiv-ran
+TestEntityA	o-ran-smo-teiv-ran
+Site	o-ran-smo-teiv-equipment
+AntennaModule	o-ran-smo-teiv-equipment
+PhysicalNetworkAppliance	o-ran-smo-teiv-equipment
+\.
+
+COPY ties_model.relationship_info("name", "aSideAssociationName", "aSideMOType", "aSideMinCardinality", "aSideMaxCardinality", "bSideAssociationName", "bSideMOType", "bSideMinCardinality", "bSideMaxCardinality", "associationKind", "relationshipDataLocation", "connectSameEntity", "moduleReferenceName") FROM stdin;
+MANAGEDELEMENTTTTTTTTTTTTTTT_MANAGES_GNBDUFUNCTIONNNNNNNNNNNNNNN	managed-gnbduFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt	1	1	managed-by-managedElementttttttttttttttttttttttttttttttttttttttt	GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENTTTTTTTTTTT_DEPLOYED_AS_CLOUDNATIVESYSTEMMMMMMMMMMM	deployed-as-cloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm	ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt	1	1	deployed-managedElementttttttttttttttttttttttttttttttttttttttttt	CloudNativeSystemmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-oam-to-cloud
+MANAGEDELEMENTTTTTTTTT_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNN	realised-by-cloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	ManagedElementtttttttttttttttttttttttttttttttttttttttttttttttttt	1	1	realised-managedElementttttttttttttttttttttttttttttttttttttttttt	CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	1	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-cloud
+MANAGEDELEMENT_MANAGES_ENODEBFUNCTION	managed-enodebFunction	ManagedElement	1	1	managed-by-managedElement	ENodeBFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENT_MANAGES_GNBCUCPFUNCTION	managed-gnbcucpFunction	ManagedElement	1	1	managed-by-managedElement	GNBCUCPFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENT_MANAGES_GNBCUUPFUNCTION	managed-gnbcuupFunction	ManagedElement	1	1	managed-by-managedElement	GNBCUUPFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENT_REALISED_BY_CLOUDNATIVEAPPLICATION	realised-by-cloudNativeApplication	ManagedElement	1	1	realised-managedElement	CloudNativeApplication	1	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-cloud
+MANAGEDELEMENT_MANAGES_GNBDUFUNCTION	managed-gnbduFunction	ManagedElement	1	1	managed-by-managedElement	GNBDUFunction	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-oam-to-ran
+MANAGEDELEMENT_DEPLOYED_AS_CLOUDNATIVESYSTEM	deployed-as-cloudNativeSystem	ManagedElement	1	1	deployed-managedElement	CloudNativeSystem	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-oam-to-cloud
+NODECLUSTER_LOCATED_AT_CLOUDSITE	located-at-cloudSite	NodeCluster	0	9223372036854775807	location-of-nodeCluster	CloudSite	1	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-cloud
+CLOUDNATIVESYSTEM_COMPRISES_CLOUDNATIVEAPPLICATION	comprised-cloudNativeApplication	CloudNativeSystem	0	1	comprised-by-cloudNativeSystem	CloudNativeApplication	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-cloud
+CLOUDNATIVEAPPLICATION_DEPLOYED_ON_NAMESPACE	deployed-on-namespace	CloudNativeApplication	0	9223372036854775807	deployed-cloudNativeApplication	Namespace	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-cloud
+CLOUDNATIVEAPPLICATIONNNNNNNNNNN_DEPLOYED_ON_NAMESPACEEEEEEEEEEE	deployed-on-namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	0	9223372036854775807	deployed-cloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	Namespaceeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-cloud
+NAMESPACE_DEPLOYED_ON_NODECLUSTER	deployed-on-nodeCluster	Namespace	0	9223372036854775807	deployed-namespace	NodeCluster	1	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-cloud
+SECTOR_GROUPS_EUTRANCELL	grouped-euTranCell	Sector	0	1	grouped-by-sector	EUtranCell	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+SECTOR_GROUPS_ANTENNAMODULE	grouped-antennaModule	Sector	0	1	grouped-by-sector	AntennaModule	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+SECTOR_GROUPS_NRCELLDU	grouped-nrCellDu	Sector	0	1	grouped-by-sector	NRCellDU	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBCUUPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	realised-by-cloudNativeApplication	GNBCUUPFunction	0	9223372036854775807	realised-gnbcuupFunction	CloudNativeApplication	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud-to-ran
+ENODEBFUNCTION_PROVIDES_EUTRANCELL	provided-euTranCell	ENodeBFunction	1	1	provided-by-enodebFunction	EUtranCell	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+ENODEBFUNCTION_PROVIDES_LTESECTORCARRIER	provided-lteSectorCarrier	ENodeBFunction	1	1	provided-by-enodebFunction	LTESectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+ENODEBFUNCTION_REALISED_BY_PHYSICALNETWORKAPPLIANCE	realised-by-physicalNetworkAppliance	ENodeBFunction	0	9223372036854775807	realised-enodebFunction	PhysicalNetworkAppliance	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-equipment-to-ran
+NRCELLDU_USES_NRSECTORCARRIER	used-nrSectorCarrier	NRCellDU	0	1	used-by-nrCellDu	NRSectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+LTESECTORCARRIER_USES_ANTENNACAPABILITY	used-antennaCapability	LTESectorCarrier	0	1	used-by-lteSectorCarrier	AntennaCapability	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-ran
+GNBDUFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	realised-by-cloudNativeApplication	GNBDUFunction	0	9223372036854775807	realised-gnbduFunction	CloudNativeApplication	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud-to-ran
+GNBDUFUNCTION_PROVIDES_NRSECTORCARRIER	provided-nrSectorCarrier	GNBDUFunction	1	1	provided-by-gnbduFunction	NRSectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBDUFUNCTION_PROVIDES_NRCELLDU	provided-nrCellDu	GNBDUFunction	1	1	provided-by-gnbduFunction	NRCellDU	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBDUFUNCTIONNNNNNNNN_REALISED_BY_CLOUDNATIVEAPPLICATIONNNNNNNNN	realised-by-cloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	0	9223372036854775807	realised-gnbduFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	CloudNativeApplicationnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud-to-ran
+GNBDUFUNCTIONNNNNNNNNNNNNNUUU_PROVIDES_NRCELLDUUUUUUUUUUUUUUUUUU	provided-nrCellDuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu	GNBDUFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	1	1	provided-by-gnbduFunctionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn	NRCellDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+EUTRANCELL_USES_LTESECTORCARRIER	used-lteSectorCarrier	EUtranCell	0	1	used-by-euTranCell	LTESectorCarrier	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBCUCPFUNCTION_PROVIDES_NRCELLCU	provided-nrCellCu	GNBCUCPFunction	1	1	provided-by-gnbcucpFunction	NRCellCU	0	9223372036854775807	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+GNBCUCPFUNCTION_REALISED_BY_CLOUDNATIVEAPPLICATION	realised-by-cloudNativeApplication	GNBCUCPFunction	0	9223372036854775807	realised-gnbcucpFunction	CloudNativeApplication	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-cloud-to-ran
+NRSECTORCARRIER_USES_ANTENNACAPABILITY	used-antennaCapability	NRSectorCarrier	0	9223372036854775807	used-by-nrSectorCarrier	AntennaCapability	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-ran
+ANTENNACAPABILITY_REALISED_BY_ANTENNAMODULE	realised-by-antennaModule	AntennaCapability	0	9223372036854775807	realised-antennaCapability	AntennaModule	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-equipment-to-ran
+TESTENTITYA_PROVIDES_TESTENTITYB	provided-testEntityB	TestEntityA	0	2	provided-by-testEntityA	TestEntityB	0	3	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-ran
+TESTENTITYA_USES_TESTENTITYB	used-TestEntityB	TestEntityA	0	1	used-by-testEntityA	TestEntityB	0	2	BI_DIRECTIONAL	B_SIDE	false	o-ran-smo-teiv-ran
+TESTENTITYA_GROUPS_TESTENTITYB	grouped-testEntityB	TestEntityA	0	2	grouped-by-testEntityA	TestEntityB	0	9223372036854775807	BI_DIRECTIONAL	RELATION	false	o-ran-smo-teiv-ran
+ANTENNAMODULE_INSTALLED_AT_SITE	installed-at-site	AntennaModule	0	9223372036854775807	installed-antennaModule	Site	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-equipment
+PHYSICALNETWORKAPPLIANCE_INSTALLED_AT_SITE	installed-at-site	PhysicalNetworkAppliance	0	9223372036854775807	installed-physicalNetworkAppliance	Site	0	1	BI_DIRECTIONAL	A_SIDE	false	o-ran-smo-teiv-equipment
+ANTENNAMODULE_REALISED_BY_ANTENNAMODULE	realised-by-antennaModule	AntennaModule	0	9223372036854775807	realised-antennaModule	AntennaModule	0	9223372036854775807	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-equipment
+ANTENNAMODULEEEEEEEEEEEE_REALISED_BY_ANTENNAMODULEEEEEEEEEEEEEEE	realised-by-antennaModule	AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	0	1	realised-antennaModule	AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	0	9223372036854775807	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-equipment
+ANTENNAMODULEEEEEEEEEEEE_DEPLOYED_ON_ANTENNAMODULEEEEEEEEEEEEEEE	deployed-on-antennaModule	AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	0	1	deployed-antennaModule	AntennaModuleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee	0	1	BI_DIRECTIONAL	RELATION	true	o-ran-smo-teiv-equipment
+\.
+
+;
diff --git a/teiv/src/test/resources/testcontainers.properties b/teiv/src/test/resources/testcontainers.properties
new file mode 100644
index 0000000..4d2aa1a
--- /dev/null
+++ b/teiv/src/test/resources/testcontainers.properties
@@ -0,0 +1,23 @@
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2024 Ericsson
+# Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+image.substitutor=org.oran.smo.teiv.db.RyukImageNameSubstitutor
+substitutor.ryuk.container.image = testcontainers/ryuk:0.5.1
\ No newline at end of file
diff --git a/yang-parser/pom.xml b/yang-parser/pom.xml
new file mode 100644
index 0000000..72a5ff8
--- /dev/null
+++ b/yang-parser/pom.xml
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- spotless:off -->
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<!-- spotless:on -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.oran.smo</groupId>
+        <artifactId>topology-exposure-inventory</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.oran.smo.yangtools.parser</groupId>
+    <artifactId>yang-parser-jar</artifactId>
+    <name>Yang Parser</name>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <sonar.tests>src/test/java</sonar.tests>
+        <sonar.sources>pom.xml,src/main/java</sonar.sources>
+        <sonar.exclusions>**/*.java</sonar.exclusions>
+        <!-- External Yang model destination location -->
+        <src.modules>${project.basedir}/src/main/resources/modules/</src.modules>
+        <src.test.orig.modules>${project.basedir}/src/test/resources/_orig-modules/</src.test.orig.modules>
+    </properties>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>3.0.0-M3</version>
+                <configuration>
+                    <useFile>false</useFile>
+                    <includes>
+                        <include>**/*Test.java</include>
+                    </includes>
+                    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>com.mycila</groupId>
+                <artifactId>license-maven-plugin</artifactId>
+                <version>${version.license-maven-plugin}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.diffplug.spotless</groupId>
+                <artifactId>spotless-maven-plugin</artifactId>
+                <version>${version.spotless-plugin}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <version>${version.antrun-maven-plugin}</version>
+                <executions>
+                    <execution>
+                        <id>download-src-external-yang-models</id>
+                        <phase>initialize</phase>
+                        <configuration>
+                            <target>
+                                <mkdir dir="${src.modules}" />
+                                <resources id="src-ietf-yang-downloads">
+                                    <url
+                                        url="${source.ietfcatalog}ietf-yang-library@2019-01-04.yang" />
+                                    <url
+                                        url="${source.ietfcatalog}ietf-datastores@2018-02-14.yang" />
+                                    <url
+                                        url="${source.ietfcatalog}ietf-inet-types@2019-11-04.yang" />
+                                    <url
+                                        url="${source.ietfcatalog}ietf-yang-types@2019-11-04.yang" />
+                                </resources>
+                                <get dest="${src.modules}" skipexisting="true">
+                                    <resources refid="src-ietf-yang-downloads" />
+                                    <mapper type="regexp" from="^.*/([^/@]+)@([^/]+)$"
+                                        to="\1-\2" />
+                                </get>
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>download-test-external-yang-models</id>
+                        <phase>generate-test-sources</phase>
+                        <configuration>
+                            <target>
+                                <get
+                                    src="${source.3gpp.Rel18_SA98}_3gpp-common-yang-extensions.yang"
+                                    dest="${src.test.orig.modules}_3gpp-common-yang-extensions-2022-10-20.yang"
+                                    skipexisting="true" />
+                                <get
+                                    src="${source.3gpp.Rel17_SA91}_3gpp-common-yang-extensions.yang"
+                                    dest="${src.test.orig.modules}_3gpp-common-yang-extensions-2019-06-23.yang"
+                                    skipexisting="true" />
+
+                                <resources id="orig-ietf-yang-downloads">
+                                    <!-- spotless:off -->
+                                    <url url="${source.ietfcatalog}iana-crypt-hash@2014-08-06.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-crypto-types@2019-11-20.yang" />
+                                    <url url="${source.ietfcatalog}ietf-datastores@2018-02-14.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-inet-types@2019-11-04.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-interfaces@2018-02-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-ip@2018-02-22.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-keystore@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-netconf-acm@2018-02-14.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-netconf-client@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-netconf-monitoring@2010-10-04.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-netconf-notifications@2012-02-06.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-netconf-server@2018-09-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-netconf-with-defaults@2011-06-01.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-netconf@2011-06-01.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-network-instance@2019-01-21.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-origin@2018-02-14.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-restconf-monitoring@2017-01-26.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-restconf@2017-01-26.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-ssh-client@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-ssh-common@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-ssh-server@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-subscribed-notifications@2019-05-06.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-system@2014-08-06.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-tcp-client@2019-10-18.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-tcp-common@2019-10-18.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-tcp-server@2019-10-18.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-tls-client@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-tls-common@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-tls-server@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-trust-anchors@2019-04-29.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-truststore@2019-11-20.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-x509-cert-to-name@2014-12-10.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-yang-library@2019-01-04.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-yang-metadata@2016-08-05.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-yang-patch@2017-02-22.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-yang-push@2019-05-21.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-yang-schema-mount@2019-01-14.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-yang-types@2010-09-24.yang"/>
+                                    <url url="${source.ietfcatalog}ietf-yang-types@2019-11-04.yang"/>
+                                    <!-- spotless:on -->
+                                </resources>
+                                <get dest="${src.test.orig.modules}" skipexisting="true">
+                                    <resources refid="orig-ietf-yang-downloads" />
+                                    <mapper type="regexp" from="^.*/([^/@]+)@([^/]+)$"
+                                        to="\1-\2" />
+                                </get>
+                            </target>
+                        </configuration>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.jacoco</groupId>
+                    <artifactId>jacoco-maven-plugin</artifactId>
+                    <version>0.8.4</version>
+                    <executions>
+                        <execution>
+                            <id>prepare-unit-tests</id>
+                            <goals>
+                                <goal>prepare-agent</goal>
+                            </goals>
+                        </execution>
+                        <execution>
+                            <id>report</id>
+                            <phase>test</phase>
+                            <goals>
+                                <goal>report</goal>
+                            </goals>
+                        </execution>
+                    </executions>
+                    <configuration>
+                        <outputDirectory>${project.build.directory}/coverage-reports/jacoco</outputDirectory>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/CheckYangLibraryAgainstSchema.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/CheckYangLibraryAgainstSchema.java
new file mode 100644
index 0000000..b546d26
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/CheckYangLibraryAgainstSchema.java
@@ -0,0 +1,241 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.yanglibrary.Datastore;
+import org.oran.smo.yangtools.parser.yanglibrary.Module;
+import org.oran.smo.yangtools.parser.yanglibrary.Submodule;
+import org.oran.smo.yangtools.parser.yanglibrary.YangLibrary;
+
+/**
+ * Checks the contents of a YANG Library (instance data) against a schema (and thereby the modules
+ * supplied by the client). This is useful to compare the modules supplied for a schema against a YL.
+ *
+ * @author Mark Hollmann
+ */
+public class CheckYangLibraryAgainstSchema {
+
+    private final ParserExecutionContext parserContext;
+    private final Schema schema;
+    private final YangLibrary yangLibrary;
+
+    public CheckYangLibraryAgainstSchema(final ParserExecutionContext parserContext, final Schema schema,
+            final YangLibrary yangLibrary) {
+        this.parserContext = parserContext;
+        this.schema = schema;
+        this.yangLibrary = yangLibrary;
+    }
+
+    /**
+     * Checks the YL against the modules. Any findings will be added to the supplied findings manager.
+     */
+    public void performChecks() {
+
+        /*
+         * There has to be a running datastore.
+         */
+        final Datastore runningDatastore = yangLibrary.getRunningDatastore();
+        if (runningDatastore == null) {
+            parserContext.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                    "Could not find 'running' datastore in YANG library data."));
+            return;
+        }
+
+        /*
+         * Collect the identities of the modules listed in the Yang Library
+         */
+        final Set<Module> yangLibImplementingModules = runningDatastore.getImplementingModules();
+        final Set<Module> yangLibImportOnlyModules = runningDatastore.getImportOnlyModules();
+        final Set<Submodule> yangLibSubmodules = new HashSet<>();
+        yangLibImplementingModules.forEach(module -> yangLibSubmodules.addAll(module.getSubmodules()));
+        yangLibImportOnlyModules.forEach(module -> yangLibSubmodules.addAll(module.getSubmodules()));
+
+        final Set<ModuleIdentity> yangLibImplementingModuleIdentities = yangLibImplementingModules.stream().map(
+                Module::getModuleIdentity).collect(Collectors.toSet());
+        final Set<ModuleIdentity> yangLibImportOnlyModuleIdentities = yangLibImportOnlyModules.stream().map(
+                Module::getModuleIdentity).collect(Collectors.toSet());
+        final Set<ModuleIdentity> yangLibSubmoduleIdentities = yangLibSubmodules.stream().map(Submodule::getModuleIdentity)
+                .collect(Collectors.toSet());
+
+        /*
+         * Collect the identities of the modules supplied to the parser
+         */
+        final List<YangModel> yangModels = new ArrayList<>(schema.getModuleRegistry().getAllYangModels());
+
+        final Set<ModuleIdentity> inputImplementingModuleIdentities = yangModels.stream().filter(input -> input
+                .getYangModelRoot().isModule() && input.getConformanceType() == ConformanceType.IMPLEMENT).map(
+                        YangModel::getModuleIdentity).collect(Collectors.toSet());
+        final Set<ModuleIdentity> inputImportOnlyModuleIdentities = yangModels.stream().filter(input -> input
+                .getYangModelRoot().isModule() && input.getConformanceType() == ConformanceType.IMPORT).map(
+                        YangModel::getModuleIdentity).collect(Collectors.toSet());
+        final Set<ModuleIdentity> inputSubmoduleIdentities = yangModels.stream().filter(input -> input.getYangModelRoot()
+                .isSubmodule()).map(YangModel::getModuleIdentity).collect(Collectors.toSet());
+
+        /*
+         * Now we simply compare these. They must fully match up - no missing/superfluous YAMs; correct conformance type.
+         */
+        checkInputMatchesYangLibraryForModules(inputImplementingModuleIdentities, yangLibImplementingModuleIdentities,
+                ConformanceType.IMPLEMENT);
+        checkInputMatchesYangLibraryForModules(inputImportOnlyModuleIdentities, yangLibImportOnlyModuleIdentities,
+                ConformanceType.IMPORT);
+        checkInputMatchesYangLibraryForSubmodules(inputSubmoduleIdentities, yangLibSubmoduleIdentities);
+
+        /*
+         * The Yang Library will also list features and the namespaces. Check these match up.
+         */
+        checkFeaturesAndNamespaces();
+    }
+
+    /**
+     * Cross-check the modules listed in Yang Library against the YAMs in the input.
+     */
+    private void checkInputMatchesYangLibraryForModules(final Set<ModuleIdentity> inputModuleIdentities,
+            final Set<ModuleIdentity> yangLibModuleIdentities, final ConformanceType conformanceType) {
+
+        final Set<ModuleIdentity> inInputButNotYangLib = new HashSet<>(inputModuleIdentities);
+        inInputButNotYangLib.removeAll(yangLibModuleIdentities);
+
+        inInputButNotYangLib.forEach(mi -> {
+            final Finding finding = new Finding(ParserFindingType.P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY,
+                    "Module '" + mi.toString() + "' with conformance type '" + conformanceType
+                            .toString() + "' is in the input, but not listed (or not with this conformance type) in the supplied YANG library.");
+            parserContext.getFindingsManager().addFinding(finding);
+        });
+
+        final Set<ModuleIdentity> inYangLibButNotInput = new HashSet<>(yangLibModuleIdentities);
+        inYangLibButNotInput.removeAll(inputModuleIdentities);
+
+        inYangLibButNotInput.forEach(mi -> {
+            final Finding finding = new Finding(ParserFindingType.P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY,
+                    "Module '" + mi.toString() + "' with conformance type '" + conformanceType
+                            .toString() + "' is listed in the supplied YANG library, but could not be found (or not with this conformance type) in the input.");
+            parserContext.getFindingsManager().addFinding(finding);
+        });
+    }
+
+    /**
+     * Cross-check the submodules listed in Yang Library against the YAMs in the input.
+     */
+    private void checkInputMatchesYangLibraryForSubmodules(final Set<ModuleIdentity> inputSubmoduleIdentities,
+            final Set<ModuleIdentity> yangLibSubmoduleIdentities) {
+
+        final Set<ModuleIdentity> inInputButNotYangLib = new HashSet<>(inputSubmoduleIdentities);
+        inInputButNotYangLib.removeAll(yangLibSubmoduleIdentities);
+
+        inInputButNotYangLib.forEach(mi -> {
+            final Finding finding = new Finding(ParserFindingType.P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY,
+                    "Submodule '" + mi.toString() + "' is in the input, but not listed in the supplied YANG library.");
+            parserContext.getFindingsManager().addFinding(finding);
+        });
+
+        final Set<ModuleIdentity> inYangLibButNotInput = new HashSet<>(yangLibSubmoduleIdentities);
+        inYangLibButNotInput.removeAll(inputSubmoduleIdentities);
+
+        inYangLibButNotInput.forEach(mi -> {
+            final Finding finding = new Finding(ParserFindingType.P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY,
+                    "Submodule '" + mi
+                            .toString() + "' is listed in the supplied YANG library, but could not be found in the input.");
+            parserContext.getFindingsManager().addFinding(finding);
+        });
+    }
+
+    /**
+     * Checks the features listed inside the YANG Library against the features that are actually
+     * declared in the models. Also checks the namespace matches.
+     */
+    private void checkFeaturesAndNamespaces() {
+
+        final Set<Module> yangLibAllModules = yangLibrary.getRunningDatastore().getAllModules();
+        final List<YangModel> inputAllModules = schema.getModuleRegistry().getAllYangModels();
+
+        for (final Module yangLibOneModule : yangLibAllModules) {
+            final ModuleIdentity yangLibOneModuleIdentity = yangLibOneModule.getModuleIdentity();
+
+            for (final YangModel inputOneModule : inputAllModules) {
+                if (yangLibOneModuleIdentity.equals(inputOneModule.getModuleIdentity())) {
+                    checkFeaturesAndNamespace(yangLibOneModule, inputOneModule);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks that the features for a given module listed in the Yang Library actually exist inside the YAM.
+     * <p>
+     * Also checks the namespaces match up.
+     */
+    private void checkFeaturesAndNamespace(final Module yangLibOneModule, final YangModel inputOneModule) {
+
+        final Set<String> featuresDeclaredInInputModule = getFeaturesDeclaredInsideInputModule(inputOneModule);
+
+        yangLibOneModule.getFeatures().forEach(featureListedInYangLib -> {
+            if (!featuresDeclaredInInputModule.contains(featureListedInYangLib)) {
+                final Finding finding = new Finding(ParserFindingType.P083_FEATURE_LISTED_IN_YANG_LIBRARY_NOT_FOUND,
+                        "YANG Library entry for module '" + yangLibOneModule
+                                .getName() + "' lists feature '" + featureListedInYangLib + "', but this feature was not found in the actual module (or its submodules).");
+                parserContext.getFindingsManager().addFinding(finding);
+            }
+        });
+
+        final String yangLibNamespace = yangLibOneModule.getNamespace();
+        final String inputNamespace = inputOneModule.getPrefixResolver().getDefaultNamespaceUri();
+
+        if (!yangLibNamespace.equals(inputNamespace)) {
+            final Finding finding = new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                    "Namespace mismatch for module '" + yangLibOneModule
+                            .getName() + "' between what is stated in the Yang Library and what is declaread in the module.");
+            parserContext.getFindingsManager().addFinding(finding);
+        }
+    }
+
+    /**
+     * Returns the features that are defined inside a module, or any of its submodules.
+     */
+    private Set<String> getFeaturesDeclaredInsideInputModule(final YangModel yangModel) {
+        final Set<String> declaredFeatures = new HashSet<>();
+
+        yangModel.getYangModelRoot().getModule().getFeatures().forEach(yFeature -> declaredFeatures.add(yFeature
+                .getFeatureName()));
+
+        /*
+         * Features can also be defined inside submodules.
+         */
+        yangModel.getYangModelRoot().getOwnedSubmodules().forEach(submoduleYangModelRoot -> {
+            submoduleYangModelRoot.getSubmodule().getFeatures().forEach(yFeature -> declaredFeatures.add(yFeature
+                    .getFeatureName()));
+        });
+
+        return declaredFeatures;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/CustomProcessor.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/CustomProcessor.java
new file mode 100644
index 0000000..15f7452
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/CustomProcessor.java
@@ -0,0 +1,48 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser;
+
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+
+/**
+ * Implementations of this interface are called during certain phases of parsing.
+ * In general, implementation will perform additional processing on the schema tree,
+ * typically to handle extensions.
+ *
+ * @author Mark Hollmann
+ */
+public interface CustomProcessor {
+
+    /**
+     * Invoked after a schema has been fully parsed but before it has been processed. Resolution
+     * of various constructs (e.g. groupings) has not yet been performed at this stage; likewise
+     * status and namespace of elements have not been set.
+     */
+    default void onPreSchemaProcessed(ParserExecutionContext context, Schema schema) {
+    }
+
+    /**
+     * Invoked after a schema has been fully parsed and processed. If fail-fast is enabled
+     * and relevant findings have been issued, this callback will not be invoked.
+     */
+    default void onPostSchemaProcessed(ParserExecutionContext context, Schema schema) {
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/ParserExecutionContext.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/ParserExecutionContext.java
new file mode 100644
index 0000000..7360873
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/ParserExecutionContext.java
@@ -0,0 +1,300 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.model.statements.StatementClassSupplier;
+import org.oran.smo.yangtools.parser.model.util.YangFeature;
+
+/**
+ * The parser execution context directs the behaviour of the parser. It is vital that the
+ * context is correctly setup by the client.
+ *
+ * @author Mark Hollmann
+ */
+public class ParserExecutionContext {
+
+    /*
+     * The findings manager will hold onto all findings issued by the parser. It should be
+     * inspected after the parsing has finished for any problems.
+     */
+    private final FindingsManager findingsManager;
+
+    /*
+     * For extensions, a list of class suppliers. The Yang Parser has in-build support for
+     * some IETF and 3GPP extensions. It is not necessary to list the statement class supplier
+     * for Yang Core classes.
+     *
+     * In general, it is not mandatory to supply these for extensions; extensions will still be
+     * correctly parsed and resolved; however, extension-specific validation will not be performed.
+     */
+    private final List<StatementClassSupplier> extensionCreators;
+
+    /*
+     * Custom processors may perform additional activities during different phases of the parse.
+     */
+    private final List<CustomProcessor> customProcessors;
+
+    /*
+     * Denotes that parsing shall stop after the initial parsing has finished, i.e. the
+     * schema tree has been generated in memory. Some downstream tooling may desire this.
+     */
+    private boolean stopAfterInitialParse = false;
+
+    /*
+     * If the modules are is really bad shape it makes no sense to do fully process them - it only
+     * results in a lot of findings. Better to fail parsing fast.
+     */
+    private boolean failFast = true;
+
+    /*
+     * The features supported by the server. This information typically comes from the YANG library.
+     * If the Set is null, the supported feature information is considered unknown. Conversely, an
+     * empty Set denotes that no features are supported. Information about the supported features is
+     * required if 'if-feature' statements should be evaluated and the schema tree adjusted accordingly.
+     */
+    private Set<YangFeature> supportedFeatures = null;
+
+    /*
+     * Denotes whether during parsing any schema node shall be removed if a 'if-feature' condition is
+     * not fulfilled. Requires the supported features to be set.
+     */
+    private boolean removeSchemaNodesNotSatisfyingIfFeature = false;
+
+    /*
+     * Denotes whether groupings and typedefs shall be resolved by the parser.
+     */
+    private boolean resolveDerivedTypesAndGroupings = true;
+
+    /*
+     * Denotes whether augmentations shall be resolved by the parser.
+     */
+    private boolean resolveAugments = true;
+
+    /*
+     * Denotes whether deviations shall be resolved by the parser.
+     */
+    private boolean resolveDeviations = true;
+
+    /*
+     * Denotes whether the contents of submodules shall be merged into their owning modules.
+     */
+    private boolean mergeSubmodulesIntoModules = true;
+
+    /*
+     * Denotes whether data nodes, or in general "protocol accessible" objects, shall be
+     * ignored. This is used to remove from the schema certain schema nodes that are part of
+     * modules of conformance type IMPORT-ONLY.
+     */
+    private boolean ignoreImportedProtocolAccessibleObjects = true;
+
+    /*
+     * Whether findings on unused schema nodes shall be reported. Sometimes, certain
+     * constructs, such as groupings and derived types, are not used. Setting this flag to
+     * TRUE will suppress findings on such constructs.
+     */
+    private boolean suppressFindingsOnUnusedSchemaNodes = false;
+
+    /*
+     * Denotes whether, during parsing, the input modules shall be checked against YANG
+     * Library instance data (ie. have the exact same modules been supplied as those listed
+     * in the YL?).
+     */
+    private boolean checkModulesAgainstYangLibrary = true;
+
+    public ParserExecutionContext(final FindingsManager findingsManager) {
+        this(findingsManager, Collections.<StatementClassSupplier> emptyList());
+    }
+
+    public ParserExecutionContext(final FindingsManager findingsManager,
+            final List<StatementClassSupplier> extensionCreators) {
+        this(findingsManager, extensionCreators, Collections.<CustomProcessor> emptyList());
+    }
+
+    public ParserExecutionContext(final FindingsManager findingsManager,
+            final List<StatementClassSupplier> extensionCreators, final List<CustomProcessor> customProcessors) {
+        this.findingsManager = Objects.requireNonNull(findingsManager);
+        this.extensionCreators = Objects.requireNonNull(extensionCreators);
+        this.customProcessors = Objects.requireNonNull(customProcessors);
+    }
+
+    public List<StatementClassSupplier> getExtensionCreators() {
+        return extensionCreators;
+    }
+
+    public List<CustomProcessor> getCustomProcessors() {
+        return customProcessors;
+    }
+
+    public FindingsManager getFindingsManager() {
+        return findingsManager;
+    }
+
+    public void addFinding(final Finding finding) {
+        findingsManager.addFinding(finding);
+    }
+
+    /**
+     * Whether parsing shall stop after the initial parsing has finished, i.e. the
+     * schema tree has been generated in memory.
+     */
+    public void setStopAfterInitialParse(final boolean val) {
+        this.stopAfterInitialParse = val;
+    }
+
+    public boolean shouldStopAfterInitialParse() {
+        return stopAfterInitialParse;
+    }
+
+    /**
+     * Fail-fast is a mechanism whereby certain findings by the parser will lead to the abort
+     * of further processing. Typically, the input must be fixed-up before the parsing can succeed.
+     */
+    public void setFailFast(final boolean val) {
+        this.failFast = val;
+    }
+
+    public boolean failFast() {
+        return failFast;
+    }
+
+    /**
+     * Set the features supported by the server. Required if 'if-feature' statements shall be evaluated.
+     */
+    public void setSupportedFeatures(final Set<YangFeature> val) {
+        this.supportedFeatures = val;
+    }
+
+    public Set<YangFeature> getSupportedFeatures() {
+        return supportedFeatures;
+    }
+
+    /**
+     * Whether schema nodes shall be removed by the parser if their if-feature condition is not fulfilled.
+     * Requires supported-features to be supplied as well.
+     */
+    public void setRemoveSchemaNodesNotSatisfyingIfFeature(final boolean val) {
+        this.removeSchemaNodesNotSatisfyingIfFeature = val;
+    }
+
+    /**
+     * Whether schema nodes shall be removed by the parser if their if-feature condition is not fulfilled. Requires
+     * supported-features to be supplied as well.
+     */
+    public boolean removeSchemaNodesNotSatisfyingIfFeature() {
+        return removeSchemaNodesNotSatisfyingIfFeature;
+    }
+
+    /**
+     * Sets whether derived types and groupings shall be resolved by the parser.
+     */
+    public void setResolveDerivedTypesAndGroupings(final boolean val) {
+        this.resolveDerivedTypesAndGroupings = val;
+    }
+
+    public boolean resolveDerivedTypesAndGroupings() {
+        return resolveDerivedTypesAndGroupings;
+    }
+
+    /**
+     * Whether augmentations shall be merged-in.
+     */
+    public void setResolveAugments(final boolean val) {
+        this.resolveAugments = val;
+    }
+
+    public boolean resolveAugments() {
+        return resolveAugments;
+    }
+
+    /**
+     * Whether deviations shall be applied.
+     */
+    public void setResolveDeviations(final boolean val) {
+        this.resolveDeviations = val;
+    }
+
+    public boolean resolveDeviations() {
+        return resolveDeviations;
+    }
+
+    /**
+     * Whether submodules shall be merged into their owning modules.
+     */
+    public void setMergeSubmodulesIntoModules(final boolean val) {
+        this.mergeSubmodulesIntoModules = val;
+    }
+
+    public boolean mergeSubmodulesIntoModules() {
+        return mergeSubmodulesIntoModules;
+    }
+
+    /**
+     * Whether data nodes of IMPORT-ONLY modules shall be ignored.
+     */
+    public void setIgnoreImportedProtocolAccessibleObjects(final boolean ignoreImportedProtocolAccessibleObjects) {
+        this.ignoreImportedProtocolAccessibleObjects = ignoreImportedProtocolAccessibleObjects;
+    }
+
+    public boolean ignoreImportedProtocolAccessibleObjects() {
+        return ignoreImportedProtocolAccessibleObjects;
+    }
+
+    /**
+     * Denotes whether findings on schema nodes that are not in use shall be
+     * removed after parsing.
+     */
+    public boolean shouldSuppressFindingsOnUnusedSchemaNodes() {
+        return suppressFindingsOnUnusedSchemaNodes;
+    }
+
+    public void setSuppressFindingsOnUnusedSchemaNodes(boolean val) {
+        this.suppressFindingsOnUnusedSchemaNodes = val;
+    }
+
+    /**
+     * Whether the input modules shall be checked against YANG Library data during parsing.
+     */
+    public void setCheckModulesAgainstYangLibrary(boolean checkModulesAgainstYangLibrary) {
+        this.checkModulesAgainstYangLibrary = checkModulesAgainstYangLibrary;
+    }
+
+    public boolean checkModulesAgainstYangLibrary() {
+        return checkModulesAgainstYangLibrary;
+    }
+
+    private final List<String> infos = new ArrayList<>();
+
+    public void addInfo(final String info) {
+        infos.add(info);
+    }
+
+    public List<String> getInfos() {
+        return Collections.unmodifiableList(infos);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/PrefixResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/PrefixResolver.java
new file mode 100644
index 0000000..8cb7cf0
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/PrefixResolver.java
@@ -0,0 +1,95 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A classic prefix resolver that can resolve prefixes to namespace URIs.
+ *
+ * @author Mark Hollmann
+ */
+public class PrefixResolver {
+
+    /**
+     * An artificial prefix to handle the default namespace URI.
+     */
+    public static final String NO_PREFIX = " NO_PREFIX ";
+
+    private final Map<String, String> mappings = new HashMap<>();
+
+    /**
+     * Sets the default namespace URI.
+     */
+    public void setDefaultNamespaceUri(final String namespaceUri) {
+        addMapping(NO_PREFIX, namespaceUri);
+    }
+
+    /**
+     * Returns the default namespace URI. May return null.
+     */
+    public String getDefaultNamespaceUri() {
+        return resolveNamespaceUri(NO_PREFIX);
+    }
+
+    /**
+     * Adds a mapping from prefix to namespace URI.
+     */
+    public void addMapping(final String prefix, final String namespaceUri) {
+        mappings.put(Objects.requireNonNull(prefix), Objects.requireNonNull(namespaceUri));
+    }
+
+    /**
+     * Returns the namespace URI for the given prefix or null if no mapping exists for the prefix.
+     */
+    public String resolveNamespaceUri(final String prefix) {
+        return mappings.containsKey(prefix) ? mappings.get(prefix) : null;
+    }
+
+    /**
+     * Creates a clone of this prefix resolver. Subsequent modifications to this resolver will not be
+     * reflected in the cloned resolver.
+     */
+    public PrefixResolver clone() {
+        final PrefixResolver clone = new PrefixResolver();
+        clone.mappings.putAll(this.mappings);
+        return clone;
+    }
+
+    @Override
+    public int hashCode() {
+        return mappings.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+
+        if (!(obj instanceof PrefixResolver)) {
+            return false;
+        }
+
+        final PrefixResolver other = (PrefixResolver) obj;
+
+        return this.mappings.equals(other.mappings);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/YangDeviceModel.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/YangDeviceModel.java
new file mode 100644
index 0000000..d3ca5e3
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/YangDeviceModel.java
@@ -0,0 +1,157 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.instance.DataTreeBuilderPredicate;
+import org.oran.smo.yangtools.parser.data.instance.InstanceDataTreeBuilder;
+import org.oran.smo.yangtools.parser.data.instance.RootInstance;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.YangInputResolver;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.schema.ModuleRegistry;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.util.StackTraceHelper;
+import org.oran.smo.yangtools.parser.yanglibrary.IetfYangLibraryParser;
+import org.oran.smo.yangtools.parser.yanglibrary.YangLibrary;
+
+/**
+ * A utility class that may be used to parse both Yang models and Yang data. This class should not
+ * really be used as it assumes that there is a single schema for a server, which doesn't hold true
+ * anymore due to schema mount. It has been retained as it is widely used by clients, and the vast
+ * majority of servers don't use or even support schema mount.
+ *
+ * @author Mark Hollmann
+ */
+public class YangDeviceModel {
+
+    private final String deviceModelIdentity;
+    private List<YangData> yangDatas;
+
+    private RootInstance combinedInstanceDataRoot = new RootInstance();
+
+    /**
+     * The top-level schema for this server.
+     */
+    private final Schema topLevelSchema;
+
+    public YangDeviceModel(final String deviceModelIdentity) {
+        this.deviceModelIdentity = deviceModelIdentity;
+        this.topLevelSchema = new Schema();
+    }
+
+    public ModuleRegistry getModuleRegistry() {
+        return topLevelSchema.getModuleRegistry();
+    }
+
+    public List<YangData> getYangInstanceDataInputs() {
+        return yangDatas != null ? yangDatas : Collections.<YangData> emptyList();
+    }
+
+    public String getDeviceModelIdentity() {
+        return deviceModelIdentity;
+    }
+
+    public Schema getTopLevelSchema() {
+        return topLevelSchema;
+    }
+
+    public RootInstance getCombinedInstanceDataRoot() {
+        return combinedInstanceDataRoot;
+    }
+
+    public void parseIntoYangModels(final ParserExecutionContext context, final List<YangModel> yangModels) {
+        topLevelSchema.parseIntoSchema(context, yangModels);
+    }
+
+    /**
+     * Parses the supplied Yang Data into their data DOMs and builds the data instance tree. If Yang Library
+     * data has been supplied it will be checked against the supplied modules (if so desired by the context).
+     */
+    public void parseYangData(final ParserExecutionContext context, final YangInputResolver instanceDataInputResolver,
+            final DataTreeBuilderPredicate topLevelInstancePredicate) {
+
+        this.yangDatas = instanceDataInputResolver.getResolvedYangInput().stream().map(YangData::new).collect(Collectors
+                .toList());
+
+        int nrTopLevelYangLibrariesFound = 0;
+        YangLibrary foundYangLibrary = null;
+
+        /*
+         * This builds the DOM for each of the instance data inputs. The root
+         * of the data DOM is held inside the YangData object.
+         */
+        for (final YangData yangData : yangDatas) {
+            try {
+                yangData.parse(context);
+                yangData.getYangDataDomDocumentRoot().resolveModuleOrNamespace(topLevelSchema.getModuleNamespaceResolver());
+
+                /*
+                 * We check for the Yang Library straight away here to avoid having to re-parse the data.
+                 */
+                final YangLibrary extracted = IetfYangLibraryParser.getTopLevelYangLibrary(yangData
+                        .getYangDataDomDocumentRoot());
+                if (extracted != null) {
+                    nrTopLevelYangLibrariesFound++;
+                    foundYangLibrary = extracted;
+                }
+
+            } catch (final Exception ex) {
+                context.addFinding(new Finding(yangData, ParserFindingType.P000_UNSPECIFIED_ERROR.toString(),
+                        "While parsing instance data '" + yangData.getYangInput().getName() + "' - " + ex.getClass()
+                                .getSimpleName() + ": " + ex.getMessage() + " - trace: " + StackTraceHelper
+                                        .getStackTraceInfo(ex)));
+            }
+        }
+
+        if (nrTopLevelYangLibrariesFound > 1) {
+
+            context.addFinding(new Finding(ParserFindingType.P084_MULTIPLE_YANG_LIBRARIES_IN_INPUT,
+                    "Multiple instances of YANG Library detected. This makes parsing of instance data ambiguous and may lead to other findings being issued."));
+
+        } else if (nrTopLevelYangLibrariesFound == 1 && context.checkModulesAgainstYangLibrary()) {
+            /*
+             * If we have been given the YANG Library as part of data we check the
+             * contents of the YANG library against the modules that we have been given.
+             */
+            new CheckYangLibraryAgainstSchema(context, topLevelSchema, foundYangLibrary).performChecks();
+        }
+
+        /*
+         * This builds the instance tree from the data DOM. For this to work, the underlying models
+         * must be available, otherwise the logic does not know whether it deals with containers or
+         * lists, and likewise cannot enforce constraints.
+         */
+        try {
+            combinedInstanceDataRoot = InstanceDataTreeBuilder.buildCombinedDataTree(context.getFindingsManager(),
+                    yangDatas, topLevelSchema.getModuleRegistry(), topLevelInstancePredicate);
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(ParserFindingType.P000_UNSPECIFIED_ERROR,
+                    "While building combined data tree - " + ex.getClass().getSimpleName() + ": " + ex
+                            .getMessage() + " - trace: " + StackTraceHelper.getStackTraceInfo(ex)));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/YangData.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/YangData.java
new file mode 100644
index 0000000..ceec152
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/YangData.java
@@ -0,0 +1,141 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.w3c.dom.Document;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot.SourceDataType;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObject;
+import org.oran.smo.yangtools.parser.data.parser.XmlParser;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.YangInput;
+import org.oran.smo.yangtools.parser.util.StackTraceHelper;
+
+/**
+ * Represents a single YANG data file, i.e. instance data, <b>not a YANG model (YAM)</b>. The instance data
+ * file can be XML or JSON. There are no dependencies onto a model when Yang data is parsed - so this class
+ * can be used even without Yang models being present.
+ *
+ * @author Mark Hollmann
+ */
+public class YangData {
+
+    /*
+     * The underlying input. Typically a file with file extension ".xml" or ".json",
+     * but could also be an arbitrary input stream.
+     */
+    private final YangInput yangInput;
+
+    /*
+     * The root of the Yang data DOM tree.
+     */
+    private YangDataDomDocumentRoot yangDataDomDocumentRoot;
+
+    /*
+     * Findings made in respect of this instance data file, if any.
+     */
+    private Set<Finding> findings = null;
+
+    public YangData(final YangInput yangInput) {
+        this.yangInput = yangInput;
+    }
+
+    public YangInput getYangInput() {
+        return yangInput;
+    }
+
+    /**
+     * Returns the document root of the XML data DOM for this input. Conceivably null
+     * if the input was not valid XML/JSON.
+     */
+    public YangDataDomDocumentRoot getYangDataDomDocumentRoot() {
+        return yangDataDomDocumentRoot;
+    }
+
+    public void addFinding(final Finding finding) {
+        if (findings == null) {
+            findings = new HashSet<>();
+        }
+        findings.add(finding);
+    }
+
+    public Set<Finding> getFindings() {
+        return findings == null ? Collections.<Finding> emptySet() : findings;
+    }
+
+    /**
+     * Parses the input into a data DOM tree.
+     */
+    public void parse(final ParserExecutionContext context) {
+
+        if (yangInput.getMediaType().equals(YangInput.MEDIA_TYPE_YANG_DATA_JSON)) {
+            parseJson(context);
+        } else {
+            parseXml(context);
+        }
+    }
+
+    private void parseJson(final ParserExecutionContext context) {
+
+        try (final InputStream inputStream = yangInput.getInputStream()) {
+
+            final JsonParser jsonParser = new JsonParser(context, this, inputStream);
+            final JsonObject rootJsonObject = (JsonObject) jsonParser.parse();
+
+            yangDataDomDocumentRoot = new YangDataDomDocumentRoot(this, SourceDataType.JSON);
+            yangDataDomDocumentRoot.buildFromJsonDocument(context, rootJsonObject);
+
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(this, ParserFindingType.P000_UNSPECIFIED_ERROR.toString(), ex.getClass()
+                    .getSimpleName() + ": " + ex.getMessage() + " - trace: " + StackTraceHelper.getStackTraceInfo(ex)));
+        }
+    }
+
+    private void parseXml(final ParserExecutionContext context) {
+
+        try (final InputStream inputStream = yangInput.getInputStream()) {
+
+            final Document document = XmlParser.createDocument(inputStream);
+            document.getDocumentElement().normalize();
+
+            yangDataDomDocumentRoot = new YangDataDomDocumentRoot(this, SourceDataType.XML);
+            yangDataDomDocumentRoot.buildFromXmlDocument(context, document);
+
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(this, ParserFindingType.P000_UNSPECIFIED_ERROR.toString(), ex.getClass()
+                    .getSimpleName() + ": " + ex.getMessage() + " - trace: " + StackTraceHelper.getStackTraceInfo(ex)));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return yangInput.getName();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomDocumentRoot.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomDocumentRoot.java
new file mode 100644
index 0000000..5f22e5c
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomDocumentRoot.java
@@ -0,0 +1,294 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.dom;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObject;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomDocumentRoot;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+/**
+ * Root element for a YANG data DOM. Contains a tree structure of data originating from XML of JSON. The direct
+ * children of this root object in effect represent the values or structure of top-level data nodes.
+ * <p/>
+ * Not to be confused with class {@link YangDomDocumentRoot}, which is the root of a *model* DOM.
+ * <p/>
+ * Will not perform a check against any YANG schema. Therefore, can also be used, if so desired, as a simple
+ * multi-purpose XML/JSON parser if so desired.
+ *
+ * @author Mark Hollmann
+ */
+public class YangDataDomDocumentRoot extends YangDataDomNode {
+
+    /**
+     * Where the data originally came from. This can make a difference. In XML, the values are all
+     * represented as strings; in JSON, a primitive value can be a String, Double or Boolean. If conversion
+     * is required later on to a highly-typed Java object, a client must know where the data originally
+     * came from.
+     */
+    public enum SourceDataType {
+        XML,
+        JSON
+    }
+
+    private final YangData yangData;
+
+    private final SourceDataType sourceDataType;
+
+    public YangDataDomDocumentRoot(final YangData yangData, final SourceDataType sourceDataType) {
+        super();
+        this.yangData = yangData;
+        this.sourceDataType = sourceDataType;
+    }
+
+    @Override
+    public YangData getYangData() {
+        return yangData;
+    }
+
+    @Override
+    public SourceDataType getSourceDataType() {
+        return sourceDataType;
+    }
+
+    public void buildFromXmlDocument(final ParserExecutionContext context, final Document document) {
+
+        /*
+         * DOM Document root is a special case. It is not an element as such. It only
+         * has a single element as "child"; this single element is the actual root XML
+         * element.
+         */
+        final Element rootXmlElement = document.getDocumentElement();
+        final String rootXmlElementName = QNameHelper.extractName(rootXmlElement.getTagName());
+
+        /*
+         * It is perfectly valid and possible and realistic for the XML root element to declare
+         * namespaces, so we populate the prefix resolver of the root here.
+         */
+        final List<Attr> rootElementXmlAttributes = getAttributesfromXmlElement(rootXmlElement);
+        populateXmlPrefixResolver(rootElementXmlAttributes, getPrefixResolver());
+
+        /*
+         * There is always confusion about the root XML element - and it usually depends on the input.
+         * Sometimes, data is parsed that sits inside a file that a programmer has prepared; sometimes
+         * it could be a NETCONF reply, etc.
+         *
+         * We are trying to be as lenient as possible, and we support the following:
+         *
+         *
+         *
+         * 1.) As root element <config>, for example:
+         *
+         * <config>
+         *   <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+         *     ...stuff ...
+         *
+         *
+         *
+         * 2.) RFC 9195 ("A File Format for YANG Instance Data")
+         *
+         * Lately, we are aligning with draft-ietf-netmod-yang-instance-file-format-10,
+         * which looks like this:
+         *
+         * <?xml version="1.0" encoding="UTF-8"?>
+         * <instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+         *   <name>read-only-acm-rules</name>
+         *   <content-schema>
+         *     <module>ietf-netconf-acm@2018-02-14</module>
+         *   </content-schema>
+         *   <revision>
+         *     <date>1776-07-04</date>
+         *     <description>Initial version</description>
+         *   </revision>
+         *   <description>Access control rules for a read-only role.</description>
+         *   <content-data>
+         *     <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
+         *       ... stuff ...
+         *   </content-data>
+         * </instance-data-set>
+         *
+         *
+         *
+         * 3.) A NETCONF RPC reply:
+         *
+         * <rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+         *   <data>
+         *     <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+         *       ... stuff ...
+         *
+         *
+         *
+         * 4.) Just <data> as root:
+         *
+         * <data>
+         *   <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+         *     ... stuff ...
+         *
+         *
+         *
+         * 5.) Data directly at the root:
+         *
+         * <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+         *   ... stuff ...
+         */
+
+        final List<Element> xmlElementsToProcess = new ArrayList<>();
+
+        if (rootXmlElementName.equals("config")) {
+
+            xmlElementsToProcess.addAll(getChildElementNodes(rootXmlElement));
+
+        } else if (rootXmlElementName.equals("instance-data-set")) {
+            /*
+             * Need to find the <content-data> element underneath first. Whatever is
+             * underneath that, will be handled.
+             */
+            final Element contentDataElement = getNamedChildElement(rootXmlElement, "content-data");
+            if (contentDataElement != null) {
+                /*
+                 * We must add handle whatever prefixes have been defined on the <content-data> element.
+                 * Never seen in the wild, but who knows....
+                 */
+                final List<Attr> contentDataXmlAttributes = getAttributesfromXmlElement(contentDataElement);
+                populateXmlPrefixResolver(contentDataXmlAttributes, getPrefixResolver());
+
+                xmlElementsToProcess.addAll(getChildElementNodes(contentDataElement));
+            }
+        } else if (rootXmlElementName.equals("rpc-reply")) {
+            /*
+             * Need to find the <data> element underneath first. Whatever is
+             * underneath that, will be handled.
+             */
+            final Element dataElement = getNamedChildElement(rootXmlElement, "data");
+            if (dataElement != null) {
+                /*
+                 * We must add handle whatever prefixes have been defined on the <data> element.
+                 */
+                final List<Attr> dataXmlAttributes = getAttributesfromXmlElement(dataElement);
+                populateXmlPrefixResolver(dataXmlAttributes, getPrefixResolver());
+
+                xmlElementsToProcess.addAll(getChildElementNodes(dataElement));
+            }
+        } else if (rootXmlElementName.equals("data")) {
+
+            xmlElementsToProcess.addAll(getChildElementNodes(rootXmlElement));
+
+        } else {
+            /*
+             * Right... assume so that the root element is immediately data.
+             */
+            context.addFinding(new Finding(yangData, ParserFindingType.P071_INCORRECT_ROOT_ELEMENT_OF_DATA_FILE.toString(),
+                    "Expected <instance-data-set> (or <config> or <rpc-reply> or <data>) as first element in data file. Assume root element represents data. If this is not the case, this will likely lead to other findings."));
+
+            xmlElementsToProcess.add(rootXmlElement);
+        }
+
+        if (xmlElementsToProcess.isEmpty()) {
+            context.addFinding(new Finding(yangData, ParserFindingType.P079_EMPTY_DATA_FILE.toString(),
+                    "The instance data input seems to be empty."));
+        }
+
+        /*
+         * Now process them.
+         */
+        for (final Element childXmlNode : xmlElementsToProcess) {
+            final YangDataDomNode childYangDataDomNode = new YangDataDomNode(context, this, childXmlNode);
+            childYangDataDomNode.processXmlChildElements(context, childXmlNode);
+        }
+
+        /*
+         * It quite frequently (at least for hand-drafted XML files) happens that namespaces are not declared
+         * at the top of the document. We make sure that the children all have a valid namespace, otherwise
+         * there will be more processing errors later on, so highlight this here.
+         */
+        for (final YangDataDomNode child : getChildren()) {
+            if (child.getNamespace() == null) {
+                context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                        "The top-level data nodes must have a namespace, but none is declared."));
+            }
+        }
+    }
+
+    /**
+     * Given the root XML element of a document, searches for a named child element, and return that child's children.
+     */
+    private Element getNamedChildElement(final Element element, final String soughtChildName) {
+
+        final Collection<? extends Element> childrenOfRoot = getChildElementNodes(element);
+        for (final Element child : childrenOfRoot) {
+            if (soughtChildName.equals(QNameHelper.extractName(child.getTagName()))) {
+                return child;
+            }
+        }
+
+        return null;
+    }
+
+    private Collection<? extends Element> getChildElementNodes(final Element element) {
+
+        final List<Element> result = new ArrayList<>();
+
+        final NodeList childXmlNodes = element.getChildNodes();
+        for (int i = 0; i < childXmlNodes.getLength(); ++i) {
+            final Node childXmlNode = childXmlNodes.item(i);
+            if (childXmlNode.getNodeType() == Node.ELEMENT_NODE) {
+                result.add((Element) childXmlNode);
+            }
+        }
+
+        return result;
+    }
+
+    // ============================ JSON handling ============================
+
+    public void buildFromJsonDocument(final ParserExecutionContext context, final JsonObject rootJsonObject) {
+
+        /*
+         * No fluffing around with namespaces here, of course.
+         */
+
+        processJsonChildElements(context, rootJsonObject);
+
+        /*
+         * We make sure that the children all have a valid module name, otherwise there will be
+         * more processing errors later on, so highlight this here.
+         */
+        for (final YangDataDomNode child : getChildren()) {
+            if (child.getModuleName().equals(ROOT_SLASH)) {
+                context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                        "The name of all top-level data nodes name must be prefixed with the name of the module that owns the data node."));
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomNode.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomNode.java
new file mode 100644
index 0000000..66384fe
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomNode.java
@@ -0,0 +1,1001 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.dom;
+
+import java.io.BufferedReader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot.SourceDataType;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.HasLineAndColumn;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonArray;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObject;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObjectMemberName;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonPrimitive;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonValue;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+/**
+ * Represents a node in the data tree. The node can be structural (container,
+ * list) or content (leaf, leaf-list).
+ *
+ * @author Mark Hollmann
+ */
+public class YangDataDomNode {
+
+    public final static String LINE_NUMBER_KEY_NAME = "lineNumber";
+    public final static String COLUMN_NUMBER_KEY_NAME = "colNumber";
+
+    protected final static String ROOT_SLASH = "/";
+
+    private final String name;
+    private String namespace;
+    private String moduleName;
+
+    private final Object value;
+
+    private final int lineNumber;
+    private final int columnNumber;
+
+    private final PrefixResolver prefixResolver;		// only applies to XML
+
+    private YangDataDomNode parentNode;
+    private final List<YangDataDomNode> children = new ArrayList<>();
+
+    private final YangDataDomDocumentRoot documentRoot;
+
+    private List<YangDataDomNodeAnnotationValue> annotations = null;
+
+    /**
+     * Findings made in respect of this piece of data, if any.
+     */
+    private Set<Finding> findings = null;
+
+    /**
+     * Special constructor just for the data DOM document root.
+     */
+    protected YangDataDomNode() {
+        this.name = ROOT_SLASH;
+        this.namespace = ROOT_SLASH;
+        this.moduleName = ROOT_SLASH;
+        this.value = null;
+        this.lineNumber = 0;
+        this.columnNumber = 0;
+        this.prefixResolver = new PrefixResolver();
+        this.documentRoot = (YangDataDomDocumentRoot) this;
+    }
+
+    /**
+     * Returns the name of the data node.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the namespace of the data node. May return null if data was JSON encoded and
+     * namespaces were not resolved yet.
+     */
+    public String getNamespace() {
+        return namespace;
+    }
+
+    /**
+     * Returns the module of the data node. May return null if data was XML encoded and
+     * module names were not resolved yet.
+     */
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    /**
+     * Returns the source type of the data.
+     */
+    public SourceDataType getSourceDataType() {
+        return getDocumentRoot().getSourceDataType();
+    }
+
+    /**
+     * Returns the value of this data DOM node. The data type of the returned object
+     * depends on the input that was used to construct this object. If it was XML,
+     * then the data type will always be String. If the input was JSON, then the data
+     * type may be String, Double, or Boolean. May return null if explicitly set to
+     * NIL in XML input or null in JSON input.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Returns a stringefied representation of the value. May return null. Note that
+     * Double objects that are integer will not be returned in integer format, but
+     * in double format.
+     */
+    public String getStringValue() {
+        return value == null ? null : value.toString();
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    public YangDataDomNode getParentNode() {
+        return parentNode;
+    }
+
+    public List<YangDataDomNode> getChildren() {
+        return Collections.unmodifiableList(children);
+    }
+
+    public YangDataDomDocumentRoot getDocumentRoot() {
+        return documentRoot;
+    }
+
+    public YangData getYangData() {
+        return getDocumentRoot().getYangData();
+    }
+
+    /**
+     * For anydata and anyxml we need to re-construct the descendant tree as the client may wish to parse it further.
+     */
+    public String getReassembledChildren() {
+        // TODO when really needed.
+        return "";
+    }
+
+    /**
+     * Return all child DOM nodes with the specified name and namespace/module.
+     */
+    public List<YangDataDomNode> getChildren(final String soughtNamespace, final String soughtModuleName,
+            final String soughtName) {
+        return children.stream().filter(child -> {
+            if (!child.getName().equals(soughtName)) {
+                return false;
+            }
+            if (child.getNamespace() != null && child.getNamespace().equals(soughtNamespace)) {
+                return true;
+            }
+            if (child.getModuleName() != null && child.getModuleName().equals(soughtModuleName)) {
+                return true;
+            }
+            return false;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * Returns a single child DOM node with the specified name and namespace or module. Returns null if not found.
+     */
+    public YangDataDomNode getChild(final String soughtNamespace, final String soughtModuleName, final String soughtName) {
+
+        for (final YangDataDomNode child : children) {
+            if (child.getName().equals(soughtName)) {
+                if (child.getNamespace() != null && child.getNamespace().equals(soughtNamespace)) {
+                    return child;
+                }
+                if (child.getModuleName() != null && child.getModuleName().equals(soughtModuleName)) {
+                    return child;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public PrefixResolver getPrefixResolver() {
+        return prefixResolver;
+    }
+
+    public List<YangDataDomNodeAnnotationValue> getAnnotations() {
+        return annotations == null ?
+                Collections.<YangDataDomNodeAnnotationValue> emptyList() :
+                Collections.unmodifiableList(annotations);
+    }
+
+    /**
+     * Returns a human-readable string with the full path to the DOM node.
+     */
+    public String getPath() {
+
+        final List<YangDataDomNode> dataDomNodes = new ArrayList<>(10);
+        YangDataDomNode runDataDomNode = this;
+
+        while (!(runDataDomNode instanceof YangDataDomDocumentRoot)) {
+            dataDomNodes.add(0, runDataDomNode);
+            runDataDomNode = runDataDomNode.getParentNode();
+        }
+
+        final StringBuilder sb = new StringBuilder();
+        for (final YangDataDomNode domNode : dataDomNodes) {
+            sb.append('/').append(domNode.getName());
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Depending on the source (JSON or XML) either module name or namespace will be missing after the
+     * initial construction of the tree. This here will fix up the missing bits of information.
+     */
+    public void resolveModuleOrNamespace(final ModuleAndNamespaceResolver resolver) {
+
+        if (moduleName == null && namespace != null) {
+            moduleName = resolver.getModuleForNamespace(namespace);
+        } else if (namespace == null && moduleName != null) {
+            namespace = resolver.getNamespaceForModule(moduleName);
+        }
+
+        if (annotations != null) {
+            annotations.forEach(anno -> anno.resolveModuleOrNamespace(resolver));
+        }
+
+        children.forEach(child -> child.resolveModuleOrNamespace(resolver));
+    }
+
+    public void addFinding(final Finding finding) {
+        if (findings == null) {
+            findings = new HashSet<>();
+        }
+        findings.add(finding);
+    }
+
+    /**
+     * Returns the findings for this data DOM node. Returns empty set if no findings found.
+     */
+    public Set<Finding> getFindings() {
+        return findings == null ? Collections.<Finding> emptySet() : findings;
+    }
+
+    @Override
+    public String toString() {
+        return value == null ? name : name + " " + value;
+    }
+
+    // ===================================== XML processing ==================================
+
+    /**
+     * Constructor for a data node instance encoded in XML.
+     */
+    public YangDataDomNode(final ParserExecutionContext context, final YangDataDomNode parentNode,
+            final Element xmlDomElement) {
+
+        parentNode.children.add(this);
+        this.parentNode = parentNode;
+
+        this.documentRoot = parentNode.getDocumentRoot();
+
+        this.lineNumber = xmlDomElement.getUserData(LINE_NUMBER_KEY_NAME) == null ?
+                0 :
+                ((Integer) xmlDomElement.getUserData(LINE_NUMBER_KEY_NAME)).intValue();
+        this.columnNumber = xmlDomElement.getUserData(COLUMN_NUMBER_KEY_NAME) == null ?
+                0 :
+                ((Integer) xmlDomElement.getUserData(COLUMN_NUMBER_KEY_NAME)).intValue();
+
+        final List<Attr> xmlAttributes = getAttributesfromXmlElement(xmlDomElement);
+
+        /*
+         * Namespace handling.
+         *
+         * Before doing anything else, we need to extract prefix mappings from the XML element. These are
+         * usually placed at the top of the document, but could be anywhere in the tree really.
+         *
+         * - If the element does not define any namespaces, then we use the prefix resolver of the parent
+         *   DOM node to save on memory.
+         * - If namespaces are defined, we create a new prefix resolver, clone the contents of the prefix
+         *   resolver of the parent, and overwrite with whatever is defined here.
+         *
+         * An example in XML is as follows:
+         *
+         * <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
+         *   <enable-nacm>true</enable-nacm>
+         *   ... stuff ...
+         * </nacm>
+         *
+         * The default namespace is always defined with xmlns="...namespace..."; a named namespace is
+         * always defined with xmlns:somename="...namespace...".
+         */
+        if (hasNamespaceMappings(xmlAttributes)) {
+            this.prefixResolver = parentNode.getPrefixResolver().clone();
+            populateXmlPrefixResolver(xmlAttributes, prefixResolver);
+        } else {
+            this.prefixResolver = parentNode.getPrefixResolver();
+        }
+
+        /*
+         * Annotation handling.
+         *
+         * RFC 7952 defines YANG annotations, which are encoded as XML attributes. Example:
+         *
+         * <foo
+         *       xmlns:elm="http://example.org/example-last-modified"
+         *       elm:last-modified="2015-09-16T10:27:35+02:00">
+         *   ...
+         * </foo>
+         *
+         * Above, the XML attribute "last-modified" denotes the value of the YANG annotation of the same name,
+         * that is defined in namespace "http://example.org/example-last-modified".
+         */
+        extractAnnotationsFromXmlAttributes(context, xmlAttributes, prefixResolver);
+
+        /*
+         * Extract the name and namespace of the data node. The name may or not be prefixed. Example:
+         *
+         * <foo>1234</foo>
+         * <bar:foo xmlns:bar="www.bar.com">1234</bar:foo>
+         *
+         * Note that a namespace does not have to be defined on the element itself - it could be defined
+         * further up the tree (and that's the reason why the prefix resolver is cloned if necessary).
+         */
+        this.name = QNameHelper.extractName(xmlDomElement.getTagName());
+
+        final String elemPrefix = QNameHelper.extractPrefix(xmlDomElement.getTagName());
+        this.namespace = prefixResolver.resolveNamespaceUri(elemPrefix);
+
+        if (namespace == null) {
+            context.addFinding(new Finding(this, ParserFindingType.P077_UNRESOLVABLE_PREFIX.toString(),
+                    "Prefix '" + elemPrefix + "' not resolvable to a namespace."));
+        }
+
+        /*
+         * Extract the value, if any, of the element. If it is a container / list, then it will not
+         * have a value. Example:
+         *
+         * <foo-container>
+         *   <bar-list>
+         *     <bar-name>name1</bar-name>
+         *     <bar-state>ENABLED</bar-state>
+         *   </bar-list>
+         *   <bar-list>
+         *     <bar-name>name1</bar-name>
+         *     <bar-state>ENABLED</bar-state>
+         *   </bar-list>
+         * </foo-container>
+         */
+        this.value = getValueOfXmlElement(xmlDomElement, prefixResolver);
+    }
+
+    public void processXmlChildElements(final ParserExecutionContext context, final Element xmlDomElement) {
+        /*
+         * Go through all XML child elements
+         */
+        final NodeList childXmlNodes = xmlDomElement.getChildNodes();
+        for (int i = 0; i < childXmlNodes.getLength(); ++i) {
+
+            final Node childXmlNode = childXmlNodes.item(i);
+
+            if (childXmlNode.getNodeType() == Node.ELEMENT_NODE) {
+                final YangDataDomNode childYangDataDomNode = new YangDataDomNode(context, this, (Element) childXmlNode);
+                childYangDataDomNode.processXmlChildElements(context, (Element) childXmlNode);
+            }
+        }
+    }
+
+    /**
+     * Extracts all XML Attributes from the XML element that define prefix-to-namespace mappings.
+     * Such XML attributes look as follows:
+     * <p>
+     * <supported-compression-types
+     * xmlns="urn:rdns:o-ran:oammodel:pm"
+     * xmlns:typese="urn:rdns:o-ran:oammodel:yang-types">
+     * </supported-compression-types>
+     */
+    private static boolean hasNamespaceMappings(final List<Attr> xmlAttributes) {
+        return xmlAttributes.stream().anyMatch(YangDataDomNode::attrDefinesPrefixMapping);
+    }
+
+    private static boolean attrDefinesPrefixMapping(final Attr attr) {
+        return attr.getName().equals("xmlns") || attr.getName().startsWith("xmlns:");
+    }
+
+    /**
+     * Given a prefix resolver, populates same with any namespace declarations
+     * found amongst the supplied list of XML attributes.
+     */
+    protected static void populateXmlPrefixResolver(final List<Attr> xmlAttributes, final PrefixResolver prefixResolver) {
+
+        for (final Attr attr : xmlAttributes) {
+            final String attrName = attr.getName();
+            final String attrValue = attr.getValue();
+
+            if (attrName.equals("xmlns")) {
+                prefixResolver.setDefaultNamespaceUri(attrValue.intern());
+            } else if (attrName.startsWith("xmlns:")) {
+                prefixResolver.addMapping(attrName.substring(6).intern(), attrValue.intern());
+            }
+        }
+    }
+
+    private void extractAnnotationsFromXmlAttributes(final ParserExecutionContext context, final List<Attr> xmlAttributes,
+            final PrefixResolver prefixResolver) {
+
+        if (xmlAttributes.isEmpty()) {
+            return;
+        }
+
+        /*
+         * We go over all XML attributes and whatever does not denote a namespace, or a nil value, we
+         * assume is an annotation.
+         */
+        for (final Attr attr : xmlAttributes) {
+
+            if (attrDefinesPrefixMapping(attr) || attrIsXsiNil(attr, prefixResolver)) {
+                continue;
+            }
+
+            final String qName = attr.getName();
+
+            final String attrPrefix = QNameHelper.extractPrefix(qName);
+            final String attrNamespace = prefixResolver.resolveNamespaceUri(attrPrefix);
+            if (attrNamespace == null) {
+                context.addFinding(new Finding(this, ParserFindingType.P077_UNRESOLVABLE_PREFIX.toString(),
+                        "Prefix '" + attrPrefix + "' not resolvable to a namespace."));
+                continue;
+            }
+
+            if (this.annotations == null) {
+                this.annotations = new ArrayList<>(2);
+            }
+
+            final String attrName = QNameHelper.extractName(qName);
+            this.annotations.add(new YangDataDomNodeAnnotationValue(attrNamespace, null, attrName, attr.getValue()));
+        }
+    }
+
+    /**
+     * Returns the value of the element. Note this may be null.
+     */
+    private static String getValueOfXmlElement(final Element xmlDomElement, final PrefixResolver prefixResolver) {
+
+        /*
+         * Null-value handling. An element can be explicitly expressed as being null by using xsi:isNull. Never
+         * seen in real life and not sure how it would make sense to have a null value in the data (just leave
+         * out the XML element...). Example:
+         *
+         * <foo
+         *       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         *       xsi:nil="true" />
+         *
+         * Note that according to w3 the XSI namespace must be explicitly declared.
+         */
+        if (elementIsNil(xmlDomElement, prefixResolver)) {
+            return null;
+        }
+
+        /*
+         * If the XML element has data (i.e. it is a leaf or leaf-list), then there should be a text node
+         * underneath (note: element.getNodeValue() is wrong to use).
+         */
+        final NodeList childXmlNodes = xmlDomElement.getChildNodes();
+        final StringBuilder value = new StringBuilder();
+
+        for (int i = 0; i < childXmlNodes.getLength(); ++i) {
+
+            final Node childXmlNode = childXmlNodes.item(i);
+
+            switch (childXmlNode.getNodeType()) {
+                case Node.TEXT_NODE:
+                    /*
+                     * The text node will contain all of the control characters and the whitespaces; all of
+                     * which needs to be stripped out to arrive at something that makes sense (or nothing).
+                     */
+                    cleanXmlText(childXmlNode.getNodeValue(), value);
+                    break;
+
+                case Node.CDATA_SECTION_NODE:
+
+                    value.append(childXmlNode.getNodeValue());
+                    break;
+
+                case Node.ELEMENT_NODE:
+                    /*
+                     * An element node exists under this one here. That implies that this element here is a
+                     * container / list, so it cannot have a value. Would be incorrect XML.
+                     */
+                    return null;
+            }
+        }
+
+        return value.toString();
+    }
+
+    /**
+     * Returns whether xsi:nil is present in the list of XML attributes.
+     */
+    private static boolean elementIsNil(final Element xmlDomElement, final PrefixResolver prefixResolver) {
+        return getAttributesfromXmlElement(xmlDomElement).stream().anyMatch(attr -> attrIsXsiNilTrue(attr, prefixResolver));
+    }
+
+    /**
+     * Returns whether the XML attribute is XSI NIL.
+     */
+    private static boolean attrIsXsiNil(final Attr attr, final PrefixResolver prefixResolver) {
+
+        final String qName = attr.getName();
+
+        final String attrName = QNameHelper.extractName(qName);
+        final String attrPrefix = QNameHelper.extractPrefix(qName);
+        final String attrNamespace = prefixResolver.resolveNamespaceUri(attrPrefix);
+
+        return ("http://www.w3.org/2001/XMLSchema-instance".equals(attrNamespace) && "nil".equals(attrName));
+    }
+
+    /**
+     * Returns whether the XML attribute denotes XSI NIL with value true.
+     */
+    private static boolean attrIsXsiNilTrue(final Attr attr, final PrefixResolver prefixResolver) {
+        return "true".equalsIgnoreCase(attr.getValue()) && attrIsXsiNil(attr, prefixResolver);
+    }
+
+    protected static List<Attr> getAttributesfromXmlElement(final Element xmlDomElement) {
+
+        List<Attr> result = null;
+
+        final NamedNodeMap attributesNodeMap = xmlDomElement.getAttributes();
+        for (int i = 0; i < attributesNodeMap.getLength(); ++i) {
+            final Node item = attributesNodeMap.item(i);
+            if (item instanceof Attr) {
+                if (result == null) {
+                    result = new ArrayList<>();
+                }
+                result.add((Attr) item);
+            }
+        }
+
+        return result != null ? result : Collections.<Attr> emptyList();
+    }
+
+    /**
+     * Strip out all control characters and leading and trailing whitespaces.
+     */
+    private static void cleanXmlText(final String inputString, final StringBuilder result) {
+
+        boolean containsNonWhitespaceChars = false;
+        boolean containsNewLine = false;
+
+        final char[] charArray = inputString.toCharArray();
+        for (int i = 0; i < charArray.length; ++i) {
+            final char c = charArray[i];
+            if (c == ' ' || c == '\t') {
+                // all ok so far...
+            } else if (c == '\n') {
+                containsNewLine = true;
+            } else {
+                containsNonWhitespaceChars = true;
+            }
+
+            if (containsNewLine && containsNonWhitespaceChars) {
+                break;
+            }
+        }
+
+        if (!containsNonWhitespaceChars) {
+            /*
+             * Contains only whitespace and/or new-line, all of which should be swallowed. We don't add
+             * anything to the result.
+             */
+            return;
+        }
+
+        /*
+         * Right...need to clean the string so. If there is no newline in it then we simply trim the string
+         * and we are done.
+         */
+        if (!containsNewLine) {
+            result.append(inputString.trim());
+            return;
+        }
+
+        /*
+         * Uhh...newlines in it...must strip these out, and trim every line individually...and then re-assemble.
+         */
+        final List<String> lines = new ArrayList<>();
+
+        try {
+            final BufferedReader br = new BufferedReader(new StringReader(inputString));
+            String str;
+            while ((str = br.readLine()) != null) {
+                str = str.trim();
+                if (!str.isEmpty()) {
+                    lines.add(str);
+                }
+            }
+        } catch (Exception wontHappen) {
+        }
+
+        boolean first = true;
+        for (final String line : lines) {
+            if (!first) {
+                result.append(' ');
+            }
+            result.append(line);
+            first = false;
+        }
+    }
+
+    // ====================================== JSON processing ===================================
+
+    /**
+     * Constructor for a data node instance encoded in JSON.
+     */
+    public YangDataDomNode(final ParserExecutionContext context, final YangDataDomNode parentNode, final String memberName,
+            final JsonValue jsonValue) {
+
+        parentNode.children.add(this);
+        this.parentNode = parentNode;
+
+        this.documentRoot = parentNode.getDocumentRoot();
+
+        this.lineNumber = jsonValue.line;
+        this.columnNumber = jsonValue.col;
+
+        this.name = extractName(memberName);
+        this.moduleName = extractModule(memberName, parentNode.getModuleName());
+        this.namespace = null;
+        this.value = jsonValue instanceof JsonPrimitive ? ((JsonPrimitive) jsonValue).getValue() : null;
+
+        this.prefixResolver = parentNode.getPrefixResolver();
+    }
+
+    /**
+     * Processing the child elements of the JSON object means that this instance here is either a container or a list.
+     */
+    protected void processJsonChildElements(final ParserExecutionContext context, final JsonObject jsonObject) {
+
+        final Map<JsonObjectMemberName, JsonValue> members = jsonObject.getValuesByMember();
+
+        /*
+         * Handle the annotations, if any, for this container or list.
+         */
+        final JsonObject annotationsForThis = getAnnotationJsonObject(context, jsonObject, "@");
+        extractAnnotationsFromJsonObject(context, annotationsForThis, this);
+
+        /*
+         * Handle any possible [null] element.
+         */
+        fixupEmptyHandling(jsonObject);
+
+        /*
+         * Process the data nodes
+         */
+        final Set<String> processedLeafAndLeafListMemberNames = new HashSet<>();
+
+        for (final Entry<JsonObjectMemberName, JsonValue> mapEntry : members.entrySet()) {
+
+            final String memberName = mapEntry.getKey().getMemberName();
+
+            /*
+             * Annotations will be handled separately as part of the data nodes, skip these here.
+             */
+            if (memberName.startsWith("@")) {
+                continue;
+            }
+
+            /*
+             * What we do now depends on the type of value:
+             * - JsonObject = container
+             * - JsonScalar = leaf
+             * - JsonArray = list or leaf-list (need to peek at the array members)
+             */
+            final JsonValue value = mapEntry.getValue();
+
+            if (value instanceof JsonPrimitive) {				// leaf
+                /*
+                 * It is a leaf.
+                 */
+                final YangDataDomNode leafDataDomNode = new YangDataDomNode(context, this, memberName,
+                        (JsonPrimitive) value);
+                final JsonObject leafAnnotations = getAnnotationJsonObject(context, jsonObject, "@" + memberName);
+                extractAnnotationsFromJsonObject(context, leafAnnotations, leafDataDomNode);
+
+                processedLeafAndLeafListMemberNames.add(memberName);
+
+            } else if (value instanceof JsonObject) {		// container
+
+                final YangDataDomNode containerDataDomNode = new YangDataDomNode(context, this, memberName,
+                        (JsonObject) value);
+                containerDataDomNode.processJsonChildElements(context, (JsonObject) value);
+
+            } else {
+
+                if (((JsonArray) value).getValues().isEmpty()) {
+
+                    // empty leaf list, nothing to do (should really not be in the JSON file)
+
+                } else if (allMembersAreJsonPrimitives((JsonArray) value)) {		// leaf-list
+
+                    final List<JsonValue> values = ((JsonArray) value).getValues();
+                    final JsonArray leafListMemberAnnotations = getAnnotationJsonArray(context, jsonObject,
+                            "@" + memberName);
+                    final List<JsonValue> annotationValues = leafListMemberAnnotations.getValues();
+
+                    if (annotationValues.size() > values.size()) {
+                        issueFindingOnJsonElement(context, ParserFindingType.P069_UNEXPECTED_JSON_VALUE.toString(),
+                                "The size of the JSON array for the annotations is bigger than the size of the JSON array used for the leaf-list values.",
+                                leafListMemberAnnotations);
+                    }
+
+                    for (int i = 0; i < values.size(); ++i) {
+                        final YangDataDomNode leafListDataDomNode = new YangDataDomNode(context, this, memberName,
+                                (JsonPrimitive) values.get(i));
+                        if (annotationValues.size() > i && annotationValues.get(i) != null) {
+                            extractAnnotationsFromJsonObject(context, (JsonObject) annotationValues.get(i),
+                                    leafListDataDomNode);
+                        }
+                    }
+
+                    processedLeafAndLeafListMemberNames.add(memberName);
+
+                } else if (allMembersAreJsonObjects((JsonArray) value)) {		// list
+
+                    ((JsonArray) value).getValues().forEach(member -> {
+                        final YangDataDomNode childYangDataDomNode = new YangDataDomNode(context, this, memberName,
+                                (JsonObject) member);
+                        childYangDataDomNode.processJsonChildElements(context, (JsonObject) member);
+                    });
+
+                } else {		// wrong JSON
+
+                    issueFindingOnJsonElement(context, ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString(),
+                            "The JSON array members must all either be objects or be primitives, but not a mixture of those.",
+                            value);
+                }
+            }
+        }
+
+        /*
+         * We check for any orphaned annotations here.
+         */
+        for (final Entry<JsonObjectMemberName, JsonValue> mapEntry : members.entrySet()) {
+
+            final String memberName = mapEntry.getKey().getMemberName();
+
+            if (memberName.equals("@") || !memberName.startsWith("@")) {
+                continue;
+            }
+
+            if (!processedLeafAndLeafListMemberNames.contains(memberName.substring(1))) {
+                /*
+                 * We have an annotation with a member name for which we do not have a leaf or leaf-list.
+                 */
+                issueFindingOnJsonElement(context, ParserFindingType.P069_UNEXPECTED_JSON_VALUE.toString(),
+                        "Annotation '" + memberName + "' cannot be matched up against a leaf or leaf-list with name '" + memberName
+                                .substring(1) + "'.", mapEntry.getKey());
+            }
+        }
+    }
+
+    /**
+     * Replaces all occurrences of [null] (i.e. a JsonArray with a single primitive
+     * member being null) with null (i.e. a primitive value being null).
+     */
+    private static void fixupEmptyHandling(final JsonObject jsonObject) {
+
+        final Map<JsonObjectMemberName, JsonValue> members = jsonObject.getValuesByMember();
+        for (final JsonObjectMemberName key : new ArrayList<>(members.keySet())) {
+
+            final JsonValue memberValue = members.get(key);
+
+            if (denotesEmpty(memberValue)) {
+                jsonObject.putMember(key, JsonPrimitive.valueOf(memberValue.line, memberValue.col, null));
+            } else if (memberValue instanceof JsonArray) {
+
+                final JsonArray jsonArray = (JsonArray) memberValue;
+                final List<JsonValue> arrayValues = jsonArray.getValues();
+
+                for (int i = 0; i < arrayValues.size(); ++i) {
+                    final JsonValue arrayValue = arrayValues.get(i);
+                    if (denotesEmpty(arrayValue)) {
+                        jsonArray.setValue(i, JsonPrimitive.valueOf(arrayValue.line, arrayValue.col, null));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns whether the supplied JSON value is [null], denoting an empty value (special syntax for data type 'empty').
+     */
+    private static boolean denotesEmpty(final JsonValue jsonValue) {
+
+        if (jsonValue instanceof JsonArray) {
+            final JsonArray jsonArray = (JsonArray) jsonValue;
+            final List<JsonValue> values = jsonArray.getValues();
+
+            if (values.size() == 1) {
+                final JsonValue firstArrayMember = values.get(0);
+                if (firstArrayMember instanceof JsonPrimitive) {
+                    return ((JsonPrimitive) firstArrayMember).getValue() == null;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns a JsonObject representing the annotations for the sought name.
+     */
+    private JsonObject getAnnotationJsonObject(final ParserExecutionContext context, final JsonObject parentJsonObject,
+            final String soughtName) {
+
+        final Optional<Entry<String, JsonValue>> anno = parentJsonObject.getValues().entrySet().stream().filter(
+                entry -> entry.getKey().equals(soughtName)).findAny();
+
+        if (!anno.isPresent()) {
+            return new JsonObject();
+        }
+
+        /*
+         * Annotations must always be encoded as JSON objects.
+         */
+        final JsonValue annoObject = anno.get().getValue();
+        if (!(annoObject instanceof JsonObject)) {
+            issueFindingOnJsonElement(context, ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString(),
+                    "Expected a JSON object to hold the annotations.", annoObject);
+            return new JsonObject();
+        }
+
+        return (JsonObject) annoObject;
+    }
+
+    /**
+     * Returns a JsonArray representing the annotations for the sought name.
+     */
+    private JsonArray getAnnotationJsonArray(final ParserExecutionContext context, final JsonObject parentJsonObject,
+            final String soughtName) {
+
+        final Optional<Entry<String, JsonValue>> anno = parentJsonObject.getValues().entrySet().stream().filter(
+                entry -> entry.getKey().equals(soughtName)).findAny();
+
+        if (!anno.isPresent()) {
+            return new JsonArray();
+        }
+
+        final JsonValue annoObject = anno.get().getValue();
+        if (!(annoObject instanceof JsonArray)) {
+            issueFindingOnJsonElement(context, ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString(),
+                    "Expected a JSON array to hold the annotations.", annoObject);
+            return new JsonArray();
+        }
+
+        /*
+         * All the members must be either a primitive null, or a JsonObject.
+         */
+        final JsonArray jsonArray = (JsonArray) annoObject;
+        final List<JsonValue> arrayValues = jsonArray.getValues();
+
+        for (int i = 0; i < arrayValues.size(); ++i) {
+
+            final JsonValue arrayMemberValue = arrayValues.get(i);
+
+            if (arrayMemberValue instanceof JsonPrimitive && ((JsonPrimitive) arrayMemberValue).equals(
+                    JsonPrimitive.NULL)) {
+                // we generate an empty object to replace the null.
+                jsonArray.setValue(i, new JsonObject());
+            } else if (arrayMemberValue instanceof JsonObject) {
+                // ok, expected
+            } else {
+                issueFindingOnJsonElement(context, ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString(),
+                        "Expected a JSON object as array element to hold the annotations.", arrayMemberValue);
+                return new JsonArray();
+            }
+        }
+
+        return jsonArray;
+    }
+
+    private void extractAnnotationsFromJsonObject(final ParserExecutionContext context,
+            final JsonObject jsonObjectWithAnnotations, final YangDataDomNode owningDomNode) {
+
+        if (jsonObjectWithAnnotations.getValues().isEmpty()) {
+            return;
+        }
+
+        owningDomNode.annotations = new ArrayList<>();
+
+        /*
+         * Clean up [null] handling, will be needed where the annotation does not have an argument.
+         */
+        fixupEmptyHandling(jsonObjectWithAnnotations);
+
+        /*
+         * Iterate over the members of the object - these are the annotations.
+         */
+        final Map<JsonObjectMemberName, JsonValue> annoMembers = jsonObjectWithAnnotations.getValuesByMember();
+        for (final Entry<JsonObjectMemberName, JsonValue> entry : annoMembers.entrySet()) {
+
+            final String moduleAndAnnoName = entry.getKey().getMemberName();
+
+            /*
+             * According to RFC, the annotation name MUST be prefixed with the module - section 5.2.1 in RFC 7952...
+             */
+            final String moduleName = extractModule(moduleAndAnnoName, null);
+            final String annoName = extractName(moduleAndAnnoName);
+
+            if (moduleName == null) {
+                issueFindingOnJsonElement(context, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                        "All members of the JSON object used for annotation values must be prefixed with the module name.",
+                        entry.getKey());
+                continue;
+            }
+
+            owningDomNode.annotations.add(new YangDataDomNodeAnnotationValue(null, moduleName, annoName,
+                    ((JsonPrimitive) entry.getValue()).getValue()));
+        }
+    }
+
+    private static String extractName(final String memberName) {
+        return memberName.contains(":") ? memberName.split(":")[1] : memberName;
+    }
+
+    private static String extractModule(final String memberName, final String parentModuleName) {
+        return memberName.contains(":") ? memberName.split(":")[0] : parentModuleName;
+    }
+
+    private static boolean allMembersAreJsonPrimitives(final JsonArray array) {
+        final List<JsonValue> values = array.getValues();
+        for (final JsonValue value : values) {
+            if (!(value instanceof JsonPrimitive)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean allMembersAreJsonObjects(final JsonArray array) {
+        final List<JsonValue> values = array.getValues();
+        for (final JsonValue value : values) {
+            if (!(value instanceof JsonObject)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void issueFindingOnJsonElement(final ParserExecutionContext context, final String findingType,
+            final String message, final HasLineAndColumn problematicJsonElement) {
+        context.addFinding(new Finding(getYangData(), findingType, message, problematicJsonElement.line,
+                problematicJsonElement.col));
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomNodeAnnotationValue.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomNodeAnnotationValue.java
new file mode 100644
index 0000000..d70a30f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/dom/YangDataDomNodeAnnotationValue.java
@@ -0,0 +1,68 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.dom;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+/**
+ * Encodes an annotation value.
+ *
+ * @author Mark Hollmann
+ */
+public class YangDataDomNodeAnnotationValue extends NamespaceModuleIdentifier {
+
+    private final Object value;
+
+    public YangDataDomNodeAnnotationValue(final String namespace, final String moduleName, final String annotationName,
+            final Object value) {
+        super(namespace, moduleName, Objects.requireNonNull(annotationName));
+        this.value = value;
+    }
+
+    /**
+     * May be null if the data input was JSON and resolution has not been done yet.
+     */
+    public String getNamespace() {
+        return super.getNamespace();
+    }
+
+    /**
+     * May be null if the data input was XML and resolution has not been done yet.
+     */
+    public String getModuleName() {
+        return super.getModuleName();
+    }
+
+    public String getName() {
+        return super.getIdentifier();
+    }
+
+    /**
+     * Returns the value of the annotation. The encoding of the value is handled in the same way
+     * how it is done for the data DOM node (i.e. it distinguishes between XML and JSON source).
+     * May return null (annotation has no argument).
+     */
+    public Object getValue() {
+        return value;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractContentInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractContentInstance.java
new file mode 100644
index 0000000..fd4b52d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractContentInstance.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * Represents something that carries data, e.g. a leaf, a leaf-list instance.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class AbstractContentInstance extends AbstractDataInstance {
+
+    private final Object value;
+
+    private final String cachedToString;
+
+    /**
+     * Constructor for a content instance that carries data.
+     */
+    public AbstractContentInstance(final AbstractStatement schemaNode, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent, final Object value) {
+        super(schemaNode, dataDomNode, parent);
+
+        this.value = Objects.requireNonNull(value);
+        this.cachedToString = "(" + getNamespace() + "):" + getName() + "=" + Objects.toString(value);
+    }
+
+    /**
+     * Constructor for a content instance that carries a default value.
+     */
+    public AbstractContentInstance(final AbstractStatement schemaNode, final AbstractStructureInstance parent,
+            final Object value) {
+        super(schemaNode, parent);
+
+        this.value = value;
+        this.cachedToString = "(" + getNamespace() + "):" + getName() + "=" + Objects.toString(value);
+    }
+
+    /**
+     * The type of the returned value depends on how the value was originally encoded. If it
+     * was encoded in XML, the value will be of type String. If it was encoded in JSON, it
+     * will be of type String, Boolean or Double.
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return cachedToString;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractDataInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractDataInstance.java
new file mode 100644
index 0000000..d50d0ef
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractDataInstance.java
@@ -0,0 +1,110 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * Represents a piece of data in the data tree (e.g. a container, a leaf)
+ *
+ * @author Mark Hollmann
+ */
+public abstract class AbstractDataInstance {
+
+    /**
+     * The node in the schema that this data relates to. Will be null for the root instance.
+     */
+    private final AbstractStatement schemaNode;
+
+    /**
+     * The data DOM node that backs this data instance. Will be null for the root instance or
+     * default values.
+     */
+    private final YangDataDomNode dataDomNode;
+
+    /**
+     * The parent structure instance (i.e., the parent container or list). Will be null for
+     * the root instance.
+     */
+    private AbstractStructureInstance parent;
+
+    /**
+     * Constructor for an instance that has been specified in data.
+     */
+    public AbstractDataInstance(final AbstractStatement schemaNode, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent) {
+        this.schemaNode = schemaNode;
+        this.dataDomNode = Objects.requireNonNull(dataDomNode);
+        this.parent = parent;
+    }
+
+    /**
+     * Constructor for an instance that has been specified as default value.
+     */
+    public AbstractDataInstance(final AbstractStatement schemaNode, final AbstractStructureInstance parent) {
+        this.schemaNode = schemaNode;
+        this.dataDomNode = null;
+        this.parent = parent;
+    }
+
+    public void reparent(final AbstractStructureInstance newParent) {
+        parent = newParent;
+    }
+
+    /**
+     * Returns the schema node (really, a data node) in the schema to which this data instance relates.
+     */
+    public AbstractStatement getSchemaNode() {
+        return schemaNode;
+    }
+
+    /**
+     * Returns the data DOM node. May be null if NP-container or default value.
+     */
+    public YangDataDomNode getDataDomNode() {
+        return dataDomNode;
+    }
+
+    public String getName() {
+        if (dataDomNode == null) {
+            return schemaNode.getStatementIdentifier();
+        }
+        return dataDomNode.getName();
+    }
+
+    /**
+     * Returns the namespace. Where a data DOM node exists, will return that - otherwise, will return the effective
+     * namespace of the schema node. May return null.
+     */
+    public String getNamespace() {
+        if (dataDomNode == null) {
+            return schemaNode.getEffectiveNamespace();
+        }
+        return dataDomNode.getNamespace();
+    }
+
+    public AbstractStructureInstance getParent() {
+        return parent;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractStructureInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractStructureInstance.java
new file mode 100644
index 0000000..13084e0
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AbstractStructureInstance.java
@@ -0,0 +1,225 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * This class represents a structural element, which can be either a true (singleton)
+ * container, or an instance of a list.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class AbstractStructureInstance extends AbstractDataInstance {
+
+    /**
+     * The child structure instances, if any (i.e. containers / lists under this container / list).
+     */
+    private final List<AbstractStructureInstance> structureChildren = new ArrayList<>();
+
+    /**
+     * The content values, if any (non-presence containers are usually empty), of the structure (i.e. leaf or leaf-list
+     * data).
+     */
+    private final List<AbstractContentInstance> contentChildren = new ArrayList<>();
+
+    /**
+     * Constructor for a structure instance that was specified in data.
+     */
+    public AbstractStructureInstance(final AbstractStatement schemaNode, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent) {
+        super(schemaNode, dataDomNode, parent);
+    }
+
+    /**
+     * Constructor for a structure instance that was created by default (i.e. not specified in data).
+     */
+    public AbstractStructureInstance(final AbstractStatement schemaNode, final AbstractStructureInstance parent) {
+        super(schemaNode, parent);
+    }
+
+    public void addStructureChild(final AbstractStructureInstance structureChild) {
+        structureChildren.add(structureChild);
+    }
+
+    public List<AbstractStructureInstance> getStructureChildren() {
+        return structureChildren;
+    }
+
+    public void addContentChild(final AbstractContentInstance contentChild) {
+        contentChildren.add(contentChild);
+    }
+
+    public List<AbstractContentInstance> getContentChildren() {
+        return contentChildren;
+    }
+
+    /**
+     * Returns the container instance of the given namespace and name. May return null if not found.
+     */
+    public ContainerInstance getContainerInstance(final String namespace, final String name) {
+        return (ContainerInstance) structureChildren.stream().filter(new InstanceTester(namespace, name,
+                ContainerInstance.class)).findFirst().orElse(null);
+    }
+
+    public boolean hasContainerInstance(final String namespace, final String name) {
+        return structureChildren.stream().filter(new InstanceTester(namespace, name, ContainerInstance.class)).findFirst()
+                .isPresent();
+    }
+
+    /**
+     * Returns the leaf instance of the given namespace and name. May return null if not found.
+     */
+    public LeafInstance getLeafInstance(final String namespace, final String name) {
+        return (LeafInstance) contentChildren.stream().filter(new InstanceTester(namespace, name, LeafInstance.class))
+                .findFirst().orElse(null);
+    }
+
+    public boolean hasLeafInstance(final String namespace, final String name) {
+        return contentChildren.stream().filter(new InstanceTester(namespace, name, LeafInstance.class)).findFirst()
+                .isPresent();
+    }
+
+    /**
+     * Returns all occurrences of list instances of the given namespace and name.
+     */
+    public List<ListInstance> getListInstances(final String namespace, final String name) {
+        return (List<ListInstance>) structureChildren.stream().filter(new InstanceTester(namespace, name,
+                ListInstance.class)).map(child -> (ListInstance) child).collect(Collectors.toList());
+    }
+
+    public ListInstance getListInstance(final String namespace, final String name, final Map<String, String> keyValues) {
+        return structureChildren.stream().filter(new InstanceTester(namespace, name, ListInstance.class)).map(
+                child -> (ListInstance) child).filter(listChild -> keyValues.equals(listChild.getKeyValues())).findFirst()
+                .orElse(null);
+    }
+
+    public boolean hasListInstance(final String namespace, final String name) {
+        return structureChildren.stream().filter(new InstanceTester(namespace, name, ListInstance.class)).findFirst()
+                .isPresent();
+    }
+
+    public boolean hasListInstance(final String namespace, final String name, final Map<String, String> keyValues) {
+        return structureChildren.stream().filter(new InstanceTester(namespace, name, ListInstance.class)).filter(
+                child -> keyValues.equals(((ListInstance) child).getKeyValues())).findFirst().isPresent();
+    }
+
+    /**
+     * Returns all occurrences of leaf-list instances of the given namespace and name.
+     */
+    public List<LeafListInstance> getLeafListInstances(final String namespace, final String name) {
+        return (List<LeafListInstance>) contentChildren.stream().filter(new InstanceTester(namespace, name,
+                LeafListInstance.class)).map(child -> (LeafListInstance) child).collect(Collectors.toList());
+    }
+
+    /**
+     * Returns the values of leaf-list. Note that the order may be undefined where a merge of multiple inputs happened.
+     */
+    public List<Object> getLeafListValues(final String namespace, final String name) {
+        return (List<Object>) contentChildren.stream().filter(new InstanceTester(namespace, name, LeafListInstance.class))
+                .map(child -> ((LeafListInstance) child).getValue()).collect(Collectors.toList());
+    }
+
+    public boolean hasLeafListInstance(final String namespace, final String name) {
+        return contentChildren.stream().filter(new InstanceTester(namespace, name, LeafListInstance.class)).findFirst()
+                .isPresent();
+    }
+
+    public boolean hasLeafListInstance(final String namespace, final String name, final Object value) {
+        return contentChildren.stream().filter(new InstanceTester(namespace, name, LeafListInstance.class)).filter(
+                child -> value.equals(((LeafListInstance) child).getValue())).findFirst().isPresent();
+    }
+
+    /**
+     * Returns the anydata instance of the given namespace and name. May return null if not found.
+     */
+    public AnyDataInstance getAnyDataInstance(final String namespace, final String name) {
+        return (AnyDataInstance) contentChildren.stream().filter(new InstanceTester(namespace, name, AnyDataInstance.class))
+                .findFirst().orElse(null);
+    }
+
+    public boolean hasAnyDataInstance(final String namespace, final String name) {
+        return contentChildren.stream().filter(new InstanceTester(namespace, name, AnyDataInstance.class)).findFirst()
+                .isPresent();
+    }
+
+    /**
+     * Returns the anyxml instance of the given namespace and name. May return null if not found.
+     */
+    public AnyXmlInstance getAnyXmlInstance(final String namespace, final String name) {
+        return (AnyXmlInstance) contentChildren.stream().filter(new InstanceTester(namespace, name, AnyXmlInstance.class))
+                .findFirst().orElse(null);
+    }
+
+    public boolean hasAnyXmlInstance(final String namespace, final String name) {
+        return contentChildren.stream().filter(new InstanceTester(namespace, name, AnyXmlInstance.class)).findFirst()
+                .isPresent();
+    }
+
+    private class InstanceTester implements Predicate<AbstractDataInstance> {
+
+        private final String namespace;
+        private final String name;
+        private final Class<? extends AbstractDataInstance> soughtClazz;
+
+        public <T extends AbstractDataInstance> InstanceTester(final String namespace, final String name,
+                final Class<T> soughtClazz) {
+            this.namespace = namespace;
+            this.name = name;
+            this.soughtClazz = soughtClazz;
+        }
+
+        @Override
+        public boolean test(final AbstractDataInstance dataInstance) {
+            return name.equals(dataInstance.getName()) && namespace.equals(dataInstance.getNamespace()) && (dataInstance
+                    .getClass().equals(soughtClazz));
+        }
+    }
+
+    /**
+     * Returns a human-readable string with the full path to the Container node.
+     */
+    public String getPath() {
+
+        final List<AbstractStructureInstance> containersFromRoot = new ArrayList<>(10);
+        AbstractStructureInstance runContainer = this;
+
+        while (runContainer != null) {
+            containersFromRoot.add(0, runContainer);
+            runContainer = runContainer.getParent();
+        }
+
+        final StringBuilder sb = new StringBuilder();
+        for (final AbstractStructureInstance container : containersFromRoot) {
+            sb.append('/').append(container.getName());
+        }
+
+        return sb.toString();
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AnyDataInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AnyDataInstance.java
new file mode 100644
index 0000000..14079f9
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AnyDataInstance.java
@@ -0,0 +1,51 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+public class AnyDataInstance extends AbstractContentInstance {
+
+    /**
+     * The value of the anyxml.
+     */
+    private final String value;
+
+    private final String cachedToString;
+
+    public AnyDataInstance(final AbstractStatement schemaLeaf, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent, final String value) {
+        super(schemaLeaf, dataDomNode, parent, value);
+        this.value = value;
+        this.cachedToString = "(" + getNamespace() + "):" + getName();
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return cachedToString;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AnyXmlInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AnyXmlInstance.java
new file mode 100644
index 0000000..f80574d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/AnyXmlInstance.java
@@ -0,0 +1,51 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+public class AnyXmlInstance extends AbstractContentInstance {
+
+    /**
+     * The value of the anyxml.
+     */
+    private final String value;
+
+    private final String cachedToString;
+
+    public AnyXmlInstance(final AbstractStatement schemaLeaf, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent, final String value) {
+        super(schemaLeaf, dataDomNode, parent, value);
+        this.value = value;
+        this.cachedToString = "(" + getNamespace() + "):" + getName();
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        return cachedToString;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/ContainerInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/ContainerInstance.java
new file mode 100644
index 0000000..0c7d436
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/ContainerInstance.java
@@ -0,0 +1,58 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * This class represents an instance of a container.
+ *
+ * @author Mark Hollmann
+ */
+public class ContainerInstance extends AbstractStructureInstance {
+
+    private final String cachedToString;
+
+    /**
+     * Constructor for a container instance that was specified in data.
+     */
+    public ContainerInstance(final AbstractStatement containerSchemaNode, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent) {
+        super(containerSchemaNode, dataDomNode, parent);
+
+        this.cachedToString = "(" + getNamespace() + "):" + getName();
+    }
+
+    /**
+     * Constructor for a container instance that was created as it is a NP container.
+     */
+    public ContainerInstance(final AbstractStatement containerSchemaNode, final AbstractStructureInstance parent) {
+        super(containerSchemaNode, parent);
+
+        this.cachedToString = "(" + getNamespace() + "):" + getName();
+    }
+
+    @Override
+    public String toString() {
+        return cachedToString;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/DataTreeBuilderPredicate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/DataTreeBuilderPredicate.java
new file mode 100644
index 0000000..144ff9b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/DataTreeBuilderPredicate.java
@@ -0,0 +1,56 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+
+/**
+ * Predicate that is used when a Yang data DOM tree is translated to an instance tree. Used to filter the
+ * top-level objects in the DOM. An example of this is where a client wishes to only process a subset of
+ * the data DOM that has been read in.
+ *
+ * @author Mark Hollmann
+ */
+public class DataTreeBuilderPredicate implements Predicate<YangDataDomNode> {
+
+    public static final DataTreeBuilderPredicate ALLOW_ALL = new DataTreeBuilderPredicate();
+
+    private final Set<String> filterInNamespaces;
+
+    public DataTreeBuilderPredicate() {
+        this.filterInNamespaces = Collections.<String> emptySet();
+    }
+
+    public DataTreeBuilderPredicate(final Set<String> filterInNamespaces) {
+        this.filterInNamespaces = Objects.requireNonNull(filterInNamespaces);
+    }
+
+    @Override
+    public boolean test(final YangDataDomNode domNode) {
+        return filterInNamespaces.isEmpty() || filterInNamespaces.contains(domNode.getNamespace());
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/InstanceDataTreeBuilder.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/InstanceDataTreeBuilder.java
new file mode 100644
index 0000000..bc12e1b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/InstanceDataTreeBuilder.java
@@ -0,0 +1,511 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot.SourceDataType;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.resolvers.Helper;
+import org.oran.smo.yangtools.parser.model.schema.ModuleRegistry;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YList;
+import org.oran.smo.yangtools.parser.model.statements.yang.YType;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.model.util.GrammarHelper;
+import org.oran.smo.yangtools.parser.yanglibrary.IetfYangLibraryParser;
+
+/**
+ * Builds a type-safe Yang instance data tree from Yang data DOM trees.
+ *
+ * @author Mark Hollmann
+ */
+public class InstanceDataTreeBuilder {
+
+    /**
+     * Given a number of data DOM trees, merges these together and forms a (single) tree with type-safe
+     * Yang instance data.
+     * <p/>
+     * This class requires the underlying Yang Model to be available, i.e. cannot be used with data only.
+     * <p/>
+     * If the input data was in JSON, module-name -&gt; namespace resolution must have been performed on
+     * the data first.
+     */
+    public static RootInstance buildCombinedDataTree(final FindingsManager findingsManager, final List<YangData> yangDatas,
+            final ModuleRegistry moduleRegistry, final DataTreeBuilderPredicate topLevelInstancePredicate) {
+
+        /*
+         * In a first step, the instance tree is build for each data file. Once this has been done the
+         * trees will be merged together.
+         */
+        final List<RootInstance> rootInstances = new ArrayList<>();
+
+        for (final YangData yangData : yangDatas) {
+
+            if (yangData.getYangDataDomDocumentRoot() == null) {
+                continue;
+            }
+
+            if (containsYangLibraryInstanceOnly(yangData) && !yangLibraryModelPresent(moduleRegistry)) {
+                /*
+                 * In case the data input only contains the data for the yang library, but the yang library
+                 * module itself was not part of the model inputs, we will not attempt to generate the data
+                 * instance tree, as this would fail - and the yang library is used as in effect BOM.
+                 */
+            } else {
+                final RootInstance rootInstance = new RootInstance();
+                /*
+                 * Schema root is handled slightly different from child-handling further down the tree...
+                 */
+                final List<AbstractStatement> allDataNodesAtTopLevel = getAllDataNodesAndChoiceAtTopLevel(moduleRegistry);
+                for (final YangDataDomNode dataDomNode : yangData.getYangDataDomDocumentRoot().getChildren()) {
+                    if (topLevelInstancePredicate.test(dataDomNode)) {
+                        processDomNode(findingsManager, dataDomNode, rootInstance, allDataNodesAtTopLevel);
+                    }
+                }
+
+                rootInstances.add(rootInstance);
+            }
+        }
+
+        /*
+         * Now all of the trees are merged together. This is a "smart" merge - the contents of the containers
+         * and lists are merged together; where content already exists and it is of the same value no finding
+         * will be issued.
+         */
+        final RootInstance result = new RootInstance();
+        for (final RootInstance rootInstance : rootInstances) {
+            mergeInDataTree(findingsManager, result, rootInstance);
+        }
+
+        return result;
+    }
+
+    public static List<AbstractStatement> getAllDataNodesAndChoiceAtTopLevel(final ModuleRegistry moduleRegistry) {
+
+        final List<AbstractStatement> result = new ArrayList<>();
+
+        for (final YangModel yangModelFile : moduleRegistry.getAllYangModels()) {
+            if (yangModelFile.getYangModelRoot().isModule()) {
+                result.addAll(getAllDataNodesAndChoiceUnderStatement(yangModelFile.getYangModelRoot().getModule()));
+            }
+        }
+
+        return result;
+    }
+
+    private static List<AbstractStatement> getAllDataNodesAndChoiceUnderStatement(final AbstractStatement statement) {
+        return statement.getChildStatements().stream().filter(child -> child.definesDataNode() || child.is(CY.STMT_CHOICE))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Returns whether this input only contains the YANG instance data.
+     */
+    private static boolean containsYangLibraryInstanceOnly(final YangData yangData) {
+
+        if (yangData.getYangDataDomDocumentRoot() == null) {
+            return false;
+        }
+
+        final List<YangDataDomNode> childrenUnderRoot = yangData.getYangDataDomDocumentRoot().getChildren();
+        if (childrenUnderRoot.size() != 1) {
+            return false;
+        }
+
+        final YangDataDomNode yangDataDomNode = childrenUnderRoot.get(0);
+
+        if (!IetfYangLibraryParser.IETF_YANG_LIBRARY_NAMESPACE.equals(yangDataDomNode.getNamespace())) {
+            return false;
+        }
+
+        return IetfYangLibraryParser.YANG_LIBRARY_MODULES_STATE.equals(yangDataDomNode
+                .getName()) || IetfYangLibraryParser.YANG_LIBRARY_YANG_LIBRARY.equals(yangDataDomNode.getName());
+    }
+
+    /**
+     * Returns whether any of the YANG library containers exist in the data nodes tree - so basically
+     * if the yang-library model was in the input.
+     */
+    private static boolean yangLibraryModelPresent(final ModuleRegistry moduleRegistry) {
+
+        final List<AbstractStatement> allDataNodesAtTopLevel = getAllDataNodesAndChoiceAtTopLevel(moduleRegistry);
+
+        final Optional<AbstractStatement> YangLibContainer = allDataNodesAtTopLevel.stream().filter(statement -> statement
+                .is(CY.STMT_CONTAINER)).filter(statement -> IetfYangLibraryParser.IETF_YANG_LIBRARY_NAMESPACE.equals(
+                        statement.getEffectiveNamespace())).filter(statement -> {
+                            final String containerName = statement.getStatementIdentifier();
+                            return IetfYangLibraryParser.YANG_LIBRARY_MODULES_STATE.equals(
+                                    containerName) || IetfYangLibraryParser.YANG_LIBRARY_YANG_LIBRARY.equals(containerName);
+                        }).findFirst();
+
+        return YangLibContainer.isPresent();
+    }
+
+    private static void processDomNode(final FindingsManager findingsManager, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parentInstance, final List<AbstractStatement> candidateDataNodes) {
+
+        final AbstractStatement matchingDataNode = Helper.findSchemaDataNode(candidateDataNodes, dataDomNode.getNamespace(),
+                dataDomNode.getName());
+        if (matchingDataNode == null) {
+            /*
+             * Well possible that the prefix is wrong / missing on the XML element, and hence the
+             * namespace of the DOM node is wrong and can't be found. Check if a schema node with
+             * the same name exists to give the user better feedback.
+             */
+            final AbstractStatement childWithSameName = Helper.findSchemaDataNode(candidateDataNodes, dataDomNode
+                    .getName());
+
+            if (childWithSameName != null) {
+                findingsManager.addFinding(new Finding(dataDomNode,
+                        ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString(),
+                        "No corresponding schema node was found in the model for data instance '" + dataDomNode
+                                .getPath() + "' in namespace '" + dataDomNode
+                                        .getNamespace() + "', but there exists a schema node with the same name in namespace '" + childWithSameName
+                                                .getEffectiveNamespace() + "'. Adjust namespace of the data instance."));
+            } else {
+                findingsManager.addFinding(new Finding(dataDomNode,
+                        ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString(),
+                        "No corresponding schema node was found in the model for data instance '" + dataDomNode
+                                .getPath() + "' (ns='" + dataDomNode.getNamespace() + "')."));
+            }
+            return;
+        }
+
+        if (matchingDataNode.is(CY.STMT_CONTAINER)) {
+            processContainer(findingsManager, dataDomNode, parentInstance, matchingDataNode);
+        } else if (matchingDataNode.is(CY.STMT_LEAF)) {
+            processLeaf(findingsManager, dataDomNode, parentInstance, matchingDataNode);
+        } else if (matchingDataNode.is(CY.STMT_LEAF_LIST)) {
+            processLeafList(findingsManager, dataDomNode, parentInstance, matchingDataNode);
+        } else if (matchingDataNode.is(CY.STMT_LIST)) {
+            processList(findingsManager, dataDomNode, parentInstance, matchingDataNode);
+        } else if (matchingDataNode.is(CY.STMT_ANYXML)) {
+            processAnyxml(findingsManager, dataDomNode, parentInstance, matchingDataNode);
+        } else if (matchingDataNode.is(CY.STMT_ANYDATA)) {
+            processAnydata(findingsManager, dataDomNode, parentInstance, matchingDataNode);
+        }
+    }
+
+    private static void processContainer(final FindingsManager findingsManager, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parentInstance, final AbstractStatement container) {
+
+        final ContainerInstance containerInstance = new ContainerInstance(container, dataDomNode, parentInstance);
+        if (parentInstance.hasContainerInstance(containerInstance.getNamespace(), containerInstance.getName())) {
+            findingsManager.addFinding(new Finding(dataDomNode, ParserFindingType.P076_DUPLICATE_INSTANCE_DATA.toString(),
+                    "Container '" + dataDomNode.getPath() + "' already defined in this input."));
+            return;
+        }
+
+        parentInstance.addStructureChild(containerInstance);
+
+        final List<AbstractStatement> allDataNodesUnderContainerStatement = getAllDataNodesAndChoiceUnderStatement(
+                container);
+        for (final YangDataDomNode childDomNode : dataDomNode.getChildren()) {
+            processDomNode(findingsManager, childDomNode, containerInstance, allDataNodesUnderContainerStatement);
+        }
+    }
+
+    private static void processLeaf(final FindingsManager findingsManager, final YangDataDomNode domNode,
+            final AbstractStructureInstance parentInstance, final AbstractStatement leaf) {
+
+        Object leafValue = domNode.getValue();
+        if (leafValue == null && domNode.getSourceDataType() == SourceDataType.JSON) {
+            leafValue = adjustNullValueForEmpty(leaf);
+        }
+        if (leafValue == null) {
+            findingsManager.addFinding(new Finding(domNode, ParserFindingType.P080_NULL_VALUE.toString(), "Leaf '" + domNode
+                    .getPath() + "' does not have a value."));
+            return;
+        }
+
+        final LeafInstance leafInstance = new LeafInstance(leaf, domNode, parentInstance, leafValue);
+        if (parentInstance.hasLeafInstance(leafInstance.getNamespace(), leafInstance.getName())) {
+            findingsManager.addFinding(new Finding(domNode, ParserFindingType.P076_DUPLICATE_INSTANCE_DATA.toString(),
+                    "Leaf '" + domNode.getPath() + "' already defined in this input."));
+            return;
+        }
+
+        parentInstance.addContentChild(leafInstance);
+    }
+
+    private static void processAnydata(final FindingsManager findingsManager, final YangDataDomNode domNode,
+            final AbstractStructureInstance parentInstance, final AbstractStatement schemaLeaf) {
+
+        final String nodeValue = domNode.getReassembledChildren();
+
+        final AnyDataInstance anyDataInstance = new AnyDataInstance(schemaLeaf, domNode, parentInstance, nodeValue);
+        if (parentInstance.hasAnyDataInstance(anyDataInstance.getNamespace(), anyDataInstance.getName())) {
+            findingsManager.addFinding(new Finding(domNode, ParserFindingType.P076_DUPLICATE_INSTANCE_DATA.toString(),
+                    "Anydata '" + domNode.getPath() + "' already defined in this input."));
+            return;
+        }
+
+        parentInstance.addContentChild(anyDataInstance);
+    }
+
+    private static void processAnyxml(final FindingsManager findingsManager, final YangDataDomNode domNode,
+            final AbstractStructureInstance parentInstance, final AbstractStatement schemaLeaf) {
+
+        final String nodeValue = domNode.getReassembledChildren();
+
+        final AnyXmlInstance anyXmlInstance = new AnyXmlInstance(schemaLeaf, domNode, parentInstance, nodeValue);
+        if (parentInstance.hasAnyXmlInstance(anyXmlInstance.getNamespace(), anyXmlInstance.getName())) {
+            findingsManager.addFinding(new Finding(domNode, ParserFindingType.P076_DUPLICATE_INSTANCE_DATA.toString(),
+                    "Anyxml '" + domNode.getPath() + "' already defined in this input."));
+            return;
+        }
+
+        parentInstance.addContentChild(anyXmlInstance);
+    }
+
+    private static void processLeafList(final FindingsManager findingsManager, final YangDataDomNode domNode,
+            final AbstractStructureInstance parentInstance, final AbstractStatement leafList) {
+
+        Object leafListValue = domNode.getValue();
+        if (leafListValue == null && domNode.getSourceDataType() == SourceDataType.JSON) {
+            leafListValue = adjustNullValueForEmpty(leafList);
+        }
+        if (leafListValue == null) {
+            findingsManager.addFinding(new Finding(domNode, ParserFindingType.P080_NULL_VALUE.toString(),
+                    "Leaf-list '" + domNode.getPath() + "' does not have a value."));
+            return;
+        }
+
+        final LeafListInstance leafListInstance = new LeafListInstance(leafList, domNode, parentInstance, leafListValue);
+
+        /*
+         * leaf-list is a bit different. The RFC states that values have to be unique in config data, so we need to check for that.
+         */
+        if (leafList.isEffectiveConfigTrue()) {
+            if (parentInstance.hasLeafListInstance(leafListInstance.getNamespace(), leafListInstance.getName(),
+                    leafListInstance.getValue())) {
+                findingsManager.addFinding(new Finding(domNode, ParserFindingType.P073_LEAF_VALUE_ALREADY_SET.toString(),
+                        "'config true' leaf-list '" + domNode
+                                .getPath() + "' instance with value '" + leafListValue + "' already defined in this input."));
+                return;
+            }
+        }
+
+        parentInstance.addContentChild(leafListInstance);
+    }
+
+    private static void processList(final FindingsManager findingsManager, final YangDataDomNode domNode,
+            final AbstractStructureInstance parentInstance, final AbstractStatement list) {
+        /*
+         * Create the list and check it doesn't exist yet. Then hook it up,
+         * and go recursively down the tree.
+         */
+        final ListInstance listInstance = createListInstance(findingsManager, parentInstance, domNode, list);
+        if (listInstance == null) {
+            /*
+             * No need for extra finding, would have been issued when creating the list instance.
+             */
+            return;
+        }
+        if (parentInstance.hasListInstance(listInstance.getNamespace(), listInstance.getName(), listInstance
+                .getKeyValues())) {
+            findingsManager.addFinding(new Finding(domNode, ParserFindingType.P076_DUPLICATE_INSTANCE_DATA.toString(),
+                    "List '" + domNode.getPath() + "' with key '" + listInstance
+                            .getKeyValues() + "' already defined in this input."));
+            return;
+        }
+        parentInstance.addStructureChild(listInstance);
+
+        final List<AbstractStatement> allDataNodesUnderListStatement = getAllDataNodesAndChoiceUnderStatement(list);
+        for (final YangDataDomNode childDomNode : domNode.getChildren()) {
+            processDomNode(findingsManager, childDomNode, listInstance, allDataNodesUnderListStatement);
+        }
+    }
+
+    private static ListInstance createListInstance(final FindingsManager findingsManager,
+            final AbstractStructureInstance parentStructure, final YangDataDomNode dataDomNode,
+            final AbstractStatement list) {
+
+        /*
+         * So it's a YANG list, get key(s), as these are important to identify the correct instance.
+         */
+        final YList yangList = (YList) list;
+
+        final List<String> keyNames = yangList.getKey() != null ?
+                GrammarHelper.parseToStringList(yangList.getKey().getValue()) :
+                Collections.<String> emptyList();
+        final Map<String, String> keyValues = new HashMap<>();
+
+        for (final String keyName : keyNames) {
+            final String value = getValueOfKeyLeaf(dataDomNode, keyName);
+            if (value == null) {
+                /*
+                 * Note that RFC7950 states:
+                 *
+                 * "All key leafs MUST be given values when a list entry is created." So if we don't have a value that is an error.
+                 */
+                findingsManager.addFinding(new Finding(dataDomNode, ParserFindingType.P072_MISSING_KEY_VALUE.toString(),
+                        "No value, or null, supplied for key leaf '" + keyName + "' for list instance '" + dataDomNode
+                                .getPath() + "'."));
+                return null;
+            }
+            keyValues.put(keyName, value);
+        }
+
+        return new ListInstance(list, dataDomNode, parentStructure, keyNames, keyValues);
+    }
+
+    /**
+     * Returns the value of the key leaf with the given name. Note that null
+     * will be returned if the key does not exist, or has an explicit null value.
+     */
+    private static String getValueOfKeyLeaf(final YangDataDomNode dataDomNode, final String keyName) {
+
+        for (final YangDataDomNode child : dataDomNode.getChildren()) {
+            if (child.getName().equals(keyName)) {
+                return child.getStringValue();
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * In JSON, an instance of a data node of type "empty" is encoded as '"my-leaf" : [null]', resulting
+     * in a DOM node with a null value. If the leaf in question is of type empty, then we will convert
+     * this to an empty string (as in NETCONF), so to allow further processing.
+     */
+    private static String adjustNullValueForEmpty(final AbstractStatement leafOrLeafList) {
+
+        final YType type = leafOrLeafList.getChild(CY.STMT_TYPE);
+        /*
+         * Sanity check - should never happen, unless the schema has defined a leaf / leaf-list
+         * without type (this would have been issued as a finding a long time ago).
+         */
+        if (type == null) {
+            return null;
+        }
+
+        /*
+         * Handle union as well - although having an empty as part of a union does not make much sense?
+         */
+        final List<YType> types = DataTypeHelper.isUnionType(type.getDataType()) ?
+                type.getTypes() :
+                Collections.singletonList(type);
+
+        for (final YType oneType : types) {
+            if (DataTypeHelper.isEmptyType(oneType.getDataType())) {
+                return "";
+            }
+        }
+
+        /*
+         * So, not an empty. Guess its really a null value, so.
+         */
+        return null;
+    }
+
+    /**
+     * Merges the content of the source tree into the content of the target tree. This
+     * behaves in the same way as the NETCONF "merge" operation.
+     */
+    private static void mergeInDataTree(final FindingsManager findingsManager,
+            final AbstractStructureInstance targetParentStructure, final AbstractStructureInstance sourceParentStructure) {
+
+        /*
+         * Do the leafs and leaf-lists first.
+         */
+        for (final AbstractContentInstance sourceLeafOrLeafList : sourceParentStructure.getContentChildren()) {
+
+            if (sourceLeafOrLeafList instanceof LeafInstance) {
+                /*
+                 * If the exact same leaf already exists, with the same value, then we are ok with that.
+                 */
+                final LeafInstance leafInstanceInTarget = targetParentStructure.getLeafInstance(sourceLeafOrLeafList
+                        .getNamespace(), sourceLeafOrLeafList.getName());
+                if (leafInstanceInTarget != null) {
+                    final Object sourceValue = ((LeafInstance) sourceLeafOrLeafList).getValue();
+                    final Object targetValue = leafInstanceInTarget.getValue();
+                    if (!Objects.equals(sourceValue, targetValue)) {
+                        findingsManager.addFinding(new Finding(sourceLeafOrLeafList.getDataDomNode(),
+                                ParserFindingType.P073_LEAF_VALUE_ALREADY_SET.toString(),
+                                "A different value for leaf '" + leafInstanceInTarget.getDataDomNode()
+                                        .getPath() + "' has already been set by input '" + leafInstanceInTarget
+                                                .getDataDomNode().getYangData().getYangInput()
+                                                .getName() + "' (" + sourceValue + " vs. " + targetValue + ")."));
+                        continue;
+                    }
+                } else {		// leaf does not exist in target, then merge
+                    targetParentStructure.addContentChild(sourceLeafOrLeafList);
+                    sourceLeafOrLeafList.reparent(targetParentStructure);
+                }
+            } else if (sourceLeafOrLeafList instanceof LeafListInstance) {
+                /*
+                 * RFC states that a merge of these is such that existing instances are
+                 * ignored, i.e.only add instance if it does not exist yet.
+                 */
+                final boolean leafListWithSameValueExistsInTarget = targetParentStructure.hasLeafListInstance(
+                        sourceLeafOrLeafList.getNamespace(), sourceLeafOrLeafList.getName(), sourceLeafOrLeafList
+                                .getValue());
+                if (!leafListWithSameValueExistsInTarget) {	// leaf-list with this value does not exist in target, then merge
+                    targetParentStructure.addContentChild(sourceLeafOrLeafList);
+                    sourceLeafOrLeafList.reparent(targetParentStructure);
+                }
+            }
+
+            // TODO in the future: anydata and anyxml
+        }
+
+        /*
+         * Now do the containers and lists. This is a bit more complex - basically, where a
+         * container/list does not exist in the target, the whole tree is merged over. Otherwise
+         * recursion has to happen downwards.
+         */
+        for (final AbstractStructureInstance sourceContainerOrList : sourceParentStructure.getStructureChildren()) {
+
+            AbstractStructureInstance sameInstanceInTarget = null;
+
+            if (sourceContainerOrList instanceof ContainerInstance) {
+                sameInstanceInTarget = targetParentStructure.getContainerInstance(sourceContainerOrList.getNamespace(),
+                        sourceContainerOrList.getName());
+            } else if (sourceContainerOrList instanceof ListInstance) {
+                sameInstanceInTarget = targetParentStructure.getListInstance(sourceContainerOrList.getNamespace(),
+                        sourceContainerOrList.getName(), ((ListInstance) sourceContainerOrList).getKeyValues());
+            }
+
+            if (sameInstanceInTarget != null) {
+                mergeInDataTree(findingsManager, sameInstanceInTarget, sourceContainerOrList);
+            } else {
+                targetParentStructure.addStructureChild(sourceContainerOrList);
+                sourceContainerOrList.reparent(targetParentStructure);
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/LeafInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/LeafInstance.java
new file mode 100644
index 0000000..8a0c4d7
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/LeafInstance.java
@@ -0,0 +1,48 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * This class represents a leaf instance.
+ *
+ * @author Mark Hollmann
+ */
+public class LeafInstance extends AbstractContentInstance {
+
+    /**
+     * Constructor for a leaf instance that carries data.
+     */
+    public LeafInstance(final AbstractStatement schemaLeaf, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent, final Object value) {
+        super(schemaLeaf, dataDomNode, parent, value);
+    }
+
+    /**
+     * Constructor for a leaf instance that carries a default value.
+     */
+    public LeafInstance(final AbstractStatement schemaLeaf, final AbstractStructureInstance parent, final Object value) {
+        super(schemaLeaf, parent, value);
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/LeafListInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/LeafListInstance.java
new file mode 100644
index 0000000..77b835b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/LeafListInstance.java
@@ -0,0 +1,48 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * This class represents an entry of a leaf-list instance (not the complete leaf-list).
+ *
+ * @author Mark Hollmann
+ */
+public class LeafListInstance extends AbstractContentInstance {
+
+    /**
+     * Constructor for a leaf-list instance that carries data.
+     */
+    public LeafListInstance(final AbstractStatement leafListStatement, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent, final Object value) {
+        super(leafListStatement, dataDomNode, parent, value);
+    }
+
+    /**
+     * Constructor for a leaf-list instance that carries a default value.
+     */
+    public LeafListInstance(final AbstractStatement leafListStatement, final AbstractStructureInstance parent,
+            final Object value) {
+        super(leafListStatement, parent, value);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/ListInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/ListInstance.java
new file mode 100644
index 0000000..55b695f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/ListInstance.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * This class represents an instance of a list.
+ *
+ * @author Mark Hollmann
+ */
+public class ListInstance extends AbstractStructureInstance {
+
+    /**
+     * The names of the keys, if any.
+     */
+    private final List<String> keyNames;
+
+    /**
+     * The key(s) for the instance.
+     */
+    final Map<String, String> keyValues;
+
+    private final String cachedToString;
+
+    public ListInstance(final AbstractStatement schemaList, final YangDataDomNode dataDomNode,
+            final AbstractStructureInstance parent, final List<String> keyNames, final Map<String, String> keyValues) {
+        super(schemaList, dataDomNode, parent);
+        this.keyNames = keyNames;
+        this.keyValues = keyValues;
+        this.cachedToString = "(" + getNamespace() + "):" + getName() + keyValues;
+    }
+
+    /**
+     * The names of the keys, in order in which they are defined. May be empty for key-less lists.
+     */
+    public List<String> getKeyNames() {
+        return keyNames;
+    }
+
+    /**
+     * The value of the key(s). May be empty for key-less lists.
+     */
+    public Map<String, String> getKeyValues() {
+        return keyValues;
+    }
+
+    @Override
+    public String toString() {
+        return cachedToString;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/RootInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/RootInstance.java
new file mode 100644
index 0000000..b3a9cae
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/instance/RootInstance.java
@@ -0,0 +1,49 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.instance;
+
+/**
+ * Top-level object for a data instance tree.
+ * <p/>
+ * A data instance tree is build from parsed data, with the help of a Yang schema. While the data DOM
+ * can live without a schema, the data instance tree requires a schema to be present that matches the
+ * data.
+ * <p/>
+ * The data instance tree contains representations for all data nodes (leaf, leaf-list, container, list);
+ * each of these point to the corresponding statement in the schema. For leaf and leaf-list, values are
+ * captured as well.
+ *
+ * @author Mark Hollmann
+ */
+public class RootInstance extends AbstractStructureInstance {
+
+    public RootInstance() {
+        super(null, null);
+    }
+
+    public String getName() {
+        return "/";
+    }
+
+    public String getNamespace() {
+        return "/";
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/JsonParser.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/JsonParser.java
new file mode 100644
index 0000000..3c7a937
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/JsonParser.java
@@ -0,0 +1,900 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.parser;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+
+/**
+ * A simple JSON parser. Created in order to not introduce 3PP dependencies.
+ *
+ * @author Mark Hollmann
+ */
+public class JsonParser {
+
+    private int currentLine = 0;
+    private int charCount = 0;
+
+    private final List<ParseToken> tokens = new ArrayList<>(10000);
+
+    private final ParserExecutionContext context;
+    private final YangData yangData;
+    private final InputStream is;
+
+    public JsonParser(final ParserExecutionContext context, final YangData yangData, final InputStream is)
+            throws IOException {
+        this.context = context;
+        this.yangData = yangData;
+        this.is = Objects.requireNonNull(is);
+    }
+
+    /**
+     * Parses the input. Returns a sub-class of JsonValue, typically JsonObject or JsonArray,
+     * depending on the root element of the input. Will return null if the root element of
+     * the input is not valid JSON or the input is empty.
+     */
+    public JsonValue parse() throws IOException {
+
+        final BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
+
+        String str;
+
+        while ((str = br.readLine()) != null) {
+            currentLine++;
+            charCount += str.length();
+            charCount++;					// +1 for the new-line character that the readLine() method will swallow
+            processLine(str);
+        }
+
+        if (tokens.isEmpty()) {
+            return null;
+        }
+
+        /*
+         * We have all the tokens. Now build up the result.
+         */
+
+        final Iterator<ParseToken> iter = tokens.iterator();
+        final ParseToken firstToken = iter.next();
+
+        JsonValue result = null;
+
+        switch (firstToken.type) {
+            case BEGIN_ARRAY:
+                result = new JsonArray(firstToken.line, firstToken.col);
+                handleArray((JsonArray) result, iter);
+                break;
+            case BEGIN_OBJECT:
+                result = new JsonObject(firstToken.line, firstToken.col);
+                handleObject((JsonObject) result, iter);
+                break;
+            case QUOTED_STRING:
+                result = JsonPrimitive.valueOf(firstToken.line, firstToken.col, firstToken.text);
+                break;
+            case UNQUOTED_STRING:
+                result = JsonPrimitive.valueOf(firstToken.line, firstToken.col, convertUnquotedStringToValue(firstToken));
+                break;
+            default:
+                issueFinding(firstToken.line, firstToken.col, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "Expected root JSON element to be either an object, an array, or a primitive.");
+        }
+
+        return result;
+    }
+
+    public int getCharCount() {
+        return charCount;
+    }
+
+    /**
+     * Process an object. The supplied index is the START_OBJECT element. Returns the position after the END_OBJECT.
+     */
+    private void handleObject(final JsonObject jsonObject, final Iterator<ParseToken> iter) {
+
+        ParseToken token = iter.next();
+        boolean valueSeparatorLastLoop = true;
+
+        while (true) {
+
+            if (token.type == ParseTokenType.END_OBJECT) {
+                return;				// Done with this object.
+            }
+
+            /*
+             * There must have been a separator last time around...but we are lenient and continue.
+             */
+            if (!valueSeparatorLastLoop) {
+                issueFinding(token, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "Expected a value separator (',') before this member.");
+            }
+
+            if (token.type != ParseTokenType.QUOTED_STRING) {
+                issueFinding(token, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "Expected a quoted member name or object-end.");
+                return;
+            }
+
+            final JsonObjectMemberName member = new JsonObjectMemberName(token.line, token.col, token.text);
+
+            token = iter.next();
+            if (token.type != ParseTokenType.NAME_SEP) {
+                issueFinding(token, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "Expected name separator character (':').");
+                return;
+            }
+
+            token = iter.next();
+
+            /*
+             * Now let's have a look to see what the value is...
+             */
+            switch (token.type) {
+                case BEGIN_ARRAY:
+                    final JsonArray memberIsArray = new JsonArray(token.line, token.col);
+                    jsonObject.putMember(member, memberIsArray);
+                    handleArray(memberIsArray, iter);
+                    break;
+                case BEGIN_OBJECT:
+                    final JsonObject memberIsObject = new JsonObject(token.line, token.col);
+                    jsonObject.putMember(member, memberIsObject);
+                    handleObject(memberIsObject, iter);
+                    break;
+                case QUOTED_STRING:
+                    jsonObject.putMember(member, JsonPrimitive.valueOf(token.line, token.col, token.text));
+                    break;
+                case UNQUOTED_STRING:
+                    jsonObject.putMember(member, JsonPrimitive.valueOf(token.line, token.col, convertUnquotedStringToValue(
+                            token)));
+                    break;
+                default:
+                    issueFinding(token, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                            "Expected a value or object or array.");
+                    return;
+            }
+
+            /*
+             * Swallow any value separator
+             */
+            token = iter.next();
+
+            if (token.type == ParseTokenType.VALUE_SEP) {
+                token = iter.next();
+                valueSeparatorLastLoop = true;
+            } else {
+                valueSeparatorLastLoop = false;
+            }
+        }
+    }
+
+    private void handleArray(final JsonArray jsonArray, final Iterator<ParseToken> iter) {
+
+        ParseToken token = iter.next();
+        boolean valueSeparatorLastLoop = true;
+
+        while (true) {
+
+            if (token.type == ParseTokenType.END_ARRAY) {
+                return;			// Done with this array.
+            }
+
+            /*
+             * There must have been a separator last time around...but we are lenient and continue.
+             */
+            if (!valueSeparatorLastLoop) {
+                issueFinding(token, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "Expected a value separator (',') before this member.");
+            }
+
+            /*
+             * Now let's have a look to see what the value is...
+             */
+            switch (token.type) {
+                case BEGIN_ARRAY:		// Array within array
+                    final JsonArray memberIsArray = new JsonArray(token.line, token.col);
+                    jsonArray.addValue(memberIsArray);
+                    handleArray(memberIsArray, iter);
+                    break;
+                case BEGIN_OBJECT:
+                    final JsonObject arrayMemberIsObject = new JsonObject(token.line, token.col);
+                    jsonArray.addValue(arrayMemberIsObject);
+                    handleObject(arrayMemberIsObject, iter);
+                    break;
+                case QUOTED_STRING:
+                    jsonArray.addValue(JsonPrimitive.valueOf(token.line, token.col, token.text));
+                    break;
+                case UNQUOTED_STRING:
+                    jsonArray.addValue(JsonPrimitive.valueOf(token.line, token.col, convertUnquotedStringToValue(token)));
+                    break;
+                default:
+                    issueFinding(token, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                            "Expected a value or object or array-end.");
+                    return;
+            }
+
+            /*
+             * Swallow any value separator
+             */
+            token = iter.next();
+
+            if (token.type == ParseTokenType.VALUE_SEP) {
+                token = iter.next();
+                valueSeparatorLastLoop = true;
+            } else {
+                valueSeparatorLastLoop = false;
+            }
+        }
+    }
+
+    private static final String S_NULL = "null";
+    private static final String S_TRUE = "true";
+    private static final String S_FALSE = "false";
+
+    private static final double MAX_DOUBLE_REPRESENTATION = Math.pow(2, 53) - 1;
+    private static final double MIN_DOUBLE_REPRESENTATION = (Math.pow(2, 53) * -1) + 1;
+
+    private Object convertUnquotedStringToValue(final ParseToken token) {
+
+        if (S_NULL.equals(token.text)) {
+            return null;
+        }
+        if (S_TRUE.equals(token.text)) {
+            return Boolean.TRUE;
+        }
+        if (S_FALSE.equals(token.text)) {
+            return Boolean.FALSE;
+        }
+
+        /*
+         * Has to be a number. In the vast majority of cases the number will be integer, i.e. not floating point.
+         * This triggers an optimization whereby a Long object is produced instead of a Double, as it is considerably
+         * easier for a client to work with integers as opposed to floating-points.
+         */
+        try {
+            final long parseLong = Long.parseLong(token.text);
+            /*
+             * If we come to here this means that the conversion to long has succeeded. If the value is integer but
+             * too large to fit into a long, an exception would have been thrown.
+             */
+            return Long.valueOf(parseLong);
+        } catch (final NumberFormatException ignore) {
+        }
+
+        /*
+         *
+         * So it's floating point, or an integer larger than what fits into a long, and we have to generate a Double
+         * However, special consideration must be paid to a stipulation in RFC 7951:
+         *
+         * A value of the "int8", "int16", "int32", "uint8", "uint16", or "uint32" type is represented as a JSON number.
+         *
+         * A value of the "int64", "uint64", or "decimal64" type is represented as a JSON string whose content is the
+         * lexical representation of the corresponding YANG type as specified in Sections 9.2.1 and 9.3.1 of [RFC7950].
+         *
+         * For example, if the type of the leaf "foo" in Section 5.1 was "uint64" instead of "uint8", the instance would
+         * have to be encoded as "foo": "123"
+         *
+         * The special handling of 64-bit numbers follows from the I-JSON recommendation to encode numbers exceeding the
+         * IEEE 754-2008 double-precision range [IEEE754-2008] as strings; see Section 2.2 in [RFC7493].
+         */
+
+        /*
+         * This here, however, is a generic JSON parser, and according to RFC7493, values within range
+         * [-(2**53)+1, (2**53)-1] are allowed to be represented as number, everything else must be a string.
+         *
+         * The problem is that we do *not* get any exception from the standard Java classes when we translate a String to a
+         * Double with loss of precision, and it is surprisingly difficult to figure this out. As there is a chance that a
+         * JSON producer will ignore the rule about Doubles / Strings, and generate a large numeric value as number, we
+         * check for this scenario and if it happens we simply return the token as string, i.e. we align with the RFC, and
+         * expect a consumer of the output of this JSON parser to likewise be standards-aware and compliant and to be able
+         * to handle Double, Long and String objects as a source of a numeric value.
+         */
+        try {
+            final Double valueOf = Double.valueOf(token.text);
+            if (valueOf > MAX_DOUBLE_REPRESENTATION || valueOf < MIN_DOUBLE_REPRESENTATION) {
+                return token.text;
+            }
+            return valueOf;
+        } catch (NumberFormatException nfex) {
+            issueFinding(token, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "value '" + token.text + "' does not translate to null / true / false / a number.");
+        }
+
+        return null;
+    }
+
+    private static final Character C_SPACE = Character.valueOf((char) 32);		// Space
+    private static final Character C_HOR_TAB = Character.valueOf((char) 9);		// Horizontal Tab
+    private static final Character C_LF = Character.valueOf((char) 10);			// Line feed or New line
+    private static final Character C_CR = Character.valueOf((char) 13);			// Carriage return
+
+    private static final Set<Character> WHITE_SPACES = new HashSet<>();
+
+    static {
+        WHITE_SPACES.add(C_SPACE);
+        WHITE_SPACES.add(C_HOR_TAB);
+        WHITE_SPACES.add(C_LF);
+        WHITE_SPACES.add(C_CR);
+    }
+
+    private static final char LEFT_SQUARE_BRACKET = '[';
+    private static final char RIGHT_SQUARE_BRACKET = ']';
+    private static final char LEFT_CURLY_BRACKET = '{';
+    private static final char RIGHT_CURLY_BRACKET = '}';
+    private static final char COLON = ':';
+    private static final char COMMA = ',';
+    private static final char QUOTATION_MARK = '"';
+
+    private static final char REVERSE_SOLIDUS = '\\';
+    private static final char SOLIDUS = '/';
+
+    /**
+     * Process the supplied line.
+     */
+    private void processLine(final String str) {
+
+        int index = 0;
+
+        while (true) {
+
+            if (index >= str.length()) {
+                /*
+                 * End of line, we are done here.
+                 */
+                return;
+            }
+
+            final char charAt = str.charAt(index);
+
+            if (WHITE_SPACES.contains(charAt)) {
+                // whitespace, ignore
+                index++;
+            } else if (charAt == LEFT_SQUARE_BRACKET) {
+                index++;
+                tokens.add(ParseToken.newBeginArray(currentLine, index));
+            } else if (charAt == RIGHT_SQUARE_BRACKET) {
+                index++;
+                tokens.add(ParseToken.newEndArray(currentLine, index));
+            } else if (charAt == LEFT_CURLY_BRACKET) {
+                index++;
+                tokens.add(ParseToken.newBeginObject(currentLine, index));
+            } else if (charAt == RIGHT_CURLY_BRACKET) {
+                index++;
+                tokens.add(ParseToken.newEndObject(currentLine, index));
+            } else if (charAt == COLON) {
+                index++;
+                tokens.add(ParseToken.newNameSep(currentLine, index));
+            } else if (charAt == COMMA) {
+                index++;
+                tokens.add(ParseToken.newValueSep(currentLine, index));
+            } else if (charAt == QUOTATION_MARK) {
+                index = extractQuotedString(str, index);
+            } else {
+                index = extractUnquotedString(str, index);
+            }
+        }
+    }
+
+    private static final Set<Character> UNQUOTED_STRING_TERMINATING_CHARACTERS = new HashSet<>();
+
+    static {
+        UNQUOTED_STRING_TERMINATING_CHARACTERS.addAll(WHITE_SPACES);
+        UNQUOTED_STRING_TERMINATING_CHARACTERS.add(LEFT_SQUARE_BRACKET);
+        UNQUOTED_STRING_TERMINATING_CHARACTERS.add(RIGHT_SQUARE_BRACKET);
+        UNQUOTED_STRING_TERMINATING_CHARACTERS.add(LEFT_CURLY_BRACKET);
+        UNQUOTED_STRING_TERMINATING_CHARACTERS.add(RIGHT_CURLY_BRACKET);
+        UNQUOTED_STRING_TERMINATING_CHARACTERS.add(COMMA);
+        UNQUOTED_STRING_TERMINATING_CHARACTERS.add(COLON);
+    }
+
+    /**
+     * Extracts an unquoted string. Returns the index position in the string after the end of the string.
+     */
+    private int extractUnquotedString(String str, int startCol) {
+
+        final StringBuilder unquotedString = new StringBuilder();
+        int index = startCol;
+
+        while (true) {
+
+            if (index >= str.length()) {
+                /*
+                 * End of line, hence we have reached the end of the unquoted string.
+                 */
+                tokens.add(ParseToken.newUnquotedString(currentLine, startCol, unquotedString.toString()));
+                return Integer.MAX_VALUE;
+            }
+
+            /*
+             * Read a character. If it is whitespace, or any of the special characters, we are done with the unquoted string.
+             */
+            final char charAt = str.charAt(index);
+
+            if (UNQUOTED_STRING_TERMINATING_CHARACTERS.contains(charAt)) {
+                tokens.add(ParseToken.newUnquotedString(currentLine, startCol, unquotedString.toString()));
+                return index;
+            }
+
+            unquotedString.append(charAt);
+            index++;
+        }
+    }
+
+    /**
+     * Extracts a quoted string. Returns the index position in the string after the closing double-quote
+     */
+    private int extractQuotedString(String str, final int startCol) {
+
+        final StringBuilder quotedString = new StringBuilder();
+        int index = startCol + 1;		// swallow starting " character
+
+        while (true) {
+
+            if (index >= str.length()) {
+                /*
+                 * We have reached the end of the string without encountering a closing
+                 * double-quote! We issue a finding, but create a string anyway.
+                 */
+                issueFinding(currentLine, startCol, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "Missing terminating double-quote character.");
+                tokens.add(ParseToken.newQuotedString(currentLine, startCol, quotedString.toString()));
+                return Integer.MAX_VALUE;
+            }
+
+            final char charAt = str.charAt(index);
+
+            if (charAt == QUOTATION_MARK) {
+                /*
+                 * Found the closing double-quote, done.
+                 */
+                tokens.add(ParseToken.newQuotedString(currentLine, startCol, quotedString.toString()));
+                return index + 1;
+            }
+
+            if (charAt == REVERSE_SOLIDUS) {
+                /*
+                 * Some escaped character.
+                 */
+                index = appendEscapedCharacter(str, index, quotedString);
+            } else {
+                /*
+                 * Regular character
+                 */
+                quotedString.append(charAt);
+                index++;
+            }
+        }
+    }
+
+    private int appendEscapedCharacter(String str, int index, StringBuilder quotedString) {
+
+        index++;		// Swallow the backslash
+
+        /*
+         * Something escaped. RFC7159 clearly stipulates what can be escaped:
+         *
+         * escape (
+         * %x22 /          ; "    quotation mark  U+0022
+         * %x5C /          ; \    reverse solidus U+005C
+         * %x2F /          ; /    solidus         U+002F
+         * %x62 /          ; b    backspace       U+0008
+         * %x66 /          ; f    form feed       U+000C
+         * %x6E /          ; n    line feed       U+000A
+         * %x72 /          ; r    carriage return U+000D
+         * %x74 /          ; t    tab             U+0009
+         * %x75 4HEXDIG )  ; uXXXX                U+XXXX
+         *
+         * Note that SOLIDUS can also exist unescaped.
+         */
+
+        /*
+         * Make sure there is another character...
+         */
+        if (index >= str.length()) {
+            issueFinding(currentLine, index, ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT,
+                    "Missing escaped character.");
+            return Integer.MAX_VALUE;
+        }
+
+        final char nextChar = str.charAt(index);
+
+        if (nextChar == 'u') {
+            /*
+             * Unicode. Handled separately.
+             */
+            return appendUnicodeCharacter(str, index, quotedString);
+        }
+
+        /*
+         * Some other character, with simple escaping.
+         */
+        if (nextChar == QUOTATION_MARK) {
+            quotedString.append(QUOTATION_MARK);
+        } else if (nextChar == REVERSE_SOLIDUS) {
+            quotedString.append(REVERSE_SOLIDUS);
+        } else if (nextChar == SOLIDUS) {
+            quotedString.append(SOLIDUS);
+        } else if (nextChar == 'b') {
+            quotedString.append('\b');
+        } else if (nextChar == 'f') {
+            quotedString.append('\f');
+        } else if (nextChar == 'n') {
+            quotedString.append('\n');
+        } else if (nextChar == 'r') {
+            quotedString.append('\r');
+        } else if (nextChar == 't') {
+            quotedString.append('\t');
+        } else {
+            /*
+             * Unrecognized character. We are lenient and allow it through, but still issue a finding.
+             */
+            quotedString.append(nextChar);
+            issueFinding(currentLine, index, ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT,
+                    "Unrecognized escaped character '\\" + nextChar + "'.");
+        }
+
+        return index + 1;
+    }
+
+    private static final Map<Character, Integer> CONVERTED = new HashMap<>();
+
+    static {
+        CONVERTED.put('0', 0);
+        CONVERTED.put('1', 1);
+        CONVERTED.put('2', 2);
+        CONVERTED.put('3', 3);
+        CONVERTED.put('4', 4);
+        CONVERTED.put('5', 5);
+        CONVERTED.put('6', 6);
+        CONVERTED.put('7', 7);
+        CONVERTED.put('8', 8);
+        CONVERTED.put('9', 9);
+        CONVERTED.put('a', 10);
+        CONVERTED.put('b', 11);
+        CONVERTED.put('c', 12);
+        CONVERTED.put('d', 13);
+        CONVERTED.put('e', 14);
+        CONVERTED.put('f', 15);
+        CONVERTED.put('A', 10);
+        CONVERTED.put('B', 11);
+        CONVERTED.put('C', 12);
+        CONVERTED.put('D', 13);
+        CONVERTED.put('E', 14);
+        CONVERTED.put('F', 15);
+    }
+
+    private int appendUnicodeCharacter(String str, int index, StringBuilder quotedString) {
+        index++;		// Swallow the u character
+
+        /*
+         * We must have at least 4 hex characters after the u character.
+         */
+        if (index + 4 >= str.length()) {
+            issueFinding(currentLine, index, ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT,
+                    "Unicode character not correctly escaped.");
+            return Integer.MAX_VALUE;
+        }
+
+        final char char1 = str.charAt(index++);
+        final char char2 = str.charAt(index++);
+        final char char3 = str.charAt(index++);
+        final char char4 = str.charAt(index++);
+
+        if (!CONVERTED.containsKey(char1) || !CONVERTED.containsKey(char2) || !CONVERTED.containsKey(char3) || !CONVERTED
+                .containsKey(char4)) {
+            issueFinding(currentLine, index, ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT,
+                    "Unicode character not correctly escaped.");
+            return Integer.MAX_VALUE;
+        }
+
+        final int unicodeChar = (CONVERTED.get(char1) * 4096) + (CONVERTED.get(char2) * 256) + (CONVERTED.get(
+                char3) * 16) + (CONVERTED.get(char4) * 1);
+
+        quotedString.append((char) unicodeChar);
+
+        return index;
+    }
+
+    private void issueFinding(final ParseToken token, final ParserFindingType findingType, final String message) {
+        issueFinding(token.line, token.col, findingType, message);
+    }
+
+    private void issueFinding(final int line, final int col, final ParserFindingType findingType, final String message) {
+        if (context != null && yangData != null) {
+            context.addFinding(new Finding(yangData, findingType.toString(), message, line, col));
+        }
+    }
+
+    private enum ParseTokenType {
+        BEGIN_ARRAY,
+        END_ARRAY,
+        BEGIN_OBJECT,
+        END_OBJECT,
+        NAME_SEP,
+        VALUE_SEP,
+        QUOTED_STRING,
+        UNQUOTED_STRING
+    }
+
+    private static class ParseToken {
+        public final int line;
+        public final int col;
+        public final ParseTokenType type;
+        public final String text;
+
+        private ParseToken(final int line, final int col, final ParseTokenType type, final String text) {
+            this.line = line;
+            this.col = col;
+            this.type = type;
+            this.text = Objects.requireNonNull(text);
+        }
+
+        public static ParseToken newBeginArray(int line, int col) {
+            return new ParseToken(line, col, ParseTokenType.BEGIN_ARRAY, "[");
+        }
+
+        public static ParseToken newEndArray(int line, int col) {
+            return new ParseToken(line, col, ParseTokenType.END_ARRAY, "]");
+        }
+
+        public static ParseToken newBeginObject(int line, int col) {
+            return new ParseToken(line, col, ParseTokenType.BEGIN_OBJECT, "{");
+        }
+
+        public static ParseToken newEndObject(int line, int col) {
+            return new ParseToken(line, col, ParseTokenType.END_OBJECT, "}");
+        }
+
+        public static ParseToken newNameSep(int line, int col) {
+            return new ParseToken(line, col, ParseTokenType.NAME_SEP, ":");
+        }
+
+        public static ParseToken newValueSep(int line, int col) {
+            return new ParseToken(line, col, ParseTokenType.VALUE_SEP, ",");
+        }
+
+        public static ParseToken newQuotedString(int line, int col, String val) {
+            return new ParseToken(line, col, ParseTokenType.QUOTED_STRING, val);
+        }
+
+        public static ParseToken newUnquotedString(int line, int col, String val) {
+            return new ParseToken(line, col, ParseTokenType.UNQUOTED_STRING, val);
+        }
+    }
+
+    public abstract static class HasLineAndColumn {
+        public final int line;
+        public final int col;
+
+        public HasLineAndColumn(final int line, final int col) {
+            this.line = line;
+            this.col = col;
+        }
+    }
+
+    /**
+     * The name of a member of a JsonObject.
+     */
+    public static class JsonObjectMemberName extends HasLineAndColumn {
+
+        private final String memberName;
+
+        public JsonObjectMemberName(final String memberName) {
+            this(0, 0, memberName);
+        }
+
+        public JsonObjectMemberName(final int line, final int col, final String memberName) {
+            super(line, col);
+            /*
+             * Member names will be interned. It is highly likely that there will be considerable
+             * duplication in member names in the JSON. This will cut down on the memory usage
+             * substantially if the JSON is very large.
+             */
+            this.memberName = Objects.requireNonNull(memberName).intern();
+        }
+
+        public String getMemberName() {
+            return memberName;
+        }
+
+        @Override
+        public int hashCode() {
+            return memberName.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return memberName;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+
+            if (obj instanceof String) {
+                return this.memberName.equals((String) obj);
+            }
+
+            return obj instanceof JsonObjectMemberName && this.memberName.equals(((JsonObjectMemberName) obj).memberName);
+        }
+    }
+
+    /**
+     * A JsonValue may be a primitive value, or an object, or an array.
+     */
+    public abstract static class JsonValue extends HasLineAndColumn {
+        public JsonValue(final int line, final int col) {
+            super(line, col);
+        }
+    }
+
+    public static class JsonPrimitive extends JsonValue {
+
+        private static final String EMPTY_STRING = "";
+
+        /*
+         * These can be used for quick comparisons for commonly used values.
+         */
+        public static final JsonPrimitive NULL = new JsonPrimitive(0, 0, null);
+        public static final JsonPrimitive TRUE = new JsonPrimitive(0, 0, Boolean.TRUE);
+        public static final JsonPrimitive FALSE = new JsonPrimitive(0, 0, Boolean.FALSE);
+        public static final JsonPrimitive ZERO = new JsonPrimitive(0, 0, Long.valueOf(0));
+        public static final JsonPrimitive ONE = new JsonPrimitive(0, 0, Long.valueOf(1));
+        public static final JsonPrimitive EMPTY = new JsonPrimitive(0, 0, EMPTY_STRING);
+
+        public final Object value;
+
+        public static JsonPrimitive valueOf(final Object obj) {
+            return valueOf(0, 0, obj);
+        }
+
+        public static JsonPrimitive valueOf(final int line, final int col, final Object obj) {
+            if (EMPTY_STRING.equals(obj)) {
+                return new JsonPrimitive(line, col, EMPTY_STRING);
+            } else {
+                return new JsonPrimitive(line, col, obj);
+            }
+        }
+
+        private JsonPrimitive(final int line, final int col, final Object value) {
+            super(line, col);
+            this.value = value;
+        }
+
+        /**
+         * Returns the primitive value, which can be one of: String, Boolean, Double, Long, null.
+         * <p>
+         * Note that for numeric values the returned object will be of type String if the value is outside
+         * the allowable range for java.lang.Long and java.lang.Double.
+         * <p>
+         * Consumers should be prepared to handle Long, Double and String values for numbers,
+         * and to convert as appropriate.
+         */
+        public Object getValue() {
+            return value;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(value);
+        }
+
+        /**
+         * The equality check on JsonPrimitive objects allows for the supplied object to be of any type.
+         */
+        @Override
+        public boolean equals(final Object obj) {
+
+            final Object otherValue = obj instanceof JsonPrimitive ? ((JsonPrimitive) obj).getValue() : obj;
+
+            if (this.value == null && otherValue == null) {
+                return true;
+            }
+
+            return this.value != null && this.value.equals(otherValue);
+        }
+    }
+
+    public static class JsonObject extends JsonValue {
+
+        private final Map<JsonObjectMemberName, JsonValue> valuesByMember = new HashMap<>();
+        private final Map<String, JsonValue> values = new HashMap<>();
+
+        public JsonObject() {
+            this(0, 0);
+        }
+
+        public JsonObject(final int line, final int col) {
+            super(line, col);
+        }
+
+        public void putMember(final String member, final Object obj) {
+            final JsonValue jsonValue = getJsonValueFromObject(obj);
+            valuesByMember.put(new JsonObjectMemberName(member), jsonValue);
+            values.put(member, jsonValue);
+        }
+
+        public void putMember(final JsonObjectMemberName memberName, final Object obj) {
+            final JsonValue jsonValue = getJsonValueFromObject(obj);
+            valuesByMember.put(memberName, Objects.requireNonNull(jsonValue));
+            values.put(memberName.getMemberName(), jsonValue);
+        }
+
+        private static JsonValue getJsonValueFromObject(final Object obj) {
+            if (obj == null) {
+                return JsonPrimitive.NULL;
+            } else if (obj instanceof JsonValue) {
+                return (JsonValue) obj;
+            } else if (obj instanceof Boolean || obj instanceof Number || obj instanceof String) {
+                return JsonPrimitive.valueOf(obj);
+            }
+
+            throw new RuntimeException("Can't handle data type " + obj.getClass().getSimpleName());
+        }
+
+        public Map<JsonObjectMemberName, JsonValue> getValuesByMember() {
+            return Collections.unmodifiableMap(valuesByMember);
+        }
+
+        public Map<String, JsonValue> getValues() {
+            return Collections.unmodifiableMap(values);
+        }
+    }
+
+    public static class JsonArray extends JsonValue {
+
+        private final List<JsonValue> values = new ArrayList<>();
+
+        public JsonArray() {
+            this(0, 0);
+        }
+
+        public JsonArray(final int line, final int col) {
+            super(line, col);
+        }
+
+        public void addValue(final JsonValue value) {
+            values.add(Objects.requireNonNull(value));
+        }
+
+        public void setValue(final int index, final JsonValue value) {
+            values.set(index, Objects.requireNonNull(value));
+        }
+
+        public List<JsonValue> getValues() {
+            return Collections.unmodifiableList(values);
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/JsonWriter.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/JsonWriter.java
new file mode 100644
index 0000000..97c53ee
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/JsonWriter.java
@@ -0,0 +1,180 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.parser;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonArray;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObject;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonPrimitive;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonValue;
+
+/**
+ * A simple writer of JSON data.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class JsonWriter {
+
+    public static void write(final JsonValue value, final OutputStream os) throws IOException {
+        final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(Objects.requireNonNull(os), Charset.forName(
+                "UTF-8")));
+        write(Objects.requireNonNull(value), bw, 0);
+        bw.close();
+    }
+
+    private static void write(final JsonValue value, final BufferedWriter bw, final int indent) throws IOException {
+        if (value instanceof JsonPrimitive) {
+            writeJsonPrimitive((JsonPrimitive) value, bw, indent);
+        } else if (value instanceof JsonArray) {
+            writeJsonArray((JsonArray) value, bw, indent);
+        } else if (value instanceof JsonObject) {
+            writeJsonObject((JsonObject) value, bw, indent);
+        }
+    }
+
+    private static void writeJsonPrimitive(final JsonPrimitive jsonPrimitive, final BufferedWriter bw, final int indent)
+            throws IOException {
+
+        final Object value = jsonPrimitive.getValue();
+
+        if (value == null) {
+            bw.append("null");
+        } else if (value instanceof String) {
+            writeString(bw, (String) value);
+        } else {
+            bw.append(Objects.toString(value));
+        }
+    }
+
+    private static void writeJsonArray(final JsonArray jsonArray, final BufferedWriter bw, final int indent)
+            throws IOException {
+
+        final List<JsonValue> jsonValues = jsonArray.getValues();
+        boolean first = true;
+
+        if (jsonValues.isEmpty()) {
+            bw.append("[]");
+            return;
+        }
+
+        bw.append('[');
+        bw.newLine();
+
+        for (final JsonValue jsonValue : jsonValues) {
+            if (!first) {
+                bw.append(" ,");
+                bw.newLine();
+            }
+            writeIndent(bw, indent + 4);
+            write(jsonValue, bw, indent + 4);
+            first = false;
+        }
+
+        bw.newLine();
+        writeIndent(bw, indent);
+        bw.append(']');
+    }
+
+    private static void writeJsonObject(final JsonObject jsonObject, final BufferedWriter bw, final int indent)
+            throws IOException {
+        final Map<String, JsonValue> members = jsonObject.getValues();
+        boolean first = true;
+
+        if (members.isEmpty()) {
+            bw.append("{}");
+            return;
+        }
+
+        bw.append('{');
+        bw.newLine();
+
+        for (final Entry<String, JsonValue> entry : members.entrySet()) {
+            if (!first) {
+                bw.append(" ,");
+                bw.newLine();
+            }
+            writeIndent(bw, indent + 2);
+            writeString(bw, entry.getKey());
+            bw.append(" : ");
+            write(entry.getValue(), bw, indent + 4);
+            first = false;
+        }
+
+        bw.newLine();
+        writeIndent(bw, indent);
+        bw.append('}');
+    }
+
+    private static final String ZEROS = "0000";
+
+    private static void writeString(final BufferedWriter bw, final String theString) throws IOException {
+        bw.append('"');
+
+        for (int i = 0; i < theString.length(); ++i) {
+            final char charAt = theString.charAt(i);
+
+            if (charAt == '"' || charAt == '\\' || charAt == '/') {
+                bw.append('\\');
+                bw.append(charAt);
+            } else if (charAt == '\b') {
+                bw.append("\\b");
+            } else if (charAt == '\f') {
+                bw.append("\\f");
+            } else if (charAt == '\n') {
+                bw.append("\\n");
+            } else if (charAt == '\r') {
+                bw.append("\\r");
+            } else if (charAt == '\t') {
+                bw.append("\\t");
+            } else if (charAt < 32 || charAt > 126) {
+                /*
+                 * We escape with unicode
+                 */
+                bw.append("\\u");
+                final String hexString = Integer.toHexString((int) charAt);
+                bw.append(ZEROS.substring(hexString.length()));
+                bw.append(hexString);
+            } else {
+                bw.append(charAt);
+            }
+        }
+
+        bw.append('"');
+    }
+
+    private static final String SPACES = "                                                                                                                                                 ";
+
+    private static void writeIndent(final BufferedWriter bw, final int indent) throws IOException {
+        if (indent == 0) {
+            return;
+        }
+        bw.append(SPACES.substring(0, indent));
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/XmlParser.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/XmlParser.java
new file mode 100644
index 0000000..5033335
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/parser/XmlParser.java
@@ -0,0 +1,161 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.parser;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Stack;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.DefaultHandler2;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+
+/**
+ * A simple XML parser. Keeps tracks of lines/columns in the XML as well for purposes of debugging.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class XmlParser {
+
+    public static Document createDocument(final InputStream is) throws IOException, SAXException {
+
+        try {
+            final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+            docBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+            docBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+            docBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+
+            final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
+            final Document doc = docBuilder.newDocument();
+            final Myhandler handler = new Myhandler(doc);
+
+            final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+            final SAXParser saxParser = saxParserFactory.newSAXParser();
+            saxParser.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
+
+            saxParser.parse(is, handler);
+
+            return doc;
+
+        } catch (final ParserConfigurationException e) {
+            throw new RuntimeException("Can't create SAX parser / DOM builder.", e);
+        }
+    }
+
+    private static class Myhandler extends DefaultHandler2 {
+
+        private final Document doc;
+
+        final Stack<Element> elementStack = new Stack<Element>();
+        final StringBuilder sb = new StringBuilder();
+
+        private Locator locator;
+
+        public Myhandler(final Document doc) {
+            this.doc = doc;
+        }
+
+        @Override
+        public void setDocumentLocator(final Locator locator) {
+            this.locator = locator;
+        }
+
+        @Override
+        public void startElement(final String uri, final String localName, final String qName, final Attributes attributes)
+                throws SAXException {
+
+            createTextNodeIfNeeded();
+
+            final Element element = doc.createElement(qName);
+            for (int i = 0; i < attributes.getLength(); i++) {
+                element.setAttribute(attributes.getQName(i), attributes.getValue(i));
+            }
+            element.setUserData(YangDataDomNode.LINE_NUMBER_KEY_NAME, Integer.valueOf(this.locator.getLineNumber()), null);
+            element.setUserData(YangDataDomNode.COLUMN_NUMBER_KEY_NAME, Integer.valueOf(this.locator.getColumnNumber()),
+                    null);
+            elementStack.push(element);
+        }
+
+        @Override
+        public void startCDATA() throws SAXException {
+            /*
+             * Flush out any text before the CDATA that may have accumulated
+             */
+            createTextNodeIfNeeded();
+        }
+
+        @Override
+        public void endCDATA() throws SAXException {
+            createCDataNodeIfNeeded();
+        }
+
+        @Override
+        public void endElement(final String uri, final String localName, final String qName) {
+
+            createTextNodeIfNeeded();
+
+            final Element closedElement = elementStack.pop();
+            if (elementStack.isEmpty()) { // Is this the root element?
+                doc.appendChild(closedElement);
+            } else {
+                final Element parentEl = elementStack.peek();
+                parentEl.appendChild(closedElement);
+            }
+        }
+
+        @Override
+        public void characters(final char ch[], final int start, final int length) throws SAXException {
+            sb.append(ch, start, length);
+        }
+
+        private void createTextNodeIfNeeded() {
+            if (sb.length() > 0) {
+                final Element element = elementStack.peek();
+                final Node textNode = doc.createTextNode(sb.toString());
+                element.appendChild(textNode);
+                sb.setLength(0);
+            }
+        }
+
+        private void createCDataNodeIfNeeded() {
+            if (sb.length() > 0) {
+                final Element element = elementStack.peek();
+                final Node cdataNode = doc.createCDATASection(sb.toString());
+                element.appendChild(cdataNode);
+                sb.setLength(0);
+            }
+        }
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/BinaryValue.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/BinaryValue.java
new file mode 100644
index 0000000..4726c00
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/BinaryValue.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util;
+
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Objects;
+
+/**
+ * Holds the value for a data node instance of type "binary".
+ *
+ * @author Mark Hollmann
+ */
+public class BinaryValue {
+
+    private byte[] binaryValue = new byte[0];
+
+    public BinaryValue(final byte[] val) {
+        binaryValue = Objects.requireNonNull(val);
+    }
+
+    public BinaryValue(final String base64encoded) {
+        try {
+            binaryValue = Base64.getDecoder().decode(base64encoded);
+        } catch (final IllegalArgumentException ignored) {
+            throw new RuntimeException("A Base64 value could not be decoded to binary.");
+        }
+    }
+
+    public byte[] getBinaryValue() {
+        return binaryValue;
+    }
+
+    @Override
+    public String toString() {
+        return Arrays.toString(binaryValue);
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(binaryValue);
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return obj instanceof BinaryValue && Arrays.equals(((BinaryValue) obj).binaryValue, this.binaryValue);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/BitsValue.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/BitsValue.java
new file mode 100644
index 0000000..56786b7
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/BitsValue.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.model.util.GrammarHelper;
+
+/**
+ * Holds the value of a data node instance of type "bits".
+ *
+ * @author Mark Hollmann
+ */
+public class BitsValue {
+
+    private final Set<String> setBits;
+
+    public BitsValue() {
+        setBits = new HashSet<>();
+    }
+
+    public BitsValue(final String val) {
+        setBits = new HashSet<>(GrammarHelper.parseToStringList(val.trim()));
+    }
+
+    public boolean isBitSet(final String bitName) {
+        return setBits.contains(bitName);
+    }
+
+    public BitsValue setBit(final String val) {
+        setBits.add(Objects.requireNonNull(val));
+        return this;		// for chaining
+    }
+
+    public Set<String> getSetBits() {
+        return Collections.unmodifiableSet(setBits);
+    }
+
+    @Override
+    public String toString() {
+        return "Bits set: " + setBits.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return setBits.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return obj instanceof BitsValue && ((BitsValue) obj).setBits.equals(this.setBits);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/IdentityRefValue.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/IdentityRefValue.java
new file mode 100644
index 0000000..13a3dee
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/IdentityRefValue.java
@@ -0,0 +1,130 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+/**
+ * Holds the value of a data node instance of type "identityref"
+ *
+ * @author Mark Hollmann
+ */
+public class IdentityRefValue {
+
+    private final NamespaceModuleIdentifier value;
+
+    public IdentityRefValue(final String namespace, final String moduleName, final String identityName) {
+        this.value = new NamespaceModuleIdentifier(namespace, moduleName, Objects.requireNonNull(identityName));
+    }
+
+    /**
+     * Constructor for data encoded in XML, where prefixes are used and a prefix resolver is available for the namespace
+     * resolution.
+     */
+    public IdentityRefValue(final String val, final PrefixResolver prefixResolver, final String defaultNamespace) {
+
+        final boolean hasPrefix = QNameHelper.hasPrefix(val);
+        final String namespace = hasPrefix ?
+                prefixResolver.resolveNamespaceUri(QNameHelper.extractPrefix(val)) :
+                defaultNamespace;
+        final String name = hasPrefix ? QNameHelper.extractName(val) : val;
+
+        value = new NamespaceModuleIdentifier(namespace, null, name);
+    }
+
+    /**
+     * Constructor for data encoded in JSON, where module names are used.
+     */
+    public IdentityRefValue(final String val, final String defaultModuleName) {
+
+        final boolean hasPrefix = QNameHelper.hasPrefix(val);
+        final String moduleName = hasPrefix ? QNameHelper.extractPrefix(val) : defaultModuleName;
+        final String name = hasPrefix ? QNameHelper.extractName(val) : val;
+
+        value = new NamespaceModuleIdentifier(null, moduleName, name);
+    }
+
+    /**
+     * The name of the identity
+     */
+    public String getIdentityName() {
+        return value.getIdentifier();
+    }
+
+    /**
+     * The name of the module in which the identity has been declared. May return null if the value was encoded in XML.
+     */
+    public String getIdentityModuleName() {
+        return value.getModuleName();
+    }
+
+    /**
+     * The namespace of the module in which the identity has been declared. May return null if the value was encoded in
+     * JSON.
+     */
+    public String getIdentityNamespace() {
+        return value.getNamespace();
+    }
+
+    @Override
+    public String toString() {
+        return "IdentityRef value " + getIdentityNamespace() + "/" + getIdentityModuleName() + "/" + getIdentityName();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+
+        if (obj == null || !obj.getClass().getName().equals(IdentityRefValue.class.getName())) {
+            return false;
+        }
+
+        final IdentityRefValue other = (IdentityRefValue) obj;
+
+        if (!this.getIdentityName().equals(other.getIdentityName())) {
+            return false;
+        }
+
+        if (this.getIdentityModuleName() != null && other.getIdentityModuleName() != null && this
+                .getIdentityNamespace() != null && other.getIdentityNamespace() != null) {
+            return this.getIdentityModuleName().equals(other.getIdentityModuleName()) && this.getIdentityNamespace().equals(
+                    other.getIdentityNamespace());
+        }
+
+        /*
+         * The comparison is a little different to how this would usually be done. Depending on the encoding
+         * of the input, either the namespace or the module name may be null. However, a client having constructed
+         * such an object, will typically have knowledge of both (as they will know the model). So we will try both.
+         */
+        if (this.getIdentityModuleName() != null && other.getIdentityModuleName() != null) {
+            return this.getIdentityModuleName().equals(other.getIdentityModuleName());
+        }
+
+        if (this.getIdentityNamespace() != null && other.getIdentityNamespace() != null) {
+            return this.getIdentityNamespace().equals(other.getIdentityNamespace());
+        }
+
+        return false;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/ValueHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/ValueHelper.java
new file mode 100644
index 0000000..41fb289
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/data/util/ValueHelper.java
@@ -0,0 +1,140 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.model.util.NumberHelper;
+
+/**
+ * Utility class that translates values expressed in lexical representation to a Java
+ * Object. The type of the object returned depends on the YANG data type. Mapping is
+ * as follows:
+ * <p>
+ * <ul>
+ * <li>integer types -&gt; BigInteger</li>
+ * <li>decimal64 -&gt; BigDecimal</li>
+ * <li>string -&gt; String</li>
+ * <li>boolean -&gt; Boolean</li>
+ * <li>enumeration -&gt; String</li>
+ * <li>bits -&gt; BitsValue</li>
+ * <li>binary -&gt; BinaryValue</li>
+ * </ul>
+ * <b>Null</b> will be returned if:
+ * <p>
+ * <ul>
+ * <li>The input value is null.</li>
+ * <li>The YANG data type is not in the list above.</li>
+ * <li>The value could not be converted.</li>
+ * </ul>
+ *
+ * @author Mark Hollmann
+ */
+public abstract class ValueHelper {
+
+    @SuppressWarnings("unchecked")
+    static public <T> T fromLexicalRepresentation(final String lexicalRepresentation,
+            final DataTypeHelper.YangDataType yangDataType) {
+
+        if (lexicalRepresentation == null) {
+            return null;
+        }
+
+        switch (yangDataType) {
+            case INT8:
+            case INT16:
+            case INT32:
+            case INT64:
+            case UINT8:
+            case UINT16:
+            case UINT32:
+            case UINT64:
+                return (T) forInteger(lexicalRepresentation);
+            case DECIMAL64:
+                return (T) forDecimal64(lexicalRepresentation);
+            case STRING:
+                return (T) forString(lexicalRepresentation);
+            case BOOLEAN:
+                return (T) forBoolean(lexicalRepresentation);
+            case ENUMERATION:
+                return (T) forEnumeration(lexicalRepresentation);
+            case BITS:
+                return (T) forBits(lexicalRepresentation);
+            case BINARY:
+                return (T) forBinary(lexicalRepresentation);
+            default:
+                break;
+        }
+
+        return null;
+    }
+
+    static private BigInteger forInteger(final String lexicalRepresentation) {
+        return NumberHelper.getIntegerDefaultValue(lexicalRepresentation);
+    }
+
+    static private BigDecimal forDecimal64(final String lexicalRepresentation) {
+        return NumberHelper.getDecimalValue(lexicalRepresentation);
+    }
+
+    static private String forString(final String lexicalRepresentation) {
+        return lexicalRepresentation;
+    }
+
+    static private Boolean forBoolean(final String lexicalRepresentation) {
+        if ("true".equals(lexicalRepresentation)) {
+            return Boolean.TRUE;
+        }
+        if ("false".equals(lexicalRepresentation)) {
+            return Boolean.FALSE;
+        }
+
+        return null;
+    }
+
+    /**
+     * 9.6.1: The lexical representation of an enumeration value is the assigned name string.
+     */
+    static private String forEnumeration(final String lexicalRepresentation) {
+        if (lexicalRepresentation.isEmpty()) {
+            return null;		// empty enum name is not a valid name.
+        }
+        return lexicalRepresentation;
+    }
+
+    /**
+     * 9.7.2: The lexical representation of the bits type is a space-separated list of the
+     * names of the bits that are set. A zero-length string thus represents a value
+     * where no bits are set.
+     */
+    static private BitsValue forBits(final String lexicalRepresentation) {
+        return new BitsValue(lexicalRepresentation);
+    }
+
+    /**
+     * 9.8.2: Binary values are encoded with the base64 encoding scheme (see Section 4 in [RFC4648]).
+     */
+    static private BinaryValue forBinary(final String lexicalRepresentation) {
+        return new BinaryValue(lexicalRepresentation);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/Finding.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/Finding.java
new file mode 100644
index 0000000..6ccc4f6
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/Finding.java
@@ -0,0 +1,306 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * A finding is something that is worth reporting back to the client. It is not necessarily
+ * always a fault in the mode.
+ *
+ * @author Mark Hollmann
+ */
+public class Finding {
+
+    private final AbstractStatement statement;		// may be null
+    private final YangDomElement domElement;		// may be null
+    private final YangModel yangModel;				// may be null
+    private final int lineNumber;					// may be zero
+    private final int columnNumber;					// may be zero
+
+    private final YangDataDomNode dataDomNode;				// may be null
+    private final YangData yangData;		// may be null
+
+    private final String findingType;
+    private final String message;
+    private final String errorMessageText;			// may be null
+
+    public Finding(final ParserFindingType findingType, final String message) {
+        this(findingType.toString(), message);
+    }
+
+    public Finding(final AbstractStatement statement, final ParserFindingType findingType, final String message) {
+        this(statement, findingType.toString(), message);
+    }
+
+    public Finding(final AbstractStatement statement, final String findingType, final String message) {
+        this(statement, findingType, message, null);
+    }
+
+    public Finding(final YangDomElement domElement, final String findingType, final String message) {
+        this(domElement, findingType, message, null);
+    }
+
+    public Finding(final YangModel yangModelFile, final ParserFindingType findingType, final String message) {
+        this(yangModelFile, 0, findingType.toString(), message);
+    }
+
+    public Finding(final YangDataDomNode dataDomNode, final String findingType, final String message) {
+        this(dataDomNode, findingType, message, null);
+    }
+
+    public Finding(final YangData yangDataFile, final String findingType, final String message) {
+        this(yangDataFile, findingType, message, 0, 0);
+    }
+
+    // ============================================================
+
+    public Finding(final String findingType, final String message) {
+        this.statement = null;
+        this.domElement = null;
+        this.yangModel = null;
+        this.lineNumber = 0;
+        this.columnNumber = 0;
+        this.dataDomNode = null;
+        this.yangData = null;
+        this.findingType = findingType;
+        this.message = message;
+        this.errorMessageText = null;
+    }
+
+    public Finding(final AbstractStatement statement, final String findingType, final String message,
+            final String errorMessageText) {
+        this.statement = statement;
+        this.domElement = statement.getDomElement();
+        this.yangModel = statement.getDomElement().getYangModel();
+        this.lineNumber = statement.getDomElement().getLineNumber();
+        this.columnNumber = 0;
+        this.dataDomNode = null;
+        this.yangData = null;
+        this.findingType = findingType;
+        this.message = message;
+        this.errorMessageText = errorMessageText;
+    }
+
+    public Finding(final YangDomElement domElement, final String findingType, final String message,
+            final String errorMessageText) {
+        this.statement = null;
+        this.domElement = domElement;
+        this.yangModel = domElement.getYangModel();
+        this.lineNumber = domElement.getLineNumber();
+        this.columnNumber = 0;
+        this.dataDomNode = null;
+        this.yangData = null;
+        this.findingType = findingType;
+        this.message = message;
+        this.errorMessageText = errorMessageText;
+    }
+
+    public Finding(final YangDataDomNode dataDomNode, final String findingType, final String message,
+            final String errorMessageText) {
+        this.statement = null;
+        this.domElement = null;
+        this.yangModel = null;
+        this.lineNumber = dataDomNode.getLineNumber();
+        this.columnNumber = dataDomNode.getColumnNumber();
+        this.dataDomNode = dataDomNode;
+        this.yangData = dataDomNode.getYangData();
+        this.findingType = findingType;
+        this.message = message;
+        this.errorMessageText = errorMessageText;
+    }
+
+    public Finding(final YangModel yangModelFile, final int lineNumber, final String findingType, final String message) {
+        this.statement = null;
+        this.domElement = null;
+        this.yangModel = yangModelFile;
+        this.lineNumber = lineNumber;
+        this.columnNumber = 0;
+        this.dataDomNode = null;
+        this.yangData = null;
+        this.findingType = findingType;
+        this.message = message;
+        this.errorMessageText = null;
+    }
+
+    public Finding(final YangData yangDataFile, final String findingType, final String message, final int line,
+            final int col) {
+        this.statement = null;
+        this.domElement = null;
+        this.yangModel = null;
+        this.lineNumber = line;
+        this.columnNumber = col;
+        this.dataDomNode = null;
+        this.yangData = yangDataFile;
+        this.findingType = findingType;
+        this.message = message;
+        this.errorMessageText = null;
+    }
+
+    /**
+     * The statement that the finding relates to. May return null.
+     */
+    public AbstractStatement getStatement() {
+        return statement;
+    }
+
+    /**
+     * The YANG DOM element the finding relates to. May return null.
+     */
+    public YangDomElement getDomElement() {
+        return domElement;
+    }
+
+    /**
+     * The Yang Model that has the finding. May (very rarely) return null.
+     */
+    public YangModel getYangModel() {
+        return yangModel;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    /**
+     * The data input (usually an XML or JSON file) the finding relates to. May return null.
+     */
+    public YangData getYangData() {
+        return yangData;
+    }
+
+    /**
+     * The data DOM node that the finding relates to. May return null.
+     */
+    public YangDataDomNode getDataDomNode() {
+        return dataDomNode;
+    }
+
+    public String getFindingType() {
+        return findingType;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * May return null.
+     */
+    public String getErrorMessageText() {
+        return errorMessageText;
+    }
+
+    public boolean isYangModelRelated() {
+        return yangModel != null;
+    }
+
+    public boolean isInstanceDataRelated() {
+        return yangData != null;
+    }
+
+    /**
+     * A general finding does not relate to a particular model or data - prime
+     * example for this is P000 being issued when a NPE is caught somewhere.
+     */
+    public boolean isGeneralFinding() {
+        return yangModel == null && yangData == null;
+    }
+
+    @Override
+    public int hashCode() {
+        return message.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+
+        if (!(obj instanceof Finding)) {
+            return false;
+        }
+
+        final Finding other = (Finding) obj;
+
+        if (!this.findingType.equals(other.findingType)) {
+            return false;
+        }
+        if (this.lineNumber != other.lineNumber) {
+            return false;
+        }
+        if (this.columnNumber != other.columnNumber) {
+            return false;
+        }
+        if (!this.message.equals(other.message)) {
+            return false;
+        }
+
+        if (this.yangModel != null && other.yangModel != null) {
+            return this.yangModel.equals(other.yangModel);
+        }
+
+        if (this.yangModel != null || other.yangModel != null) {
+            return false;
+        }
+
+        if (this.yangData != null && other.yangData != null) {
+            return this.yangData.equals(other.yangData);
+        }
+
+        return (this.yangData == null && other.yangData == null);
+    }
+
+    @Override
+    public String toString() {
+
+        final StringBuilder sb = new StringBuilder(300);
+
+        if (yangModel != null) {
+            sb.append(yangModel.getYangInput().getName());
+        } else if (yangData != null) {
+            sb.append(yangData.getYangInput().getName());
+        }
+
+        if (lineNumber != 0) {
+            sb.append(" / line ").append(lineNumber);
+        }
+        if (columnNumber != 0) {
+            sb.append(" / char ").append(columnNumber);
+        }
+        sb.append(" ");
+        sb.append(findingType);
+        sb.append(": ");
+        sb.append(message);
+
+        if (errorMessageText != null) {
+            sb.append(" (").append(errorMessageText).append(')');
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingFilterPredicate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingFilterPredicate.java
new file mode 100644
index 0000000..0f481e8
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingFilterPredicate.java
@@ -0,0 +1,36 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+import java.util.function.Predicate;
+
+/**
+ * Finding filter predicates are used during processing to filter out findings. The semantics of a finding
+ * filter predicate are such that the test(Finding) method returns true if the finding shall be filtered out,
+ * i.e. <b>not</b> retained for further processing.
+ * <p>
+ * If the predicate is used as part of stream processing, and the Stream.filter() method is used in order
+ * to <b>retain</b> Finding instances, Predicate.negate() should be invoked.
+ *
+ * @author Mark Hollmann
+ */
+public interface FindingFilterPredicate extends Predicate<Finding> {
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingSeverity.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingSeverity.java
new file mode 100644
index 0000000..0cabed4
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingSeverity.java
@@ -0,0 +1,46 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+/**
+ * Severity of a finding.
+ *
+ * @author Mark Hollmann
+ */
+public enum FindingSeverity {
+    /**
+     * A problem in the model. Serious enough to prevent the model from working properly.
+     */
+    ERROR,
+    /**
+     * Something that is likely going to cause problems somewhere.
+     */
+    WARNING,
+    /**
+     * A finding that conveys some information. Typically used to hint the user to improve
+     * on a badly-written model.
+     */
+    INFO,
+    /**
+     * The finding will be suppressed.
+     */
+    SUPPRESS
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingSeverityCalculator.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingSeverityCalculator.java
new file mode 100644
index 0000000..270b106
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingSeverityCalculator.java
@@ -0,0 +1,35 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+/**
+ * Implementations of this interface return a finding severity for a given finding type. Typically
+ * used by tooling to assign proper severities to the various findings that there can be.
+ *
+ * @author Mark Hollmann
+ */
+public interface FindingSeverityCalculator {
+
+    /**
+     * Calculates the severity for the supplied finding.
+     */
+    FindingSeverity calculateSeverity(String findingType);
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingsManager.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingsManager.java
new file mode 100644
index 0000000..dbb29dc
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/FindingsManager.java
@@ -0,0 +1,258 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Holds on to all findings issued during processing.
+ *
+ * @author Mark Hollmann
+ */
+public class FindingsManager {
+
+    private final Set<Finding> findings = new HashSet<>();
+
+    /*
+     * The severity calculator for findings.
+     */
+    private final FindingSeverityCalculator findingSeverityCalculator;
+    /*
+     * This is the predicate to handle the global "suppress all"
+     */
+    private final SuppressAllFilterPredicate suppressAllFilterPredicate;
+    /*
+     * This is the predicate to handle findings suppressed due to severity calculator.
+     */
+    private final SeverityCalculatorFilterPredicate severityCalculatorFilterPredicate;
+    /*
+     * A number of predicates used to filter-out findings.
+     */
+    private final List<FindingFilterPredicate> filterPredicates = new ArrayList<>();
+    /*
+     * Finding types that can never be suppressed.
+     */
+    private final Set<String> nonSuppressableFindingTypes = new HashSet<>();
+
+    public FindingsManager(final FindingSeverityCalculator findingSeverityCalculator) {
+
+        this.findingSeverityCalculator = findingSeverityCalculator;
+
+        this.suppressAllFilterPredicate = new SuppressAllFilterPredicate();
+        this.filterPredicates.add(suppressAllFilterPredicate);
+
+        this.severityCalculatorFilterPredicate = new SeverityCalculatorFilterPredicate(findingSeverityCalculator);
+        this.filterPredicates.add(severityCalculatorFilterPredicate);
+    }
+
+    public FindingSeverityCalculator getFindingSeverityCalculator() {
+        return findingSeverityCalculator;
+    }
+
+    /**
+     * Add a finding unless it should be filtered.
+     */
+    public void addFinding(final Finding finding) {
+        if (!nonSuppressableFindingTypes.contains(finding.getFindingType()) && shouldSuppress(finding)) {
+            return;
+        }
+
+        findings.add(finding);
+
+        /*
+         * The finding also gets attached to various objects. This is useful for downstream tooling;
+         * for example, for a tool that displays findings on statements.
+         */
+        if (finding.getStatement() != null) {
+            finding.getStatement().addFinding(finding);
+        }
+
+        if (finding.getDataDomNode() != null) {
+            finding.getDataDomNode().addFinding(finding);
+        }
+
+        if (finding.getYangModel() != null) {
+            finding.getYangModel().addFinding(finding);
+        }
+
+        if (finding.getYangData() != null) {
+            finding.getYangData().addFinding(finding);
+        }
+    }
+
+    public void addFindings(final Collection<Finding> findings) {
+        findings.forEach(this::addFinding);
+    }
+
+    public Set<Finding> getAllFindings() {
+        return findings;
+    }
+
+    /**
+     * Removes all findings from this FindingsManager.
+     */
+    public void clear() {
+        findings.clear();
+    }
+
+    /**
+     * Returns whether the finding would be suppressed, based on the supplied finding type. May be
+     * used as performance improvement to avoid complex processing that may result in findings being
+     * issued, just for these to be subsequently suppressed.
+     */
+    public boolean isFindingTypeGloballySuppressed(final String findingType) {
+        return suppressAllFilterPredicate.allSuppressed() || severityCalculatorFilterPredicate.findingTypeSuppressed(
+                findingType);
+    }
+
+    /**
+     * Adds a finding type that cannot be suppressed. Any finding added to this findings
+     * manager of any of the non-suppressable findings will never be filtered-out.
+     */
+    public void addNonSuppressableFindingType(final String findingType) {
+        nonSuppressableFindingTypes.add(Objects.requireNonNull(findingType));
+    }
+
+    /**
+     * Adds a custom filter predicate to this findings manager.
+     */
+    public void addFilterPredicate(final FindingFilterPredicate pred) {
+        filterPredicates.add(Objects.requireNonNull(pred));
+    }
+
+    /**
+     * If true, will cause all findings to be suppressed. However, certain findings are considered so serious
+     * that it is not possible to suppress these, and any attempt to do so will be ignored.
+     */
+    public void setSuppressAll(final boolean val) {
+        suppressAllFilterPredicate.setSuppressAll(val);
+    }
+
+    /**
+     * Applies the filter currently set in this FindingsManager to the supplied findings.
+     * Only findings passing the filter will be returned.
+     */
+    public Set<Finding> getFilteredFindings(final Set<Finding> findingsToFilter) {
+        Objects.requireNonNull(findingsToFilter);
+        return findingsToFilter.stream().filter(f -> !shouldSuppress(f)).collect(Collectors.toSet());
+    }
+
+    /*
+     * Whether a finding should be suppressed. May not reliably work where a finding
+     * is issued very early during the parse phase when the identity of a module is
+     * not known yet.
+     */
+    private boolean shouldSuppress(final Finding finding) {
+
+        for (final FindingFilterPredicate pred : filterPredicates) {
+            if (pred.test(finding)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Removes all findings from this FindingsManager, except those of the finding type(s) supplied.
+     */
+    public void retainFindingsOfType(final List<String> findingTypesToRetain) {
+        Objects.requireNonNull(findingTypesToRetain);
+        final Set<Finding> retainedFindings = findings.stream().filter(f -> findingTypesToRetain.contains(f
+                .getFindingType())).collect(Collectors.toSet());
+        findings.clear();
+        findings.addAll(retainedFindings);
+    }
+
+    /**
+     * Returns whether a finding of the specified type exists in this FindingsManager.
+     */
+    public boolean hasFindingOfType(final String findingType) {
+        Objects.requireNonNull(findingType);
+        return findings.stream().anyMatch(f -> f.getFindingType().equals(findingType));
+    }
+
+    /**
+     * Returns whether a finding of any of the specified types exist in this FindingsManager.
+     */
+    public boolean hasFindingOfAnyOf(final List<String> findingTypes) {
+        Objects.requireNonNull(findingTypes);
+        return findings.stream().anyMatch(f -> findingTypes.contains(f.getFindingType()));
+    }
+
+    /**
+     * Removes any finding that has been reported against the supplied YANG DOM element. Returns
+     * true if at least a single finding was removed.
+     */
+    public boolean removeFindingsOnYangDomElement(final YangDomElement domElement) {
+
+        List<Finding> toBeRemoved = null;
+
+        for (final Finding f : findings) {
+
+            final YangDomElement findingDomElement = f.getDomElement();
+            if (domElement != findingDomElement) {
+                continue;
+            }
+
+            /*
+             * We record the finding as to-be-removed.
+             */
+            if (toBeRemoved == null) {
+                toBeRemoved = new ArrayList<>();
+            }
+            toBeRemoved.add(f);
+        }
+
+        /*
+         * We also need to remove the finding from the statement or the input, if so attached,
+         * to avoid it showing up in other places.
+         */
+        if (toBeRemoved != null) {
+            for (final Finding f : toBeRemoved) {
+
+                final AbstractStatement onStatement = f.getStatement();
+                if (onStatement != null) {
+                    onStatement.removeFinding(f);
+                }
+
+                final YangModel onYangModel = f.getYangModel();
+                if (onYangModel != null) {
+                    onYangModel.removeFinding(f);
+                }
+
+                findings.remove(f);
+            }
+        }
+
+        return toBeRemoved != null;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModifyableFindingSeverityCalculator.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModifyableFindingSeverityCalculator.java
new file mode 100644
index 0000000..1a6790c
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModifyableFindingSeverityCalculator.java
@@ -0,0 +1,61 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class that can be populated with a mapping from finding types to severities.
+ *
+ * @author Mark Hollmann
+ */
+public class ModifyableFindingSeverityCalculator implements FindingSeverityCalculator {
+
+    private final Map<String, FindingSeverity> findingTypeToSeverity = new HashMap<>();
+
+    public void errorForFinding(final String findingType) {
+        findingTypeToSeverity.put(findingType, FindingSeverity.ERROR);
+    }
+
+    public void warningForFinding(final String findingType) {
+        findingTypeToSeverity.put(findingType, FindingSeverity.WARNING);
+    }
+
+    public void infoForFinding(final String findingType) {
+        findingTypeToSeverity.put(findingType, FindingSeverity.INFO);
+    }
+
+    public void suppressFinding(final String findingType) {
+        findingTypeToSeverity.put(findingType, FindingSeverity.SUPPRESS);
+    }
+
+    public void setSeverityForFindingType(final String findingType, final FindingSeverity severity) {
+        findingTypeToSeverity.put(findingType, severity);
+    }
+
+    @Override
+    public FindingSeverity calculateSeverity(final String findingType) {
+        final FindingSeverity severity = findingTypeToSeverity.get(findingType);
+        return severity == null ? FindingSeverity.ERROR : severity;
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.java
new file mode 100644
index 0000000..b56dff7
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.java
@@ -0,0 +1,181 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * A predicate that takes one or more modules, one or more finding types, and one or more
+ * schema node paths.
+ *
+ * @author Mark Hollmann
+ */
+public class ModuleAndFindingTypeAndSchemaNodePathFilterPredicate implements FindingFilterPredicate {
+
+    /**
+     * Parses the supplied string into an instance of ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.
+     * <p>
+     * Module names are separated from finding types, and from the node path, by the ";" character.
+     * <p>
+     * Module names are separated by the "," character. Finding types are likewise separated by
+     * the "," character. Only one path may be supplied at most. A value must be supplied for module
+     * names, finding types and path.
+     * <p>
+     * The only allowable wildcard character is a "*", denoting any "character sequence".
+     * <p>
+     * Example 1: The following will suppress all P114 findings in any IETF and IANA modules:
+     * "ietf-*,iana-*;P114_TYPEDEF_NOT_USED;*"
+     * <p>
+     * Example 2: The following will suppress all findings within the "modules-state" container
+     * within the IETF yang library: "ietf-yang-library;*;/container=modules-state"
+     * <p>
+     * Example 3: The following will suppress all P115 findings, in all modules: "*;P115_*;*"
+     */
+    public static ModuleAndFindingTypeAndSchemaNodePathFilterPredicate fromString(final String s) {
+
+        final String[] split = s.split(";");
+        if (split.length != 3) {
+            throw new RuntimeException("Invalid string format for ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.");
+        }
+
+        final List<Pattern> moduleNames = new ArrayList<>();
+        if (!split[0].equals("*")) {
+            final String[] moduleNamesSplit = split[0].contains(",") ? split[0].split(",") : new String[] { split[0] };
+            for (final String stringPattern : moduleNamesSplit) {
+                moduleNames.add(Pattern.compile(stringPattern.trim().replace(".", "[.]").replace("*", ".*")));
+            }
+        }
+
+        final List<Pattern> findingTypes = new ArrayList<>();
+        if (!split[1].equals("*")) {
+            final String[] findingTypesSplit = split[1].contains(",") ? split[1].split(",") : new String[] { split[1] };
+            for (final String stringPattern : findingTypesSplit) {
+                findingTypes.add(Pattern.compile(stringPattern.trim().replace(".", "[.]").replace("*", ".*")));
+            }
+        }
+
+        final String schemaNodePath = split[2].equals("*") ? null : split[2];
+
+        return new ModuleAndFindingTypeAndSchemaNodePathFilterPredicate(moduleNames, findingTypes, schemaNodePath);
+    }
+
+    private final List<Pattern> moduleNames;
+    private final List<Pattern> findingTypes;
+    private final String schemaNodePath;
+
+    /**
+     * A finding will be filtered if the statement is part of any of the supplied modules,
+     * and if the finding is of any of the supplied types, and if the path to the statement
+     * is a sub-path of the supplied paths.
+     * <p>
+     * More formally, the name of the module in which the offending statement sits must be
+     * matchable against any of the module name patterns, and the type of the finding must
+     * be matchable against any of the finding type patterns, and the schema node path of
+     * the offending statement must be the same, or a sub-path, of the supplied path.
+     * <p>
+     * Supplying an empty list for module names or finding types will match-all for that
+     * parameter. Supplying null as schema node path will match-all paths.
+     */
+    public ModuleAndFindingTypeAndSchemaNodePathFilterPredicate(final List<Pattern> moduleNames,
+            final List<Pattern> findingTypes, final String schemaNodePath) {
+        this.moduleNames = Objects.requireNonNull(moduleNames);
+        this.findingTypes = Objects.requireNonNull(findingTypes);
+        this.schemaNodePath = schemaNodePath;
+    }
+
+    @Override
+    public boolean test(final Finding f) {
+        return matchOnModule(f) && matchOnFindingType(f) && matchOnSchemaNode(f);
+    }
+
+    private boolean matchOnModule(final Finding finding) {
+
+        if (moduleNames.isEmpty()) {
+            return true;
+        }
+
+        /*
+         * If the finding does not relate to a YAM then obviously we cannot match.
+         */
+        if (finding.getYangModel() == null) {
+            return false;
+        }
+
+        /*
+         * It can happen that we don't have a module identity yet, because a finding was found
+         * before we actually got a chance to extract the module name. In this case we use the
+         * name of the input. This is not foolproof, of course.
+         */
+        final ModuleIdentity moduleIdentity = finding.getYangModel().getModuleIdentity();
+        final String moduleOrSubModuleName = moduleIdentity == null ?
+                finding.getYangModel().getYangInput().getName() :
+                moduleIdentity.getModuleName();
+
+        for (final Pattern pattern : moduleNames) {
+            if (pattern.matcher(moduleOrSubModuleName).matches()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private boolean matchOnFindingType(final Finding finding) {
+
+        if (findingTypes.isEmpty()) {
+            return true;
+        }
+
+        final String findingType = finding.getFindingType();
+
+        for (final Pattern pattern : findingTypes) {
+            if (pattern.matcher(findingType).matches()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private boolean matchOnSchemaNode(final Finding finding) {
+
+        if (schemaNodePath == null) {
+            return true;
+        }
+
+        if (finding.getStatement() == null) {
+            return false;
+        }
+
+        final YangDomElement domElement = finding.getStatement().getDomElement();
+        if (domElement == null) {
+            return false;
+        }
+
+        return domElement.getSimplifiedPath().startsWith(schemaNodePath);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModuleAndSeverityFilterPredicate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModuleAndSeverityFilterPredicate.java
new file mode 100644
index 0000000..ae514ec
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ModuleAndSeverityFilterPredicate.java
@@ -0,0 +1,146 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+
+/**
+ * A predicate that takes one or more modules, and one or more severities.
+ *
+ * @Author Mark Hollmann
+ */
+public class ModuleAndSeverityFilterPredicate implements FindingFilterPredicate {
+
+    /**
+     * Parses the supplied string into an instance of ModuleAndSeverityFilterPredicate.
+     * <p>
+     * Module names are separated from severities by the ";" character.
+     * <p>
+     * Module names are separated by the "," character. Severities are likewise separated by
+     * the "," character. A value must be supplied for both module names and severities.
+     * <p>
+     * The only allowable wildcard character is a "*", denoting any "character sequence".
+     * <p>
+     * Example: The following will suppress all findings of severity INFO and WARNING in any IETF
+     * and IANA modules: "ietf-*,iana-*;INFO,WARNING"
+     */
+    public static ModuleAndSeverityFilterPredicate fromString(final String s,
+            final FindingSeverityCalculator findingSeverityCalculator) {
+
+        final String[] split = s.split(";");
+        if (split.length != 2) {
+            throw new RuntimeException("Invalid string format for ModuleAndSeverityFilterPredicate.");
+        }
+
+        final List<Pattern> moduleNames = new ArrayList<>();
+        if (!split[0].equals("*")) {
+            final String[] moduleNamesSplit = split[0].contains(",") ? split[0].split(",") : new String[] { split[0] };
+            for (final String stringPattern : moduleNamesSplit) {
+                moduleNames.add(Pattern.compile(stringPattern.trim().replace(".", "[.]").replace("*", ".*")));
+            }
+        }
+
+        final Set<FindingSeverity> severities = new HashSet<>();
+        if (!split[1].equals("*")) {
+            final String[] severitiesSplit = split[1].contains(",") ? split[1].split(",") : new String[] { split[1] };
+            for (final String severity : severitiesSplit) {
+                severities.add(FindingSeverity.valueOf(severity.trim().toUpperCase()));
+            }
+        }
+
+        return new ModuleAndSeverityFilterPredicate(moduleNames, severities, findingSeverityCalculator);
+    }
+
+    private final List<Pattern> moduleNames;
+    private final Set<FindingSeverity> severities;
+    private final FindingSeverityCalculator findingSeverityCalculator;
+
+    /**
+     * A finding will be filtered if the statement is part of any of the supplied modules,
+     * and has any of the supplied severities.
+     * <p>
+     * More formally, the name of the module in which the offending statement sits must be
+     * matchable against any of the module name patterns, and the severity of the finding must
+     * be part of the supplied set of severities.
+     * <p>
+     * Supplying an empty list for module names, or empty set for severities, will match-all
+     * for that parameter.
+     */
+    public ModuleAndSeverityFilterPredicate(final List<Pattern> moduleNames, final Set<FindingSeverity> severities,
+            final FindingSeverityCalculator findingSeverityCalculator) {
+        this.moduleNames = Objects.requireNonNull(moduleNames);
+        this.severities = Objects.requireNonNull(severities);
+        this.findingSeverityCalculator = Objects.requireNonNull(findingSeverityCalculator);
+    }
+
+    @Override
+    public boolean test(final Finding f) {
+        return matchOnModule(f) && matchOnSeverity(f);
+    }
+
+    private boolean matchOnModule(final Finding finding) {
+
+        if (moduleNames.isEmpty()) {
+            return true;
+        }
+
+        /*
+         * If the finding does not relate to a YAM then obviously we cannot match.
+         */
+        if (finding.getYangModel() == null) {
+            return false;
+        }
+
+        /*
+         * It can happen that we don't have a module identity yet, because a finding was found
+         * before we actually got a chance to extract the module name. In this case we use the
+         * name of the input. This is not foolproof, of course.
+         */
+        final ModuleIdentity moduleIdentity = finding.getYangModel().getModuleIdentity();
+        final String moduleOrSubModuleName = moduleIdentity == null ?
+                finding.getYangModel().getYangInput().getName() :
+                moduleIdentity.getModuleName();
+
+        for (final Pattern pattern : moduleNames) {
+            if (pattern.matcher(moduleOrSubModuleName).matches()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private boolean matchOnSeverity(final Finding finding) {
+
+        if (severities.isEmpty()) {
+            return true;
+        }
+
+        return severities.contains(findingSeverityCalculator.calculateSeverity(finding.getFindingType()));
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ParserFindingType.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ParserFindingType.java
new file mode 100644
index 0000000..907f3cd
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/ParserFindingType.java
@@ -0,0 +1,507 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+/**
+ * A collection of finding types by the parser.
+ * <p/>
+ * Note that although these are defined as an enum, the finding type is of data type string. It is
+ * therefore possible to use finding types declared outside of this enum.
+ *
+ * @author Mark Hollmann
+ */
+public enum ParserFindingType {
+
+    // Basic processing errors
+
+    /**
+     * Usually thrown if there is a code error, typically a NPE caused by the model being really bad.
+     */
+    P000_UNSPECIFIED_ERROR,
+    /**
+     * Couldn't read the file. Or the stream.
+     */
+    P001_BASIC_FILE_READ_ERROR,
+    /**
+     * The type-safe class for an extension does not have the correct constructor.
+     */
+    P002_INVALID_EXTENSION_STATEMENT_CLASS,
+    /**
+     * The exact same input has been supplied twice. Usually means the exact same file has been
+     * supplied twice for parsing.
+     */
+    P003_DUPLICATE_INPUT,
+    /**
+     * A module may only be implemented once by a server. It is possible that the same module, of
+     * different revisions, is listed multiple times in the input - but then only one of them can
+     * be conformance IMPLEMENT, the other ones must be conformance IMPORT.
+     */
+    P004_SAME_MODULE_DUPLICATE_IMPLEMENTS,
+    /**
+     * There is no module in the input that has a conformance of IMPLEMENTS. Hence there will be
+     * no data nodes in the schema, which is rather pointless.
+     */
+    P005_NO_IMPLEMENTS,
+    /**
+     * There is a mismatch in conformance type between a module and its submodules.
+     */
+    P006_IMPLEMENT_IMPORT_MISMATCH,
+
+    /**
+     * Fail-fast. Denotes that during parsing some issues were found that are so severe that it
+     * does not really make sense to keep processing the schema, and the parser exists out.
+     */
+    P009_FAIL_FAST,
+
+    // Basic syntax errors not relating to any particular statement or language construct.
+
+    /**
+     * There are certain rules in YANG about how characters can be escaped in quoted text.
+     */
+    P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT,
+    /**
+     * Same, just for unquoted text.
+     */
+    P012_INVALID_CHARACTER_IN_UNQUOTED_TEXT,
+    /**
+     * Something wrong at the start of the document. May also indicate that the file is not
+     * Yang at all but something else entirely.
+     */
+    P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
+    /**
+     * Usually due to a mismatch of curly braces.
+     */
+    P014_INVALID_SYNTAX_AT_DOCUMENT_END,
+    /**
+     * Bit of a catch-all finding for any syntax that is wrong in a document (not just Yang,
+     * also XML/JSON documents).
+     */
+    P015_INVALID_SYNTAX_IN_DOCUMENT,
+    /**
+     * This statement is not allowed here.
+     */
+    P018_ILLEGAL_CHILD_STATEMENT,
+    /**
+     * A mandatory statement is missing.
+     */
+    P019_MISSING_REQUIRED_CHILD_STATEMENT,
+
+    /*
+     *
+     */
+    P025_INVALID_EXTENSION,
+
+    // The following relate to prefix, import's etc.
+
+    /**
+     * In a YAM a declared prefix is not unique. This is a serious issue.
+     */
+    P031_PREFIX_NOT_UNIQUE,
+    /**
+     * A YAM does not have a revision. While this is allowed in Yang, it is very poor modeling.
+     */
+    P032_MISSING_REVISION,
+    /**
+     * A prefix is used and cannot be resolved. This is usually a typo in the prefix.
+     */
+    P033_UNRESOLVEABLE_PREFIX,
+    /**
+     * There is an 'import' statement, but the module has not been supplied in the input.
+     */
+    P034_UNRESOLVABLE_IMPORT,
+    /**
+     * Yang allows for multiple revisions of the same name to be part of the schema, as long as
+     * only at most one of them is of conformance IMPLEMENT. In those situations, other modules
+     * importing such modules must use an explicit revision-date.
+     */
+    P035_AMBIGUOUS_IMPORT,
+    /**
+     * A YAM is importing the same module (possibly of different revision) multiple times.
+     */
+    P036_MODULE_IMPORTED_MULTIPLE_TIMES,
+    /**
+     * A module includes a submodule, but the submodule has not been found in the input.
+     */
+    P037_UNRESOLVABLE_INCLUDE,
+    /**
+     * Multiple revisions of a subnmodule are in the input. Not allowed.
+     */
+    P038_AMBIGUOUS_INCLUDE,
+    /**
+     * A submodule refers to a module, but the module is not in the input.
+     */
+    P039_UNRESOLVABLE_BELONGS_TO,
+    /**
+     * Submodules include each other. Extremely bad modeling.
+     */
+    P040_CIRCULAR_INCLUDE_REFERENCES,
+    /**
+     * There is a mix of Yang 1 and Yang 1.1 versions between the module and its submodule(s).
+     * We don't really care, but technically that's not allowed by the spec.
+     */
+    P041_DIFFERENT_YANG_VERSIONS_BETWEEN_MODULE_AND_SUBMODULES,
+    /**
+     * A YAM of conformance IMPORT is in the input but not referred-to from any other module.
+     * Not really an issue, but should be removed.
+     */
+    P042_UNREFERENCED_IMPORTED_FILE,
+    /**
+     * If a module of different revisions is supplied more than once in the input, only one of
+     * them can have conformance IMPLEMENT.
+     */
+    P043_SAME_MODULE_IMPLEMENTS_MORE_THAN_ONCE,
+    /**
+     * The same module is supplied as both conformance IMPLEMENT and IMPORT. That is not
+     * necessarily a problem, it may well be intentioned to be that way.
+     */
+    P044_SAME_MODULE_IMPLEMENTS_AND_IMPORTS,
+    /**
+     * An 'include' resolves to a module, not a submodule.
+     */
+    P045_NOT_A_SUBMODULE,
+    /**
+     * An 'belongs-to' resolves to a submodule, not a module.
+     */
+    P046_NOT_A_MODULE,
+    /**
+     * There is a mismatch between the 'include' and 'belongs-to' statements between a module
+     * and a submodule.
+     */
+    P047_SUBMODULE_OWNERSHIP_MISMATCH,
+    /**
+     * A submodule is in the input, but its owning module is not in the input.
+     */
+    P048_ORPHAN_SUBMODULE,
+    /**
+     * Two 'revision' statements (not latest) inside a YAM have the same date.
+     */
+    P049_DUPLICATE_REVISION,
+    /**
+     * Two 'revision' statements (latest) inside a YAM have the same date. This is potentially
+     * a very serious problem. It indicates that the module content was updated, the revision
+     * statement was copied/pasted, but the date not updated. As a consequence there might be
+     * two modules in circulation having different content but the same revision date.
+     */
+    P050_DUPLICATE_LATEST_REVISION,
+
+    // Other generic YANG issues
+
+    /**
+     * The cardinality of a statement is incorrect.
+     */
+    P051_INVALID_STATEMENT_CARDINALITY,
+    /**
+     * Syntax error on a Yang identifier. Yang only allows a relatively small set of non-alphanumeric
+     * characters.
+     */
+    P052_INVALID_YANG_IDENTIFIER,
+    /**
+     * A value is used part of a statement, but the value is not valid in the context where it
+     * is used.
+     */
+    P053_INVALID_VALUE,
+    /**
+     * A path could not be resolved. This is usually due to typos, or the model designer forgetting
+     * to include all schema node names along the path. There is possibly also a prefix missing as
+     * part of one of the path elements.
+     */
+    P054_UNRESOLVABLE_PATH,
+    /**
+     * Stuff in the YAM that need not be there.
+     */
+    P055_SUPERFLUOUS_STATEMENT,
+    /**
+     * TODO - check this.
+     */
+    P056_CONSTRAINT_NARROWED,
+    /**
+     * It is possible to change the data type of data nodes by means of a deviation. This is likely
+     * to cause problems for clients that expect the original data type.
+     */
+    P057_DATA_TYPE_CHANGED,
+
+    // Relating to instance data
+
+    P064_ANNOTATION_USAGE,
+    P065_CANNOT_CONVERT,
+    P066_NO_SETTER,
+    P067_NOT_SINGLE_INSTANCE,
+
+    // Relating to instance data
+
+    /**
+     * During parsing of annotation data a mismatch between leaf/leaf-list data and annotations
+     * was found.
+     */
+    P069_UNEXPECTED_JSON_VALUE,
+    /**
+     * During parsing of JSON data a JSON element of the wrong type was encountered (e.g. an
+     * array where an object was expected)
+     */
+    P070_WRONG_JSON_VALUE_TYPE,
+    /**
+     * The root XML element of an XML file containing data is wrong. Only certain elements are
+     * supported.
+     */
+    P071_INCORRECT_ROOT_ELEMENT_OF_DATA_FILE,
+    /**
+     * When building an instance data tree the key value for a list instance was not found.
+     */
+    P072_MISSING_KEY_VALUE,
+    /**
+     * During the merge of data from different sources into an instance data tree a leaf was
+     * encountered whose value differs between the inputs.
+     */
+    P073_LEAF_VALUE_ALREADY_SET,
+    /**
+     * Data has been attempted to be set for a schema node that is not a data node.
+     */
+    P074_NOT_A_DATA_NODE,
+    /**
+     * Data has been supplied for a data node that has not been found in the schema.
+     */
+    P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND,
+    /**
+     * The same data node is declared more than once in the data (e.g., the same leaf is listed
+     * twice in the data).
+     */
+    P076_DUPLICATE_INSTANCE_DATA,
+    /**
+     * There is a prefix in the XML file that has not been declared.
+     */
+    P077_UNRESOLVABLE_PREFIX,
+    /**
+     * Nothing in the data file.
+     */
+    P079_EMPTY_DATA_FILE,
+    /**
+     * A null value was encountered when building the instance data tree.
+     */
+    P080_NULL_VALUE,
+
+    // Yang Library
+
+    /**
+     * Some data in the Yang Library is wrong.
+     */
+    P081_INCORRECT_YANG_LIBRARY_DATA,
+    /**
+     * A mandatory piece of information from the data.
+     */
+    P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING,
+    /**
+     * There is a feature listed inside the Yang Library, but this feature has not been defined
+     * in the corresponding module.
+     */
+    P083_FEATURE_LISTED_IN_YANG_LIBRARY_NOT_FOUND,
+    /**
+     * There is more than one YL in the input
+     */
+    P084_MULTIPLE_YANG_LIBRARIES_IN_INPUT,
+    /**
+     * What has been supplied as input in terms of modules does not match up with the modules
+     * listed in the Yang Library.
+     */
+    P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY,
+    /**
+     * A feature has been marked as supported, but it depends on other features that are not supported.
+     */
+    P086_FEATURE_CANNOT_BE_SUPPORTED,
+
+    // Collector
+
+    /**
+     * The same module has been found twice by the collector.
+     */
+    P091_COLLECTOR_DUPLICATE_INPUT,
+    /**
+     * The collector found an input that does not appear to be a valid YAM.
+     */
+    P092_COLLECTOR_NOT_A_VALID_YAM,
+    /**
+     * A dependent module was not found by a collector.
+     */
+    P093_COLLECTOR_MODULE_NOT_FOUND,
+
+    // NACM
+
+    /**
+     * Some data in NACM is wrong.
+     */
+    P096_INCORRECT_NACM_DATA,
+
+    // Specific issues, general statements
+
+    /**
+     * A description statement has no content (which is a bit pointless)
+     */
+    P101_EMPTY_DOCUMENTATION_VALUE,
+    /**
+     * A schema node has an illegal status
+     */
+    P102_INVALID_STATUS,
+    /**
+     * The syntax of an 'if-feature' statement is wrong.
+     */
+    P103_ILLEGAL_IF_FEATURE_SYNTAX,
+    /**
+     * A deprecated statement is being used.
+     */
+    P104_USAGE_OF_DEPRECATED_ELEMENT,
+
+    // Specific issues: typedef
+
+    /**
+     * typedefs have a circular dependency.
+     */
+    P111_CIRCULAR_TYPEDEF_REFERENCES,
+    /**
+     * There is a lot of nesting of typedefs. Typically makes the model unreadable.
+     */
+    P112_EXCESSIVE_TYPEDEF_DEPTH,
+    /**
+     * A derived type could not be resolved.
+     */
+    P113_UNRESOLVABLE_DERIVED_TYPE,
+    /**
+     * A typedef is not being used. Not necessarily an issue, but might indicate a buggy model.
+     */
+    P114_TYPEDEF_NOT_USED,
+    /**
+     * A typedef is only used once. Doesn't really make sense, why not simply inline the content?
+     */
+    P115_TYPEDEF_USED_ONCE_ONLY,
+    /**
+     * A derived type refers to yet another derived type, but that one is not resolvable.
+     */
+    P116_NESTED_DERIVED_TYPE_NOT_RESOLVABLE,
+    /**
+     * A derived type is restricting the base type in illegal manner.
+     */
+    P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+
+    // Specific issues: uses / grouping
+
+    /**
+     * uses have a circular dependency.
+     */
+    P121_CIRCULAR_USES_REFERENCES,
+    /**
+     * There is a lot of nesting of uses/grouping. Typically makes the model unreadable.
+     */
+    P122_EXCESSIVE_USES_DEPTH,
+    /**
+     * An 'augment' part of a 'uses' augments a schema node that may not be augmented.
+     */
+    P123_INVALID_USES_AUGMENT_TARGET_NODE,
+    /**
+     * A 'refine' part of a 'uses' refines a schema node that may not be refined.
+     */
+    P124_INVALID_REFINE_TARGET_NODE,
+    /**
+     * A uses statement could be resolved to a grouping.
+     */
+    P131_UNRESOLVABLE_GROUPING,
+    /**
+     * A grouping is not being used.
+     */
+    P132_GROUPING_NOT_USED,
+    /**
+     * A grouping is used only once (why not inline?)
+     */
+    P133_GROUPING_USED_ONCE_ONLY,
+    /**
+     * A 'uses' points to a 'grouping' that itself has a 'uses', and that 'uses' is not resolvable.
+     */
+    P134_NESTED_USES_NOT_RESOLVABLE,
+
+    // Specific issues: enum / bits
+
+    /**
+     * There is a whitespace in the name of an enum member. While this is technically allowed by
+     * the RFC, it is very bad modeling, as it goes against the coding convention of every major
+     * programming language and it will lead to problems downstream somewhere.
+     */
+    P141_WHITESPACE_IN_ENUM,
+    /**
+     * An enum member name contains characters that are usually disallowed as part of enums in
+     * major programming languages. Expect issues downstream.
+     */
+    P142_UNUSUAL_CHARACTERS_IN_ENUM,
+    /**
+     * An enum member does not have a value. This is allowed in Yang as the values can be auto-generated,
+     * but it is dangerous as a new / removed enum inside the enumeration will cause the auto-generated
+     * values to change in an incompatible manner.
+     */
+    P143_ENUM_WITHOUT_VALUE,
+    /**
+     * A bit does not have a position. This is allowed in Yang as the positions can be auto-generated,
+     * but it is dangerous as a new / removed bits cause the auto-generated positions to change in an
+     * incompatible manner.
+     */
+    P144_BIT_WITHOUT_POSITION,
+
+    // Specific issues: augmentation
+
+    /**
+     * An 'augment's target schema node may not be augmented.
+     */
+    P151_TARGET_NODE_CANNOT_BE_AUGMENTED,
+    /**
+     * The 'augment' and its target sit in the same module. Bad modeling.
+     */
+    P152_AUGMENT_TARGET_NODE_IN_SAME_MODULE,
+
+    // Specific issues: deviation
+
+    /**
+     * Invalid operation for a deviate.
+     */
+    P161_INVALID_DEVIATE_OPERATION,
+    /**
+     * The 'deviation' and its target sit in the same module. Bad modeling.
+     */
+    P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE,
+    /**
+     * There are two 'deviate replace' statements that modify the exact same schema node.
+     */
+    P163_AMBIGUOUS_DEVIATE_REPLACE_OF_SAME_STATEMENT,
+    /**
+     * A statement that has been added previously has now been replaced.
+     */
+    P164_DEVIATE_REPLACE_OF_DEVIATE_ADDED_STATEMENT,
+    /**
+     * A statement that has been modified via a deviation has now also beed deleted.
+     */
+    P165_DEVIATE_DELETE_OF_DEVIATED_STATEMENT,
+    /**
+     * The deviate would result in a statement cardinality validation.
+     */
+    P166_DEVIATE_RESULTS_IN_CHILD_CARDINALITY_VIOLATION,
+    /**
+     * Certain statements cannot be added or deleted, only replaced. This is a hint.
+     */
+    P167_CANNOT_USE_UNDER_DEVIATE_ADD_OR_DELETE
+
+    /*
+     * Values 200+ reserved for downstream tooling, so don't go beyond P199
+     */
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/SeverityCalculatorFilterPredicate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/SeverityCalculatorFilterPredicate.java
new file mode 100644
index 0000000..028974a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/SeverityCalculatorFilterPredicate.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+import java.util.Objects;
+
+/**
+ * A predicate that is based on a severity calculator. If the calculator denotes the
+ * severity of the finding to be SUPPRESS, the finding will be filtered.
+ *
+ * @author Mark Hollmann
+ */
+public class SeverityCalculatorFilterPredicate implements FindingFilterPredicate {
+
+    private final FindingSeverityCalculator findingSeverityCalculator;
+
+    public SeverityCalculatorFilterPredicate(final FindingSeverityCalculator findingSeverityCalculator) {
+        this.findingSeverityCalculator = Objects.requireNonNull(findingSeverityCalculator);
+    }
+
+    public boolean findingTypeSuppressed(final String findingType) {
+        return findingSeverityCalculator.calculateSeverity(findingType) == FindingSeverity.SUPPRESS;
+    }
+
+    @Override
+    public boolean test(final Finding f) {
+        return findingTypeSuppressed(f.getFindingType());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/SuppressAllFilterPredicate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/SuppressAllFilterPredicate.java
new file mode 100644
index 0000000..66ac4e4
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/findings/SuppressAllFilterPredicate.java
@@ -0,0 +1,44 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings;
+
+/**
+ * A predicate that globally suppresses findings and that is configurable at runtime.
+ *
+ * @author Mark Hollmann
+ */
+public class SuppressAllFilterPredicate implements FindingFilterPredicate {
+
+    private boolean suppressAll = false;
+
+    public void setSuppressAll(final boolean val) {
+        this.suppressAll = val;
+    }
+
+    public boolean allSuppressed() {
+        return suppressAll;
+    }
+
+    @Override
+    public boolean test(final Finding f) {
+        return suppressAll;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/BufferedStreamYangInput.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/BufferedStreamYangInput.java
new file mode 100644
index 0000000..29b51ab
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/BufferedStreamYangInput.java
@@ -0,0 +1,55 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Supplies input from a stream. Closing of the stream is responsibility of the client.
+ *
+ * @author Mark Hollmann
+ */
+public class BufferedStreamYangInput extends ByteArrayYangInput {
+
+    public BufferedStreamYangInput(final String name, final InputStream inputStream) throws IOException {
+        this(name, inputStream, MEDIA_TYPE_YANG);
+    }
+
+    public BufferedStreamYangInput(final String name, final InputStream inputStream, final String mediaType)
+            throws IOException {
+        super(getBytes(inputStream), name, mediaType);
+    }
+
+    private static byte[] getBytes(final InputStream inputStream) throws IOException {
+        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+        int nRead;
+        byte[] data = new byte[100000];
+
+        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+            buffer.write(data, 0, nRead);
+        }
+
+        return buffer.toByteArray();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/ByteArrayYangInput.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/ByteArrayYangInput.java
new file mode 100644
index 0000000..313d283
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/ByteArrayYangInput.java
@@ -0,0 +1,93 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * An input based on a byte buffer.
+ *
+ * @author Mark Hollmann
+ */
+public class ByteArrayYangInput implements YangInput {
+
+    private final byte[] data;
+    private final String name;
+    private final String mediaType;
+
+    public ByteArrayYangInput(final byte[] data, final String name) {
+        this(data, name, MEDIA_TYPE_YANG);
+    }
+
+    public ByteArrayYangInput(final byte[] data, final String name, final String mediaType) {
+        this.data = Objects.requireNonNull(data);
+        this.name = Objects.requireNonNull(name);
+        this.mediaType = Objects.requireNonNull(mediaType);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public InputStream getInputStream() {
+        try {
+            return new ByteArrayInputStream(data);
+        } catch (final Exception ex) {
+            throw new RuntimeException("Cannot open input stream: " + ex.getMessage(), ex);
+        }
+    }
+
+    @Override
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other == null) {
+            return false;
+        }
+        if (this.getClass() == other.getClass()) {
+            return this.name.equals(((ByteArrayYangInput) other).name) && Arrays.equals(this.data,
+                    ((ByteArrayYangInput) other).data);
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/DirectYangInputResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/DirectYangInputResolver.java
new file mode 100644
index 0000000..1f31ef3
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/DirectYangInputResolver.java
@@ -0,0 +1,43 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A resolver that has been explicitly given the set of YANG inputs.
+ *
+ * @author Mark Hollmann
+ */
+public class DirectYangInputResolver implements YangInputResolver {
+
+    private final Set<YangInput> yangInputs;
+
+    public DirectYangInputResolver(final Set<YangInput> yangInputs) {
+        this.yangInputs = Objects.requireNonNull(yangInputs);
+    }
+
+    @Override
+    public Set<YangInput> getResolvedYangInput() {
+        return yangInputs;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/FileBasedYangInput.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/FileBasedYangInput.java
new file mode 100644
index 0000000..3190435
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/FileBasedYangInput.java
@@ -0,0 +1,98 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * An input based on a file
+ *
+ * @author Mark Hollmann
+ */
+public class FileBasedYangInput implements YangInput {
+
+    private final File file;
+
+    public FileBasedYangInput(final File file) {
+        this.file = Objects.requireNonNull(file);
+        if (!file.isFile() || !file.exists()) {
+            throw new RuntimeException("File not found: " + file.getAbsolutePath());
+        }
+    }
+
+    @Override
+    public String getName() {
+        return file.getName();
+    }
+
+    @Override
+    public File getFile() {
+        return file;
+    }
+
+    @Override
+    public InputStream getInputStream() {
+        try {
+            return new FileInputStream(file);
+        } catch (final Exception ex) {
+            throw new RuntimeException("Cannot open input stream: " + ex.getMessage(), ex);
+        }
+    }
+
+    @Override
+    public String getMediaType() {
+        if (file.getName().endsWith(".json")) {
+            return MEDIA_TYPE_YANG_DATA_JSON;
+        } else if (file.getName().endsWith(".xml")) {
+            return MEDIA_TYPE_YANG_DATA_XML;
+        }
+
+        return MEDIA_TYPE_YANG;
+    }
+
+    @Override
+    public int hashCode() {
+        return file.getName().hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other == null) {
+            return false;
+        }
+        if (this.getClass() == other.getClass()) {
+            return this.file.equals(((FileBasedYangInput) other).file);
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/FileBasedYangInputResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/FileBasedYangInputResolver.java
new file mode 100644
index 0000000..bbc77c6
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/FileBasedYangInputResolver.java
@@ -0,0 +1,98 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A resolver that recursively searches through a list of files and directory paths and
+ * identifies all files having any of the specified file extensions.
+ * <p/>
+ * Duplicate files will not be returned.
+ *
+ * @author Mark Hollmann
+ */
+public class FileBasedYangInputResolver implements YangInputResolver {
+
+    public static final String FILE_EXTENSION_YANG = "yang";
+    public static final String FILE_EXTENSION_XML = "xml";
+    public static final String FILE_EXTENSION_JSON = "json";
+
+    private final List<String> fileExtensionsToConsider;
+    private final List<File> filesAndDirectoriesToConsider;
+
+    public FileBasedYangInputResolver(final List<File> filesAndDirectoriesToConsider) {
+        this.fileExtensionsToConsider = Collections.<String> emptyList();
+        this.filesAndDirectoriesToConsider = Objects.requireNonNull(filesAndDirectoriesToConsider);
+    }
+
+    public FileBasedYangInputResolver(final List<File> filesAndDirectoriesToConsider,
+            final List<String> fileExtensionsToConsider) {
+        this.filesAndDirectoriesToConsider = Objects.requireNonNull(filesAndDirectoriesToConsider);
+        this.fileExtensionsToConsider = Objects.requireNonNull(fileExtensionsToConsider);
+    }
+
+    @Override
+    public Set<YangInput> getResolvedYangInput() {
+
+        final Set<YangInput> result = new HashSet<>();
+
+        for (final File file : filesAndDirectoriesToConsider) {
+            resolveFile(result, file);
+        }
+
+        return result;
+    }
+
+    private void resolveFile(final Set<YangInput> result, final File file) {
+
+        if (file.exists()) {
+            if (file.isFile()) {
+                filterAgainstFileExtensions(result, file);
+            } else {
+                for (final File subFile : file.listFiles()) {
+                    resolveFile(result, subFile);
+                }
+            }
+        }
+    }
+
+    private void filterAgainstFileExtensions(final Set<YangInput> result, final File file) {
+
+        final String fileName = file.getName();
+        final int lastIndexOf = fileName.lastIndexOf('.');
+        final String fileExtension = lastIndexOf > -1 ?
+                fileName.substring(lastIndexOf + 1).toLowerCase(Locale.ENGLISH) :
+                null;
+
+        if (fileExtensionsToConsider.isEmpty() || (fileExtension != null && fileExtensionsToConsider.contains(
+                fileExtension))) {
+            result.add(new FileBasedYangInput(file));
+        }
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/StringYangInput.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/StringYangInput.java
new file mode 100644
index 0000000..b15d084
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/StringYangInput.java
@@ -0,0 +1,36 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.util.Objects;
+
+/**
+ * A YangInput based on a String. The String object would typically be a complete YAM, or a
+ * complete XML / JSON document.
+ *
+ * @author Mark Hollmann
+ */
+public class StringYangInput extends ByteArrayYangInput {
+
+    public StringYangInput(final String data, final String name, final String mediaType) {
+        super(data.getBytes(), Objects.requireNonNull(name), Objects.requireNonNull(mediaType));
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/YangInput.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/YangInput.java
new file mode 100644
index 0000000..41b40d5
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/YangInput.java
@@ -0,0 +1,68 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * Implementations of this interface can provide input to the parser. The input may be a YAM
+ * (model), or perhaps an XML/JSON document (data) that aligns with a model.
+ *
+ * @author Mark Hollmann
+ */
+public interface YangInput {
+
+    public static final String MEDIA_TYPE_YANG = "application/yang";
+    public static final String MEDIA_TYPE_YANG_DATA_XML = "application/yang-data+xml";
+    public static final String MEDIA_TYPE_YANG_DATA_JSON = "application/yang-data+json";
+
+    /**
+     * Returns the name of this input.
+     */
+    String getName();
+
+    /**
+     * Returns the file, if any, backing this input. May return null if there is no file
+     * (e.g. because the contents are streamed from memory).
+     */
+    default File getFile() {
+        return null;
+    }
+
+    /**
+     * Returns an input stream for the contents of the input.
+     * <p>
+     * The stream will be closed by the parser when finished with the input.
+     * <p>
+     * <b>Note:</b> this method may be called multiple times on the same object. If the content
+     * is returned from a "live" stream (perhaps coming over a network), implementations
+     * <b>must</b> buffer the complete contents of the live stream into a suitable temporary object
+     * (memory, file), and then return (possibly multiple times) an appropriate stream based on
+     * that temporary object.
+     */
+    InputStream getInputStream();
+
+    /**
+     * Returns the media type of this input.
+     */
+    String getMediaType();
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/YangInputResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/YangInputResolver.java
new file mode 100644
index 0000000..492459d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/input/YangInputResolver.java
@@ -0,0 +1,38 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input;
+
+import java.util.Set;
+
+/**
+ * Implementations of this interface can resolve instances of YangInput.
+ * These may be used as input for modules or instance data.
+ *
+ * @author Mark Hollmann
+ */
+public interface YangInputResolver {
+
+    /**
+     * Returns all resolved input.
+     */
+    public Set<YangInput> getResolvedYangInput();
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ConformanceType.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ConformanceType.java
new file mode 100644
index 0000000..7e598b1
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ConformanceType.java
@@ -0,0 +1,48 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model;
+
+/**
+ * This enum serves a purpose similar to the corresponding leaf inside the YANG library
+ * (urn:ietf:params:xml:ns:yang:ietf-yang-library). It indicates whether a module is purely
+ * used as source of imports (e.g. because another module only needs its derived types and
+ * groupings) or whether the whole module should be considered and the containers / lists
+ * / etc. ("protocol-accessible objects") within it form part of the device model.
+ * <p/>
+ * Usually, a server will IMPLEMENT the vast majority of modules, and only in some rare
+ * cases will only IMPORT from some.
+ *
+ * @author Mark Hollmann
+ */
+public enum ConformanceType {
+    /**
+     * The server implements this module, i.e. makes available all protocol-accessible
+     * objects defined within.
+     */
+    IMPLEMENT,
+    /**
+     * The device only uses this module to import types and groupings; any containers /
+     * lists / etc. defined within at the root of the module will be ignored.
+     *
+     * The conformance type IMPORT should not be confused with the YANG 'import' statement.
+     */
+    IMPORT
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ModuleIdentity.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ModuleIdentity.java
new file mode 100644
index 0000000..e0704ca
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ModuleIdentity.java
@@ -0,0 +1,114 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model;
+
+import java.util.Objects;
+
+/**
+ * Encodes the identity of a YAM.
+ *
+ * @author Mark Hollmann
+ */
+public class ModuleIdentity {
+
+    public static final String UNKWOWN_REVISION = "__UNKNOWN__";
+
+    private final String moduleName;
+    private final String revision;
+
+    /**
+     * Constructor for YAMs whose revision are not known. This typically happens with 'import'
+     * statements where only a module name is specified, but not the actual revision. Note that
+     * an "unknown" revision is not the same as a non-existing revision.
+     */
+    public ModuleIdentity(final String moduleName) {
+        this.moduleName = Objects.requireNonNull(moduleName);
+        this.revision = UNKWOWN_REVISION;
+    }
+
+    /**
+     * Constructor for YAMs whose name and revision are known. The revision may be null (but not
+     * empty), as in their wisdom the creators of YANG decided it is ok for a YAM to not have a
+     * revision - and there actually a few YAMs in the wild that do not declare a revision.
+     */
+    public ModuleIdentity(final String moduleName, final String revision) {
+        this.moduleName = Objects.requireNonNull(moduleName);
+        this.revision = revision;
+
+        if ("".equals(revision)) {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    /**
+     * Returns the revision of the YAM. May return any of the following:
+     * <ul>
+     * <li>The actual known revision of a module (e.g. "2020-10-27")</li>
+     * <li>null if the module does not declare a revision (happens rarely, but is possible)</li>
+     * <li>The constant UNKWOWN_REVISION if the revision of the module is not known</li>
+     * </ul>
+     */
+    public String getRevision() {
+        return revision;
+    }
+
+    public boolean isUnknownRevision() {
+        return UNKWOWN_REVISION.equals(revision);
+    }
+
+    @Override
+    public int hashCode() {
+        return moduleName.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+
+        if (other instanceof ModuleIdentity) {
+            if (!this.moduleName.equals(((ModuleIdentity) other).moduleName)) {
+                return false;
+            }
+            if (this.revision == null && ((ModuleIdentity) other).revision == null) {
+                return true;
+            }
+            if (this.revision != null && this.revision.equals(((ModuleIdentity) other).revision)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        if (isUnknownRevision()) {
+            return moduleName + "/<unknown-rev>";
+        }
+        if (revision == null) {
+            return moduleName + "/<no-rev>";
+        }
+        return moduleName + "/" + revision;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ModulePrefixResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ModulePrefixResolver.java
new file mode 100644
index 0000000..fa5f05f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/ModulePrefixResolver.java
@@ -0,0 +1,134 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+
+/**
+ * A resolver that can handle prefixes, module names, and namespaces, and map
+ * back and forth between these. Namespaces are of importance when it comes to
+ * data; specifically, YANG data over NETCONF is XML encoded, requiring namespaces.
+ * <p/>
+ * However, this class should not be used for handling of data, as it does not
+ * support setting the default namespace.
+ *
+ * @author Mark Hollmann
+ */
+public class ModulePrefixResolver extends PrefixResolver {
+
+    private final ModuleAndNamespaceResolver globalNamespaceResolver;
+
+    private final Map<String, ModuleIdentity> prefixToModulename = new HashMap<>();
+
+    public ModulePrefixResolver(final ModuleAndNamespaceResolver globalNamespaceResolver) {
+        this.globalNamespaceResolver = globalNamespaceResolver;
+    }
+
+    /*
+     * ================ Here is all the module stuff =====================
+     */
+
+    /**
+     * Records a mapping between a prefix and a module name. This mapping has typically
+     * been extracted from the header of a YAM.
+     */
+    public void addModuleMapping(final String prefix, final ModuleIdentity moduleIdentity) {
+        prefixToModulename.put(Objects.requireNonNull(prefix), Objects.requireNonNull(moduleIdentity));
+    }
+
+    /**
+     * Records the default mapping for this prefix resolver, i.e. the module that is mapped
+     * to "no prefix".
+     */
+    public void setDefaultModuleMapping(final ModuleIdentity moduleIdentity) {
+        prefixToModulename.put(PrefixResolver.NO_PREFIX, Objects.requireNonNull(moduleIdentity));
+    }
+
+    /**
+     * Returns the module representing the prefix. May return null if the prefix is unknown.
+     */
+    public ModuleIdentity getModuleForPrefix(final String prefix) {
+        if (prefix == null) {
+            return getDefaultModuleIdentity();
+        }
+        return prefixToModulename.get(prefix);
+    }
+
+    /**
+     * Returns the module representing the default prefix. May be null if unknown.
+     */
+    public ModuleIdentity getDefaultModuleIdentity() {
+        return prefixToModulename.get(PrefixResolver.NO_PREFIX);
+    }
+
+    /*
+     * ================ Here is all the namespace stuff =====================
+     */
+
+    @Override
+    public void setDefaultNamespaceUri(final String namespaceUri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addMapping(final String prefix, final String namespaceUri) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the default namespace URI for this module. May return null.
+     */
+    @Override
+    public String getDefaultNamespaceUri() {
+        final ModuleIdentity moduleIdentityForPrefix = getDefaultModuleIdentity();
+        return moduleIdentityForPrefix == null ?
+                null :
+                globalNamespaceResolver.getNamespaceForModule(moduleIdentityForPrefix.getModuleName());
+    }
+
+    /**
+     * Returns the namespace URI for the given prefix or null if no mapping exists for the prefix.
+     */
+    @Override
+    public String resolveNamespaceUri(final String prefix) {
+        final ModuleIdentity moduleIdentityForPrefix = getModuleForPrefix(prefix);
+        return moduleIdentityForPrefix == null ?
+                null :
+                globalNamespaceResolver.getNamespaceForModule(moduleIdentityForPrefix.getModuleName());
+    }
+
+    /**
+     * Returns the name of the module for the given namespace.
+     */
+    public String resolveModuleName(final String namespace) {
+        return globalNamespaceResolver.getModuleForNamespace(namespace);
+    }
+
+    @Override
+    public String toString() {
+        return "Mappings: " + prefixToModulename.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/YangModel.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/YangModel.java
new file mode 100644
index 0000000..b4b14e2
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/YangModel.java
@@ -0,0 +1,472 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.YangInput;
+import org.oran.smo.yangtools.parser.model.parser.TokenIterator;
+import org.oran.smo.yangtools.parser.model.parser.YamTokenizer;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.model.statements.YangModelRoot;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomDocumentRoot;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.util.StackTraceHelper;
+
+/**
+ * Represents a single YANG model (a "YAM"). This will be either a module or a submodule.
+ *
+ * @author Mark Hollmann
+ */
+public class YangModel {
+
+    /*
+     * The underlying input. Typically a file with file extension ".yang", but could
+     * also be an arbitrary input stream.
+     */
+    private final YangInput yangInput;
+
+    private int lineCount;		// some useful information, not super-important.
+    private int charCount;		// ditto
+
+    private final ConformanceType conformanceType;
+
+    /*
+     * The prefix resolver track all prefixes defined in this YAM.
+     */
+    private ModulePrefixResolver prefixResolver;
+
+    /*
+     * The identity of this YAM. May be null if there are fundamental errors in the document.
+     */
+    private ModuleIdentity moduleIdentity;
+
+    /*
+     * The root of the Yang DOM tree.
+     */
+    private YangDomDocumentRoot yangDomDocumentRoot;
+
+    /*
+     * The root of the type-safe schema tree.
+     */
+    private YangModelRoot yangModelRoot;
+
+    /*
+     * Findings made in respect of this YAM, if any.
+     */
+    private Set<Finding> findings = null;
+
+    public YangModel(final YangInput yangInput, final ConformanceType conformanceType) {
+        this.yangInput = yangInput;
+        this.conformanceType = conformanceType;
+    }
+
+    public YangInput getYangInput() {
+        return yangInput;
+    }
+
+    public int getLineCount() {
+        return lineCount;
+    }
+
+    public int getCharCount() {
+        return charCount;
+    }
+
+    public ConformanceType getConformanceType() {
+        return conformanceType;
+    }
+
+    /**
+     * Returns the root of the type-safe statement tree. Note that the returned root is not the
+     * representation of the 'module' (or 'submodule'). Returns null if during parsing the type-safe
+     * statement was not built.
+     */
+    public YangModelRoot getYangModelRoot() {
+        return yangModelRoot;
+    }
+
+    /**
+     * Returns the root of the DOM element tree.
+     */
+    public YangDomDocumentRoot getYangDomDocumentRoot() {
+        return yangDomDocumentRoot;
+    }
+
+    /**
+     * The identity of this YAM. May return null if there are fundamental
+     * syntax errors in the document (basically, this is not a valid YAM).
+     */
+    public ModuleIdentity getModuleIdentity() {
+        return moduleIdentity;
+    }
+
+    /**
+     * The prefix resolver used by this input. This will only be available after the module has been parsed.
+     */
+    public ModulePrefixResolver getPrefixResolver() {
+        return prefixResolver;
+    }
+
+    /**
+     * Parses a YAM and builds the DOM element tree, and the type-safe statement tree,
+     * for this YAM.
+     */
+    public void parse(final ParserExecutionContext context, final ModuleAndNamespaceResolver namespaceResolver,
+            final Schema owningSchema) {
+        parse(context, namespaceResolver, owningSchema, true);
+    }
+
+    /**
+     * Parses a YAM and builds the DOM element tree for this YAM. If so desired, also
+     * builds the type-safe statement tree.
+     */
+    public void parse(final ParserExecutionContext context, final ModuleAndNamespaceResolver namespaceResolver,
+            final Schema owningSchema, final boolean createTypeSafeStatementTree) {
+
+        this.prefixResolver = new ModulePrefixResolver(namespaceResolver);
+
+        try {
+            /*
+             * There might be issues during the parsing, especially syntax errors, somewhere
+             * in the bowels of a model. This is likely to result in a NPE somewhere, which is
+             * caught here.
+             */
+
+            final TokenIterator tokenIterator = tokenize(context);
+            if (tokenIterator == null) {
+                // Super-basic syntax errors, exit out!
+                return;
+            }
+
+            /*
+             * We create the DOM element tree.
+             */
+            yangDomDocumentRoot = new YangDomDocumentRoot(this, owningSchema);
+            yangDomDocumentRoot.processTokens(context, tokenIterator);
+
+            /*
+             * The module identity, and all the prefixes, are extracted *before* the type-safe tree is
+             * constructed. Reason: Some of the prefixes defined in the module may be used by extension
+             * statements, and in order to instantiate these the prefixes used by these have to be resolvable
+             * to their module names *during* the actual processing of the tree.
+             */
+            extractModuleIdentity(context, yangDomDocumentRoot);
+            extractPrefixes(yangDomDocumentRoot);
+            extractNamespace(yangDomDocumentRoot, namespaceResolver);
+
+            if (createTypeSafeStatementTree) {
+                /*
+                 * We build the type-safe tree.
+                 */
+                yangModelRoot = new YangModelRoot(yangDomDocumentRoot, owningSchema);
+                yangModelRoot.processYangDom(context, yangDomDocumentRoot);
+            }
+
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(this, ParserFindingType.P000_UNSPECIFIED_ERROR, ex.getClass()
+                    .getSimpleName() + ": " + ex.getMessage() + " - trace: " + StackTraceHelper.getStackTraceInfo(ex)));
+        }
+    }
+
+    private TokenIterator tokenize(final ParserExecutionContext context) {
+
+        TokenIterator tokenIterator = null;
+
+        try (final InputStream inputStream = yangInput.getInputStream()) {
+
+            final YamTokenizer tokenizer = new YamTokenizer(context, this, inputStream);
+            tokenIterator = tokenizer.tokenize();
+
+            this.lineCount = tokenizer.getLineCount();
+            this.charCount = tokenizer.getCharCount();
+
+        } catch (final IOException ioex) {
+            context.addFinding(new Finding(this, ParserFindingType.P001_BASIC_FILE_READ_ERROR, ioex.getMessage()));
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(this, ParserFindingType.P000_UNSPECIFIED_ERROR, ex.getClass()
+                    .getSimpleName() + ": " + ex.getMessage() + " - trace: " + StackTraceHelper.getStackTraceInfo(ex)));
+        }
+
+        return tokenIterator;
+    }
+
+    private void extractPrefixes(final YangDomDocumentRoot docRoot) {
+
+        if (docRoot.getChildren().isEmpty()) {
+            return;
+        }
+
+        final YangDomElement moduleOrSubmodule = docRoot.getChildren().get(0);
+        if (CY.MODULE.equals(moduleOrSubmodule.getName())) {
+            /*
+             * extract 'prefix' statement (if it exists, which it should as it is mandatory according to RFC).
+             */
+            final List<YangDomElement> prefixChildren = getDomChildrenOfName(moduleOrSubmodule, CY.PREFIX);
+            if (prefixChildren.size() == 1 && prefixChildren.get(0).getValue() != null) {
+                recordModuleMapping(prefixChildren.get(0).getValue(), this.moduleIdentity.getModuleName(),
+                        this.moduleIdentity.getRevision());
+            }
+        } else {
+            /*
+             * It's a submodule, extract 'belongs-to' statement.
+             */
+            final List<YangDomElement> belongsToChildren = getDomChildrenOfName(moduleOrSubmodule, CY.BELONGS_TO);
+            if (belongsToChildren.size() == 1) {
+                final YangDomElement belongsToDomElement = belongsToChildren.get(0);
+                final String belongsToModuleName = belongsToDomElement.getValue();
+
+                final List<YangDomElement> prefixChildren = getDomChildrenOfName(belongsToDomElement, CY.PREFIX);
+                if (prefixChildren.size() == 1 && prefixChildren.get(0).getValue() != null) {
+                    recordSubmoduleMapping(prefixChildren.get(0).getValue(), belongsToModuleName);
+                }
+            }
+        }
+
+        /*
+         * For both 'module' and 'submodule', handle 'import' statements.
+         */
+        final List<YangDomElement> importChildren = getDomChildrenOfName(moduleOrSubmodule, CY.IMPORT);
+        for (final YangDomElement importDomElement : importChildren) {
+
+            final String importedModuleName = importDomElement.getValue();
+            String importedModuleRevision = null;
+
+            final List<YangDomElement> revisionDateChildren = getDomChildrenOfName(importDomElement, CY.REVISION_DATE);
+            if (revisionDateChildren.size() == 1 && !"".equals(revisionDateChildren.get(0).getValue())) {
+                importedModuleRevision = revisionDateChildren.get(0).getValue();
+            }
+
+            final List<YangDomElement> prefixChildren = getDomChildrenOfName(importDomElement, CY.PREFIX);
+            if (prefixChildren.size() == 1 && prefixChildren.get(0).getValue() != null) {
+                recordImportMapping(prefixChildren.get(0).getValue(), importedModuleName, importedModuleRevision);
+            }
+        }
+    }
+
+    /**
+     * Records a mapping for a submodule. A submodule will always refer to its owning module by name only, never by
+     * revision.
+     * <p>
+     * Will also record the default mapping, i.e. which module shall be resolved when no prefix is used.
+     */
+    private void recordSubmoduleMapping(final String prefix, final String moduleName) {
+        prefixResolver.addModuleMapping(Objects.requireNonNull(prefix), new ModuleIdentity(Objects.requireNonNull(
+                moduleName)));
+        prefixResolver.setDefaultModuleMapping(new ModuleIdentity(moduleName));
+    }
+
+    /**
+     * Records a mapping for a module. A module usually has a revision, in rare cases it does not. If not, then
+     * the module revision is truly "unspecified" (not "unknown").
+     * <p>
+     * Will also record the default mapping, i.e. which module shall be resolved when no prefix is used.
+     */
+    private void recordModuleMapping(final String prefix, final String moduleName, final String moduleRevision) {
+        prefixResolver.addModuleMapping(Objects.requireNonNull(prefix), new ModuleIdentity(Objects.requireNonNull(
+                moduleName), moduleRevision));
+        prefixResolver.setDefaultModuleMapping(new ModuleIdentity(moduleName, moduleRevision));
+    }
+
+    /**
+     * Records a mapping for an import statement. The 'import' may have omitted the revision, which can
+     * mean either "whatever revision of the module is also in the input", or "a module without revision".
+     */
+    private void recordImportMapping(final String prefix, final String moduleName, final String moduleRevision) {
+
+        if (moduleRevision == null) {
+            /*
+             * Unknown revision
+             */
+            prefixResolver.addModuleMapping(Objects.requireNonNull(prefix), new ModuleIdentity(Objects.requireNonNull(
+                    moduleName)));
+        } else {
+            /*
+             * Exact revision specified
+             */
+            prefixResolver.addModuleMapping(Objects.requireNonNull(prefix), new ModuleIdentity(Objects.requireNonNull(
+                    moduleName), moduleRevision));
+        }
+    }
+
+    private void extractNamespace(final YangDomDocumentRoot docRoot, final ModuleAndNamespaceResolver namespaceResolver) {
+
+        if (docRoot.getChildren().isEmpty()) {
+            return;
+        }
+
+        final YangDomElement moduleOrSubmodule = docRoot.getChildren().get(0);
+        if (CY.MODULE.equals(moduleOrSubmodule.getName())) {
+            /*
+             * Get the 'namespace' statement (if it exists, which it should).
+             */
+            final List<YangDomElement> namespaceChildren = getDomChildrenOfName(moduleOrSubmodule, CY.NAMESPACE);
+            if (namespaceChildren.size() == 1) {
+                final YangDomElement namespaceDomElement = namespaceChildren.get(0);
+                if (namespaceDomElement.getValue() != null) {
+                    namespaceResolver.recordModuleMapping(this.moduleIdentity.getModuleName(), namespaceDomElement
+                            .getValue());
+                    namespaceResolver.recordNamespaceMapping(namespaceDomElement.getValue(), this.moduleIdentity
+                            .getModuleName());
+                }
+            }
+        }
+    }
+
+    /**
+     * Extracts the module identity from the DOM tree, if possible. If there are fundamental issues
+     * with this, the ModuleIdentity will not be extracted, and subsequently the module will not be
+     * added to the registry.
+     */
+    private void extractModuleIdentity(final ParserExecutionContext context, final YangDomDocumentRoot docRoot) {
+
+        /*
+         * We are expecting a single child under root - that being 'module' or 'submodule'.
+         */
+        if (docRoot.getChildren().size() != 1) {
+            return;
+        }
+
+        final YangDomElement moduleOrSubmoduleDomElement = docRoot.getChildren().get(0);
+        if (!CY.MODULE.equals(moduleOrSubmoduleDomElement.getName()) && !CY.SUBMODULE.equals(moduleOrSubmoduleDomElement
+                .getName())) {
+            return;
+        }
+
+        /*
+         * We are expecting the module to have a non-null name.
+         */
+        if (moduleOrSubmoduleDomElement.getValue() == null || moduleOrSubmoduleDomElement.getValue().isEmpty()) {
+            return;
+        }
+
+        /*
+         * We set the module identity here already now although we don't know the revision yet, as
+         * some of the processing in this method may depend on at least the module name being set,
+         * especially for filtering of findings.
+         */
+        final String moduleName = moduleOrSubmoduleDomElement.getValue();
+        String revision = null;
+
+        this.moduleIdentity = new ModuleIdentity(moduleName);
+
+        /* From the RFC:
+         *
+         * "A module SHOULD have at least one "revision" statement. For every
+         * published editorial change, a new one SHOULD be added in front of the
+         * revisions sequence so that all revisions are in reverse chronological
+         * order."
+         *
+         * That's a bit loose of course. Says SHOULD, so it could be omitted,
+         * and the order is not guaranteed.
+         */
+        final List<YangDomElement> revisions = getDomChildrenOfName(moduleOrSubmoduleDomElement, CY.REVISION);
+
+        if (revisions.isEmpty()) {
+            context.addFinding(new Finding(docRoot.getYangModel(), ParserFindingType.P032_MISSING_REVISION,
+                    "(Sub-)Module does not have a 'revision' statement."));
+            this.moduleIdentity = new ModuleIdentity(moduleName, null);
+        } else {
+            /*
+             * We reverse-sort the revisions to get the 'newest' (i.e. most recent) to the beginning of
+             * the list since we don't trust module designers to get this right (somebody might put the
+             * latest revision at the *end* of the list of revisions). This sort should
+             * be just fine as the format of the revision has to be YYYY-MM-DD so lexical sorting works.
+             */
+            final Comparator<YangDomElement> byRevision = (YangDomElement r1, YangDomElement r2) -> {
+                final String revision1 = r1.getTrimmedValueOrEmpty();
+                final String revision2 = r2.getTrimmedValueOrEmpty();
+                return revision2.compareTo(revision1);
+            };
+            revisions.sort(byRevision);
+
+            revision = revisions.get(0).getValue();
+            this.moduleIdentity = new ModuleIdentity(moduleName, revision);
+        }
+    }
+
+    private List<YangDomElement> getDomChildrenOfName(final YangDomElement element, final String soughtDomElementName) {
+        final List<YangDomElement> result = new ArrayList<>();
+
+        for (final YangDomElement oneChild : element.getChildren()) {
+            if (oneChild.getName().equals(soughtDomElementName)) {
+                result.add(oneChild);
+            }
+        }
+
+        return result;
+    }
+
+    public void addFinding(final Finding finding) {
+        if (findings == null) {
+            findings = new HashSet<>();
+        }
+        findings.add(finding);
+    }
+
+    public void removeFinding(final Finding finding) {
+        if (findings != null) {
+            findings.remove(finding);
+        }
+    }
+
+    public Set<Finding> getFindings() {
+        return findings == null ? Collections.<Finding> emptySet() : findings;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.yangInput.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other == null) {
+            return false;
+        }
+        if (this.getClass() == other.getClass()) {
+            return this.yangInput.equals(((YangModel) other).yangInput);
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return moduleIdentity != null ? moduleIdentity.toString() : yangInput.getName();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/YangModelUtil.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/YangModelUtil.java
new file mode 100644
index 0000000..af4023f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/YangModelUtil.java
@@ -0,0 +1,48 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.input.YangInput;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+
+public abstract class YangModelUtil {
+
+    /**
+     * Utility to extract the identity of a module from a YAM.
+     * <p>
+     * If the input is not a YAM, or is significantly corrupted or badly formatted, the module identity
+     * cannot be extracted and null will be returned.
+     */
+    public static ModuleIdentity getYamModuleIdentity(final YangInput yangInput) {
+
+        final ParserExecutionContext context = new ParserExecutionContext(new FindingsManager(
+                new ModifyableFindingSeverityCalculator()));
+        final Schema schema = new Schema();
+
+        final YangModel yangModel = new YangModel(yangInput, ConformanceType.IMPLEMENT);
+        yangModel.parse(context, schema.getModuleNamespaceResolver(), schema, false);
+
+        return yangModel.getModuleIdentity();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/Token.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/Token.java
new file mode 100644
index 0000000..9d2a603
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/Token.java
@@ -0,0 +1,91 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.parser;
+
+/**
+ * @author Mark Hollmann
+ */
+public class Token {
+
+    public static Token newLeftBraceToken(final int lineNumber) {
+        final Token token = new Token();
+        token.type = TokenType.LEFT_BRACE;
+        token.lineNumber = lineNumber;
+        token.value = "{";
+        return token;
+    }
+
+    public static Token newRightBraceToken(final int lineNumber) {
+        final Token token = new Token();
+        token.type = TokenType.RIGHT_BRACE;
+        token.lineNumber = lineNumber;
+        token.value = "}";
+        return token;
+    }
+
+    public static Token newSemiColonToken(final int lineNumber) {
+        final Token token = new Token();
+        token.type = TokenType.SEMI_COLON;
+        token.lineNumber = lineNumber;
+        token.value = ";";
+        return token;
+    }
+
+    public static Token newPlusToken(final int lineNumber) {
+        final Token token = new Token();
+        token.type = TokenType.PLUS;
+        token.lineNumber = lineNumber;
+        token.value = "+";
+        return token;
+    }
+
+    public static Token newQuotedStringToken(final int lineNumber, final String str) {
+        final Token token = new Token();
+        token.type = TokenType.QUOTED_STRING;
+        token.lineNumber = lineNumber;
+        token.value = str;
+        return token;
+    }
+
+    public static Token newStringToken(final int lineNumber, final String str) {
+        final Token token = new Token();
+        token.type = TokenType.STRING;
+        token.lineNumber = lineNumber;
+        token.value = str;
+        return token;
+    }
+
+    public int lineNumber = 0;
+    public TokenType type = null;
+    public String value = null;
+
+    private Token() {
+    }
+
+    public enum TokenType {
+        LEFT_BRACE,      // {
+        RIGHT_BRACE,     // }
+        SEMI_COLON,      // ;
+        PLUS,            // +
+        QUOTED_STRING,   // "some text" or 'some text'
+        STRING           // any text, possibly containing spaces
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/TokenIterator.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/TokenIterator.java
new file mode 100644
index 0000000..9330a32
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/TokenIterator.java
@@ -0,0 +1,49 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.parser;
+
+import java.util.List;
+
+/**
+ * @author Mark Hollmann
+ */
+public class TokenIterator {
+
+    private final List<Token> tokens;
+    private int index = 0;
+
+    public TokenIterator(final List<Token> tokens) {
+        this.tokens = tokens;
+    }
+
+    public Token getToken(final int offsetToCurrentPos) {
+        final int toFetch = index + offsetToCurrentPos;
+        return toFetch < tokens.size() ? tokens.get(toFetch) : null;
+    }
+
+    public void advance(int i) {
+        index += i;
+    }
+
+    public boolean done() {
+        return index >= tokens.size();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/YamTokenizer.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/YamTokenizer.java
new file mode 100644
index 0000000..65c39d8
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/parser/YamTokenizer.java
@@ -0,0 +1,492 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.parser;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.parser.Token.TokenType;
+
+/**
+ * The sole purpose of this class is to tokenize a YAM (supplied as an input stream). Tokens are generated
+ * for various constructs of special significance (for example, the {} characters). Comment sections are skipped.
+ * String concatenation (usage of the + character) is also performed.
+ * <p>
+ * A new instance of this class must be created for each YAM parsed.
+ *
+ * @author Mark Hollmann
+ */
+public class YamTokenizer {
+
+    private static final String EMPTY_STRING = "";
+
+    private boolean yangVersionStatementAlreadyHandled = false;
+    private StringParseRules stringParseRules = StringParseRules.YANG1;
+
+    private int currentLine = 0;
+    private int charCount = 0;
+
+    private boolean inBlockComment = false;
+    private boolean inDoubleQuoteString = false;
+    private boolean inSingleQuoteString = false;
+    private StringBuilder quotedString;
+
+    private final List<Token> tokens = new ArrayList<>(10000);
+
+    private final ParserExecutionContext context;
+    private final YangModel yangModel;
+    private final InputStream is;
+
+    public YamTokenizer(final ParserExecutionContext context, final YangModel yangModel, final InputStream is)
+            throws IOException {
+        this.context = context;
+        this.yangModel = yangModel;
+        this.is = is;
+    }
+
+    public TokenIterator tokenize() throws IOException {
+
+        final BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
+
+        String str;
+
+        while ((str = br.readLine()) != null) {
+            currentLine++;
+
+            charCount += str.length();
+            charCount++;					// +1 for the new-line character that the readLine() method will swallow
+
+            if (inDoubleQuoteString && str.trim().isEmpty()) {
+                quotedString.append('\n');
+            } else {
+                while (!str.isEmpty()) {
+                    str = processString(str);
+                }
+            }
+        }
+
+        /*
+         * Make sure there are no dangling quoted strings and block comments at the end of the document.
+         */
+        if (inBlockComment) {
+            context.addFinding(new Finding(yangModel, ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END,
+                    "Document ends with an unclosed block comment. Be sure to close block comments with '*/'."));
+            return null;
+        }
+        if (inDoubleQuoteString || inSingleQuoteString) {
+            context.addFinding(new Finding(yangModel, ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END,
+                    "Document ends with non-terminated single- or double-quoted string."));
+            return null;
+        }
+
+        /*
+         * Make sure that the last token is not a + token
+         */
+        if (!tokens.isEmpty() && tokens.get(tokens.size() - 1).type == TokenType.PLUS) {
+            context.addFinding(new Finding(yangModel, ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END,
+                    "Document ends with a '+' symbol."));
+            return null;
+        }
+
+        final List<Token> result = new ArrayList<>(tokens.size());
+
+        /*
+         * Now we clean up the tokens and concatenate string tokens with their corresponding plus tokens.
+         * That takes care of constructs such as "'Hello ' + 'World!'" in the model.
+         */
+        for (int i = 0; i < tokens.size(); ++i) {
+
+            final Token oneToken = tokens.get(i);
+
+            if (oneToken.type == TokenType.QUOTED_STRING) {
+                /*
+                 * Concatenate quote strings that have + symbols between them
+                 */
+                final StringBuilder sb = new StringBuilder(10000);
+                sb.append(oneToken.value);
+                final int lineNumberStart = oneToken.lineNumber;
+
+                while (i + 1 < tokens.size()) {
+                    if (tokens.get(i + 1).type == TokenType.PLUS) {
+                        if (tokens.get(i + 2).type == TokenType.QUOTED_STRING) {
+                            // regular concatenation
+                            sb.append(tokens.get(i + 2).value);
+                            i += 2;
+                        } else if (tokens.get(i + 2).type == TokenType.STRING) {
+                            /*
+                             * We have the following: "Hello " + World. Technically disallowed by the spec, but we allow it.
+                             */
+                            context.addFinding(new Finding(yangModel, tokens.get(i + 2).lineNumber,
+                                    ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                                    "The '+' symbol is followed by an unquoted string (the string must be quoted for the '+' to work)."));
+                            sb.append(tokens.get(i + 2).value);
+                            i += 2;
+                        } else if (tokens.get(i + 2).type == TokenType.PLUS) {
+                            /*
+                             * We have a "+ +" in the document. Illegal syntax, but we allow it.
+                             */
+                            context.addFinding(new Finding(yangModel, tokens.get(i + 1).lineNumber,
+                                    ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                                    "The '+' symbol is repeated. Remove one of them."));
+                            i++;
+                        } else {
+                            /*
+                             * Something else unexpected. Hard finding.
+                             */
+                            context.addFinding(new Finding(yangModel, tokens.get(i + 1).lineNumber,
+                                    ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                                    "The '+' symbol is not followed by quoted string."));
+                            return null;
+                        }
+                    } else {
+                        break;
+                    }
+                }
+
+                result.add(Token.newStringToken(lineNumberStart, sb.toString()));
+
+            } else if (oneToken.type == TokenType.PLUS) {
+                /*
+                 * A plus token cannot just exist by itself, it must always sit between quoted strings.
+                 */
+                context.addFinding(new Finding(yangModel, oneToken.lineNumber,
+                        ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                        "Encountered standalone '+' symbol (are the strings on either side of it quoted?)."));
+                return null;
+
+            } else if (oneToken.type == TokenType.SEMI_COLON) {
+                result.add(oneToken);
+                /*
+                 * Consume any repeated semicolons. That's not a finding, but simply poor model editing.
+                 */
+                while (i + 1 < tokens.size()) {
+                    if (tokens.get(i + 1).type != TokenType.SEMI_COLON) {
+                        break;
+                    }
+                    context.addFinding(new Finding(yangModel, tokens.get(i + 1).lineNumber,
+                            ParserFindingType.P055_SUPERFLUOUS_STATEMENT.toString(), "Multiple semicolons."));
+                    i++;
+                }
+            } else {
+                /*
+                 * An unquoted string, or a left/right brace. Retain as-is.
+                 */
+                result.add(oneToken);
+            }
+        }
+
+        return new TokenIterator(result);
+    }
+
+    public int getCharCount() {
+        return charCount;
+    }
+
+    public int getLineCount() {
+        return currentLine;
+    }
+
+    /**
+     * Process the supplied string. Whatever part of the string could not be processed will be returned for iterative
+     * processing.
+     */
+    private String processString(final String str) {
+
+        if (inBlockComment) {
+            /*
+             * Must try to find character sequence star-slash that ends the block comment.
+             */
+            final int indexOf = str.indexOf("*/");
+            if (indexOf < 0) {
+                // not found, the whole string is part of the comment, so we are done processing this string here
+                return EMPTY_STRING;
+            }
+
+            // found, so end the comment and return everything after the comment for further processing.
+            inBlockComment = false;
+            return str.substring(indexOf + 2);
+
+        } else if (inDoubleQuoteString) {
+            /*
+             * Must try to find the closing quote character. Must be careful with character escaping.
+             * We trim anyway (idiotic YANG rule about indentation).
+             */
+            final String trimmed = str.trim();
+
+            for (int i = 0; i < trimmed.length(); ++i) {
+                final char charAt = trimmed.charAt(i);
+
+                if (charAt == '"') {
+                    // done with this double-quoted string. Create token and return leftovers, if any
+                    tokens.add(Token.newQuotedStringToken(currentLine, quotedString.toString()));
+                    handleYangVersionStatement();
+
+                    inDoubleQuoteString = false;
+                    return trimmed.substring(i + 1);
+                }
+                if (charAt == '\\') {
+                    // possible escaping
+                    i++;
+                    if (i >= trimmed.length()) {
+                        /*
+                         * The backslash character is the last character on the line. This is always wrong. We will be nice,
+                         * though, and assume what the user means is that the next line continues this line, which it does
+                         * anyway. So basically we swallow the character and continue on with the next line.
+                         */
+                        issueFinding(ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT,
+                                "Cannot have single backslash character at end of line.");
+                        return EMPTY_STRING;
+                    }
+
+                    final char nextChar = trimmed.charAt(i);
+
+                    if (nextChar == '\\') {
+                        quotedString.append('\\');
+                    } else if (nextChar == 'n') {
+                        quotedString.append('\n');
+                    } else if (nextChar == 't') {
+                        quotedString.append('\t');
+                    } else if (nextChar == '"') {
+                        quotedString.append('"');
+                    } else {
+                        /*
+                         * RFC 6020 (YANG 1) does not explicitly say that any other character is disallowed.
+                         * In contrast, RFC 7950 (YANG 1.1) explicitly states that any other character is
+                         * not allowed. In either case, we handle it gracefully by appending the backslash
+                         * and the character literally. But finding will only be issued for YANG 1.1 modules.
+                         */
+                        quotedString.append('\\');
+                        quotedString.append(nextChar);
+                        if (stringParseRules == StringParseRules.YANG1DOT1) {
+                            issueFinding(ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT,
+                                    "Invalid character escaping (\\" + nextChar + ") inside double-quoted string.");
+                        }
+                    }
+                } else {
+                    quotedString.append(charAt);
+                }
+            }
+
+            // end of quoted string not found yet, this line is fully consumed, continue...
+            quotedString.append(' ');
+            return EMPTY_STRING;
+
+        } else if (inSingleQuoteString) {
+            /*
+             * We are within a string enclosed in single quotes ('). According to RFC6020:
+             * A single-quoted string (enclosed within ’ ’) preserves each character
+             * within the quotes. A single quote character cannot occur in a
+             * single-quoted string, even when preceded by a backslash.
+             *
+             * Try to find ending single quote
+             */
+            final int indexOfSingleQuote = str.indexOf('\'');
+            if (indexOfSingleQuote < 0) {
+                // not found, so the quoted text must stretch multiple lines. So we simply copy over the
+                // remainder of the string as-is (no trimming) plus a newline and done with this string here.
+                quotedString.append(str);
+                quotedString.append('\n');
+                return EMPTY_STRING;
+            }
+            // found, so go to the end of the quoted string, create token and then return the leftovers.
+            quotedString.append(str.substring(0, indexOfSingleQuote));
+            tokens.add(Token.newQuotedStringToken(currentLine, quotedString.toString()));
+            handleYangVersionStatement();
+
+            inSingleQuoteString = false;
+            return str.substring(indexOfSingleQuote + 1);
+
+        } else {
+            /*
+             * Something else. Let's trim it first to remove all whitespace noise at beginning and end.
+             */
+            final String trimmed = str.trim();
+            if (trimmed.isEmpty()) {
+                return EMPTY_STRING;
+            }
+
+            /*
+             * Check for comments
+             */
+            if (trimmed.length() >= 2 && trimmed.startsWith("//")) {
+                // A single-comment line, we are done with the rest of the string.
+                return EMPTY_STRING;
+            }
+            if (trimmed.length() >= 2 && trimmed.startsWith("/*")) {
+                // block comment starts
+                inBlockComment = true;
+                return trimmed.substring(2);
+            }
+
+            /*
+             * Check for special characters and create tokens as required
+             */
+            if (trimmed.charAt(0) == '{') {
+                tokens.add(Token.newLeftBraceToken(currentLine));
+                return trimmed.substring(1);
+            }
+            if (trimmed.charAt(0) == '}') {
+                tokens.add(Token.newRightBraceToken(currentLine));
+                return trimmed.substring(1);
+            }
+            if (trimmed.charAt(0) == ';') {
+                tokens.add(Token.newSemiColonToken(currentLine));
+                return trimmed.substring(1);
+            }
+            if (trimmed.charAt(0) == '+') {
+                tokens.add(Token.newPlusToken(currentLine));
+                return trimmed.substring(1);
+            }
+
+            /*
+             * Check for beginning of double-quote or single-quote string
+             */
+            if (trimmed.charAt(0) == '"') {
+                quotedString = new StringBuilder(100);
+                inDoubleQuoteString = true;
+                String remainder = trimmed.substring(1);
+                /*
+                 * In case there are any spaces or tabs directly after the double-quote, these are retained.
+                 */
+                while (!remainder.isEmpty() && (remainder.charAt(0) == ' ' || remainder.charAt(0) == '\t')) {
+                    quotedString.append(remainder.charAt(0));
+                    remainder = remainder.substring(1);
+                }
+
+                return remainder;
+            }
+            if (trimmed.charAt(0) == '\'') {
+                quotedString = new StringBuilder(100);
+                inSingleQuoteString = true;
+                return trimmed.substring(1);
+            }
+
+            /*
+             * Some other string not in quotes. Consume one character at a time until we
+             * either reach the end of the string or a whitespace character or a special
+             * character. Note no character escaping allowed.
+             */
+            final StringBuilder unquotedString = new StringBuilder(100);
+            for (int i = 0; i < trimmed.length(); ++i) {
+                final char charAt = trimmed.charAt(i);
+
+                if (charAt == ';' || charAt == '{') {
+                    // reached the end
+                    tokens.add(Token.newStringToken(currentLine, unquotedString.toString()));
+                    handleYangVersionStatement();
+                    return trimmed.substring(i);
+
+                } else if (charAt == '"' || charAt == '\'') {
+                    /*
+                     * This rule has changed in YANG 1.1. Prior to that, double-quotes and single-quotes
+                     * were ok inside unquoted text; starting with YANG 1.1, these are not acceptable
+                     * anymore. Either case we continue (best effort).
+                     */
+                    if (stringParseRules == StringParseRules.YANG1DOT1) {
+                        issueFinding(ParserFindingType.P012_INVALID_CHARACTER_IN_UNQUOTED_TEXT,
+                                "Single-quote or double-quote character not allowed inside non-quoted string.");
+                    }
+
+                } else if (Character.isWhitespace(charAt)) {
+                    // done with this unquoted string
+                    tokens.add(Token.newStringToken(currentLine, unquotedString.toString()));
+                    handleYangVersionStatement();
+                    return trimmed.substring(i + 1);
+                }
+
+                unquotedString.append(charAt);
+            }
+
+            // reached string-end, then done as well.
+            tokens.add(Token.newStringToken(currentLine, unquotedString.toString()));
+            handleYangVersionStatement();
+            return EMPTY_STRING;
+        }
+    }
+
+    /**
+     * In order to apply YANG 1 or YANG 1.1. parse rules we need to know whether this is a
+     * YANG 1 or YANG 1.1 module. The only way of finding this out is by looking at the
+     * "yang-version" statement. This method tries to find this statement, and its value
+     * ("1" or "1.1").
+     */
+    private void handleYangVersionStatement() {
+
+        if (yangVersionStatementAlreadyHandled) {
+            return;
+        }
+
+        /*
+         * We try to find tokens as follows:
+         * - Second-last token is a string token with value 'yang-version'
+         * - Last token is a string token with value 1 or 1.0 or 1.1.
+         *
+         * Note: "1.0" is not a valid YANG version according to RFC. But what are the chances
+         * of somebody using it...
+         */
+
+        final int tokensSize = tokens.size();
+        if (tokensSize < 2) {
+            return;
+        }
+
+        final Token secondLastToken = tokens.get(tokensSize - 2);
+        if ((secondLastToken.type == TokenType.QUOTED_STRING || secondLastToken.type == TokenType.STRING) && secondLastToken.value
+                .equals("yang-version")) {
+
+            final Token lastToken = tokens.get(tokensSize - 1);
+            if ((lastToken.type == TokenType.QUOTED_STRING || lastToken.type == TokenType.STRING)) {
+                switch (lastToken.value) {
+                    case "1":
+                    case "1.0":
+                        stringParseRules = StringParseRules.YANG1;
+                        yangVersionStatementAlreadyHandled = true;
+                        break;
+                    case "1.1":
+                        stringParseRules = StringParseRules.YANG1DOT1;
+                        yangVersionStatementAlreadyHandled = true;
+                        break;
+                }
+            }
+        }
+    }
+
+    private void issueFinding(final ParserFindingType findingType, final String message) {
+        context.addFinding(new Finding(yangModel, currentLine, findingType.toString(), message));
+    }
+
+    /**
+     * The string parse rules have slightly changed between YANG 1 and YANG 1.1.
+     */
+    private enum StringParseRules {
+        YANG1,
+        YANG1DOT1
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/AugmentResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/AugmentResolver.java
new file mode 100644
index 0000000..1ef3e6a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/AugmentResolver.java
@@ -0,0 +1,446 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.resolvers;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.model.schema.SchemaProcessor;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YAugment;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIfFeature;
+import org.oran.smo.yangtools.parser.model.statements.yang.YStatus;
+import org.oran.smo.yangtools.parser.model.statements.yang.YWhen;
+import org.oran.smo.yangtools.parser.model.util.StringHelper;
+
+/**
+ * Resolves 'augment' statements that sit at the root of YAMs.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class AugmentResolver {
+
+    /**
+     * Resolves all augments by placing these into the correct part of the statement tree.
+     * The DOM element tree is not modified.
+     */
+    public static void resolveAugments(final ParserExecutionContext context, final Schema schema) {
+
+        boolean atLeastOneResolved = true;
+
+        @SuppressWarnings("unchecked") final List<YAugment> allAugments = (List<YAugment>) Helper
+                .findStatementsAtModuleRootInSchema(CY.STMT_AUGMENT, schema);
+
+        /*
+         * There are edge cases where an 'augment' refers to data nodes part of yet another 'augment'.
+         * This means that the resolution of an augment will fail unless another augment is resolved
+         * first. We handle this below by simply retrying.
+         */
+        while (atLeastOneResolved && !allAugments.isEmpty()) {
+
+            atLeastOneResolved = false;
+
+            for (int i = 0; i < allAugments.size();) {
+                try {
+                    final YAugment augment = allAugments.get(i);
+                    final boolean resolved = resolveAugment(context, augment, schema);
+                    /*
+                     * If the augments was resolved we remove it from the list - otherwise move to
+                     * the next one.
+                     */
+                    if (resolved) {
+                        atLeastOneResolved = true;
+                        allAugments.remove(i);
+                    } else {
+                        i++;
+                    }
+                } catch (final Exception ex) {
+                    // Swallow and move to next. Best effort here, keep trying other augments.
+                    i++;
+                }
+            }
+        }
+
+        /*
+         * If after all that there are still 'augment' statement left, then these are not resolvable.
+         */
+        for (final YAugment augment : allAugments) {
+            context.addFinding(new Finding(augment, ParserFindingType.P054_UNRESOLVABLE_PATH,
+                    "Path to schema node '" + augment
+                            .getAugmentTargetNode() + "', part of 'augment' statement, cannot be resolved."));
+        }
+    }
+
+    /**
+     * These are the statements that may be the target of an augmentation.
+     * <p>
+     * See RFC 7950, chapter 7.17
+     */
+    private static final Set<StatementModuleAndName> ALLOWABLE_TARGETS_OF_AUGMENT = new HashSet<>(Arrays.asList(
+            CY.STMT_CONTAINER, CY.STMT_LIST, CY.STMT_CHOICE, CY.STMT_CASE, CY.STMT_INPUT, CY.STMT_OUTPUT,
+            CY.STMT_NOTIFICATION));
+
+    /**
+     * These are the statements that can sit under the augment that we will merge-in under the target of the augmentation.
+     */
+    private static final Set<StatementModuleAndName> STATEMENTS_UNDER_AUGMENT_TO_HANDLE = new HashSet<>(Arrays.asList(
+            CY.STMT_ACTION, CY.STMT_ANYDATA, CY.STMT_ANYXML, CY.STMT_CASE, CY.STMT_CHOICE, CY.STMT_CONTAINER,
+            CY.STMT_LEAF_LIST, CY.STMT_LEAF, CY.STMT_LIST, CY.STMT_NOTIFICATION));
+
+    private static boolean resolveAugment(final ParserExecutionContext context, final YAugment augment,
+            final Schema schema) {
+
+        final String augmentTargetNode = augment.getAugmentTargetNode();
+        if (augmentTargetNode.isEmpty()) {
+            /*
+             * Pointless trying to resolve the path. No point issuing a finding either, a
+             * P015_INVALID_SYNTAX_IN_DOCUMENT would have been issued already. We return TRUE
+             * to pretend that we handled the augment as it makes no sense re-trying it over
+             * and over again.
+             */
+            return true;
+        }
+
+        final AbstractStatement augmentedStatement = findTargetSchemaNode(context, augment, schema);
+        if (augmentedStatement == null) {
+            /*
+             * Possibly not found because the schema node is missing since it will be
+             * merged-in by another augment statement that will be processed later on.
+             * So delay processing.
+             */
+            return false;
+        }
+
+        /*
+         * Check that the target (schema node) of the augments can actually be augmented.
+         */
+        if (!ALLOWABLE_TARGETS_OF_AUGMENT.contains(augmentedStatement.getStatementModuleAndName())) {
+            final String allowableTargetsAsString = StringHelper.toString(ALLOWABLE_TARGETS_OF_AUGMENT, "[", "]", ", ", "'",
+                    "'");
+            context.addFinding(new Finding(augment, ParserFindingType.P151_TARGET_NODE_CANNOT_BE_AUGMENTED,
+                    "Statement '" + augmentedStatement.getStatementModuleAndName() + "' pointed to by '" + augment
+                            .getAugmentTargetNode() + "' cannot be augmented (only statements " + allowableTargetsAsString + ")."));
+            /*
+             * We return TRUE to pretend that we handled the augment as it makes no sense
+             * re-trying it over and over again.
+             */
+            return true;
+        }
+
+        /*
+         * Special handling: if the target of the augmentation is a choice statement, then the RFC
+         * allows the shorthand notation to be used (i.e. not to augment with a 'case' but some
+         * other data node). Example:
+         *
+         * Augmenting module:
+         * ==================
+         *
+         * augment /abc:cont1/foo-choice {
+         *   container bar { ... }
+         * }
+         *
+         * Augmented module:
+         * =================
+         *
+         * container cont1 {
+         *   choice foo-choice {
+         *     ...
+         *   }
+         * }
+         *
+         * In the example, we would not want to directly place the container under the 'choice', as this
+         * may cause problems elsewhere - instead, we inject a 'case' statement, so we will end up with
+         * this here in the end which is cleaner:
+         *
+         * Augmenting module:
+         * ==================
+         *
+         * augment /abc:cont1/foo-choice {
+         *   case bar {
+         *     container bar { ... }
+         *   }
+         * }
+         */
+        if (augmentedStatement.is(CY.STMT_CHOICE)) {
+            SchemaProcessor.injectCaseForShorthandedStatements(augment);
+        }
+
+        /*
+         * Collect all the statements that will be moved under the augment's target node in a moment
+         * and mark these as having been augmented-in.
+         *
+         * Note: Any extensions sitting directly under the 'augment' statement are considered to
+         * relate to the 'augment' itself, i.e. will NOT be moved under the target of the augments. The
+         * RFC does not mention extensions at all when it comes to 'augments' (not even that is it
+         * 'undefined') so the assumption here is that extensions can only ever be "added" to other
+         * statements by using a "deviate add".
+         */
+        final List<AbstractStatement> statementsToMoveUnderTargetNode = augment.getChildren(
+                STATEMENTS_UNDER_AUGMENT_TO_HANDLE);
+
+        /*
+         * Check that whatever sits under the 'augment' statement is actually allowed under the
+         * target of the augment. We can use the CY class for this that gets us the allowed optional
+         * children.
+         */
+        final List<String> allowedOptionalChildren = CY.getOptionalMultipleChildren(augmentedStatement.getStatementName());
+
+        for (final AbstractStatement statementToMove : statementsToMoveUnderTargetNode) {
+            if (!allowedOptionalChildren.contains(statementToMove.getStatementName())) {
+                context.addFinding(new Finding(statementToMove, ParserFindingType.P151_TARGET_NODE_CANNOT_BE_AUGMENTED,
+                        "Statement '" + statementToMove.getStatementName() + "' is not allowed under '" + augmentedStatement
+                                .getStatementName() + "' and therefore cannot be augmented-in."));
+                /*
+                 * We return TRUE to pretend that we handled the augment as it makes no sense
+                 * re-trying it over and over again.
+                 */
+                return true;
+            }
+        }
+
+        /*
+         * 'when' and 'if-feature' must be cloned as well.
+         */
+        handleWhenAndIfFeature(augment, statementsToMoveUnderTargetNode);
+
+        /*
+         * Also inherit down the status if needs be.
+         */
+        handleStatus(augment, statementsToMoveUnderTargetNode);
+
+        /*
+         * Mark the children as having been augmented-in.
+         */
+        for (final AbstractStatement oneStatement : statementsToMoveUnderTargetNode) {
+            addAugmentingReference(oneStatement, augment);
+            addAugmentAppData(oneStatement, "statement augmented-in by 'augment' in " + StringHelper.getModuleLineString(
+                    augment));
+        }
+
+        /*
+         * Now take all of the statements that are under the augment statement and re-parent
+         * them under the target schema node of the augment. They retain their own namespace
+         * and prefix resolver. The DOM element tree is not modified.
+         */
+        augmentedStatement.addChildren(statementsToMoveUnderTargetNode);
+
+        return true;
+    }
+
+    /**
+     * Handles any 'when' or 'if-feature' under the augment.
+     */
+    private static void handleWhenAndIfFeature(final YAugment augment,
+            final List<AbstractStatement> statementsToMoveUnderTargetNode) {
+        /*
+         * If the 'augment' has a 'when' clause this gets cloned to all statements within
+         * the 'augment'. For example:
+         *
+         * Augmented module XYZ:
+         * =====================
+         *
+         * container foo {
+         *   leaf bar { type string; }
+         * }
+         *
+         * Augmenting module
+         * ==================
+         *
+         * augment /xyz:foo {
+         *   when "bar = 'Hello!'";
+         *
+         *   leaf rock { type int32; }
+         *   leaf roll { type int16; }
+         * }
+         *
+         * We can't just drop the 'when' statement, it must be retained in order to make the
+         * "rock" and "roll" leafs conditional. We want to be ending up with this here after
+         * the augments has been resolved:
+         *
+         * Augmented module XYZ:
+         * =====================
+         *
+         * container foo {
+         *   leaf bar { type string; }
+         *   leaf rock {
+         *     when "bar = 'Hello!'";
+         *     type int32;
+         *   }
+         *   leaf roll {
+         *     type int16;
+         *     when "bar = 'Hello!'";
+         *   }
+         * }
+         *
+         * Of course the issue now is that the 'when' statement inside the 'augment' refers to
+         * the augment's target node, which is the container "foo". When we clone the 'when'
+         * statement, we can only clone it to the *child* of the target node (here, the leafs).
+         * The path inside the 'when' statement is now wrong - it applies to the parent of the
+         * leafs. This is the reason why "appliesToParentSchemaNode" exists inside the YWhen class.
+         *
+         * So why not simply update the path of the 'when' statement? Because it is really hard
+         * to do that. In this example here, it would be easy - simply place a "../" in front of
+         * the path. However, the path could be really complex, involving multi-level navigation,
+         * predicates, etc., and to correctly clean that up is a real challenge.
+         *
+         * Also note that the "when" statement is *added* to the child statement of the augment,
+         * not *replaced*. That's a bit of a hack, as YANG only allows for a single occurrence
+         * of 'when' for statements. However, it could conceivably be the case that each of the
+         * statements amended thus has itself already a 'when' statement - and that must be
+         * retained, so using a *replace* would be wrong. (And that's the reason why various
+         * type-safe statement classes return 0..n 'when' statements, as opposed to 0..1.)
+         */
+        final YWhen whenUnderAugment = augment.getWhen();
+        if (whenUnderAugment != null) {
+            for (final AbstractStatement oneStatement : statementsToMoveUnderTargetNode) {
+                final YWhen clonedWhen = new YWhen(oneStatement, whenUnderAugment.getDomElement());
+                clonedWhen.cloneFrom(whenUnderAugment);
+                clonedWhen.setAppliesToParentSchemaNode();
+                addAugmentAppData(clonedWhen,
+                        "This 'when' statement has been inherited from the 'when' statement that sits under the augment in " + StringHelper
+                                .getModuleLineString(whenUnderAugment));
+            }
+        }
+
+        /*
+         * If the 'augment' has one or multiple 'if-feature' statements then these will be cloned
+         * as well, similar to how this is done above. Only we don't have to worry about a path
+         * here, we can simply clone the if-feature(s).
+         */
+        for (final YIfFeature ifFeature : augment.getIfFeatures()) {
+            for (final AbstractStatement oneStatement : statementsToMoveUnderTargetNode) {
+                final YIfFeature clonedIfFeature = new YIfFeature(oneStatement, ifFeature.getDomElement());
+                clonedIfFeature.cloneFrom(ifFeature);
+                addAugmentAppData(clonedIfFeature,
+                        "This 'if-feature' statement has been inherited from the 'if-feature' statement that sits under the augment in " + StringHelper
+                                .getModuleLineString(ifFeature));
+            }
+        }
+    }
+
+    /**
+     * Handle a possible 'status' statement under the 'augment'. We must do this here during the merge of
+     * the 'augment' content, as the 'augment' and its child 'status' will disappear from the schema tree,
+     * hence the 'status' will be lost. To retain the information, we must clone the 'status' statement
+     * into the contents of the 'augment'.
+     *
+     * Note there is some special handling - if the status is more restrictive under the augmented
+     * statement then this would not be replaced. For example, if the status is DEPRECATED under the
+     * augment, but it is explicitly OBSOLETE under a container being a child of the augment, this would
+     * not be updated.
+     */
+    private static void handleStatus(final YAugment augment,
+            final List<AbstractStatement> statementsToMoveUnderTargetNode) {
+
+        final YStatus statusUnderAugment = augment.getStatus();
+        if (statusUnderAugment == null) {
+            return;
+        }
+
+        for (final AbstractStatement oneStatement : statementsToMoveUnderTargetNode) {
+
+            final YStatus childExplicitStatus = oneStatement.getChild(CY.STMT_STATUS);
+            boolean clone = true;
+
+            if (childExplicitStatus == null) {
+                /*
+                 * There is no 'status' statement under the child, so then we will simply
+                 * clone down the parent 'status' in a moment.
+                 */
+            } else if (childExplicitStatus.getStatusOrder() >= statusUnderAugment.getStatusOrder()) {
+                /*
+                 * There is an explicit 'status' statement under the child. If the child 'status'
+                 * is more restrictive, or the same, as the 'status' of the parent we don't have
+                 * to do anything, i.e. don't clone.
+                 *
+                 * For example, child is DEPRECATED, parent is CURRENT - hence child is more
+                 * restrictive, so don't overwrite the 'status' (don't clone the parent 'status').
+                 */
+                clone = false;
+            }
+
+            if (clone) {
+                /*
+                 * Must clone, so first remove the 'status' statement under the child (if it exists).
+                 */
+                if (childExplicitStatus != null) {
+                    oneStatement.removeChild(childExplicitStatus);
+                }
+                /*
+                 * Now clone down the parent's (the augment's) 'status' into the child.
+                 */
+                final YStatus clonedStatus = new YStatus(oneStatement, statusUnderAugment.getDomElement());
+                clonedStatus.cloneFrom(statusUnderAugment);
+                addAugmentAppData(clonedStatus,
+                        "This 'status' statement has been inherited from the 'status' statement that sits under the augment in " + StringHelper
+                                .getModuleLineString(statusUnderAugment));
+            }
+        }
+    }
+
+    private static AbstractStatement findTargetSchemaNode(final ParserExecutionContext context, final YAugment augment,
+            final Schema schema) {
+
+        final AbstractStatement targetSchemaNode = Helper.findSchemaNode(context, augment, augment.getAugmentTargetNode(),
+                schema);
+        if (targetSchemaNode == null) {
+            return null;
+        }
+
+        /*
+         * Check whether the 'augment' and the target node sit inside the very same module. Poor modeling.
+         */
+        if (augment.getDomElement().getYangModel() == targetSchemaNode.getDomElement().getYangModel()) {
+            context.addFinding(new Finding(augment, ParserFindingType.P152_AUGMENT_TARGET_NODE_IN_SAME_MODULE,
+                    "Both 'augment' and it's target node sit in the same (sub-)module."));
+        }
+
+        return targetSchemaNode;
+    }
+
+    private static final String AUGMENTED_IN_REFERENCE = "AUGMENTED_IN_REFERENCE";
+
+    private static void addAugmentingReference(final AbstractStatement statementAugmentedIn, final YAugment origAugment) {
+        Helper.addAppDataListInfo(statementAugmentedIn, AUGMENTED_IN_REFERENCE, origAugment);
+    }
+
+    public static List<YAugment> getAugmentingReference(final AbstractStatement augmentedStatement) {
+        return Helper.getAppDataListInfo(augmentedStatement, AUGMENTED_IN_REFERENCE);
+    }
+
+    private static final String AUGMENTED_IN_INFO = "AUGMENTED_IN_INFO";
+
+    private static void addAugmentAppData(final AbstractStatement statement, final String info) {
+        Helper.addAppDataListInfo(statement, AUGMENTED_IN_INFO, info);
+    }
+
+    public static List<String> getAugmentedInInfosForStatement(final AbstractStatement statement) {
+        return Helper.getAppDataListInfo(statement, AUGMENTED_IN_INFO);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/DeviationResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/DeviationResolver.java
new file mode 100644
index 0000000..9eb097f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/DeviationResolver.java
@@ -0,0 +1,797 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.resolvers;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementFactory;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement.MaxCardinality;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDeviate;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDeviate.DeviateType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDeviation;
+import org.oran.smo.yangtools.parser.model.statements.yang.YMaxElements;
+import org.oran.smo.yangtools.parser.model.statements.yang.YMinElements;
+import org.oran.smo.yangtools.parser.model.statements.yang.YType;
+import org.oran.smo.yangtools.parser.model.util.StringHelper;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+/**
+ * Resolves 'deviation' statements.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class DeviationResolver {
+
+    /*
+     * A note on how properties and statements are handled. Some properties for data nodes *always* exist,
+     * even though their corresponding statements may not be listed in the YAM. For example, a data node
+     * will always have a 'config' property, which may or may not be explicitly set by means of a statement
+     * in the YAM. Technically, those properties cannot be ADDED or DELETED vi a deviate, only REPLACED.
+     * This is not clear in the spec; but was clarified as part of a discussion on the netmod mailing list:
+     * <p/>
+     * "I think that config, mandatory, type, max-elements, min-elements cannot be added or
+     *  deleted, only replaced, because they always exist."
+     * <p/>
+     * However, most YAM designers are not aware of this, and will use a deviate add/remove for these
+     * properties. To avoid noise we are lenient in the code and will allow any of deviate
+     * add/replace/remove for these properties.
+     */
+    private static final Set<StatementModuleAndName> PROPERTIES_THAT_ALWAYS_EXIST = new HashSet<>(Arrays.asList(
+            CY.STMT_CONFIG, CY.STMT_MANDATORY, CY.STMT_TYPE, CY.STMT_MAX_ELEMENTS, CY.STMT_MIN_ELEMENTS));
+
+    /**
+     * Resolves all deviates by applying the deviate operation against the respective target nodes.
+     */
+    public static void resolveDeviates(final ParserExecutionContext context, final Schema schema) {
+
+        @SuppressWarnings("unchecked") final List<YDeviation> allDeviations = (List<YDeviation>) Helper
+                .findStatementsAtModuleRootInSchema(CY.STMT_DEVIATION, schema);
+
+        /*
+         * This is done in a certain order, to facilitate multiple deviations affecting
+         * each other. E.g., a deviation may replace a property added by another deviation.
+         */
+        for (final YDeviation deviation : allDeviations) {
+            resolveDeviation(context, deviation, YDeviate.DeviateType.ADD, schema);
+        }
+        for (final YDeviation deviation : allDeviations) {
+            resolveDeviation(context, deviation, YDeviate.DeviateType.REPLACE, schema);
+        }
+        for (final YDeviation deviation : allDeviations) {
+            resolveDeviation(context, deviation, YDeviate.DeviateType.DELETE, schema);
+        }
+        for (final YDeviation deviation : allDeviations) {
+            resolveDeviation(context, deviation, YDeviate.DeviateType.NOT_SUPPORTED, schema);
+        }
+    }
+
+    private static void resolveDeviation(final ParserExecutionContext context, final YDeviation deviation,
+            final DeviateType deviateTypeToProcess, final Schema schema) {
+
+        final String deviationTargetNode = deviation.getDeviationTargetNode();
+        if (deviationTargetNode.isEmpty() || !deviationTargetNode.startsWith("/")) {
+            /*
+             * Pointless trying to resolve the path. No point issuing a finding either, a
+             * P015_INVALID_SYNTAX_IN_DOCUMENT would have been issued already.
+             */
+            return;
+        }
+
+        final AbstractStatement deviationTarget = findTargetSchemaNode(context, deviation, schema);
+        if (deviationTarget == null) {
+            /*
+             * It is possible that the deviation is trying to remove parts of the tree that
+             * have already been removed by a different deviation. If that's the case, we
+             * simply continue.
+             */
+            if (deviateTypeToProcess == DeviateType.NOT_SUPPORTED && deviationRefersToPreviouslyRemovedSchemaNode(context,
+                    deviation, schema)) {
+                /* do nothing */
+            } else {
+                context.addFinding(new Finding(deviation, ParserFindingType.P054_UNRESOLVABLE_PATH,
+                        "Path to schema node '" + deviation
+                                .getDeviationTargetNode() + "', part of 'deviation' statement, cannot be resolved."));
+            }
+
+            return;
+        }
+
+        for (final YDeviate deviate : deviation.getDeviates()) {
+            if (deviateTypeToProcess == deviate.getDeviateType()) {
+                handleDeviate(context, deviate, deviationTarget);
+            }
+        }
+    }
+
+    private static void handleDeviate(final ParserExecutionContext context, final YDeviate deviate,
+            final AbstractStatement deviationTarget) {
+
+        if (deviate.getDeviateType() == DeviateType.ADD || deviate.getDeviateType() == DeviateType.REPLACE) {
+            /*
+             * Run a check first to see whether the statements underneath the 'deviate add/replace' are
+             * actually allowed as children of the statement that is the target of the deviation. The RFC
+             * says that handling of extensions is not defined; we assume that any extension listed under
+             * a deviate add/replace is meant to be handled such.
+             */
+            final List<String> statementsAllowedAsChild = deviationTarget.getStatementsAllowedAsChild();
+            boolean illegalChildFound = false;
+
+            for (final AbstractStatement childOfDeviate : deviate.getChildStatements()) {
+                if (!childOfDeviate.isExtension() && !statementsAllowedAsChild.contains(childOfDeviate.getDomElement()
+                        .getName())) {
+                    illegalChildFound = true;
+                    context.addFinding(new Finding(childOfDeviate, ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT,
+                            "Statement '" + childOfDeviate
+                                    .getStatementName() + "' not a valid child statement of deviated statement '" + deviationTarget
+                                            .getStatementName()));
+                }
+                if (childOfDeviate.isExtension() && !((ExtensionStatement) childOfDeviate).canBeChildOf(deviationTarget
+                        .getStatementModuleAndName())) {
+                    illegalChildFound = true;
+                    context.addFinding(new Finding(childOfDeviate, ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT,
+                            "Extension '" + childOfDeviate
+                                    .getStatementName() + "' not a valid child statement of deviated statement '" + deviationTarget
+                                            .getStatementName()));
+                }
+            }
+
+            if (illegalChildFound) {
+                addDeviateInfo(deviate, "'deviate' has not been applied due to findings.");
+                return;
+            }
+        }
+
+        /*
+         * Now manipulate the tree in accordance with the deviate operation.
+         */
+        switch (deviate.getDeviateType()) {
+            case NOT_SUPPORTED:
+                handleDeviateNotSupported(deviationTarget, deviate);
+                break;
+            case ADD:
+                handleDeviateAdd(context, deviationTarget, deviate);
+                break;
+            case DELETE:
+                handleDeviateDelete(context, deviationTarget, deviate);
+                break;
+            case REPLACE:
+                handleDeviateReplace(context, deviationTarget, deviate);
+                break;
+        }
+
+        addDeviateInfo(deviate, "'deviate' has been applied.");
+    }
+
+    private static void handleDeviateDelete(final ParserExecutionContext context, final AbstractStatement deviationTarget,
+            final YDeviate deviate) {
+        /*
+         * From the RFC:
+         *
+         * The argument "delete" deletes properties from the target node. The
+         * properties to delete are identified by substatements to the "delete"
+         * statement. The substatement’s keyword MUST match a corresponding
+         * keyword in the target node, and the argument’s string MUST be equal
+         * to the corresponding keyword’s argument string in the target node.
+         */
+
+        /*
+         * So we need to get the child statements of the "deviate delete" statement,
+         * and try to match these up against the child statements of the deviated statement.
+         * "Match up" means the statement type must be the exact same, and the statements
+         * value must be the exact same.
+         */
+        for (final AbstractStatement childOfDeviate : deviate.getChildStatements()) {
+            deleteStatementFromUnderDeviatedStatement(context, deviationTarget, childOfDeviate, deviate);
+        }
+    }
+
+    private static void deleteStatementFromUnderDeviatedStatement(final ParserExecutionContext context,
+            final AbstractStatement deviationTarget, final AbstractStatement statementToDelete, final YDeviate deviate) {
+
+        boolean matchFound = false;
+        final List<? extends AbstractStatement> statementsOfTypeUnderDeviationTarget = deviationTarget.getChildren(
+                statementToDelete.getStatementModuleAndName());
+
+        for (final AbstractStatement childOfDeviationTarget : statementsOfTypeUnderDeviationTarget) {
+            if (statementValuesAreSame(statementToDelete, childOfDeviationTarget)) {
+                /*
+                 * We do a check first to see how many instances of the statement would be left after we delete the statement.
+                 * If 0, and the statement is mandatory, that's a finding. We ignore extensions, as extensions (by definition)
+                 * can never be mandatory.
+                 */
+                final int newOccurenceCount = statementsOfTypeUnderDeviationTarget.size() - 1;
+                if (newOccurenceCount == 0 && !statementToDelete.isExtension()) {
+                    final String statementName = statementToDelete.getDomElement().getName();
+                    if (deviationTarget.getMandatorySingleChildStatementNames().contains(statementName) || deviationTarget
+                            .getMandatoryMultipleChildStatementNames().contains(statementName)) {
+                        context.addFinding(new Finding(statementToDelete,
+                                ParserFindingType.P166_DEVIATE_RESULTS_IN_CHILD_CARDINALITY_VIOLATION,
+                                "Cannot 'deviate delete' this statement as at least a single '" + statementToDelete
+                                        .getStatementName() + "' statement is required under deviated statement '" + deviationTarget
+                                                .getStatementName() + "'."));
+                        return;
+                    }
+                }
+
+                if (statementHasBeenAddedInByDeviateAdd(childOfDeviationTarget)) {
+                    context.addFinding(new Finding(statementToDelete,
+                            ParserFindingType.P165_DEVIATE_DELETE_OF_DEVIATED_STATEMENT, "Deletes a '" + statementToDelete
+                                    .getStatementName() + "' statement that was previously added by a separate 'deviate add' operation."));
+                } else if (statementHasBeenAddedInByDeviateReplace(childOfDeviationTarget)) {
+                    context.addFinding(new Finding(statementToDelete,
+                            ParserFindingType.P165_DEVIATE_DELETE_OF_DEVIATED_STATEMENT, "Deletes a '" + statementToDelete
+                                    .getStatementName() + "' statement that was previously replaced by a separate 'deviate replace' operation."));
+                }
+
+                addDeviationHistory(deviationTarget, DeviationHistory.delete(childOfDeviationTarget, statementToDelete));
+                addDeviateInfo(deviationTarget, "statement " + childOfDeviationTarget.getDomElement()
+                        .getNameValue() + " in " + StringHelper.getModuleLineString(
+                                childOfDeviationTarget) + " deleted by 'deviate delete' in " + StringHelper
+                                        .getModuleLineString(statementToDelete));
+
+                deviationTarget.removeChild(childOfDeviationTarget);
+
+                matchFound = true;
+                break;
+            }
+        }
+
+        if (!matchFound) {
+            context.addFinding(new Finding(statementToDelete, ParserFindingType.P161_INVALID_DEVIATE_OPERATION,
+                    "Cannot 'deviate delete' this statement as the statement does not exist under the deviated statement."));
+        }
+    }
+
+    private static boolean statementValuesAreSame(final AbstractStatement statement1, final AbstractStatement statement2) {
+        final String value1 = statement1.getDomElement().getValue();
+        final String value2 = statement2.getDomElement().getValue();
+        return Objects.equals(value1, value2);
+    }
+
+    private static void handleDeviateAdd(final ParserExecutionContext context, final AbstractStatement deviationTarget,
+            final YDeviate deviate) {
+        /*
+         * From the RFC:
+         *
+         * "The argument "add" adds properties to the target node. The
+         * properties to add are identified by substatements to the "deviate"
+         * statement. If a property can only appear once, the property MUST NOT
+         * exist in the target node."
+         */
+
+        /*
+         * The following can only exists once, hence MUST NOT already exist under the deviated schema node.
+         */
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_CONFIG);
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MANDATORY);
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MAX_ELEMENTS);
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MIN_ELEMENTS);
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_TYPE);
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_UNITS);
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_DEFAULT);
+        /*
+         * The following can exist more than once, hence there can be statements under the deviated statement already.
+         */
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MUST);
+        addUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_UNIQUE);
+
+        /*
+         * Also make sure to deviate-in extensions. No special handling applies to these, as the
+         * RFC stipulates this to be extension-specific.
+         */
+        handleDeviateAddForExtensions(context, deviationTarget, deviate);
+    }
+
+    private static void handleDeviateAddForExtensions(final ParserExecutionContext context,
+            final AbstractStatement deviatedStatement, final YDeviate deviate) {
+        /*
+         * For extensions we don't know upfront what the exact module/statement names are.
+         * We must figure these out first, before we start adding these:
+         */
+        final Set<StatementModuleAndName> extensionModulesAndNames = deviate.getExtensionChildStatements().stream().map(
+                ext -> ext.getStatementModuleAndName()).collect(Collectors.toSet());
+
+        extensionModulesAndNames.forEach(sman -> addUnderDeviatedStatement(context, deviatedStatement, deviate, sman));
+    }
+
+    /**
+     * Given a statement type, verifies that the deviated statement does not already have as child this
+     * statement, and assuming that this is not the case, adds it / them.
+     * <p>
+     * Note: Will gracefully handle a 'deviate add' of properties, i.e. allow these, although according
+     * to RFC these should only ever be replaced.
+     */
+    private static <T extends AbstractStatement> void addUnderDeviatedStatement(final ParserExecutionContext context,
+            final AbstractStatement deviationTarget, final YDeviate deviate, final StatementModuleAndName soughtChildType) {
+
+        /*
+         * Get the instances of the statement type.
+         */
+        final List<T> statementsOfTypeUnderDeviate = deviate.getChildren(soughtChildType);
+        final List<T> statementsOfTypeUnderTargetStatement = deviationTarget.getChildren(soughtChildType);
+
+        if (statementsOfTypeUnderDeviate.isEmpty()) {
+            return;
+        }
+
+        /*
+         * Figure out whether there can be multiple instances of the statement under the target.
+         */
+        final AbstractStatement oneChildUnderDeviate = deviate.getChild(soughtChildType);
+        boolean canHaveMultiple;
+
+        if (oneChildUnderDeviate.isExtension()) {
+            canHaveMultiple = ((ExtensionStatement) oneChildUnderDeviate)
+                    .getMaxCardinalityUnderParent() == MaxCardinality.MULTIPLE;
+        } else {
+            final String coreStatementName = soughtChildType.getStatementName();
+            canHaveMultiple = deviationTarget.getMandatoryMultipleChildStatementNames().contains(
+                    coreStatementName) || deviationTarget.getOptionalMultipleChildStatementNames().contains(
+                            coreStatementName);
+        }
+
+        if (!statementsOfTypeUnderTargetStatement.isEmpty() && !canHaveMultiple) {
+            /*
+             * A statement of this type already exists under the target, and there cannot be more than one.
+             */
+            for (final AbstractStatement statementUnderDeviate : statementsOfTypeUnderDeviate) {
+                context.addFinding(new Finding(statementUnderDeviate, ParserFindingType.P161_INVALID_DEVIATE_OPERATION,
+                        "Cannot 'deviate add' statement '" + statementUnderDeviate
+                                .getStatementName() + "' as it already exists under the deviated statement. Use a 'deviate replace' instead."));
+            }
+            return;
+        }
+
+        /*
+         * Check whether the max cardinality would be violated by adding the statements.
+         */
+        final int newCount = statementsOfTypeUnderDeviate.size() + statementsOfTypeUnderTargetStatement.size();
+        if (newCount > 1 && !canHaveMultiple) {
+            context.addFinding(new Finding(statementsOfTypeUnderDeviate.get(0),
+                    ParserFindingType.P166_DEVIATE_RESULTS_IN_CHILD_CARDINALITY_VIOLATION,
+                    "Cannot 'deviate add' this statement as at most one '" + statementsOfTypeUnderDeviate.get(0)
+                            .getStatementName() + "' statement is allowed under under '" + deviationTarget
+                                    .getStatementName() + "'."));
+            return;
+        }
+
+        /*
+         * Good - either a statement of this type does not already exist under the deviation target, or
+         * this fact doesn't matter. Then simply clone it so that it ends up under the deviated statement.
+         *
+         * Really, cloning is not necessary - we could simply move the statement. However, if there is
+         * downstream tooling that visualizes the schema it would be nice to retain the original content
+         * of the deviation so that a user can see it. Also useful for debugging.
+         */
+        for (final T statementUnderDeviate : statementsOfTypeUnderDeviate) {
+            final T clonedStatementPlacedUnderDeviationTarget = StatementFactory.cloneYangStatement(statementUnderDeviate,
+                    deviationTarget);
+            clonedStatementPlacedUnderDeviationTarget.cloneFrom(statementUnderDeviate);
+
+            addDeviationHistory(clonedStatementPlacedUnderDeviationTarget, DeviationHistory.add(statementUnderDeviate));
+            addDeviateInfo(clonedStatementPlacedUnderDeviationTarget,
+                    "statement added by 'deviate add' in module " + StringHelper.getModuleLineString(
+                            statementUnderDeviate));
+        }
+    }
+
+    private static void handleDeviateReplace(final ParserExecutionContext context, final AbstractStatement deviationTarget,
+            final YDeviate deviate) {
+        /*
+         * From the RFC:
+         *
+         * The argument "replace" replaces properties of the target node. The
+         * properties to replace are identified by substatements to the
+         * "deviate" statement. The properties to replace MUST exist in the
+         * target node.
+         */
+
+        /*
+         * Before we do the actual replacement, we check for shrinking of boundaries.
+         */
+        checkForNarrowedMinMaxElements(context, deviationTarget.getChild(CY.STMT_MIN_ELEMENTS), deviate.getMinElements(),
+                deviationTarget.getChild(CY.STMT_MAX_ELEMENTS), deviate.getMaxElements());
+        /*
+         * ...and check for data type replacements...
+         */
+        checkForReplacedDataType(context, deviationTarget.getChild(CY.STMT_TYPE), deviate.getType());
+
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_CONFIG);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_DEFAULT);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MANDATORY);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MAX_ELEMENTS);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MIN_ELEMENTS);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_MUST);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_TYPE);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_UNIQUE);
+        replaceUnderDeviatedStatement(context, deviationTarget, deviate, CY.STMT_UNITS);
+
+        handleReplaceDeviateForExtensions(context, deviationTarget, deviate);
+    }
+
+    private static void handleReplaceDeviateForExtensions(final ParserExecutionContext context,
+            final AbstractStatement deviatedStatement, final YDeviate deviate) {
+        /*
+         * For extensions we don't know upfront what the exact module/statement names are.
+         * We must figure these out first, before we start replacing these:
+         */
+        final Set<StatementModuleAndName> extensionModulesAndNames = deviate.getExtensionChildStatements().stream().map(
+                ext -> ext.getStatementModuleAndName()).collect(Collectors.toSet());
+
+        extensionModulesAndNames.forEach(sman -> replaceUnderDeviatedStatement(context, deviatedStatement, deviate, sman));
+    }
+
+    private static void checkForReplacedDataType(final ParserExecutionContext context, final YType oldType,
+            final YType newType) {
+
+        if (newType == null) {
+            return;
+        }
+
+        final Set<String> oldDataTypes = new HashSet<>();
+        final Set<String> newDataTypes = new HashSet<>();
+
+        collectDataTypes(oldDataTypes, oldType);
+        collectDataTypes(newDataTypes, newType);
+
+        if (!oldDataTypes.equals(newDataTypes)) {
+            context.addFinding(new Finding(newType, ParserFindingType.P057_DATA_TYPE_CHANGED,
+                    "Data type has changed from " + oldDataTypes.toString() + " to " + newDataTypes.toString() + "."));
+        }
+    }
+
+    private static void collectDataTypes(final Set<String> dataTypes, final YType type) {
+        if (type.getDataType().equals("union")) {
+            for (final YType unionMemberType : type.getTypes()) {
+                collectDataTypes(dataTypes, unionMemberType);
+            }
+        } else {
+            dataTypes.add(type.getDataType());
+        }
+    }
+
+    private static void checkForNarrowedMinMaxElements(final ParserExecutionContext context,
+            final YMinElements oldMinElements, final YMinElements newMinElements, final YMaxElements oldMaxElements,
+            final YMaxElements newMaxElements) {
+
+        final long oldMinValue = oldMinElements == null ? 0L : oldMinElements.getMinValue();
+        final long newMinValue = newMinElements == null ? 0L : newMinElements.getMinValue();
+
+        if (newMinValue > oldMinValue) {
+            context.addFinding(new Finding(newMinElements, ParserFindingType.P056_CONSTRAINT_NARROWED,
+                    "Replacement raises min-elements boundary from '" + oldMinValue + "' to '" + newMinValue + "'."));
+        }
+
+        final boolean oldMaxIsUnbounded = oldMaxElements == null ? true : oldMaxElements.isUnbounded();
+        final boolean newMaxIsUnbounded = newMaxElements == null ? true : newMaxElements.isUnbounded();
+        final long oldMaxValue = oldMaxIsUnbounded ? 0L : oldMaxElements.getMaxValue();
+        final long newMaxValue = newMaxIsUnbounded ? 0L : newMaxElements.getMaxValue();
+
+        if (oldMaxIsUnbounded && !newMaxIsUnbounded) {
+            context.addFinding(new Finding(newMaxElements, ParserFindingType.P056_CONSTRAINT_NARROWED,
+                    "Replacement lowers max-elements boundary from 'unbounded' to '" + newMaxValue + "'."));
+        } else if (!oldMaxIsUnbounded && !newMaxIsUnbounded && newMaxValue < oldMaxValue) {
+            context.addFinding(new Finding(newMaxElements, ParserFindingType.P056_CONSTRAINT_NARROWED,
+                    "Replacement lowers max-elements boundary from '" + oldMaxValue + "' to '" + newMaxValue + "'."));
+        }
+    }
+
+    /**
+     * Given a statement type, verifies that the deviated statement *does* have as child this
+     * statement, and assuming that this is the case, removes the original child and replaces
+     * it with the deviate's child. Note: exception is made for properties that *always* exist.
+     */
+    @SuppressWarnings("unchecked")
+    private static <T extends AbstractStatement> void replaceUnderDeviatedStatement(final ParserExecutionContext context,
+            final AbstractStatement deviationTarget, final YDeviate deviate, final StatementModuleAndName soughtChildType) {
+
+        /*
+         * Establish whether an instance of the supplied class exists under the "deviate" and/or under the deviated statement.
+         */
+        final List<T> statementsOfTypeUnderDeviate = deviate.getChildren(soughtChildType);
+        final List<T> statementsOfTypeUnderDeviationTarget = deviationTarget.getChildren(soughtChildType);
+
+        if (statementsOfTypeUnderDeviate.isEmpty()) {
+            return;
+        }
+
+        final StatementModuleAndName statementModuleAndName = statementsOfTypeUnderDeviate.get(0)
+                .getStatementModuleAndName();
+
+        if (statementsOfTypeUnderDeviationTarget.isEmpty() && !PROPERTIES_THAT_ALWAYS_EXIST.contains(
+                statementModuleAndName)) {
+            context.addFinding(new Finding(statementsOfTypeUnderDeviate.get(0),
+                    ParserFindingType.P161_INVALID_DEVIATE_OPERATION,
+                    "Cannot 'deviate replace' statement '" + statementsOfTypeUnderDeviate.get(0)
+                            .getStatementName() + "' as it does not exist under the deviated statement."));
+            return;
+        }
+
+        /*
+         * Check whether cardinality would be violated by doing the replace.
+         */
+        final int newOccurencesOfStatementType = statementsOfTypeUnderDeviate.size();
+        if (statementModuleAndName.isYangCoreStatement() && newOccurencesOfStatementType > 1) {
+            if (!deviationTarget.getMandatoryMultipleChildStatementNames().contains(statementModuleAndName
+                    .getStatementName()) && !deviationTarget.getOptionalMultipleChildStatementNames().contains(
+                            statementModuleAndName.getStatementName())) {
+                context.addFinding(new Finding(statementsOfTypeUnderDeviate.get(0),
+                        ParserFindingType.P166_DEVIATE_RESULTS_IN_CHILD_CARDINALITY_VIOLATION,
+                        "Cannot 'deviate replace' this statement as at most one '" + statementModuleAndName
+                                .getStatementName() + "' statement is allowed under '" + deviationTarget
+                                        .getStatementName() + "'."));
+                return;
+            }
+        }
+
+        /*
+         * Exists in both, so remove the original statement(s), and add the statements under deviate. We do a
+         * quick check first, though, to see whether the statements that are being replaced likewise have been
+         * deviated-in previously.
+         */
+        boolean replacingPreviouslyReplaced = false;
+        boolean replacingPreviouslyAdded = false;
+
+        for (final T oneReplacedStatement : statementsOfTypeUnderDeviationTarget) {
+            if (statementHasBeenAddedInByDeviateReplace(oneReplacedStatement)) {
+                replacingPreviouslyReplaced = true;
+            } else if (statementHasBeenAddedInByDeviateAdd(oneReplacedStatement)) {
+                replacingPreviouslyAdded = true;
+            }
+
+            addDeviateInfo(deviationTarget, "Previous statement/property " + oneReplacedStatement.getDomElement()
+                    .getNameValue() + " in " + StringHelper.getModuleLineString(
+                            deviationTarget) + " replaced by 'deviate replace' in " + StringHelper.getModuleLineString(
+                                    deviate));
+        }
+
+        deviationTarget.removeChildren(statementsOfTypeUnderDeviationTarget);
+
+        for (final T statementUnderDeviate : statementsOfTypeUnderDeviate) {
+
+            if (replacingPreviouslyReplaced) {
+                context.addFinding(new Finding(statementUnderDeviate,
+                        ParserFindingType.P163_AMBIGUOUS_DEVIATE_REPLACE_OF_SAME_STATEMENT,
+                        "Replaces another '" + statementUnderDeviate
+                                .getStatementName() + "' statement that has replaced the original statement by a separate 'deviate replace' operation."));
+            } else if (replacingPreviouslyAdded) {
+                context.addFinding(new Finding(statementUnderDeviate,
+                        ParserFindingType.P164_DEVIATE_REPLACE_OF_DEVIATE_ADDED_STATEMENT,
+                        "Replaces another '" + statementUnderDeviate
+                                .getStatementName() + "' statement that has been previously added by a separate 'deviate add' operation."));
+            }
+
+            final T clonedStatementPlacedUnderDeviationTarget = StatementFactory.cloneYangStatement(statementUnderDeviate,
+                    deviationTarget);
+            clonedStatementPlacedUnderDeviationTarget.cloneFrom(statementUnderDeviate);
+
+            addDeviationHistory(clonedStatementPlacedUnderDeviationTarget, DeviationHistory.replace(
+                    (List<AbstractStatement>) statementsOfTypeUnderDeviationTarget, statementUnderDeviate));
+            addDeviateInfo(clonedStatementPlacedUnderDeviationTarget,
+                    "Replacement for previous statement or (possibly implicit) property, replaced by 'deviate replace' in " + StringHelper
+                            .getModuleLineString(statementUnderDeviate));
+        }
+    }
+
+    private static void handleDeviateNotSupported(final AbstractStatement deviationTarget, final YDeviate deviate) {
+
+        /*
+         * We add some additional information to the parent that will help the user to make sense of
+         * what has happened. We also keep a record of the statement that we have removed. This is useful
+         * later on if there is another statement referring to the deleted statement, because then we can
+         * be smart about it and not issue findings.
+         */
+        addDeviationHistory(deviationTarget.getParentStatement(), DeviationHistory.notSupported(deviationTarget, deviate));
+        addDeviateInfo(deviationTarget.getParentStatement(), "Statement " + deviationTarget.getDomElement()
+                .getNameValue() + " in " + StringHelper.getModuleLineString(
+                        deviationTarget) + " marked as 'not-supported' by deviation in " + StringHelper.getModuleLineString(
+                                deviate) + " and thus removed.");
+
+        /*
+         * That's easy - the schema node (the found statement) is not supported, so simply remove it.
+         */
+        deviationTarget.getParentStatement().removeChild(deviationTarget);
+    }
+
+    /**
+     * Finds the schema node that is being deviated.
+     */
+    private static AbstractStatement findTargetSchemaNode(final ParserExecutionContext context, final YDeviation deviation,
+            final Schema schema) {
+
+        final AbstractStatement targetSchemaNode = Helper.findSchemaNode(context, deviation, deviation
+                .getDeviationTargetNode(), schema);
+        if (targetSchemaNode == null) {
+            return null;
+        }
+
+        /*
+         * Check whether they both sit inside the very same module
+         */
+        if (deviation.getDomElement().getYangModel() == targetSchemaNode.getDomElement().getYangModel()) {
+            context.addFinding(new Finding(deviation, ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE,
+                    "Both 'deviation' and it's target node sit in the same (sub-)module."));
+        }
+
+        return targetSchemaNode;
+    }
+
+    /**
+     * We try to figure out whether a 'deviate not-supported' refers to something in the
+     * tree that has previously been removed. That's a bit involved, but well possible...
+     */
+    private static boolean deviationRefersToPreviouslyRemovedSchemaNode(final ParserExecutionContext context,
+            final YDeviation deviation, final Schema schema) {
+
+        final String deviationTargetNode = deviation.getDeviationTargetNode();
+        if (deviationTargetNode.isEmpty() || !deviationTargetNode.startsWith("/")) {
+            /*
+             * Pointless trying to resolve the path. No point issuing a finding either, a
+             * P015_INVALID_SYNTAX_IN_DOCUMENT would have been issued already.
+             */
+            return false;
+        }
+
+        /*
+         * We split the path, and get the starting point for navigation.
+         */
+        final String[] identifierParts = Helper.getIdentifierParts(true, deviationTargetNode);
+        AbstractStatement traversalStatement = Helper.findStartingSchemaNode(context, deviation, true, identifierParts[0],
+                schema);
+        if (traversalStatement == null) {
+            return false;
+        }
+
+        /*
+         * Go down the tree until we get stuck...
+         */
+        for (final String possiblyPrefixedIdentifier : identifierParts) {
+            final AbstractStatement foundChildStatement = Helper.findChildSchemaNode(context, traversalStatement,
+                    possiblyPrefixedIdentifier, deviation);
+            if (foundChildStatement == null) {
+                /*
+                 * OK, so this is the point where we could not follow the path anymore. We extract the
+                 * identifier that we were actually looking for, and check whether such an identifier
+                 * has been marked as previously not-supported.
+                 */
+                final String unprefixedIdentifierSought = QNameHelper.extractName(possiblyPrefixedIdentifier);
+
+                final List<DeviationHistory> removedStatementsHistory = getDeviationHistory(traversalStatement).stream()
+                        .filter(dh -> dh.deviateType == DeviateType.NOT_SUPPORTED).collect(Collectors.toList());
+                for (final DeviationHistory history : removedStatementsHistory) {
+                    if (unprefixedIdentifierSought.equals(history.deviatedStatements.get(0).getStatementIdentifier())) {
+                        return true;
+                    }
+                }
+
+                /*
+                 * There is nothing in the history, so truly not found.
+                 */
+                return false;
+            }
+
+            traversalStatement = foundChildStatement;
+        }
+
+        /*
+         * We really should never ever be getting here.
+         */
+        return false;
+    }
+
+    private static final String DEVIATION_INFO = "DEVIATION_INFO";
+
+    private static void addDeviateInfo(final AbstractStatement statement, final String info) {
+        Helper.addAppDataListInfo(statement, DEVIATION_INFO, info);
+    }
+
+    public static List<String> getDeviationInfosForStatement(final AbstractStatement statement) {
+        return Helper.getAppDataListInfo(statement, DEVIATION_INFO);
+    }
+
+    private static final String DEVIATION_HISTORY = "DEVIATION_HISTORY";
+
+    private static void addDeviationHistory(final AbstractStatement onStatement, final DeviationHistory deviationHistory) {
+        Helper.addAppDataListInfo(onStatement, DEVIATION_HISTORY, deviationHistory);
+    }
+
+    public static List<DeviationHistory> getDeviationHistory(final AbstractStatement onStatement) {
+        return Helper.getAppDataListInfo(onStatement, DEVIATION_HISTORY);
+    }
+
+    private static boolean statementHasBeenAddedInByDeviateAdd(final AbstractStatement statement) {
+        final List<DeviationHistory> deviationHistory = getDeviationHistory(statement);
+        return deviationHistory.size() > 0 && deviationHistory.get(0).deviateType == DeviateType.ADD;
+    }
+
+    private static boolean statementHasBeenAddedInByDeviateReplace(final AbstractStatement statement) {
+        final List<DeviationHistory> deviationHistory = getDeviationHistory(statement);
+        return deviationHistory.size() > 0 && deviationHistory.get(0).deviateType == DeviateType.REPLACE;
+    }
+
+    public static class DeviationHistory {
+
+        static DeviationHistory notSupported(final AbstractStatement notSupportedChild, final YDeviate yDeviate) {
+            return new DeviationHistory(YDeviate.DeviateType.NOT_SUPPORTED, Collections.singletonList(notSupportedChild),
+                    yDeviate);
+        }
+
+        static DeviationHistory delete(final AbstractStatement deletedChild, final AbstractStatement deviatingStatement) {
+            return new DeviationHistory(YDeviate.DeviateType.DELETE, Collections.singletonList(deletedChild),
+                    deviatingStatement);
+        }
+
+        static DeviationHistory add(final AbstractStatement deviatingStatement) {
+            return new DeviationHistory(YDeviate.DeviateType.ADD, Collections.<AbstractStatement> emptyList(),
+                    deviatingStatement);
+        }
+
+        static DeviationHistory replace(final List<AbstractStatement> replacedStatements,
+                final AbstractStatement deviatingStatement) {
+            return new DeviationHistory(YDeviate.DeviateType.REPLACE, replacedStatements, deviatingStatement);
+        }
+
+        /**
+         * The type of deviation applied.
+         */
+        public final YDeviate.DeviateType deviateType;
+
+        /**
+         * The statement that was deviated. This will be:
+         * <p>
+         * not-supported: The single statement (which will be a data node) that was removed.
+         * delete: The single statement (typically a property) that was removed.
+         * add: empty, no content.
+         * replace: The statements (0..n) that were replaced.
+         *
+         * that were added, removed, or were changed. If the statements were
+         * removed, the statement will not have a parent anymore.
+         */
+        public final List<AbstractStatement> deviatedStatements;
+
+        /**
+         * The statement that performed the deviation, i.e. the 'deviate' statement itself,
+         * or a child statement of 'deviate'.
+         */
+        public final AbstractStatement deviatingStatement;
+
+        private DeviationHistory(final DeviateType deviateType, final List<AbstractStatement> deviatedStatements,
+                final AbstractStatement deviatingStatement) {
+            this.deviateType = deviateType;
+            this.deviatedStatements = deviatedStatements;
+            this.deviatingStatement = deviatingStatement;
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/Helper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/Helper.java
new file mode 100644
index 0000000..001706a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/Helper.java
@@ -0,0 +1,534 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.resolvers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.YangModelRoot;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+/**
+ * Utility class for navigation
+ *
+ * @author Mark Hollmann
+ */
+public abstract class Helper {
+
+    /**
+     * Finds a schema node in the schema tree. Returns null if not found.
+     *
+     * The schema node identifier supplied may be absolute or relative. If it is absolute, navigation will
+     * start at the root of the module that owns the original statement, or the module as indicated by the
+     * prefix. If it is relative, navigation will start at the original statement.
+     *
+     * @param originalStatement
+     *     The statement containing the schema node identifier (e.g. an augment statement)
+     * @param schemaNodeIdentifier
+     *     An absolute or relative schema node identifier.
+     */
+    public static AbstractStatement findSchemaNode(final ParserExecutionContext context,
+            final AbstractStatement originalStatement, final String schemaNodeIdentifier, final Schema schema) {
+
+        /*
+         * For navigation it will be important in a moment if the schema node identifier is
+         * absolute (at root) or relative (starts somewhere in the tree).
+         */
+        final boolean isAbsoluteSchemaNodeIdentifier = schemaNodeIdentifier.startsWith("/");
+
+        /*
+         * Quickly split them...
+         */
+        final String[] identifierParts = getIdentifierParts(isAbsoluteSchemaNodeIdentifier, schemaNodeIdentifier);
+
+        /*
+         * This is the starting point of our navigation. Might be at root of the same module
+         * as the original statement, or root of a different module, or the original statement
+         * itself.
+         */
+        AbstractStatement traversalStatement = findStartingSchemaNode(context, originalStatement,
+                isAbsoluteSchemaNodeIdentifier, identifierParts[0], schema);
+        if (traversalStatement == null) {
+            return null;
+        }
+
+        /*
+         * And now we simply follow the identifiers down the tree.
+         */
+        for (final String identifier : identifierParts) {
+
+            final AbstractStatement foundChildStatement = findChildSchemaNode(context, traversalStatement, identifier,
+                    originalStatement);
+            if (foundChildStatement == null) {
+                /*
+                 * It is well possible that a schema node is not found because it hasn't been augmented-in
+                 * yet, or already deviated-out. Issuing a finding here would therefore not be such a good
+                 * idea, as it would be confusing (and potentially wrong).
+                 */
+                return null;
+            }
+
+            traversalStatement = foundChildStatement;
+        }
+
+        return traversalStatement;
+    }
+
+    /**
+     * Splits the schema node identifier into individual parts.
+     */
+    public static String[] getIdentifierParts(final boolean isAbsoluteSchemaNodeIdentifier,
+            final String schemaNodeIdentifier) {
+
+        final String relativeSchemaNodeIdentifier = isAbsoluteSchemaNodeIdentifier ?
+                schemaNodeIdentifier.substring(1) :
+                schemaNodeIdentifier;
+
+        /*
+         * The relative schema node identifier is split up into parts. For example, path
+         * "if:interfaces/if:interface/ethxipos:ethernet/l2vlanxipos:dot1q/l2vlanxipos:pvc"
+         * is split up into:
+         *
+         * if:interfaces
+         * if:interface
+         * ethxipos:ethernet
+         * l2vlanxipos:dot1q
+         * l2vlanxipos:pvc
+         *
+         * We can split on the '/' character as this is not a valid character for a schema node
+         * identifier and a schema node identifier cannot use predicates.
+         */
+        final String[] identifierParts = relativeSchemaNodeIdentifier.contains("/") ?
+                relativeSchemaNodeIdentifier.split("/") :
+                new String[] { relativeSchemaNodeIdentifier };
+        return identifierParts;
+    }
+
+    /**
+     * Given the first part of a schema node identifier (which can be absolute or relative) returns the schema
+     * node that should serve as starting point of subsequent navigation.
+     */
+    public static AbstractStatement findStartingSchemaNode(final ParserExecutionContext context,
+            final AbstractStatement originalStatement, final boolean isAbsoluteSchemaNodeIdentifier,
+            final String firstIdentifierPart, final Schema schema) {
+
+        if (!isAbsoluteSchemaNodeIdentifier) {
+            /*
+             * Relative path, that's easy: start at the original statement.
+             */
+            return originalStatement;
+        }
+
+        final YangModel currentYangFile = originalStatement.getDomElement().getYangModel();
+
+        /*
+         * The path is absolute, so the starting point for traversal will be at the root
+         * of a module / submodule. Need to figure out which one...
+         */
+        if (!QNameHelper.hasPrefix(firstIdentifierPart)) {
+            /*
+             * No prefix, hence the module is the same module in which the original statement sits.
+             */
+            return originalStatement.getYangModelRoot().getModuleOrSubmodule();
+        }
+
+        /*
+         * We have a prefix, so resolve that.
+         */
+        final String prefix = QNameHelper.extractPrefix(firstIdentifierPart);
+        final ModuleIdentity moduleIdentity = currentYangFile.getPrefixResolver().getModuleForPrefix(prefix);
+
+        if (moduleIdentity == null) {
+            context.addFinding(new Finding(originalStatement, ParserFindingType.P033_UNRESOLVEABLE_PREFIX,
+                    "Prefix '" + prefix + "' part of path '" + firstIdentifierPart + "' cannot be resolved."));
+            return null;
+        }
+
+        final YangModel modelInputForModuleIdentity = schema.getModuleRegistry().find(moduleIdentity);
+        if (modelInputForModuleIdentity == null) {	// avoid NPE if module not in input
+            return null;
+        }
+
+        return modelInputForModuleIdentity.getYangModelRoot().getModuleOrSubmodule();
+    }
+
+    /**
+     * Given a statement containing some kind of child schema identifier (posibly prefixed), finds that child with that
+     * identity under the statement.
+     */
+    public static AbstractStatement findChildSchemaNode(final ParserExecutionContext context,
+            final AbstractStatement parentStatement, final String possiblyPrefixedIdentifier,
+            final AbstractStatement originalStatement) {
+
+        final YangModel currentYangFile = originalStatement.getDomElement().getYangModel();
+
+        String soughtNamespace = null;
+        final String soughtIdentifier = QNameHelper.extractName(possiblyPrefixedIdentifier);
+
+        if (QNameHelper.hasPrefix(possiblyPrefixedIdentifier)) {
+
+            final String prefix = QNameHelper.extractPrefix(possiblyPrefixedIdentifier);
+
+            final ModuleIdentity moduleIdentity = currentYangFile.getPrefixResolver().getModuleForPrefix(prefix);
+            if (moduleIdentity == null) {
+                context.addFinding(new Finding(originalStatement, ParserFindingType.P033_UNRESOLVEABLE_PREFIX,
+                        "Prefix '" + prefix + "' part of path '" + possiblyPrefixedIdentifier + "' cannot be resolved."));
+                return null;
+            }
+
+            soughtNamespace = currentYangFile.getPrefixResolver().resolveNamespaceUri(prefix);
+        }
+
+        for (final AbstractStatement child : parentStatement.getChildStatements()) {
+            if (child.definesSchemaNode() && soughtIdentifier.equals(child.getStatementIdentifier())) {
+                if (soughtNamespace == null || soughtNamespace.equals(child.getEffectiveNamespace())) {
+                    return child;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Extracts all occurrences of a specific YANG statement from a schema.
+     */
+    public static List<?> findStatementsInSchema(final StatementModuleAndName soughtStatementModuleAndName,
+            final Schema schema) {
+
+        final List<AbstractStatement> result = new ArrayList<>();
+
+        for (final YangModel yaml : schema.getModuleRegistry().getAllYangModels()) {
+            final AbstractStatement moduleOrSubmodule = yaml.getYangModelRoot().getModuleOrSubmodule();
+            findStatementsInSubtree(moduleOrSubmodule, soughtStatementModuleAndName, result);
+        }
+
+        return result;
+    }
+
+    /**
+     * Extracts all occurrences of a specific YANG statement underneath the supplied statement, and possibly including the
+     * statement itself.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends AbstractStatement> void findStatementsInSubtree(final AbstractStatement statement,
+            final StatementModuleAndName soughtStatementModuleAndName, final List<T> result) {
+        if (statement.getStatementModuleAndName().equals(soughtStatementModuleAndName)) {
+            result.add((T) statement);
+        }
+        for (final AbstractStatement child : statement.getChildStatements()) {
+            findStatementsInSubtree(child, soughtStatementModuleAndName, result);
+        }
+    }
+
+    /**
+     * Returns all occurrences of the supplied statement module/name that sit at the root of all modules in the schema.
+     */
+    public static List<?> findStatementsAtModuleRootInSchema(final StatementModuleAndName soughtStatementModuleAndName,
+            final Schema schema) {
+
+        final List<AbstractStatement> result = new ArrayList<>();
+
+        for (final YangModel yaml : schema.getModuleRegistry().getAllYangModels()) {
+            final List<AbstractStatement> childStatements = yaml.getYangModelRoot().getModuleOrSubmodule()
+                    .getChildStatements();
+            for (final AbstractStatement child : childStatements) {
+                if (child.getStatementModuleAndName().equals(soughtStatementModuleAndName)) {
+                    result.add((AbstractStatement) child);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends AbstractStatement> T findStatement(final ParserExecutionContext context, final Schema schema,
+            final AbstractStatement originalStatement, final StatementModuleAndName soughtSman,
+            final String possiblyPrefixedSoughtNodeIdentifier) {
+
+        String prefix = "";
+        ModuleIdentity moduleIdentityOfSoughtStatement;
+        String unprefixedSoughtNodeIdentifier;
+
+        if (QNameHelper.hasPrefix(possiblyPrefixedSoughtNodeIdentifier)) {
+            prefix = QNameHelper.extractPrefix(possiblyPrefixedSoughtNodeIdentifier);
+            moduleIdentityOfSoughtStatement = originalStatement.getPrefixResolver().getModuleForPrefix(prefix);
+            unprefixedSoughtNodeIdentifier = QNameHelper.extractName(possiblyPrefixedSoughtNodeIdentifier);
+
+            if (moduleIdentityOfSoughtStatement == null) {
+                context.addFinding(new Finding(originalStatement, ParserFindingType.P033_UNRESOLVEABLE_PREFIX,
+                        "Prefix '" + prefix + "' not resolvable to a (sub-)module name."));
+                return null;
+            }
+
+        } else {
+            /*
+             * Statement has no prefix, hence statement must sit in the same module as the original statement. Note that
+             * "original" here means the original place where the statement has occurred - which may be different from
+             * where the statement is here now, due to uses / grouping (which copies the contents of the group into
+             * potentially a different module.)
+             */
+            moduleIdentityOfSoughtStatement = originalStatement.getDomElement().getYangModel().getModuleIdentity();
+            unprefixedSoughtNodeIdentifier = possiblyPrefixedSoughtNodeIdentifier;
+        }
+
+        /*
+         * What we do now depends on the module in which the sought statement is located. If it is in the same module,
+         * it can sit anywhere in the model upwards from where the original statement is (could even possibly
+         * be the previous statement in the document). So we need to work our way up the tree to try to find it.
+         * If it is in a different module, then it must be at the root of the module.
+         */
+        if (moduleIdentityOfSoughtStatement.equals(originalStatement.getYangModelRoot().getYangModel()
+                .getModuleIdentity())) {
+            /*
+             * In same module, or an included submodule. Work our way up the tree until we find it (or don't, then check included modules).
+             */
+            AbstractStatement parentStatement = originalStatement;
+
+            while (true) {
+                parentStatement = parentStatement.getParentStatement();
+                if (parentStatement == null) {
+                    return (T) findStatementAtModuleRootOrIncludedSubmodule(originalStatement.getYangModelRoot(),
+                            soughtSman, unprefixedSoughtNodeIdentifier);
+                }
+                for (final AbstractStatement child : parentStatement.getChildStatements()) {
+                    if (child.is(soughtSman) && unprefixedSoughtNodeIdentifier.equals(child.getStatementIdentifier())) {
+                        return (T) child;
+                    }
+                }
+            }
+        } else {
+            /*
+             * In different module. Must be at root of that other module, or included submodules.
+             */
+            final YangModel yangInputContainingSoughtStatement = schema.getModuleRegistry().find(
+                    moduleIdentityOfSoughtStatement);
+            if (yangInputContainingSoughtStatement == null) {	// avoid NPE if module not in input
+                context.addFinding(new Finding(originalStatement, ParserFindingType.P033_UNRESOLVEABLE_PREFIX,
+                        "Prefix '" + prefix + "' resolves to '" + moduleIdentityOfSoughtStatement + "' but this is either not found in the input or is ambiguous."));
+                return null;
+            }
+            return (T) findStatementAtModuleRootOrIncludedSubmodule(yangInputContainingSoughtStatement.getYangModelRoot(),
+                    soughtSman, unprefixedSoughtNodeIdentifier);
+        }
+    }
+
+    /**
+     * Tries to find the statement at the root of the module, or at the root of any included submodule.
+     */
+    private static AbstractStatement findStatementAtModuleRootOrIncludedSubmodule(final YangModelRoot modelRoot,
+            final StatementModuleAndName soughtSman, final String unprefixedSoughtNodeIdentifier) {
+
+        if (modelRoot.isModule()) {
+            return findStatementAtModuleRoot(modelRoot, soughtSman, unprefixedSoughtNodeIdentifier);
+        } else {
+            /*
+             * It's a submodule, navigate to owning module first.
+             */
+            return findStatementAtModuleRoot(modelRoot.getOwningYangModelRoot(), soughtSman,
+                    unprefixedSoughtNodeIdentifier);
+        }
+    }
+
+    private static AbstractStatement findStatementAtModuleRoot(final YangModelRoot moduleModelRoot,
+            final StatementModuleAndName soughtSman, final String unprefixedSoughtNodeIdentifier) {
+
+        /*
+         * Try to find statement at the root of the module.
+         */
+        AbstractStatement foundStatement = findStatementUnderParent(moduleModelRoot.getModule(), soughtSman,
+                unprefixedSoughtNodeIdentifier);
+        if (foundStatement != null) {
+            return foundStatement;
+        }
+
+        /*
+         * Not found here, check submodules of the module.
+         */
+        for (final YangModelRoot ownedSubmodule : moduleModelRoot.getOwnedSubmodules()) {
+            foundStatement = findStatementUnderParent(ownedSubmodule.getSubmodule(), soughtSman,
+                    unprefixedSoughtNodeIdentifier);
+            if (foundStatement != null) {
+                return foundStatement;
+            }
+        }
+
+        return null;
+    }
+
+    private static AbstractStatement findStatementUnderParent(final AbstractStatement moduleOrSubmodule,
+            final StatementModuleAndName soughtSman, final String soughtNodeIdentifier) {
+
+        for (final AbstractStatement child : moduleOrSubmodule.getChildStatements()) {
+            if (child.is(soughtSman) && soughtNodeIdentifier.equals(child.getStatementIdentifier())) {
+                return child;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Given a set of statements, finds a data node of a given ns/name within those statements. choice / case are followed.
+     */
+    public static AbstractStatement findSchemaDataNode(final List<AbstractStatement> statements,
+            final String soughtNamespace, final String soughtName) {
+
+        for (final AbstractStatement statement : statements) {
+
+            if (statement.definesDataNode() && statement.getEffectiveNamespace().equals(soughtNamespace) && soughtName
+                    .equals(statement.getStatementIdentifier())) {
+                return statement;
+            } else if (statement.is(CY.STMT_CHOICE)) {
+
+                for (final AbstractStatement yCase : statement.getChildren(CY.STMT_CASE)) {
+                    final AbstractStatement dataNodeUnderChoiceCase = findSchemaDataNode(yCase.getChildStatements(),
+                            soughtNamespace, soughtName);
+                    if (dataNodeUnderChoiceCase != null) {
+                        return dataNodeUnderChoiceCase;
+                    }
+                }
+
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Given a set of statements, finds a data node of a given name within those statements. choice / case are followed.
+     */
+    public static AbstractStatement findSchemaDataNode(final List<AbstractStatement> statements, final String soughtName) {
+
+        for (final AbstractStatement statement : statements) {
+
+            if (statement.definesDataNode() && soughtName.equals(statement.getStatementIdentifier())) {
+                return statement;
+            } else if (statement.is(CY.STMT_CHOICE)) {
+
+                for (final AbstractStatement yCase : statement.getChildren(CY.STMT_CASE)) {
+                    final AbstractStatement dataNodeUnderChoiceCase = findSchemaDataNode(yCase.getChildStatements(),
+                            soughtName);
+                    if (dataNodeUnderChoiceCase != null) {
+                        return dataNodeUnderChoiceCase;
+                    }
+                }
+
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Given a statement, returns all data nodes under the statement. Data nodes underneath
+     * choice / case, possibly nested, are likewise returned.
+     */
+    public static List<AbstractStatement> getChildDataNodes(final AbstractStatement parent) {
+
+        List<AbstractStatement> result = null;
+
+        for (final AbstractStatement child : parent.getChildStatements()) {
+            if (child.definesDataNode()) {
+
+                if (result == null) {
+                    result = new ArrayList<>();
+                }
+                result.add(child);
+
+            } else if (child.is(CY.STMT_CHOICE)) {
+
+                /*
+                 * Handle shorthand notation:
+                 */
+                final List<AbstractStatement> dataNodesUnderChoice = getChildDataNodes(child);
+                if (!dataNodesUnderChoice.isEmpty()) {
+                    if (result == null) {
+                        result = new ArrayList<>();
+                    }
+                    result.addAll(dataNodesUnderChoice);
+                }
+
+                /*
+                 * Handle cases:
+                 */
+                for (final AbstractStatement yCase : child.getChildren(CY.STMT_CASE)) {
+                    final List<AbstractStatement> dataNodesUnderCase = getChildDataNodes(yCase);
+                    if (!dataNodesUnderCase.isEmpty()) {
+                        if (result == null) {
+                            result = new ArrayList<>();
+                        }
+                        result.addAll(dataNodesUnderCase);
+                    }
+                }
+            }
+        }
+
+        return result == null ? Collections.<AbstractStatement> emptyList() : result;
+    }
+
+    public static final String GENERAL_INFO_APP_DATA = "GENERAL_INFO_APP_DATA";
+
+    public static void addGeneralInfoAppData(final AbstractStatement statement, final String info) {
+        addAppDataListInfo(statement, GENERAL_INFO_APP_DATA, info);
+    }
+
+    public static List<String> getGeneralInfoAppData(final AbstractStatement statement) {
+        return getAppDataListInfo(statement, GENERAL_INFO_APP_DATA);
+    }
+
+    /**
+     * Adds opaque application information to a list identified by the key. If the information
+     * already exists in the list, will not be added again.
+     */
+    public static void addAppDataListInfo(final AbstractStatement statement, final String key, final Object info) {
+
+        List<Object> infos = Objects.requireNonNull(statement).getCustomAppData(key);
+        if (infos == null) {
+            infos = new ArrayList<>(1);
+            statement.setCustomAppData(key, infos);
+        }
+        if (!infos.contains(info)) {
+            infos.add(info);
+        }
+    }
+
+    /**
+     * Returns the application information for the given key. Returns an empty list (not null) if the
+     * application information has not been specified for the statement.
+     */
+    public static <T> List<T> getAppDataListInfo(final AbstractStatement statement, final String key) {
+        final List<T> infos = Objects.requireNonNull(statement).getCustomAppData(key);
+        return infos == null ? Collections.<T> emptyList() : infos;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/TypeResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/TypeResolver.java
new file mode 100644
index 0000000..ac3550c
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/TypeResolver.java
@@ -0,0 +1,824 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.resolvers;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YBit;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDefault;
+import org.oran.smo.yangtools.parser.model.statements.yang.YEnum;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLength;
+import org.oran.smo.yangtools.parser.model.statements.yang.YPosition;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRange;
+import org.oran.smo.yangtools.parser.model.statements.yang.YType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YTypedef;
+import org.oran.smo.yangtools.parser.model.statements.yang.YValue;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper.YangDataType;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+/**
+ * A class that can resolve usages of derived types to their base type.
+ * <p/>
+ * This class will correctly handle nested type resolution - that means, can handle a typedef
+ * referring to another typedef (which can and does happen in reality).
+ *
+ * @author Mark Hollmann
+ */
+public abstract class TypeResolver {
+
+    /**
+     * Resolving usages of derived types means that all places where a "type" statement is used, and the type
+     * referred-to is not one of the build-in types, that usage is replaced with the actual base type.
+     */
+    public static void resolveUsagesOfDerivedTypes(final ParserExecutionContext context, final Schema schema) {
+
+        /*
+         * Get all occurrences of the "type" statement. For each statement, check whether the type refers
+         * to an in-build type - if not, it refers to a type defined within a "typedef". The "typedef"
+         * itself will contain a "type" statement, that can likewise be an in-built type, or a derived type.
+         *
+         * The easiest way of doing this is to iterate a number of times over all the "type" statements, and
+         * only to resolve them if the underlying typedef refers to a base type. We guard against infinite loops.
+         */
+
+        int iterationCount = 10;
+        boolean atLeastOneResolved = true;
+
+        while (iterationCount > 0 && atLeastOneResolved) {
+
+            atLeastOneResolved = false;
+            iterationCount--;
+
+            /*
+             * It is correct that the list of "type" statements is fetched every time here, and not once outside
+             * the while-loop. The reason is that otherwise we would simply keep doing the same merge/replace 10 times,
+             * and also replaced "type" statements are detached from the tree, so no need to do these again.
+             */
+            final List<YType> types = findTypeStatementsToConsider(schema);
+            for (final YType type : types) {
+                try {
+                    atLeastOneResolved |= resolveTypeToBaseType(context, schema, type);
+                } catch (final Exception ex) {
+                    /* Swallow and move to next. Best effort here, keep trying other types. */
+                }
+            }
+
+            if (iterationCount == 7) {
+                final List<YType> typesWithExcessiveTypedefDepth = findTypeStatementsToConsider(schema);
+                for (final YType type : typesWithExcessiveTypedefDepth) {
+                    context.addFinding(new Finding(type, ParserFindingType.P112_EXCESSIVE_TYPEDEF_DEPTH,
+                            "Statement refers to 'typedef' with nesting depth > 3."));
+                    break;
+                }
+            }
+        }
+
+        /*
+         * Done resolving. If some type statements are left with derived types they could not
+         * be resolved because of circular dependencies.
+         */
+        final List<YType> stillUnresolvedTypeStatements = findTypeStatementsToConsider(schema);
+        stillUnresolvedTypeStatements.forEach(yType -> context.addFinding(new Finding(yType,
+                ParserFindingType.P111_CIRCULAR_TYPEDEF_REFERENCES,
+                "Likely circular references between 'type' and 'typedef'. Use the quoted file and line number as starting point for investigation.")));
+
+        /*
+         * Perform a check to see which typedef statements have not been used or only used
+         * once and create findings for these (possibly poor modeling).
+         */
+        @SuppressWarnings("unchecked") final List<YTypedef> allTypedefs = (List<YTypedef>) Helper.findStatementsInSchema(
+                CY.STMT_TYPEDEF, schema);
+        for (final YTypedef oneTypedef : allTypedefs) {
+            final int used = getTypedefUsageCount(oneTypedef);
+            if (used == 0) {
+                context.addFinding(new Finding(oneTypedef, ParserFindingType.P114_TYPEDEF_NOT_USED,
+                        "typedef statement '" + oneTypedef.getTypedefName() + "' not used."));
+            } else if (used == 1) {
+                context.addFinding(new Finding(oneTypedef, ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY,
+                        "typedef statement '" + oneTypedef.getTypedefName() + "' used only once; consider inlining."));
+            }
+        }
+
+        /*
+         * It is possible that the replacement of typedefs has resulted in union-within-union.
+         * This will be resolved so that there is only a single union.
+         */
+        atLeastOneResolved = true;
+
+        while (atLeastOneResolved) {
+            atLeastOneResolved = false;
+
+            @SuppressWarnings("unchecked") final List<YType> allTypes = (List<YType>) Helper.findStatementsInSchema(
+                    CY.STMT_TYPE, schema);
+            for (final YType type : allTypes) {
+                atLeastOneResolved |= resolveUnionInUnion(context, type);
+            }
+        }
+    }
+
+    /**
+     * Resolves usage of a derived type to its underlying type.
+     *
+     * 1.) Find the actual base type (basically the sought typedef)
+     * 2.) Clone the complete tree that hangs under the "type", under the found "typedef". The clone is necessary as
+     * it may be used again by some other type or typedef, so we can't just shift the tree but must clone it.
+     * 3.) Merge together the statements that hang under the original "type", and the cloned "type". Certain override
+     * rules apply here.
+     * 4.) Replace the original "type" with the clone that has been updated.
+     *
+     * Note that the cloned tree keeps its reference to its original prefix-resolver. This is really important as the
+     * prefixes between the original YAML and the YAML in which the typedef is can be different!
+     *
+     * There is a small issue, however: We have to ensure that the resolution is done backwards, i.e. always only
+     * resolve if the typedef itself points to a base type. Otherwise we run into problems with modules and prefixes.
+     */
+    private static boolean resolveTypeToBaseType(final ParserExecutionContext context, final Schema schema,
+            final YType typeUsingDerivedType) {
+
+        final AbstractStatement parentOfTypeStatement = typeUsingDerivedType.getParentStatement();
+
+        final String derivedDataType = typeUsingDerivedType.getDataType();
+        if (derivedDataType.isEmpty()) {
+            /*
+             * Pointless trying to resolve the data type. No point issuing a finding either, a
+             * P015_INVALID_SYNTAX_IN_DOCUMENT would have been issued already.
+             */
+            setDerivedTypeNotResolvable(typeUsingDerivedType);
+            return false;
+        }
+
+        /*
+         * We look for the typedef. This could sit further up the tree, at the top of the module, in an included submodule.
+         */
+        final YTypedef typedef = Helper.findStatement(context, schema, typeUsingDerivedType, CY.STMT_TYPEDEF,
+                derivedDataType);
+        if (typedef == null) {
+            setDerivedTypeNotResolvable(typeUsingDerivedType);
+            context.addFinding(new Finding(typeUsingDerivedType, ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE,
+                    "Cannot resolve typedef '" + typeUsingDerivedType.getDataType() + "'."));
+            return false;
+        }
+
+        /*
+         * Mark the typedef has been used.
+         */
+        increaseUsageCount(typedef);
+
+        /*
+         * Check for nested derived type usage, and if found resolve those first.
+         */
+        if (derivedTypeUsedWithinFoundTypedef(context, typeUsingDerivedType, typedef)) {
+            return false;
+        }
+
+        /*
+         * We have found the typedef, and the type within it is a build-in type. We attach some meta data to it first
+         * to keep track of where it came from. Downstream tooling may find this information useful, as quite often
+         * derived types have special semantics, and the resolving of these to their base type loses these semantics.
+         */
+        addOriginallyDefinedInYam(typedef.getType(), typedef.getYangModelRoot().getModuleOrSubModuleName());
+
+        /*
+         * The typedef may be used multiple times so we can't simply re-parent the YType statement tree - we must clone it.
+         */
+        final YType clonedTypeUnderTypedef = new YType(typedef, typedef.getType().getDomElement());
+        clonedTypeUnderTypedef.cloneFrom(typedef.getType());
+
+        /*
+         * Type restrictions can be applied to various sub-statements of the type, which always must make
+         * the allowable value set more restrictive (or be the same). We check for these here. See section
+         * 9.4 in the RFC, and the paragraphs in the various sub-statement that discuss restrictions.
+         */
+        checkAndRestrictPatterns(context, typeUsingDerivedType, clonedTypeUnderTypedef);
+        checkAndRestrictLength(context, typeUsingDerivedType, clonedTypeUnderTypedef);
+        checkAndRestrictRange(context, typeUsingDerivedType, clonedTypeUnderTypedef);
+        checkAndRestrictBits(context, typeUsingDerivedType, clonedTypeUnderTypedef);
+        checkAndRestrictEnumeration(context, typeUsingDerivedType, clonedTypeUnderTypedef);
+
+        /*
+         * A possible default value under the typedef will be copied over to the leaf /
+         * leaf-list / typedef, but only if that does not always have a default value. See
+         * section 7.3.4 and 7.6.1 in the RFC.
+         */
+        if (typedef.getDefault() != null) {
+            assignDefaultFromTypedefToWhereItIsUsed(typedef, typeUsingDerivedType);
+        }
+
+        /*
+         * We are now removing the original 'type' statement (that referred to the derived type) and are
+         * replacing it with the cloned and updated 'type' statement of the 'typedef'. That will then
+         * also clean up the tree underneath the typedef where temporarily we had two 'type' statements.
+         * Note that the replacement must be done such to keep the order of statements in the statement tree.
+         * This is required to handle nested unions correctly.
+         */
+        parentOfTypeStatement.replaceChildInPlace(typeUsingDerivedType, clonedTypeUnderTypedef);
+
+        /*
+         * Keep a record of the reference for later analysis.
+         */
+        addTypedefReference(clonedTypeUnderTypedef, typedef);
+
+        /*
+         * If there is a 'range' statement under the type now we need to re-validate. Same with
+         * 'length' statement.
+         */
+        if (clonedTypeUnderTypedef.getRange() != null) {
+            clonedTypeUnderTypedef.getRange().validateBoundaries(context);
+        }
+        if (clonedTypeUnderTypedef.getLength() != null) {
+            clonedTypeUnderTypedef.getLength().validateBoundaries(context);
+        }
+
+        return true;
+    }
+
+    private static boolean derivedTypeUsedWithinFoundTypedef(final ParserExecutionContext context,
+            final YType typeUsingDerivedType, final YTypedef typedef) {
+
+        final List<YType> typesUnderFoundTypedef = getTypesFromUnderTypedef(typedef);
+
+        boolean hasTypeThatIsNotResolveable = false;
+        boolean hasTypeThatIsDerived = false;
+
+        for (final YType typeInTypedef : typesUnderFoundTypedef) {
+
+            if (isDerivedTypeNotResolvable(typeInTypedef)) {
+
+                hasTypeThatIsNotResolveable = true;
+                context.addFinding(new Finding(typeUsingDerivedType,
+                        ParserFindingType.P116_NESTED_DERIVED_TYPE_NOT_RESOLVABLE,
+                        "Referenced typedef '" + typeUsingDerivedType
+                                .getDataType() + "' has nested unresolvable 'type' statement " + typeInTypedef
+                                        .getDomElement().getNameValue() + "."));
+            }
+
+            if (DataTypeHelper.isDerivedType(typeInTypedef.getDataType())) {
+                hasTypeThatIsDerived = true;
+            }
+        }
+
+        if (hasTypeThatIsNotResolveable) {
+            /*
+             * If the typedef that this type refers to has a 'type' that cannot be resolved,
+             * then this 'type' here likewise cannot be resolved.
+             */
+            setDerivedTypeNotResolvable(typeUsingDerivedType);
+        }
+
+        /*
+         * The typedef itself references another typedef, so resolve the other
+         * typedef first before attempting this one here.
+         */
+        return hasTypeThatIsDerived;
+    }
+
+    private static List<YType> getTypesFromUnderTypedef(final YTypedef typedef) {
+        final List<YType> result = new ArrayList<>();
+
+        result.add(typedef.getType());
+
+        for (final YType unionMember : typedef.getType().getTypes()) {
+            result.add(unionMember);
+        }
+
+        return result;
+    }
+
+    /**
+     * A typedef can have a default value. If the derived type does not have a default, such a default must be copied over.
+     */
+    private static void assignDefaultFromTypedefToWhereItIsUsed(final YTypedef typedef, final YType originalTypeStatement) {
+
+        AbstractStatement parent = originalTypeStatement.getParentStatement();
+
+        if (parent.is(CY.STMT_TYPE)) {
+            /*
+             * type-under-type, i.e. union.
+             */
+            parent = parent.getParentStatement();
+        }
+
+        /*
+         * Safety check so we don't end up adding a default value to a statement that
+         * doesn't support default as child statement.
+         */
+        if (parent.is(CY.STMT_LEAF) || parent.is(CY.STMT_LEAF_LIST) || parent.is(CY.STMT_TYPEDEF)) {
+            if (parent.hasAtLeastOneChildOf(CY.STMT_DEFAULT)) {
+                /*
+                 * The parent statement of where the derived type is used has already a default value, so
+                 * the default value that hangs under the found typedef should be ignored.
+                 */
+            } else {
+                /*
+                 * We simple clone the default value from the found typedef under where the type is
+                 * being used.
+                 */
+                final YDefault defaultUnderFoundTypedef = typedef.getDefault();
+                final YDefault clonedDefault = new YDefault(parent, defaultUnderFoundTypedef.getDomElement());
+                clonedDefault.cloneFrom(defaultUnderFoundTypedef);
+            }
+        }
+    }
+
+    private static void checkAndRestrictPatterns(final ParserExecutionContext context, final YType typeUsingTypedef,
+            final YType clonedTypeUnderTypedef) {
+
+        if (typeUsingTypedef.getPatterns().isEmpty()) {
+            /*
+             * There is no 'pattern' under the type that uses the derived type; nothing to do.
+             */
+            return;
+        }
+
+        if (!DataTypeHelper.isStringType(clonedTypeUnderTypedef.getDataType())) {
+            context.addFinding(new Finding(typeUsingTypedef.getParentStatement(),
+                    ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                    "Base type of derived type is not 'string'; hence cannot use 'pattern' as substatement to restrict the type."));
+            return;
+        }
+
+        /*
+         * Patterns work slightly different compared to length or range. It is possible to specify multiple
+         * patterns as part of a type, and they must logically ALL (not ANY) be true. This means that the
+         * patterns from the derived type and the using-type are simply added together. So all we have to do
+         * is move any pattern from the using-type into the cloned derived type.
+         */
+        clonedTypeUnderTypedef.addChildren(typeUsingTypedef.getPatterns());
+    }
+
+    private static void checkAndRestrictLength(final ParserExecutionContext context, final YType typeUsingTypedef,
+            final YType clonedTypeUnderTypedef) {
+
+        if (typeUsingTypedef.getLength() == null) {
+            /*
+             * There is no 'length' under the type that uses the derived type, hence there is no restriction
+             * currently, hence no need to check if any length is more restrictive or the same.
+             */
+            return;
+        }
+
+        if (!DataTypeHelper.isStringType(clonedTypeUnderTypedef.getDataType()) && !DataTypeHelper.isBinaryType(
+                clonedTypeUnderTypedef.getDataType())) {
+            context.addFinding(new Finding(typeUsingTypedef.getParentStatement(),
+                    ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                    "Base type of derived type is not 'string' or 'binary'; hence cannot use 'length' as substatement to restrict the type."));
+            return;
+        }
+
+        if (clonedTypeUnderTypedef.getLength() != null) {
+            /*
+             * A 'length' has been defined as part of the derived type. We must check that the length defined
+             * on the using type is more restrictive, or at least equal.
+             *
+             * To do this, we make sure that all boundaries defined by the using type fit into any (single)
+             * boundary defined by the derived type. For example, this is here is fine:
+             *
+             * Derived type: [0-10],[30-35],[80-99]
+             * Using type:   [0-5],[30-31],[33-35]
+             *
+             * Conversely, this here is not OK:
+             *
+             * Derived type: [0-10],[30-35],[80-99]
+             * Using type:   [0-20],[30-90
+             */
+            final List<YLength.BoundaryPair> derivedTypeBoundaries = clonedTypeUnderTypedef.getLength().getBoundaries();
+            final List<YLength.BoundaryPair> usingTypeBoundaries = typeUsingTypedef.getLength().getBoundaries();
+
+            for (final YLength.BoundaryPair oneUsingTypeBoundary : usingTypeBoundaries) {
+                if (!fitsIntoLengthBoundary(oneUsingTypeBoundary, derivedTypeBoundaries)) {
+                    context.addFinding(new Finding(typeUsingTypedef.getLength(),
+                            ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                            "When using a derived type and specifying 'length', the allowed length can only become more restrictive, not wider."));
+                }
+            }
+        }
+
+        /*
+         * We replace any 'length' from under the cloned type, and replace it with the length under the
+         * type that uses the typedef. That's fine, as the cloned type will in a moment replace the
+         * type that uses the typedef.
+         */
+        clonedTypeUnderTypedef.replaceChildrenWith(typeUsingTypedef.getLength());
+    }
+
+    private static boolean fitsIntoLengthBoundary(final YLength.BoundaryPair boundaryToCheck,
+            final List<YLength.BoundaryPair> allowedBoundaries) {
+
+        final long lowerToCheck = boundaryToCheck.lower;
+        final long upperToCheck = boundaryToCheck.upper;
+
+        for (final YLength.BoundaryPair oneAllowedBoundary : allowedBoundaries) {
+            if (oneAllowedBoundary.lower <= lowerToCheck && oneAllowedBoundary.upper >= upperToCheck) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static void checkAndRestrictRange(final ParserExecutionContext context, final YType typeUsingTypedef,
+            final YType clonedTypeUnderTypedef) {
+
+        if (typeUsingTypedef.getRange() == null) {
+            /*
+             * There is no 'range' under the type that uses the typedef, hence
+             * there is no restriction, hence nothing to check or do.
+             */
+            return;
+        }
+
+        if (!DataTypeHelper.isYangNumericType(clonedTypeUnderTypedef.getDataType())) {
+            context.addFinding(new Finding(typeUsingTypedef.getParentStatement(),
+                    ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                    "Base type of derived type is not a numeric type; hence cannot use 'range' as substatement to restrict the type."));
+            return;
+        }
+
+        if (clonedTypeUnderTypedef.getRange() != null) {
+            /*
+             * Logic is very similar to how 'length' is handled, so see comments further above...
+             */
+            final List<YRange.BoundaryPair> derivedTypeBoundaries = clonedTypeUnderTypedef.getRange().getBoundaries();
+            final List<YRange.BoundaryPair> usingTypeBoundaries = typeUsingTypedef.getRange().getBoundaries(
+                    clonedTypeUnderTypedef);
+
+            for (final YRange.BoundaryPair oneUsingTypeBoundary : usingTypeBoundaries) {
+                if (!fitsIntoRangeBoundary(oneUsingTypeBoundary, derivedTypeBoundaries)) {
+                    context.addFinding(new Finding(typeUsingTypedef.getRange(),
+                            ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                            "When using a derived type and specifying 'range', the allowed range can only become more restrictive, not wider."));
+                }
+            }
+        }
+
+        /*
+         * We replace any 'range' from under the cloned type, and replace it with the range under the
+         * type that uses the typedef. That's fine, as the cloned type will in a moment replace the
+         * type that uses the typedef.
+         */
+        clonedTypeUnderTypedef.replaceChildrenWith(typeUsingTypedef.getRange());
+    }
+
+    private static boolean fitsIntoRangeBoundary(final YRange.BoundaryPair boundaryToCheck,
+            final List<YRange.BoundaryPair> allowedBoundaries) {
+
+        final BigDecimal lowerToCheck = boundaryToCheck.lower;
+        final BigDecimal upperToCheck = boundaryToCheck.upper;
+
+        for (final YRange.BoundaryPair oneAllowedBoundary : allowedBoundaries) {
+            if (oneAllowedBoundary.lower.compareTo(lowerToCheck) <= 0 && oneAllowedBoundary.upper.compareTo(
+                    upperToCheck) >= 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * A 'bits' data type has been restricted. The restricted bits must be a subset of the original
+     * type, and the position values must match up. See chapter 9.7 in the RFC.
+     */
+    private static void checkAndRestrictBits(final ParserExecutionContext context, final YType typeUsingTypedef,
+            final YType clonedTypeUnderTypedef) {
+
+        if (typeUsingTypedef.getBits().isEmpty()) {
+            return;
+        }
+
+        if (DataTypeHelper.getYangDataType(clonedTypeUnderTypedef.getDataType()) != YangDataType.BITS) {
+            context.addFinding(new Finding(typeUsingTypedef.getParentStatement(),
+                    ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                    "Base type of derived type is not 'bits'; hence cannot use 'bit' as substatement to restrict the type."));
+            return;
+        }
+
+        /*
+         * We first establish what the positions are (implicit or explicit) for all bits.
+         */
+        final Map<String, Long> positionOfBitsInDerivedType = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), clonedTypeUnderTypedef, null);
+
+        /*
+         * If there is a bit-restriction, the RFC states that the bit under the type-using-typdef will
+         * retain all position values if the bit is listed. In other words, the position does not have
+         * to be explicitly supplied. This will cause significant issues in a moment when we perform the
+         * restriction. We there fore explicitly create position statements to overcome this.
+         */
+        typeUsingTypedef.getBits().forEach(yBit -> {
+
+            if (yBit.getPosition() == null) {
+
+                final Long positionOfBit = positionOfBitsInDerivedType.get(yBit.getBitName());
+                /*
+                 * We create a new DOM node and 'position' statement on-the-fly under the 'bit' element.
+                 */
+                final YangDomElement artificialPositionDomElement = new YangDomElement(CY.POSITION, positionOfBit == null ?
+                        "0" :
+                        positionOfBit.toString(), yBit.getDomElement(), yBit.getDomElement().getLineNumber());
+                new YPosition(yBit, artificialPositionDomElement);
+            }
+        });
+
+        /*
+         * Now that the 'bit' statements under the type-using-typedef all have a 'position', we can compare
+         * these. According to RFC, the restriction must be a sub-set of the bits defined in the typedef
+         * and the position values must match up.
+         */
+        final Map<String, Long> positionOfBitsInTypeUsingTypedef = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typeUsingTypedef, null);
+
+        for (final YBit bit : typeUsingTypedef.getBits()) {
+            final String bitName = bit.getBitName();
+
+            if (!positionOfBitsInDerivedType.containsKey(bitName)) {
+                context.addFinding(new Finding(bit, ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                        "Bit '" + bitName + "' does not exist in derived type."));
+            } else {
+
+                final long bitPositionInTypeUsingTypedef = positionOfBitsInTypeUsingTypedef.get(bitName).longValue();
+                if (positionOfBitsInDerivedType.get(bitName).longValue() != bitPositionInTypeUsingTypedef) {
+                    context.addFinding(new Finding(bit, ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                            "'position' mismatch for bit '" + bitName + "'. In derived type: '" + positionOfBitsInDerivedType
+                                    .get(bitName) + "'; in type using the derived type: '" + bitPositionInTypeUsingTypedef + "'."));
+                }
+            }
+        }
+
+        /*
+         * And eventually replace the bits statements (due to this replace, we had
+         * to create artificial 'position' statements further above).
+         */
+        clonedTypeUnderTypedef.replaceChildrenWith(typeUsingTypedef.getBits());
+    }
+
+    /**
+     * Does the exact same as the previous method, only for enumerations.
+     */
+    private static void checkAndRestrictEnumeration(final ParserExecutionContext context, final YType typeUsingTypedef,
+            final YType clonedDerivedType) {
+
+        if (typeUsingTypedef.getEnums().isEmpty()) {
+            return;
+        }
+
+        if (DataTypeHelper.getYangDataType(clonedDerivedType.getDataType()) != YangDataType.ENUMERATION) {
+            context.addFinding(new Finding(typeUsingTypedef.getParentStatement(),
+                    ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                    "Base type of derived type is not 'enumeration'; hence cannot use 'enum' as substatement to restrict the type."));
+            return;
+        }
+
+        final Map<String, Long> valueOfEnumsInDerivedType = DataTypeHelper.calculateValuesOfEnums(context
+                .getFindingsManager(), clonedDerivedType, null);
+
+        /*
+         * If there is a enum-restriction, the RFC states that the enum under the type-using-typdef will
+         * retain all 'value' values if the enum is listed. In other words, the value does not have
+         * to be explicitly supplied. This will cause significant issues in a moment when we perform the
+         * restriction. We there fore explicitly create value statements to overcome this.
+         */
+        typeUsingTypedef.getEnums().forEach(yEnum -> {
+
+            if (yEnum.getValue() == null) {
+
+                final Long valueOfEnum = valueOfEnumsInDerivedType.get(yEnum.getEnumName());
+                /*
+                 * We create a new DOM node and 'value' statement on-the-fly under the 'enum' element.
+                 */
+                final YangDomElement artificialPositionDomElement = new YangDomElement(CY.VALUE, valueOfEnum == null ?
+                        "0" :
+                        valueOfEnum.toString(), yEnum.getDomElement(), yEnum.getDomElement().getLineNumber());
+                new YValue(yEnum, artificialPositionDomElement);
+            }
+        });
+
+        final Map<String, Long> valueOfEnumsInTypeUsingTypedef = DataTypeHelper.calculateValuesOfEnums(context
+                .getFindingsManager(), typeUsingTypedef, null);
+
+        /*
+         * According to RFC, the restriction must be a sub-set of the enums defined in the typedef - and the values must match up (or be omitted).
+         */
+        for (final YEnum oneEnum : typeUsingTypedef.getEnums()) {
+
+            final String enumName = oneEnum.getEnumName();
+
+            if (!valueOfEnumsInDerivedType.containsKey(enumName)) {
+                context.addFinding(new Finding(oneEnum, ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                        "Enum '" + enumName + "' does not exist in derived type."));
+            } else {
+
+                final long enumValueInTypeUsingTypedef = valueOfEnumsInTypeUsingTypedef.get(enumName).longValue();
+
+                if (valueOfEnumsInDerivedType.get(enumName).longValue() != enumValueInTypeUsingTypedef) {
+                    context.addFinding(new Finding(oneEnum, ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION,
+                            "'value' mismatch for enum '" + enumName + "'. In derived type: '" + valueOfEnumsInDerivedType
+                                    .get(enumName) + "'; in type using the derived type: '" + enumValueInTypeUsingTypedef + "'."));
+                }
+            }
+        }
+
+        /*
+         * And eventually replace the enum statements.
+         */
+        clonedDerivedType.replaceChildrenWith(typeUsingTypedef.getEnums());
+    }
+
+    /**
+     * Returns all 'type' statements that should be considered. In effect, all 'type' statements that
+     * are not build-in YANG types and which have not been ruled out to be un-resolvable.
+     */
+    @SuppressWarnings("unchecked")
+    private static List<YType> findTypeStatementsToConsider(final Schema schema) {
+
+        final List<YType> yTypes = (List<YType>) Helper.findStatementsInSchema(CY.STMT_TYPE, schema);
+
+        return yTypes.stream().filter(yType -> !DataTypeHelper.isBuiltInType(yType.getDataType())).filter(
+                yType -> !isDerivedTypeNotResolvable(yType)).collect(Collectors.toList());
+    }
+
+    /**
+     * Resolves any usages of union-in-union
+     */
+    private static boolean resolveUnionInUnion(final ParserExecutionContext context, final YType yType) {
+
+        /*
+         * This type has to be a union, and it must have sub-types also of union, for this to fire.
+         */
+        if (!DataTypeHelper.isUnionType(yType.getDataType())) {
+            return false;
+        }
+
+        final boolean hasChildUnion = yType.getTypes().stream().filter(childType -> DataTypeHelper.isUnionType(childType
+                .getDataType())).findAny().isPresent();
+        if (!hasChildUnion) {
+            return false;
+        }
+
+        /*
+         * The sub-unions need to be resolved. There is a complication here in respect of the order of
+         * union statements. Basically, the general order must be maintained. Consider this input:
+         *
+         * type union {
+         *      type int16;
+         *      type union {
+         *           type string;
+         *           type enumeration;
+         *      }
+         *      type uint64;
+         * }
+         *
+         * ... then the resolved union should look like this:
+         *
+         * type union {
+         *      type int16;
+         *      type string;
+         *      type enumeration;
+         *      type uint64;
+         * }
+         *
+         * This means we have to be careful with the order of the type
+         * statements when re-arranging these.
+         */
+
+        final List<YType> collectedTypeStatements = new ArrayList<>();
+        yType.getTypes().forEach(childType -> {
+            if (DataTypeHelper.isUnionType(childType.getDataType())) {
+                /*
+                 * A union, so we need to add the children type statements of the union type.
+                 */
+                collectedTypeStatements.addAll(childType.getTypes());
+            } else {
+                /*
+                 * Not a union, so simple add to the collected types
+                 */
+                collectedTypeStatements.add(childType);
+            }
+        });
+
+        /*
+         * And now simply replace the original children with the collected types. That will effectively
+         * remove the (now resolved) child-union from the statement tree.
+         */
+        yType.replaceChildrenWith(collectedTypeStatements);
+
+        return true;
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String DERIVED_TYPE_NOT_RESOLVABLE = "DERIVED_TYPE_NOT_RESOLVABLE";
+
+    private static void setDerivedTypeNotResolvable(final YType yType) {
+        yType.setCustomAppData(DERIVED_TYPE_NOT_RESOLVABLE);
+    }
+
+    private static boolean isDerivedTypeNotResolvable(final YType yType) {
+        return yType.hasCustomAppData(DERIVED_TYPE_NOT_RESOLVABLE);
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String TYPEDEF_USAGE_COUNT = "TYPEDEF_USAGE_COUNT";
+
+    private static int getTypedefUsageCount(final YTypedef typedef) {
+        final Integer usageCount = typedef.getCustomAppData(TYPEDEF_USAGE_COUNT);
+        return usageCount == null ? 0 : usageCount.intValue();
+    }
+
+    private static void increaseUsageCount(final YTypedef yTypedef) {
+        final Integer usageCount = yTypedef.getCustomAppData(TYPEDEF_USAGE_COUNT);
+        if (usageCount == null) {
+            yTypedef.setCustomAppData(TYPEDEF_USAGE_COUNT, Integer.valueOf(1));
+        } else {
+            yTypedef.setCustomAppData(TYPEDEF_USAGE_COUNT, Integer.valueOf(usageCount.intValue() + 1));
+        }
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String TYPEDEF_REFERENCE = "TYPEDEF_REFERENCE";
+    private static final String TYPEDEF_STACK = "TYPEDEF_STACK";
+
+    private static void addTypedefReference(final YType clonedType, final YTypedef origTypedef) {
+        Helper.addAppDataListInfo(clonedType, TYPEDEF_REFERENCE, origTypedef);
+
+        /*
+         * We keep track of the stack of typedefs. We only do this if the typedef is at the root
+         * of the YAM, otherwise it is "private" and can't be used outside of the module.
+         */
+        final AbstractStatement parentOfOrigTypedef = origTypedef.getParentStatement();
+
+        if (parentOfOrigTypedef.is(CY.STMT_MODULE) || parentOfOrigTypedef.is(CY.STMT_SUBMODULE)) {
+            final String moduleName = parentOfOrigTypedef.getYangModelRoot().getOwningYangModelRoot().getModule()
+                    .getModuleName();
+            final String namespace = parentOfOrigTypedef.getYangModelRoot().getNamespace();
+            final NamespaceModuleIdentifier nsmi = new NamespaceModuleIdentifier(namespace, moduleName, origTypedef
+                    .getTypedefName());
+
+            Helper.addAppDataListInfo(clonedType, TYPEDEF_STACK, nsmi);
+        }
+    }
+
+    public static List<YTypedef> getTypedefReference(final YType yType) {
+        return Helper.getAppDataListInfo(yType, TYPEDEF_REFERENCE);
+    }
+
+    /**
+     * Returns 0..n entries denoting the chain of typedefs that were resolved for the supplied type.
+     * Index [0] denotes the typedef that defines the original type.
+     *
+     * Note that if the typedef is declared on a submodule, the name of its owning module will be
+     * returned. To avoid confusion, it is recommended to use the namespace when looking for a
+     * particular module.
+     */
+    public static List<NamespaceModuleIdentifier> getTypedefStack(final YType yType) {
+        return Helper.getAppDataListInfo(yType, TYPEDEF_STACK);
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String ORIGINALLY_DEFINED_IN_YAM = "ORIGINALLY_DEFINED_IN_YAM";
+
+    private static void addOriginallyDefinedInYam(final YType yType, final String yamName) {
+        yType.setCustomAppData(ORIGINALLY_DEFINED_IN_YAM, yamName);
+    }
+
+    /**
+     * Returns the name of the YAM where this type was originally defined. May return null in
+     * which case the type did not refer to a derived type.
+     */
+    public static String getOriginallyDefinedInYamName(final YType yType) {
+        return yType.getCustomAppData(ORIGINALLY_DEFINED_IN_YAM);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/UsesResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/UsesResolver.java
new file mode 100644
index 0000000..659c6dd
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/resolvers/UsesResolver.java
@@ -0,0 +1,815 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.resolvers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.model.schema.SchemaProcessor;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YAugment;
+import org.oran.smo.yangtools.parser.model.statements.yang.YGrouping;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIfFeature;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRefine;
+import org.oran.smo.yangtools.parser.model.statements.yang.YStatus;
+import org.oran.smo.yangtools.parser.model.statements.yang.YUses;
+import org.oran.smo.yangtools.parser.model.statements.yang.YWhen;
+import org.oran.smo.yangtools.parser.model.util.StringHelper;
+
+/**
+ * A class that can resolve all usage of "uses" by including the referenced grouping.
+ *
+ * This class will correctly handle nested grouping resolution - that means, can handle a
+ * grouping referring to another grouping (as it has a uses).
+ *
+ * @author Mark Hollmann
+ */
+public abstract class UsesResolver {
+
+    /**
+     * Resolving means all occurrences of "uses" are replaced by the grouping they are referring to.
+     */
+    public static void resolveUsagesOfUses(final ParserExecutionContext context, final Schema schema) {
+
+        int iterationCount = 10;
+        boolean atLeastOneResolved = true;
+
+        while (iterationCount > 0 && atLeastOneResolved) {
+
+            atLeastOneResolved = false;
+            iterationCount--;
+
+            /*
+             * It is correct that the list of "uses" statements is fetched every time here, and not once outside
+             * the while-loop. The reason is that otherwise we would simply keep doing the same merge/replace 10 times,
+             * and also replaced "uses" statements are detached from the tree, so no need to do these again.
+             */
+            final List<YUses> allUses = findUsesToConsider(schema);
+            for (final YUses uses : allUses) {
+                try {
+                    atLeastOneResolved |= resolveUses(context, schema, uses);
+                } catch (final Exception ex) {
+                    /* Swallow and move to next. Best effort here, keep trying other uses. */
+                }
+            }
+
+            if (iterationCount == 7) {
+                final List<YUses> usesWithExcessiveGroupingDepth = findUsesToConsider(schema);
+                usesWithExcessiveGroupingDepth.forEach(yUses -> context.addFinding(new Finding(yUses,
+                        ParserFindingType.P122_EXCESSIVE_USES_DEPTH,
+                        "'uses' statement refers to 'grouping' with nesting depth > 3.")));
+            }
+        }
+
+        /*
+         * Done resolving. If some 'uses' are left they could not be resolved because of circular dependencies.
+         */
+        final List<YUses> allUses = findUsesToConsider(schema);
+        allUses.forEach(yUses -> context.addFinding(new Finding(yUses, ParserFindingType.P121_CIRCULAR_USES_REFERENCES,
+                "Likely circular references between 'uses' and 'grouping'. Use the quoted file and line number as starting point for investigation.")));
+
+        /*
+         * Finished with replacing all usages of grouping. Perform a check to see
+         * which groupings have only be used once, or not used at all.
+         */
+        @SuppressWarnings("unchecked") final List<YGrouping> allGroupings = (List<YGrouping>) Helper.findStatementsInSchema(
+                CY.STMT_GROUPING, schema);
+        for (final YGrouping oneGrouping : allGroupings) {
+            final int used = getGroupingUsageCount(oneGrouping);
+            if (used == 0) {
+                context.addFinding(new Finding(oneGrouping, ParserFindingType.P132_GROUPING_NOT_USED,
+                        "grouping statement '" + oneGrouping.getGroupingName() + "' not used."));
+            } else if (used == 1) {
+                context.addFinding(new Finding(oneGrouping, ParserFindingType.P133_GROUPING_USED_ONCE_ONLY,
+                        "grouping statement '" + oneGrouping.getGroupingName() + "' used only once; consider inlining."));
+            }
+        }
+    }
+
+    /**
+     * Does what it says on the tin. Note that the 'uses' statement will be removed from the tree once it has been
+     * resolved (and likewise it will remain in the statement tree if it cannot be resolved).
+     */
+    private static boolean resolveUses(final ParserExecutionContext context, final Schema schema,
+            final YUses usesStatement) {
+
+        final String groupingName = usesStatement.getUsesGroupingName();
+        if (groupingName.isEmpty()) {
+            /*
+             * Pointless trying to resolve the grouping. No point issuing a finding either, a
+             * P015_INVALID_SYNTAX_IN_DOCUMENT would have been issued already.
+             */
+            setUsesNotResolvable(usesStatement);
+            return false;
+        }
+
+        /*
+         * Only now attempt to resolve grouping
+         */
+        final YGrouping foundGrouping = Helper.findStatement(context, schema, usesStatement, CY.STMT_GROUPING,
+                groupingName);
+        if (foundGrouping == null) {
+            setUsesNotResolvable(usesStatement);
+            context.addFinding(new Finding(usesStatement, ParserFindingType.P131_UNRESOLVABLE_GROUPING,
+                    "Cannot resolve grouping '" + usesStatement.getUsesGroupingName() + "'."));
+            return false;
+        }
+
+        /*
+         * Mark the grouping has been used.
+         */
+        incGroupingUsageCount(foundGrouping);
+
+        /*
+         * Check for nested 'uses' within the 'grouping'. If found, this means that the contents of the
+         * grouping itself must be resolved first.
+         */
+        if (usesExistWithinFoundGrouping(context, usesStatement, foundGrouping)) {
+            return false;
+        }
+
+        /*
+         * We first create a 1:1 clone of the grouping. Note that the prefix resolver stays the same, i.e. is the
+         * prefix resolver from the module containing the found grouping statement. The cloned grouping statement
+         * is a sibling of the found grouping so that we can apply refine/augments to it (the cloned grouping will
+         * be removed again later on).
+         */
+        final YGrouping clonedGrouping = new YGrouping(foundGrouping.getParentStatement(), foundGrouping.getDomElement());
+        clonedGrouping.cloneFrom(foundGrouping);
+
+        for (final AbstractStatement oneChildOfClonedGrouping : clonedGrouping.getChildStatements()) {
+            Helper.addGeneralInfoAppData(oneChildOfClonedGrouping, "statement placed here by 'uses' in " + StringHelper
+                    .getModuleLineString(usesStatement) + " of grouping '" + usesStatement
+                            .getUsesGroupingName() + "' from " + StringHelper.getModuleLineString(foundGrouping));
+            addGroupingReference(oneChildOfClonedGrouping, foundGrouping);
+        }
+
+        /*
+         * Handle any status statement under the 'uses' or 'grouping'.
+         */
+        handleStatus(usesStatement, clonedGrouping);
+
+        /*
+         * Handle 'refine'. These are used to update the contents of the grouping.
+         */
+        handleRefines(context, schema, usesStatement, clonedGrouping, foundGrouping);
+
+        /*
+         * We apply any "augments". The augments hangs under the "uses" statement; we simply re-parent
+         * all statements that hang under augments into the correct location in the group, based on the
+         * target node of the augments.
+         */
+        for (final YAugment augment : usesStatement.getAugments()) {
+            handleAugment(context, schema, augment, clonedGrouping, foundGrouping, usesStatement);
+        }
+
+        /*
+         * If there is an "if-feature" underneath the 'uses', then this if-feature will be
+         * applied to each of the direct children of the cloned grouping statement. Note that
+         * any if-feature will be *added*, not set (i.e. it's a merge operation of the
+         * if-feature statements, not a replace.)
+         */
+        for (final YIfFeature origUsesOneIfFeature : usesStatement.getIfFeatures()) {
+            for (final AbstractStatement childOfClonedGrouping : clonedGrouping.getChildStatements()) {
+                final YIfFeature clonedIfFeature = new YIfFeature(childOfClonedGrouping, origUsesOneIfFeature
+                        .getDomElement());
+                clonedIfFeature.cloneFrom(origUsesOneIfFeature);
+                // No need to explicitly add it - the YIfFeature constructor will add it as child already.
+            }
+        }
+
+        /*
+         * If there is a 'when' statement underneath the 'uses', then this 'when' will be applied to each of the
+         * direct children of the cloned grouping statement. Note this is different from a 'when' statement that
+         * is part of the augments for a uses. The original 'when' clause relates to the 'uses' statement, whose
+         * data node is the parent of the uses. Hence the cloned when statements apply to the parent of the
+         * respective data node, not the data node in the grouping itself!
+         */
+        final YWhen origUsesWhen = usesStatement.getWhen();
+        if (origUsesWhen != null) {
+            for (final AbstractStatement statementToApplyWhenTo : clonedGrouping.getChildStatements()) {
+                final YWhen clonedWhen = new YWhen(statementToApplyWhenTo, origUsesWhen.getDomElement());
+                clonedWhen.cloneFrom(origUsesWhen);
+                clonedWhen.setAppliesToParentSchemaNode();
+                // No need to explicitly add it - the YWhen constructor will add it as child already.
+            }
+        }
+
+        /*
+         * The cloned grouping is now complete. We now hang the contents of the cloned grouping underneath the parent
+         * statement of the 'uses' (i.e., in effect replace the 'uses' statement with the contents of the cloned grouping).
+         *
+         * When we do this, the following child elements of the cloned grouping can be ignored:
+         * - if-feature (not a valid child underneath grouping)
+         * - grouping (nested, would have resolved any uses of the grouping beforehand)
+         * - typedef (would have been resolved beforehand)
+         * - uses (nested, would have been resolved beforehand)
+         *
+         * Note that we have to re-parent the cloned groupings child statements, of course. The prefix resolver is ok,
+         * as it would have inherited down from the cloned grouping, and the cloned grouping got the prefix resolver
+         * of the original 'grouping' statement.
+         */
+        final AbstractStatement parentOfUsesStatement = usesStatement.getParentStatement();
+
+        parentOfUsesStatement.addChildren(clonedGrouping.getActions());
+        parentOfUsesStatement.addChildren(clonedGrouping.getAnyxmls());
+        parentOfUsesStatement.addChildren(clonedGrouping.getAnydata());
+        parentOfUsesStatement.addChildren(clonedGrouping.getChoices());
+        parentOfUsesStatement.addChildren(clonedGrouping.getContainers());
+        parentOfUsesStatement.addChildren(clonedGrouping.getLeafs());
+        parentOfUsesStatement.addChildren(clonedGrouping.getLeafLists());
+        parentOfUsesStatement.addChildren(clonedGrouping.getLists());
+        parentOfUsesStatement.addChildren(clonedGrouping.getNotifications());
+
+        /*
+         * Any finally, remove the cloned grouping as it is not needed anymore, and remove the original "uses" statement
+         */
+        clonedGrouping.getParentStatement().removeChild(clonedGrouping);
+        usesStatement.getParentStatement().removeChild(usesStatement);
+
+        return true;
+    }
+
+    /**
+     * Handle a possible 'status' statement under the 'uses' or 'grouping'. We must do this here during
+     * the merge of the 'grouping' content, as the 'grouping' and the 'uses' and their possible child
+     * 'status' will disappear from the schema tree, hence the 'status' will be lost. To retain the
+     * information, we must clone the 'status' statement into the contents of the 'grouping'.
+     *
+     * Note there is some special handling - if the status is more restrictive under the used
+     * statement then this would not be replaced. For example, if the status is DEPRECATED under the
+     * 'uses', but it is explicitly OBSOLETE under a container being a child of the 'grouping', this would
+     * not be updated.
+     */
+    private static void handleStatus(final YUses uses, final YGrouping clonedGrouping) {
+
+        final YStatus statusUnderUses = uses.getStatus();
+        final YStatus statusUnderGrouping = clonedGrouping.getStatus();
+
+        if (statusUnderUses == null && statusUnderGrouping == null) {
+            return;
+        }
+
+        /*
+         * So this gets a bit tricky. There can be a 'status' statement either under the 'uses',
+         * or under the 'grouping', or possibly both.
+         */
+        YStatus overrideStatus = null;
+        if (statusUnderUses != null && statusUnderGrouping != null) {
+            /*
+             * We are interested in pushing-down the more severe status, so we need to compare these to
+             * find which one it is.
+             */
+            overrideStatus = statusUnderUses.getStatusOrder() > statusUnderGrouping.getStatusOrder() ?
+                    statusUnderUses :
+                    statusUnderGrouping;
+
+        } else if (statusUnderUses != null) {
+
+            overrideStatus = statusUnderUses;
+
+        } else if (statusUnderGrouping != null) {
+
+            overrideStatus = statusUnderGrouping;
+        }
+
+        /*
+         * Now apply the override 'status' to the contents of the 'grouping'.
+         */
+        for (final AbstractStatement childOfClonedGrouping : clonedGrouping.getChildStatements()) {
+
+            if (childOfClonedGrouping.is(CY.STMT_STATUS)) {
+                continue;
+            }
+
+            final YStatus childExplicitStatus = childOfClonedGrouping.getChild(CY.STMT_STATUS);
+            boolean clone = true;
+
+            if (childExplicitStatus == null) {
+                /*
+                 * There is no 'status' statement under the child, so then we will simply
+                 * clone down the parent 'status' in a moment.
+                 */
+            } else if (childExplicitStatus.getStatusOrder() >= overrideStatus.getStatusOrder()) {
+                /*
+                 * There is an explicit 'status' statement under the child. If the child 'status'
+                 * is more restrictive, or the same, as the 'status' of the parent we don't have
+                 * to do anything, i.e. don't clone.
+                 *
+                 * For example, child is DEPRECATED, parent is CURRENT - hence child is more
+                 * restrictive, so don't overwrite the 'status' (don't clone the parent 'status').
+                 */
+                clone = false;
+            }
+
+            if (clone) {
+                /*
+                 * Must clone, so first remove the 'status' statement under the child (if it exists).
+                 */
+                if (childExplicitStatus != null) {
+                    childOfClonedGrouping.removeChild(childExplicitStatus);
+                }
+                /*
+                 * Now clone down the parent's (the uses's or grouping's) 'status' into the child.
+                 */
+                final YStatus clonedStatus = new YStatus(childOfClonedGrouping, overrideStatus.getDomElement());
+                clonedStatus.cloneFrom(overrideStatus);
+                addUsesResolutionAppData(clonedStatus,
+                        "This 'status' statement has been inherited from the 'uses'/'grouping' statement.");
+            }
+        }
+    }
+
+    private static final List<StatementModuleAndName> TARGETS_ALLOWED_FOR_AUGMENTATION = Arrays.asList(CY.STMT_CONTAINER,
+            CY.STMT_LIST, CY.STMT_CHOICE, CY.STMT_CASE, CY.STMT_INPUT, CY.STMT_OUTPUT, CY.STMT_NOTIFICATION);
+
+    private static final Set<StatementModuleAndName> STATEMENTS_UNDER_AUGMENT_TO_HANDLE = new HashSet<>(Arrays.asList(
+            CY.STMT_ACTION, CY.STMT_ANYDATA, CY.STMT_ANYXML, CY.STMT_CASE, CY.STMT_CHOICE, CY.STMT_CONTAINER,
+            CY.STMT_LEAF_LIST, CY.STMT_LEAF, CY.STMT_LIST, CY.STMT_NOTIFICATION));
+
+    private static void handleAugment(final ParserExecutionContext context, final Schema schema, final YAugment augment,
+            final YGrouping clonedGrouping, final YGrouping foundGrouping, final YUses usesStatement) {
+
+        final String augmentTargetNode = augment.getAugmentTargetNode();
+        if (augmentTargetNode.isEmpty() || augmentTargetNode.startsWith("/")) {
+            /*
+             * Pointless trying to resolve the path. No point issuing a finding either, a
+             * P015_INVALID_SYNTAX_IN_DOCUMENT would have been issued already.
+             */
+            return;
+        }
+
+        /*
+         * First thing check the status of the 'augment'. If it is OBSOLETE nothing gets merged in.
+         */
+        final String augmentStatus = augment.getStatus() != null ? augment.getStatus().getValue() : YStatus.CURRENT;
+        if (augmentStatus.equals(YStatus.OBSOLETE)) {
+            Helper.addGeneralInfoAppData(augment,
+                    "'augment' not applied to grouping as the augment is marked as OBSOLETE.");
+            return;
+        }
+
+        final AbstractStatement targetSchemaNodeOfAugment = Helper.findSchemaNode(context, clonedGrouping,
+                augmentTargetNode, schema);
+        if (targetSchemaNodeOfAugment == null) {
+            context.addFinding(new Finding(augment.getDomElement(), ParserFindingType.P054_UNRESOLVABLE_PATH.toString(),
+                    "Cannot find schema node with path '" + augment
+                            .getAugmentTargetNode() + "' relative to the 'uses' statement."));
+            return;
+        }
+
+        /*
+         * Make sure what is being augmented is actually allowed according to the RFC.
+         */
+        if (!TARGETS_ALLOWED_FOR_AUGMENTATION.contains(targetSchemaNodeOfAugment.getStatementModuleAndName())) {
+            context.addFinding(new Finding(augment.getDomElement(), ParserFindingType.P123_INVALID_USES_AUGMENT_TARGET_NODE
+                    .toString(), "Statement '" + targetSchemaNodeOfAugment
+                            .getStatementName() + "' pointed to by '" + augment
+                                    .getAugmentTargetNode() + "' cannot be augmented."));
+            return;
+        }
+
+        /*
+         * Collect all the statements that will be added to the augment's target node in a moment.
+         */
+        final List<AbstractStatement> statementsToAddAsChildrenOfTargetNode = augment.getChildren(
+                STATEMENTS_UNDER_AUGMENT_TO_HANDLE);
+        for (final AbstractStatement statementToAddAsChildOfTargetNode : statementsToAddAsChildrenOfTargetNode) {
+            Helper.addGeneralInfoAppData(statementToAddAsChildOfTargetNode,
+                    "augmented-in into used grouping '" + foundGrouping
+                            .getGroupingName() + "' by 'uses' statement in " + StringHelper.getModuleLineString(
+                                    usesStatement));
+        }
+
+        /*
+         * This is where things get interesting. The target node could be a CHOICE, and the children nodes could be data
+         * definition statements (short-hand notation). In this scenario we want to interject an artificial CASE statement
+         * to clean up the schema tree. Otherwise, other augments (or deviations) may not work subsequently.
+         */
+        if (targetSchemaNodeOfAugment.is(CY.STMT_CHOICE)) {
+
+            SchemaProcessor.injectCaseForShorthandedStatements(augment);
+
+            /*
+             * The direct children of choice may have have changed (case interjected), so we
+             * need to re-fetch these before further processing.
+             */
+            statementsToAddAsChildrenOfTargetNode.clear();
+            statementsToAddAsChildrenOfTargetNode.addAll(augment.getChildren(STATEMENTS_UNDER_AUGMENT_TO_HANDLE));
+        }
+
+        /*
+         * If the augment has a 'when' clause this gets applied to all statements within the 'grouping'.
+         *
+         * Note that the "when" statement is *added*, not *replaced*. That's a bit of a hack, as YANG only allows for a single
+         * "when" for statements. However, it could conceivably be the case that each of the statements amended thus has
+         * itself already a "when" clause - so using a *replace* would be wrong.
+         */
+        if (augment.getWhen() != null) {
+            for (final AbstractStatement childToAdd : statementsToAddAsChildrenOfTargetNode) {
+                final YWhen clonedWhen = new YWhen(childToAdd, augment.getWhen().getDomElement());
+                clonedWhen.cloneFrom(augment.getWhen());
+                clonedWhen.setAppliesToParentSchemaNode();
+            }
+        }
+
+        /*
+         * If the augment has one or multiple "if-feature" statements then these will be applied to each
+         * of the augment's statements individually.
+         */
+        for (final YIfFeature ifFeature : augment.getIfFeatures()) {
+            for (final AbstractStatement childToAdd : statementsToAddAsChildrenOfTargetNode) {
+                final YIfFeature clonedIfFeature = new YIfFeature(childToAdd, ifFeature.getDomElement());
+                clonedIfFeature.cloneFrom(ifFeature);
+            }
+        }
+
+        /*
+         * If the 'augment' has a status then this status must likewise be applied to the
+         * children. Really, it can only conceivable have CURRENT or DEPRECATED.
+         */
+        if (augmentStatus.equals(YStatus.DEPRECATED)) {
+            for (final AbstractStatement childToAdd : statementsToAddAsChildrenOfTargetNode) {
+                /*
+                 * Rules:
+                 *
+                 * 1. Child does not have a status -> then it gets one (same as status on the augment).
+                 * 2. Child has status and it is the same as that on augment -> do nothing.
+                 * 3. Child has status and it is OBSOLETE -> do nothing.
+                 */
+                final YStatus childStatus = childToAdd.getChild(CY.STMT_STATUS);
+                if (childStatus == null) {
+                    final YStatus clonedStatus = new YStatus(childToAdd, augment.getStatus().getDomElement());
+                    clonedStatus.cloneFrom(augment.getStatus());
+                } else if (childStatus.getValue().equals(augmentStatus) || childStatus.isObsolete()) {
+                    // do nothing.
+                }
+            }
+        }
+
+        /*
+         * And now simply move all the statements from under the augment under the target node.
+         */
+        targetSchemaNodeOfAugment.addChildren(statementsToAddAsChildrenOfTargetNode);
+    }
+
+    /**
+     * Check if the found grouping itself contains any "uses", and/or any "uses" that are not resolvable.
+     */
+    private static boolean usesExistWithinFoundGrouping(final ParserExecutionContext context, final YUses usesStatement,
+            final YGrouping grouping) {
+
+        final List<YUses> usesWithinGrouping = new ArrayList<>();
+        Helper.findStatementsInSubtree(grouping, CY.STMT_USES, usesWithinGrouping);
+
+        boolean groupingContainsNonResolveableUses = false;
+        for (final YUses usesWithin : usesWithinGrouping) {
+            if (isUsesNotResolvable(usesWithin)) {
+
+                groupingContainsNonResolveableUses = true;
+
+                /*
+                 * We issue additional findings here to help the user figure out which
+                 * nested 'uses' is/are causing the problem.
+                 */
+                context.addFinding(new Finding(usesStatement, ParserFindingType.P134_NESTED_USES_NOT_RESOLVABLE,
+                        "Referenced grouping '" + usesStatement
+                                .getUsesGroupingName() + "' has nested unresolvable 'uses' statement " + usesWithin
+                                        .getDomElement().getNameValue() + "."));
+            }
+        }
+
+        if (groupingContainsNonResolveableUses) {
+            /*
+             * If the found grouping has itself a 'uses' that is not resolvable, then this 'uses'
+             * here likewise cannot be resolved.
+             */
+            setUsesNotResolvable(usesStatement);
+        }
+
+        return usesWithinGrouping.size() > 0;
+    }
+
+    private static void handleRefines(final ParserExecutionContext context, final Schema schema, final YUses usesStatement,
+            final YGrouping clonedGrouping, final YGrouping foundGrouping) {
+        /*
+         * We refine the contents of the group, if so required. Note that the 'refine' statement hangs
+         * under the 'uses' statement.
+         */
+        for (final YRefine refine : usesStatement.getRefines()) {
+
+            final String refineTargetNode = refine.getRefineTargetNode();
+            if (refineTargetNode.isEmpty() || refineTargetNode.startsWith("/")) {
+                /*
+                 * Pointless trying to resolve the path. No point issuing a finding either, a
+                 * P015_INVALID_SYNTAX_IN_DOCUMENT would have been issued already.
+                 */
+                continue;
+            }
+
+            final AbstractStatement refinedStatement = Helper.findSchemaNode(context, clonedGrouping, refineTargetNode,
+                    schema);
+            if (refinedStatement == null) {
+                context.addFinding(new Finding(refine, ParserFindingType.P054_UNRESOLVABLE_PATH,
+                        "Cannot find schema node with path '" + refineTargetNode + "' for refine of grouping '" + foundGrouping
+                                .getGroupingName() + "'."));
+                continue;
+            }
+
+            refineYangStatements(context, refinedStatement, usesStatement, refine);
+            refineExtensionStatements(refinedStatement, refine);
+        }
+    }
+
+    private static void refineExtensionStatements(final AbstractStatement refinedStatement, final YRefine refine) {
+        /*
+         * Extensions have to be handled. The RFC does not stipulate how these are to be handled. The
+         * working assumption here is that 'replace' semantics shall apply to all of these. In other
+         * words, extensions of a given type (identified through the extension name and its owning module
+         * name) replace any instance of the same type.
+         *
+         * We first collect all extensions that are refined, and keep a note of their "type"
+         * (combination of module name + extension name).
+         */
+        final List<AbstractStatement> extensionsUnderRefine = new ArrayList<>();
+        final Set<String> moduleNameAndExtensionNameOfExtensionsUnderRefine = new HashSet<>();
+
+        refine.getExtensionChildStatements().forEach(extensionStatement -> {
+            extensionsUnderRefine.add(extensionStatement);
+            final String moduleNameAndExtensionName = getModuleNameAndExtensionName(extensionStatement);
+            moduleNameAndExtensionNameOfExtensionsUnderRefine.add(moduleNameAndExtensionName);
+            Helper.addGeneralInfoAppData(extensionStatement, "refines previous extension statement(s) of the same type.");
+        });
+
+        if (extensionsUnderRefine.isEmpty()) {
+            return;
+        }
+
+        /*
+         * Now collect all extensions instances that sit under the refined statement, and that are of
+         * the same type as any of those sitting under 'refine'.
+         */
+        final List<AbstractStatement> extensionsUnderRefinedStatementToRemove = new ArrayList<>();
+
+        refinedStatement.getExtensionChildStatements().forEach(extensionStatement -> {
+            final String moduleNameAndExtensionName = getModuleNameAndExtensionName(extensionStatement);
+            if (moduleNameAndExtensionNameOfExtensionsUnderRefine.contains(moduleNameAndExtensionName)) {
+                Helper.addGeneralInfoAppData(refinedStatement, "previous extension statement " + extensionStatement
+                        .getDomElement().getNameValue() + " removed as it has been refined by 'uses'.");
+                extensionsUnderRefinedStatementToRemove.add(extensionStatement);
+            }
+        });
+
+        /*
+         * And now simply remove from the refined statement the replaced extensions, and add all
+         * the extension statements that sit under the refine statement.
+         */
+        refinedStatement.removeChildren(extensionsUnderRefinedStatementToRemove);
+        refinedStatement.addChildren(extensionsUnderRefine);
+    }
+
+    /**
+     * Given an extension, returns a concatenation of the name of the module owning the
+     * extension definition, and the name of the extension.
+     */
+    private static String getModuleNameAndExtensionName(final ExtensionStatement extensionStatement) {
+
+        final String extensionModulePrefix = extensionStatement.getExtensionModulePrefix();
+        final String extensionStatementName = extensionStatement.getExtensionStatementName();
+
+        final ModuleIdentity owningModuleModuleIdentity = extensionStatement.getPrefixResolver().getModuleForPrefix(
+                extensionModulePrefix);
+        if (owningModuleModuleIdentity == null) {
+            return null;
+        }
+
+        return owningModuleModuleIdentity.getModuleName() + ":::" + extensionStatementName;
+    }
+
+    private static final Set<String> ALLOWABLE_ELEMENTS_FOR_REFINE_MANDATORY = new HashSet<>(Arrays.asList(CY.LEAF,
+            CY.ANYDATA, CY.ANYXML, CY.CHOICE));
+    private static final Set<String> ALLOWABLE_ELEMENTS_FOR_REFINE_DEFAULT = new HashSet<>(Arrays.asList(CY.LEAF,
+            CY.LEAF_LIST, CY.CHOICE));
+    private static final Set<String> ALLOWABLE_ELEMENTS_FOR_REFINE_PRESENCE = new HashSet<>(Arrays.asList(CY.CONTAINER));
+    private static final Set<String> ALLOWABLE_ELEMENTS_FOR_REFINE_MUST = new HashSet<>(Arrays.asList(CY.LEAF, CY.LEAF_LIST,
+            CY.LIST, CY.CONTAINER, CY.ANYDATA, CY.ANYXML));
+    private static final Set<String> ALLOWABLE_ELEMENTS_FOR_REFINE_MIN_MAX_ELEMENTS = new HashSet<>(Arrays.asList(
+            CY.LEAF_LIST, CY.LIST));
+    private static final Set<String> ALLOWABLE_ELEMENTS_FOR_REFINE_IF_FEATURE = new HashSet<>(Arrays.asList(CY.LEAF,
+            CY.LEAF_LIST, CY.LIST, CY.CONTAINER, CY.CHOICE, CY.CASE, CY.ANYDATA, CY.ANYXML));
+
+    private static void refineYangStatements(final ParserExecutionContext context, final AbstractStatement refinedStatement,
+            final YUses uses, final YRefine refine) {
+        /*
+         * We refine the contents of the group, if so required. For this, we simply grab the 'refine' statement, and
+         * apply its content to whatever schema node it should be applied to. Note that the 'refine' statement hangs
+         * under the 'uses' statement.
+         *
+         * The RFC is pretty clear about what statements are "replaced" and "added", see 7.13.2.
+         */
+        refineReplaceChild(context, uses, refine, refinedStatement, refine.getDescription(), null);
+        refineReplaceChild(context, uses, refine, refinedStatement, refine.getReference(), null);
+        refineReplaceChild(context, uses, refine, refinedStatement, refine.getConfig(), null);
+        refineReplaceChildren(context, uses, refine, refinedStatement, refine.getDefaults(),
+                ALLOWABLE_ELEMENTS_FOR_REFINE_DEFAULT);
+        refineReplaceChild(context, uses, refine, refinedStatement, refine.getMandatory(),
+                ALLOWABLE_ELEMENTS_FOR_REFINE_MANDATORY);
+        refineReplaceChild(context, uses, refine, refinedStatement, refine.getPresence(),
+                ALLOWABLE_ELEMENTS_FOR_REFINE_PRESENCE);
+        refineAddChildren(context, uses, refine, refinedStatement, refine.getMusts(), ALLOWABLE_ELEMENTS_FOR_REFINE_MUST);
+        refineReplaceChild(context, uses, refine, refinedStatement, refine.getMinElements(),
+                ALLOWABLE_ELEMENTS_FOR_REFINE_MIN_MAX_ELEMENTS);
+        refineReplaceChild(context, uses, refine, refinedStatement, refine.getMaxElements(),
+                ALLOWABLE_ELEMENTS_FOR_REFINE_MIN_MAX_ELEMENTS);
+        refineAddChildren(context, uses, refine, refinedStatement, refine.getIfFeatures(),
+                ALLOWABLE_ELEMENTS_FOR_REFINE_IF_FEATURE);
+    }
+
+    private static void refineReplaceChild(final ParserExecutionContext context, final YUses uses, final YRefine refine,
+            final AbstractStatement refinedStatement, final AbstractStatement statementUnderRefine,
+            final Set<String> allowableElementsAsRefinedStatement) {
+
+        if (statementUnderRefine == null) {
+            return;
+        }
+
+        refineReplaceChildren(context, uses, refine, refinedStatement, Collections.singletonList(statementUnderRefine),
+                allowableElementsAsRefinedStatement);
+    }
+
+    private static <T extends AbstractStatement> void refineReplaceChildren(final ParserExecutionContext context,
+            final YUses uses, final YRefine refine, final AbstractStatement refinedStatement,
+            final List<T> statementsUnderRefine, final Set<String> allowableElementsAsRefinedStatement) {
+
+        if (statementsUnderRefine.isEmpty()) {
+            return;
+        }
+
+        if (allowableElementsAsRefinedStatement != null && !allowableElementsAsRefinedStatement.contains(refinedStatement
+                .getDomElement().getName())) {
+            /*
+             * We only issue a finding on the first occurrence to prevent spamming of findings.
+             */
+            context.addFinding(new Finding(uses.getParentStatement(), ParserFindingType.P124_INVALID_REFINE_TARGET_NODE,
+                    "Statement '" + statementsUnderRefine.get(0)
+                            .getStatementName() + "' cannot be used to refine a '" + refinedStatement
+                                    .getStatementName() + "'."));
+            return;
+        }
+
+        /*
+         * Special case: The 'refine' statement allows for multiple instances of 'default' underneath, but that would
+         * only be allowed if the refined schema node is a leaf-list. Otherwise there can only be a single instance
+         * of default (leaf, choice). Same with the reverse, of course.
+         */
+        if (statementsUnderRefine.get(0).is(CY.STMT_DEFAULT)) {
+            final int nrDefaults = statementsUnderRefine.size();
+
+            if ((refinedStatement.is(CY.STMT_LEAF) || refinedStatement.is(CY.STMT_CHOICE)) && nrDefaults > 1) {
+                /*
+                 * Note the finding gets issued on the *second* occurrence of 'default' (the first is correct!)
+                 */
+                context.addFinding(new Finding(uses.getParentStatement(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "There can only be a single instance of 'default' under " + refine.getDomElement()
+                                .getNameValue() + " as the refine's target node is a leaf or choice."));
+                return;
+            }
+        }
+
+        /*
+         * Replace all existing instances of the statements, and keep a note of it.
+         */
+        for (final AbstractStatement childOfRefinedStatement : refinedStatement.getChildren(statementsUnderRefine.get(0)
+                .getStatementModuleAndName())) {
+            Helper.addGeneralInfoAppData(refinedStatement, "previous statement " + childOfRefinedStatement.getDomElement()
+                    .getNameValue() + " removed as it has been refined by 'uses'.");
+        }
+
+        for (final AbstractStatement refineWithStatement : statementsUnderRefine) {
+            Helper.addGeneralInfoAppData(refineWithStatement, "refines previous statement(s).");
+        }
+
+        refinedStatement.replaceChildrenWith(statementsUnderRefine);
+    }
+
+    private static <T extends AbstractStatement> void refineAddChildren(final ParserExecutionContext context,
+            final YUses uses, final YRefine refine, final AbstractStatement refinedStatement,
+            final List<T> statementsUnderRefine, final Set<String> allowableElementsAsRefinedStatement) {
+
+        if (statementsUnderRefine.isEmpty()) {
+            return;
+        }
+
+        if (allowableElementsAsRefinedStatement != null && !allowableElementsAsRefinedStatement.contains(refinedStatement
+                .getDomElement().getName())) {
+            /*
+             * We only issue a finding on the first occurrence to prevent spamming of findings.
+             */
+            context.addFinding(new Finding(uses.getParentStatement(), ParserFindingType.P124_INVALID_REFINE_TARGET_NODE,
+                    "Statement '" + statementsUnderRefine.get(0)
+                            .getStatementName() + "' cannot be used to refine a '" + refinedStatement
+                                    .getStatementName() + "'."));
+            return;
+        }
+
+        /*
+         * Simply add the statements.
+         */
+        for (final AbstractStatement refineWithStatement : statementsUnderRefine) {
+            Helper.addGeneralInfoAppData(refineWithStatement, "refines previous statement(s).");
+        }
+
+        refinedStatement.addChildren(statementsUnderRefine);
+    }
+
+    /**
+     * Returns all 'uses' statements that should be considered. In effect, all 'uses'
+     * statements that (still) sit in the tree and which have not been ruled out to be unresolvable.
+     */
+    @SuppressWarnings("unchecked")
+    private static List<YUses> findUsesToConsider(final Schema schema) {
+        final List<YUses> allUses = (List<YUses>) Helper.findStatementsInSchema(CY.STMT_USES, schema);
+        return allUses.stream().filter(yUses -> !isUsesNotResolvable(yUses)).collect(Collectors.toList());
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String USES_RESOLUTION_INFO = "USES_RESOLUTION_INFO";
+
+    private static void addUsesResolutionAppData(final AbstractStatement statement, final String info) {
+        Helper.addAppDataListInfo(statement, USES_RESOLUTION_INFO, info);
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String GROUPING_USAGE_COUNT = "GROUPING_USAGE_COUNT";
+
+    private static void incGroupingUsageCount(final YGrouping grouping) {
+        final Integer usageCount = grouping.getCustomAppData(GROUPING_USAGE_COUNT);
+        if (usageCount == null) {
+            grouping.setCustomAppData(GROUPING_USAGE_COUNT, Integer.valueOf(1));
+        } else {
+            grouping.setCustomAppData(GROUPING_USAGE_COUNT, Integer.valueOf(usageCount.intValue() + 1));
+        }
+    }
+
+    private static int getGroupingUsageCount(final YGrouping grouping) {
+        final Integer usageCount = grouping.getCustomAppData(GROUPING_USAGE_COUNT);
+        return usageCount == null ? 0 : usageCount.intValue();
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String USES_NOT_RESOLVABLE = "USES_NOT_RESOLVABLE";
+
+    private static void setUsesNotResolvable(final YUses yUses) {
+        yUses.setCustomAppData(USES_NOT_RESOLVABLE);
+    }
+
+    private static boolean isUsesNotResolvable(final YUses yUses) {
+        return yUses.hasCustomAppData(USES_NOT_RESOLVABLE);
+    }
+
+    // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+    private static final String GROUPING_REFERENCE = "GROUPING_REFERENCE";
+
+    private static void addGroupingReference(final AbstractStatement statement, final YGrouping origGrouping) {
+        Helper.addAppDataListInfo(statement, GROUPING_REFERENCE, origGrouping);
+    }
+
+    public static List<YGrouping> getGroupingReference(final AbstractStatement statement) {
+        return Helper.getAppDataListInfo(statement, GROUPING_REFERENCE);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/AnnotationRegistry.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/AnnotationRegistry.java
new file mode 100644
index 0000000..3d5dc7f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/AnnotationRegistry.java
@@ -0,0 +1,46 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.model.util.YangAnnotation;
+
+/**
+ * Keeps track of all annotations defined in a given schema.
+ *
+ * @author Mark Hollmann
+ */
+public class AnnotationRegistry {
+
+    private List<YangAnnotation> annotations = new ArrayList<>();
+
+    public void addAnnotation(final YangAnnotation annotation) {
+        annotations.add(Objects.requireNonNull(annotation));
+    }
+
+    public List<YangAnnotation> getAnnotations() {
+        return Collections.unmodifiableList(annotations);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/IdentityRegistry.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/IdentityRegistry.java
new file mode 100644
index 0000000..5ce0ded
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/IdentityRegistry.java
@@ -0,0 +1,114 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.model.util.YangIdentity;
+
+/**
+ * Keeps track of all identities in a given schema. For each identity, its base(s)
+ * and derived identities are also stored.
+ *
+ * @author Mark Hollmann
+ */
+public class IdentityRegistry {
+
+    /**
+     * Map<identity, bases-of-the-identity>
+     */
+    private Map<YangIdentity, Set<YangIdentity>> identitiesAndBases = new HashMap<>();
+
+    /**
+     * Map<identity, identities-derived-from-the-identity>
+     */
+    private Map<YangIdentity, Set<YangIdentity>> identitiesAndDerived = new HashMap<>();
+
+    public void clear() {
+        identitiesAndBases.clear();
+        identitiesAndDerived.clear();
+    }
+
+    /**
+     * Adds an identity to the registry.
+     */
+    public void addIdentity(final YangIdentity yangIdentity) {
+        identitiesAndBases.put(Objects.requireNonNull(yangIdentity), new HashSet<>());
+        identitiesAndDerived.put(Objects.requireNonNull(yangIdentity), new HashSet<>());
+    }
+
+    /**
+     * Adds base/derived information to two existing identity (so puts these into a
+     * relation to each other).
+     */
+    public void addBaseIdentity(final YangIdentity derivedIdentity, final YangIdentity baseIdentity) {
+
+        final Set<YangIdentity> bases = identitiesAndBases.get(Objects.requireNonNull(derivedIdentity));
+        final Set<YangIdentity> derivates = identitiesAndDerived.get(Objects.requireNonNull(baseIdentity));
+
+        if (bases != null && derivates != null) {
+            bases.add(baseIdentity);
+            derivates.add(derivedIdentity);
+        }
+    }
+
+    public Set<YangIdentity> getIdentities() {
+        return Collections.unmodifiableSet(identitiesAndBases.keySet());
+    }
+
+    public Set<YangIdentity> getBasesForIdentity(final YangIdentity derivedIdentity) {
+        return identitiesAndBases.get(Objects.requireNonNull(derivedIdentity));
+    }
+
+    public Set<YangIdentity> getDerivatesOfIdentity(final YangIdentity baseIdentity) {
+        return identitiesAndDerived.get(Objects.requireNonNull(baseIdentity));
+    }
+
+    /**
+     * Returns the identity and all identities deriving from it (at all levels, not
+     * just those directly deriving from the identity).
+     */
+    public Set<YangIdentity> getIdentityAndDerivedIdentitiesRecursively(final YangIdentity identity) {
+
+        if (!identitiesAndDerived.containsKey(Objects.requireNonNull(identity))) {
+            return Collections.<YangIdentity> emptySet();
+        }
+
+        final Set<YangIdentity> result = new HashSet<>();
+        addIdentityAndDerivedIdentities(identity, result);
+        return result;
+    }
+
+    private void addIdentityAndDerivedIdentities(final YangIdentity identity, final Set<YangIdentity> result) {
+
+        if (result.contains(identity)) {		// prevents infinite loops
+            return;
+        }
+
+        result.add(identity);
+        identitiesAndDerived.get(identity).forEach(derived -> addIdentityAndDerivedIdentities(derived, result));
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/ModuleAndNamespaceResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/ModuleAndNamespaceResolver.java
new file mode 100644
index 0000000..d8b62a2
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/ModuleAndNamespaceResolver.java
@@ -0,0 +1,72 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Holds mappings between module names and namespaces.
+ *
+ * @author Mark Hollmann
+ */
+public class ModuleAndNamespaceResolver {
+
+    private final Map<String, String> moduleNameToNamespace = new HashMap<>();
+    private final Map<String, String> namespaceToModuleName = new HashMap<>();
+
+    /**
+     * Records a mapping between a module or submodule name, and its namespace (in the case of
+     * submodule, the namespace of the owning module).
+     */
+    public void recordModuleMapping(final String moduleName, final String namespace) {
+        moduleNameToNamespace.put(Objects.requireNonNull(moduleName), Objects.requireNonNull(namespace));
+    }
+
+    /**
+     * Records a mapping between a namespace and the module defining it.
+     */
+    public void recordNamespaceMapping(final String namespace, final String moduleName) {
+        namespaceToModuleName.put(Objects.requireNonNull(namespace), Objects.requireNonNull(moduleName));
+    }
+
+    /**
+     * Returns the namespace for the supplied module name. If the module name refers to a submodule, will
+     * return the namespace of the module owning the submodule. Returns null if the module is unknown.
+     */
+    public String getNamespaceForModule(final String moduleName) {
+        return moduleNameToNamespace.get(moduleName);
+    }
+
+    /**
+     * Returns the module name for the supplied namespace. Returns null if the namespace is unknown.
+     */
+    public String getModuleForNamespace(final String namespace) {
+        return namespaceToModuleName.get(namespace);
+    }
+
+    @Override
+    public String toString() {
+        return "Mappings: " + moduleNameToNamespace.toString();
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/ModuleRegistry.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/ModuleRegistry.java
new file mode 100644
index 0000000..902a06a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/ModuleRegistry.java
@@ -0,0 +1,175 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.YangModel;
+
+/**
+ * Keeps track of all the YAMs for a given schema.
+ *
+ * @author Mark Hollmann
+ */
+public class ModuleRegistry {
+
+    private final List<YangModel> yangModels = new ArrayList<>();
+    private final Set<String> duplicatedModuleNames = new HashSet<>();
+
+    public ModuleRegistry() {
+    }
+
+    public void addModule(final FindingsManager findingsManager, final YangModel yangModelToAdd) {
+
+        final String toAddModuleName = yangModelToAdd.getModuleIdentity().getModuleName();
+        final String toAddRevision = yangModelToAdd.getModuleIdentity().getRevision();
+
+        /*
+         * Make sure that this very module has not been added twice, or more than once as IMPLEMENTS.
+         */
+        for (final YangModel validYangModel : yangModels) {
+            if (validYangModel.getModuleIdentity().getModuleName().equals(toAddModuleName)) {
+
+                duplicatedModuleNames.add(toAddModuleName);
+
+                if (validYangModel.getModuleIdentity().getRevision() == null && toAddRevision == null) {
+                    findingsManager.addFinding(new Finding(yangModelToAdd, ParserFindingType.P003_DUPLICATE_INPUT,
+                            "Same module '" + toAddModuleName + "' provided twice as input. Remove the duplicate."));
+                } else if (validYangModel.getModuleIdentity()
+                        .getRevision() != null && toAddRevision != null && validYangModel.getModuleIdentity().getRevision()
+                                .equals(toAddRevision)) {
+                    findingsManager.addFinding(new Finding(yangModelToAdd, ParserFindingType.P003_DUPLICATE_INPUT,
+                            "Same module '" + toAddModuleName + "/" + toAddRevision + "' provided twice as input. Remove the duplicate."));
+                } else {
+                    /*
+                     * We are not out of the woods yet. So the revisions are not the same - but then at
+                     * most one of them can be IMPLEMENTS, the others have to be IMPORTS.
+                     */
+                    checkForDuplicateImplements(findingsManager, toAddModuleName, yangModelToAdd);
+                }
+            }
+        }
+
+        yangModels.add(yangModelToAdd);
+    }
+
+    private void checkForDuplicateImplements(final FindingsManager findingsManager, final String toAddModuleName,
+            final YangModel modelInputToAdd) {
+
+        final List<YangModel> allYangFilesOfSameModuleName = byModuleName(toAddModuleName);
+        allYangFilesOfSameModuleName.add(modelInputToAdd);
+
+        int conformImplementsCount = 0;
+
+        for (final YangModel yangFileOfSameName : allYangFilesOfSameModuleName) {
+            if (yangFileOfSameName.getConformanceType() == ConformanceType.IMPLEMENT) {
+                conformImplementsCount++;
+            }
+        }
+
+        if (conformImplementsCount > 1) {
+            findingsManager.addFinding(new Finding(modelInputToAdd, ParserFindingType.P004_SAME_MODULE_DUPLICATE_IMPLEMENTS,
+                    "(Sub-)Module with different revisions supplied multiple times as conformance IMPLEMENTS."));
+        }
+    }
+
+    public List<YangModel> getAllYangModels() {
+        return Collections.unmodifiableList(yangModels);
+    }
+
+    /**
+     * Returns all modules with the given name. May return multiple results if the module is in
+     * the input multiple times (with different revisions, of course).
+     */
+    public List<YangModel> byModuleName(final String soughtModuleName) {
+
+        return yangModels.stream().filter(ymi -> ymi.getModuleIdentity().getModuleName().equals(soughtModuleName)).collect(
+                Collectors.toList());
+    }
+
+    /**
+     * Returns an exact match for the supplied module name and revision (or null if no match was found).
+     * <p>
+     * The sought revision may be null, in which case the module will be tested for having no revision.
+     */
+    public YangModel exactMatch(final String soughtModuleName, final String soughtRevision) {
+
+        return yangModels.stream().filter(ymi -> ymi.getModuleIdentity().getModuleName().equals(soughtModuleName)).filter(
+                ymi -> {
+                    if (soughtRevision == null && ymi.getModuleIdentity().getRevision() == null) {
+                        return true;
+                    }
+                    if (soughtRevision != null && soughtRevision.equals(ymi.getModuleIdentity().getRevision())) {
+                        return true;
+                    }
+                    return false;
+                }).findAny().orElse(null);
+    }
+
+    /**
+     * Returns exactly one match, or null if not found.
+     * <p/>
+     * Where the sought revision is UNKWOWN_REVISION, will return the first found module matching
+     * the module name. Where this could be ambiguous for the caller, use byModuleName() instead
+     * and iterate over the results to find the correct module.
+     * <p/>
+     * Where the sought revision is null, or an actual revision-date, will try to find an exact match.
+     */
+    public YangModel find(final ModuleIdentity moduleIdentity) {
+        return find(moduleIdentity.getModuleName(), moduleIdentity.getRevision());
+    }
+
+    /**
+     * Returns exactly one match, or null if not found.
+     * <p/>
+     * Where the sought revision is UNKWOWN_REVISION, will return the first found module matching
+     * the module name. Where this could be ambiguous for the caller, use byModuleName() instead
+     * and iterate over the results to find the correct module.
+     * <p/>
+     * Where the sought revision is null, or an actual revision-date, will try to find an exact match.
+     */
+    public YangModel find(final String soughtModuleName, final String soughtRevision) {
+
+        return yangModels.stream().filter(ymi -> ymi.getModuleIdentity().getModuleName().equals(soughtModuleName)).filter(
+                ymi -> {
+                    if (ModuleIdentity.UNKWOWN_REVISION.equals(soughtRevision)) {
+                        return true;
+                    }
+                    if (soughtRevision == null && ymi.getModuleIdentity().getRevision() == null) {
+                        return true;
+                    }
+                    if (soughtRevision != null && soughtRevision.equals(ymi.getModuleIdentity().getRevision())) {
+                        return true;
+                    }
+                    return false;
+                }).findAny().orElse(null);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/Schema.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/Schema.java
new file mode 100644
index 0000000..d5ba911
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/Schema.java
@@ -0,0 +1,571 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.resolvers.AugmentResolver;
+import org.oran.smo.yangtools.parser.model.resolvers.DeviationResolver;
+import org.oran.smo.yangtools.parser.model.resolvers.TypeResolver;
+import org.oran.smo.yangtools.parser.model.resolvers.UsesResolver;
+import org.oran.smo.yangtools.parser.model.statements.ietf.CIETF;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YBase;
+import org.oran.smo.yangtools.parser.model.statements.yang.YBelongsTo;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIdentity;
+import org.oran.smo.yangtools.parser.model.util.YangAnnotation;
+import org.oran.smo.yangtools.parser.model.util.YangIdentity;
+import org.oran.smo.yangtools.parser.model.yangdom.DefaultOutputFileNameResolver;
+import org.oran.smo.yangtools.parser.model.yangdom.OutputFileNameResolver;
+import org.oran.smo.yangtools.parser.model.yangdom.OutputStreamResolver;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomWriter;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+import org.oran.smo.yangtools.parser.util.StackTraceHelper;
+
+/**
+ * Represents a YANG schema. A schema is the totally of all modules advertized through
+ * a single instance of a Yang Library. In a given server, it is possible to mount
+ * additional schemas (via the schema-mount mechanism), which requires Yang Library
+ * instances to be present under the mount-point. This would result in additional
+ * instances of this class having to be created.
+ * <p/>
+ * Where a server does not use schema-mount, an instance of this class in effect
+ * represents the complete schema of the server.
+ *
+ * @author Mark Hollmann
+ */
+public class Schema {
+
+    /**
+     * The module registry contains the modules that are part of this schema.
+     */
+    private final ModuleRegistry moduleRegistry = new ModuleRegistry();
+
+    /**
+     * The identity registry keeps track of all identities in the schema.
+     */
+    private final IdentityRegistry identityRegistry = new IdentityRegistry();
+
+    /**
+     * The annotation registry keeps track of all annotations in the schema.
+     */
+    private final AnnotationRegistry annotationRegistry = new AnnotationRegistry();
+
+    /**
+     * The module/namespace resolver for this schema.
+     */
+    private final ModuleAndNamespaceResolver moduleNamespaceResolver = new ModuleAndNamespaceResolver();
+
+    /**
+     * Prevents double-processing of the schema.
+     */
+    private boolean hasBeenProcessed = false;
+
+    public ModuleRegistry getModuleRegistry() {
+        return moduleRegistry;
+    }
+
+    public IdentityRegistry getIdentityRegistry() {
+        return identityRegistry;
+    }
+
+    public AnnotationRegistry getAnnotationRegistry() {
+        return annotationRegistry;
+    }
+
+    public ModuleAndNamespaceResolver getModuleNamespaceResolver() {
+        return moduleNamespaceResolver;
+    }
+
+    /*
+     * These are findings we would not want to lose, as they are quite fundamental.
+     */
+    private static final List<String> FINDINGS_WE_ALWAYS_WANT = Arrays.asList(ParserFindingType.P000_UNSPECIFIED_ERROR
+            .toString(), ParserFindingType.P001_BASIC_FILE_READ_ERROR.toString(),
+            ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString(),
+            ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString());
+
+    /**
+     * Causes the supplied inputs to be parsed into a tree of schema nodes. After parsing, the trees
+     * are available by invoking getYangModelRoot() on each input.
+     * <p>
+     * Unless "stopAfterInitialParse" has been set to true on the context, this method will also
+     * process the contents of the schema and perform various resolutions.
+     * <p>
+     * Irrespective of the "stopAfterInitialParse" setting, custom processors will be invoked with the
+     * onPreSchemaProcessed call-back.
+     */
+    public void parseIntoSchema(final ParserExecutionContext context, final List<YangModel> yangModels) {
+
+        FINDINGS_WE_ALWAYS_WANT.forEach(ft -> context.getFindingsManager().addNonSuppressableFindingType(ft));
+
+        if (context.failFast()) {
+            FAIL_FAST_FINDINGS.forEach(ft -> context.getFindingsManager().addNonSuppressableFindingType(ft));
+        }
+
+        final Set<YangModel> uniqueYangModels = getUniqueInputs(context, yangModels);
+
+        for (final YangModel yangModel : uniqueYangModels) {
+            yangModel.parse(context, moduleNamespaceResolver, this);
+
+            /*
+             * Don't add the module to the registry if there are fundamental issues
+             * with it, as denoted by a missing ModuleIdentity.
+             */
+            if (yangModel.getModuleIdentity() != null) {
+                moduleRegistry.addModule(context.getFindingsManager(), yangModel);
+            }
+        }
+
+        try {
+            /*
+             * First thing: link-up the modules and their submodules, and also update the namespace
+             * resolver with the namespaces of the submodules (as this could not be previously done
+             * during direct parsing of the submodule).
+             */
+            relateSubmodulesToModulesAndUpdateNamespaceResolver();
+
+            /*
+             * Before we proceed we make sure that all imports / includes / belongs-to can be fulfilled.
+             * That cuts down on the number of checks we have to do later on for missing modules etc.
+             */
+            SchemaCheckModuleRelationships.performChecks(context, moduleRegistry);
+
+            /*
+             * Before proceeding, we check whether there are already any findings that should cause us to fail-fast.
+             */
+            if (context.failFast() && context.getFindingsManager().hasFindingOfAnyOf(FAIL_FAST_FINDINGS)) {
+                context.getFindingsManager().retainFindingsOfType(FAIL_FAST_FINDINGS);
+                context.addFinding(new Finding(ParserFindingType.P009_FAIL_FAST,
+                        "Parsing has been stopped early due to significant findings with the input. Address these findings first, and then retry your operation."));
+                return;
+            }
+
+            /*
+             * Run onPreSchemaProcessed hook
+             */
+            context.getCustomProcessors().forEach(proc -> {
+                try {
+                    proc.onPreSchemaProcessed(context, this);
+                } catch (final Exception ex) {
+                    context.addFinding(new Finding(ParserFindingType.P000_UNSPECIFIED_ERROR,
+                            "Custom processor exception: " + ex.getMessage() + " - trace: " + StackTraceHelper
+                                    .getStackTraceInfo(ex)));
+                }
+            });
+
+            /*
+             * Now we process, which will resolve groupings, typedefs, deviations, augments
+             */
+            if (!context.shouldStopAfterInitialParse()) {
+                processParsedYangModules(context);
+            }
+
+        } catch (final Exception ex) {
+            /*
+             * If this happens there is a most likely a NPE somewhere as a result of a seriously
+             * bad model, make sure to issue the finding so that we can debug.
+             */
+            context.addFinding(new Finding(ParserFindingType.P000_UNSPECIFIED_ERROR, ex.getClass()
+                    .getSimpleName() + ": " + ex.getMessage() + " - trace: " + StackTraceHelper.getStackTraceInfo(ex)));
+        }
+    }
+
+    /*
+     * These findings will cause us to issue a FAIL-FAST finding. It is likely that
+     * further processing of the schema would lead to significant issues.
+     */
+    private static final List<String> FAIL_FAST_FINDINGS = Arrays.asList(ParserFindingType.P000_UNSPECIFIED_ERROR
+            .toString(), ParserFindingType.P001_BASIC_FILE_READ_ERROR.toString(), ParserFindingType.P003_DUPLICATE_INPUT
+                    .toString(), ParserFindingType.P004_SAME_MODULE_DUPLICATE_IMPLEMENTS.toString(),
+            ParserFindingType.P005_NO_IMPLEMENTS.toString(), ParserFindingType.P006_IMPLEMENT_IMPORT_MISMATCH.toString(),
+            ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString(),
+            ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString(), ParserFindingType.P031_PREFIX_NOT_UNIQUE
+                    .toString(), ParserFindingType.P032_MISSING_REVISION.toString(), ParserFindingType.P035_AMBIGUOUS_IMPORT
+                            .toString(), ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES.toString(),
+            ParserFindingType.P037_UNRESOLVABLE_INCLUDE.toString(), ParserFindingType.P038_AMBIGUOUS_INCLUDE.toString(),
+            ParserFindingType.P039_UNRESOLVABLE_BELONGS_TO.toString(), ParserFindingType.P040_CIRCULAR_INCLUDE_REFERENCES
+                    .toString(), ParserFindingType.P041_DIFFERENT_YANG_VERSIONS_BETWEEN_MODULE_AND_SUBMODULES.toString(),
+            ParserFindingType.P043_SAME_MODULE_IMPLEMENTS_MORE_THAN_ONCE.toString(),
+            ParserFindingType.P044_SAME_MODULE_IMPLEMENTS_AND_IMPORTS.toString(), ParserFindingType.P045_NOT_A_SUBMODULE
+                    .toString(), ParserFindingType.P046_NOT_A_MODULE.toString(),
+            ParserFindingType.P047_SUBMODULE_OWNERSHIP_MISMATCH.toString(), ParserFindingType.P048_ORPHAN_SUBMODULE
+                    .toString(), ParserFindingType.P050_DUPLICATE_LATEST_REVISION.toString());
+
+    /**
+     * Process the parsed schema tree. This will tweak the schema tree in a number of ways, which depends
+     * on the context. Normally, resolution of submodules, groupings, typedefs, deviations and augmentation
+     * is performed. Also, the namespace, status and config value of each node is computed, and various
+     * registries are populated.
+     * <p>
+     * Normally, there is no need to invoke this method, as it will be invoked internally after the modules
+     * have been parsed; however, where the context denotes to stop parsing after the initial read, this
+     * method must be explicitly called to process the schema (if so desired).
+     */
+    public void processParsedYangModules(final ParserExecutionContext context) {
+
+        if (hasBeenProcessed) {
+            throw new IllegalStateException("Schema has already been processed.");
+        }
+
+        hasBeenProcessed = true;
+
+        try {
+            /*
+             * The content of submodules is merged into the owning modules.
+             */
+            if (context.mergeSubmodulesIntoModules()) {
+                SchemaProcessor.resolveSubmodules(this);
+            }
+
+            /*
+             * Handle the case short-hand notation. Important that this is
+             * done before further processing.
+             */
+            SchemaProcessor.fixupOmittedCaseStatements(this);
+
+            /*
+             * Handle any missing input/output statements.
+             */
+            SchemaProcessor.fixupMissingInputOutputStatements(this);
+
+            /*
+             * Assign the status to everything. This is needed in some processing in a moment. The
+             * status will be adjusted later on, after typedefs and groupings have been resolved.
+             */
+            SchemaProcessor.assignStatus(this);
+
+            /*
+             * Any usage of a derived type is resolved to their respective base types. Usage of
+             * grouping are also resolved.
+             */
+            if (context.resolveDerivedTypesAndGroupings()) {
+                TypeResolver.resolveUsagesOfDerivedTypes(context, this);
+                UsesResolver.resolveUsagesOfUses(context, this);
+            }
+
+            /*
+             * Namespace and conformance type must be assigned at this stage, as in the next steps
+             * augmentations may be applied which will move statements between trees - so in a given
+             * module we can now have data nodes of namespaces different from that of the module.
+             * Same is true for the conformance type.
+             */
+            SchemaProcessor.assignEffectiveNamespaces(this);
+            SchemaProcessor.assignEffectiveConformanceType(this);
+
+            /*
+             * Merge-in augmentations and deviations
+             */
+            if (context.resolveAugments()) {
+                AugmentResolver.resolveAugments(context, this);
+            }
+            if (context.resolveDeviations()) {
+                DeviationResolver.resolveDeviates(context, this);
+            }
+
+            /*
+             * Only now will we handle the import-only modules. The reason for this is an edge case
+             * where an 'implementing' module augment/deviates multiple other modules, and some of
+             * those other modules are conformance 'import-only'. If import-only data nodes are
+             * removed before the augments/deviations are handled, the augment/deviate will fail
+             * and issue a finding which is really "noise".
+             */
+            if (context.ignoreImportedProtocolAccessibleObjects()) {
+                SchemaProcessor.removeProtocolAccessibleObjects(this);
+            }
+
+            /*
+             * The status needs to be re-calculated, as there can have been changes to the schema
+             * tree due to uses / deviation / augment.
+             */
+            SchemaProcessor.assignStatus(this);
+
+            /*
+             * Also can assign the effective config value here now.
+             */
+            SchemaProcessor.assignConfig(this);
+
+            /*
+             * Now that everything is merged-in and resolved, we can remove any schema node that does
+             * not satisfy an if-feature statement. Again, we are doing this relatively late as an
+             * augment/deviation may refer to a data node that is removed due to if-feature, and we
+             * don't want the augment/deviate to fail unnecessarily.
+             */
+            if (context.removeSchemaNodesNotSatisfyingIfFeature()) {
+                if (context.getSupportedFeatures() == null) {
+                    context.addFinding(new Finding(ParserFindingType.P000_UNSPECIFIED_ERROR,
+                            "Cannot remove schema nodes whose if-feature is not satisfied, as information about the features supported has not been supplied."));
+                } else {
+                    SchemaProcessor.removeDataNodesNotSatisfyingIfFeature(context, this);
+                }
+            }
+
+            /*
+             * If so desired, remove any findings on schema nodes that are not referenced. This improves
+             * the output - if part of a model is not being used, or if parts of the model have been removed
+             * due to unsatisfied if-feature or maybe deviations, then the client can choose to not get
+             * any findings on those parts of the model.
+             */
+            if (context.shouldSuppressFindingsOnUnusedSchemaNodes()) {
+                SchemaProcessor.removeFindingsOnUnusedSchemaNodes(context, this);
+            }
+
+            /*
+             * Build the identity registry.
+             */
+            buildIdentityRegistry();
+
+            /*
+             * Collect all annotations that have been declared.
+             */
+            populateAnnotationRegistry();
+
+            /*
+             * Run onPostSchemaProcessed hook
+             */
+            context.getCustomProcessors().forEach(proc -> {
+                try {
+                    proc.onPostSchemaProcessed(context, this);
+                } catch (final Exception ex) {
+                    context.addFinding(new Finding(ParserFindingType.P000_UNSPECIFIED_ERROR,
+                            "Custom processor exception: " + ex.getMessage() + " - trace: " + StackTraceHelper
+                                    .getStackTraceInfo(ex)));
+                }
+            });
+
+        } catch (final Exception ex) {
+            /*
+             * Usually a NPE due to a really bad model, create finding so we can debug.
+             */
+            context.addFinding(new Finding(ParserFindingType.P000_UNSPECIFIED_ERROR, ex.getClass()
+                    .getSimpleName() + ": " + ex.getMessage() + " - trace: " + StackTraceHelper.getStackTraceInfo(ex)));
+        }
+    }
+
+    private static Set<YangModel> getUniqueInputs(final ParserExecutionContext context, final List<YangModel> yangModels) {
+
+        final Set<YangModel> uniqueYangModels = new HashSet<>();
+
+        for (final YangModel yangModel : yangModels) {
+            if (uniqueYangModels.contains(yangModel)) {
+                context.addFinding(new Finding(ParserFindingType.P003_DUPLICATE_INPUT, "Model Input '" + yangModel
+                        .getYangInput().getName() + "' supplied more than once. Remove duplicate from input."));
+            } else {
+                uniqueYangModels.add(yangModel);
+            }
+        }
+
+        return uniqueYangModels;
+    }
+
+    /**
+     * Link up the modules and their submodules so that these can be easily navigated later on.
+     */
+    private void relateSubmodulesToModulesAndUpdateNamespaceResolver() {
+
+        moduleRegistry.getAllYangModels().stream().filter(input -> input.getYangModelRoot().isSubmodule()).forEach(
+                submoduleInput -> {
+
+                    final YBelongsTo yBelongsTo = submoduleInput.getYangModelRoot().getSubmodule().getBelongsTo();
+                    final List<YangModel> owningModule = yBelongsTo != null ?
+                            moduleRegistry.byModuleName(yBelongsTo.getBelongsToModuleName()) :
+                            Collections.<YangModel> emptyList();
+
+                    if (owningModule.size() == 1 && owningModule.get(0).getYangModelRoot().isModule()) {
+                        /*
+                         * We now have both the submodule and the module that owns it. We can hook
+                         * them up so we can easily navigate between them. We also now know the namespace
+                         * of the submodule (it is the same as that of the owning module) and can set
+                         * the submodule namespace.
+                         */
+                        submoduleInput.getYangModelRoot().setOwningYangModelRoot(owningModule.get(0).getYangModelRoot());
+                        moduleNamespaceResolver.recordModuleMapping(submoduleInput.getYangModelRoot().getSubmodule()
+                                .getSubmoduleName(), owningModule.get(0).getYangModelRoot().getNamespace());
+                    } else {
+                        /*
+                         * There is a basic problem linking up the submodule with its owning module.
+                         */
+                        submoduleInput.getYangModelRoot().setOwningYangModelRoot(null);
+                    }
+                });
+    }
+
+    /**
+     * Builds the IdentityRegistry from the schema.
+     */
+    public void buildIdentityRegistry() {
+
+        identityRegistry.clear();
+
+        /*
+         * Pass 1 - simply add all identities to the registry.
+         */
+        moduleRegistry.getAllYangModels().forEach(yangModel -> {
+            final String namespace = yangModel.getYangModelRoot().getNamespace();
+            final String moduleName = moduleNamespaceResolver.getModuleForNamespace(namespace);
+
+            final List<YIdentity> identities = yangModel.getYangModelRoot().getModuleOrSubmodule().getChildren(
+                    CY.STMT_IDENTITY);
+            identities.forEach(yIdentity -> {
+                identityRegistry.addIdentity(new YangIdentity(namespace, moduleName, yIdentity.getIdentityName()));
+            });
+        });
+
+        /*
+         * Pass 2 - now handle the bases
+         */
+        moduleRegistry.getAllYangModels().forEach(yangModel -> {
+            final String namespace = yangModel.getYangModelRoot().getNamespace();
+            final String moduleName = moduleNamespaceResolver.getModuleForNamespace(namespace);
+
+            final List<YIdentity> identities = yangModel.getYangModelRoot().getModuleOrSubmodule().getChildren(
+                    CY.STMT_IDENTITY);
+            identities.forEach(yIdentity -> {
+
+                final YangIdentity oneIdentity = new YangIdentity(namespace, moduleName, yIdentity.getIdentityName());
+
+                for (final YBase yBase : yIdentity.getBases()) {
+
+                    final String base = yBase.getValue();
+                    String baseNamespace = null;
+
+                    if (base == null) {
+                        continue;
+                    }
+
+                    if (QNameHelper.hasPrefix(base)) {
+                        final ModuleIdentity moduleIdentity = yIdentity.getDomElement().getPrefixResolver()
+                                .getModuleForPrefix(QNameHelper.extractPrefix(base));
+                        if (moduleIdentity != null) {
+                            final YangModel baseYangModel = moduleRegistry.find(moduleIdentity);
+                            baseNamespace = baseYangModel.getYangModelRoot().getNamespace();
+                        }
+                    } else {
+                        /*
+                         * no prefix, namespace same as that for the other identity.
+                         */
+                        baseNamespace = namespace;
+                    }
+
+                    identityRegistry.addBaseIdentity(oneIdentity, new YangIdentity(baseNamespace, moduleNamespaceResolver
+                            .getModuleForNamespace(baseNamespace), QNameHelper.extractName(base)));
+                }
+            });
+        });
+    }
+
+    private void populateAnnotationRegistry() {
+
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+
+            yangModel.getYangModelRoot().getModuleOrSubmodule().getExtensionChildStatements().forEach(
+                    extensionStatement -> {
+
+                        final String prefix = extensionStatement.getExtensionModulePrefix();
+                        final String extensionStatementName = extensionStatement.getExtensionStatementName();
+                        final ModuleIdentity moduleOwningExtensionDefinition = yangModel.getPrefixResolver()
+                                .getModuleForPrefix(prefix);
+
+                        if (CIETF.ANNOTATION.equals(extensionStatementName) && CIETF.IETF_YANG_METADATA_MODULE_NAME.equals(
+                                moduleOwningExtensionDefinition.getModuleName())) {
+
+                            final String annotationNamespace = yangModel.getYangModelRoot().getNamespace();
+                            final String annotationModuleName = yangModel.getYangModelRoot().getOwningYangModelRoot()
+                                    .getModule().getModuleName();
+                            final String annotationName = extensionStatement.getValue();
+
+                            annotationRegistry.addAnnotation(new YangAnnotation(annotationNamespace, annotationModuleName,
+                                    annotationName));
+                        }
+                    });
+        }
+    }
+
+    /**
+     * Writes out all YANG modules to the specified directory. This is typically done when the DOM has been
+     * manipulated (for example, after findings have been fixed) and the resulting DOM should be written
+     * out again.
+     */
+    public void writeOut(final File targetDirectory) throws IOException {
+        writeOut(targetDirectory, new DefaultOutputFileNameResolver());
+    }
+
+    public void writeOut(final File targetDirectory, final OutputFileNameResolver resolver) throws IOException {
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+            YangDomWriter.writeOut(yangModel, resolver, targetDirectory);
+        }
+    }
+
+    public void writeOut(final OutputStreamResolver resolver) throws IOException {
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+            YangDomWriter.writeOut(yangModel, resolver);
+        }
+    }
+
+    /**
+     * Writes out to file(s) those YANG modules that have been marked as having changed.
+     * <p>
+     * Modules that have been written out are returned as FYI to the client.
+     */
+    public List<YangModel> writeOutChanged(final File targetDirectory, final OutputFileNameResolver resolver)
+            throws IOException {
+
+        final List<YangModel> writtenModelInputs = new ArrayList<>();
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+            if (yangModel.getYangModelRoot().getDomDocumentRoot().domHasBeenModified()) {
+                YangDomWriter.writeOut(yangModel, resolver, targetDirectory);
+                writtenModelInputs.add(yangModel);
+            }
+        }
+
+        return writtenModelInputs;
+    }
+
+    /**
+     * Writes out to output stream(s) those YANG modules that have been marked as having changed.
+     * <p>
+     * Modules that have been written out are returned as FYI to the client.
+     */
+    public List<YangModel> writeOutChanged(final OutputStreamResolver resolver) throws IOException {
+
+        final List<YangModel> writtenModelInputs = new ArrayList<>();
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+            if (yangModel.getYangModelRoot().getDomDocumentRoot().domHasBeenModified()) {
+                YangDomWriter.writeOut(yangModel, resolver);
+                writtenModelInputs.add(yangModel);
+            }
+        }
+
+        return writtenModelInputs;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/SchemaCheckModuleRelationships.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/SchemaCheckModuleRelationships.java
new file mode 100644
index 0000000..e233659
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/SchemaCheckModuleRelationships.java
@@ -0,0 +1,558 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.yang.YBelongsTo;
+import org.oran.smo.yangtools.parser.model.statements.yang.YImport;
+import org.oran.smo.yangtools.parser.model.statements.yang.YInclude;
+import org.oran.smo.yangtools.parser.model.statements.yang.YPrefix;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRevision;
+import org.oran.smo.yangtools.parser.model.util.StringHelper;
+
+/**
+ * Checks for prefixes, imports, revisions, includes and belongs-to in order to catch
+ * basic issues before further processing is done.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class SchemaCheckModuleRelationships {
+
+    public static void performChecks(final ParserExecutionContext context, final ModuleRegistry moduleRegistry) {
+
+        checkPrefixesUnique(context, moduleRegistry);
+        checkImportsUnique(context, moduleRegistry);
+        checkImportsSatisfied(context, moduleRegistry);
+        checkIncludesSatisfied(context, moduleRegistry);
+        checkBelongsTosSatisfied(context, moduleRegistry);
+        checkForDuplicateModules(context, moduleRegistry);
+        checkForDuplicateRevisions(context, moduleRegistry);
+        checkImplementsAndImports(context, moduleRegistry);
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * For each YAM check that all prefixes declared within the YAM are unique. If this is not the case
+     * then there will be ambiguity later on when prefixes are resolved.
+     */
+    private static void checkPrefixesUnique(final ParserExecutionContext context, final ModuleRegistry moduleRegistry) {
+
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+
+            final Set<String> prefixesInYam = new HashSet<>();
+
+            final YPrefix yPrefix = yangModel.getYangModelRoot().getPrefix();
+            if (yPrefix != null) {
+                prefixesInYam.add(yPrefix.getPrefix());
+            }
+
+            for (final YImport yImport : yangModel.getYangModelRoot().getImports()) {
+                if (yImport.getPrefix() == null) {
+                    /* No need for a finding, a invalid syntax finding would have previously issued. */
+                    continue;
+                }
+
+                final String importPrefix = yImport.getPrefix().getValue();
+                if (prefixesInYam.contains(importPrefix)) {
+                    context.addFinding(new Finding(yImport.getPrefix(), ParserFindingType.P031_PREFIX_NOT_UNIQUE,
+                            "Prefix '" + importPrefix + "' not unique in document."));
+                }
+                prefixesInYam.add(importPrefix);
+            }
+        }
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * For each YAM check that each import is unique. Note that YANG 1.1 allows the same module to be
+     * imported more than once, but then the revision has to be explicitly specified.
+     */
+    private static void checkImportsUnique(final ParserExecutionContext context, final ModuleRegistry moduleRegistry) {
+
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+
+            final Set<String> importedModulesUsingRevision = new HashSet<>();
+            final Set<String> importedModulesWithoutRevision = new HashSet<>();
+            final Set<String> importedModulesNameAndRevision = new HashSet<>();
+
+            for (final YImport yImport : yangModel.getYangModelRoot().getImports()) {
+
+                final String importedModuleName = yImport.getImportedModuleName();
+                if (importedModuleName == null) {
+                    /* No need for a finding, a invalid syntax finding would have previously issued. */
+                    continue;
+                }
+
+                final String importedModuleRevision = yImport.getRevisionDate() == null ?
+                        null :
+                        yImport.getRevisionDate().getValue();
+
+                if (importedModuleRevision == null) {
+                    checkOneImportWithoutRevisionIsUnique(context, yImport, importedModuleName,
+                            importedModulesUsingRevision, importedModulesWithoutRevision);
+                } else {
+                    checkOneImportWithRevisionIsUnique(context, yImport, importedModuleName, importedModuleRevision,
+                            importedModulesUsingRevision, importedModulesWithoutRevision, importedModulesNameAndRevision);
+                }
+            }
+        }
+    }
+
+    private static void checkOneImportWithoutRevisionIsUnique(final ParserExecutionContext context, final YImport yImport,
+            final String importedModuleName, final Set<String> importedModulesUsingRevision,
+            final Set<String> importedModulesWithoutRevision) {
+
+        /*
+         * Imported without revision, i.e. use "any" version of the module. Check that there is not already
+         * an import with an explicit revision.
+         */
+        if (importedModulesUsingRevision.contains(importedModuleName)) {
+            context.addFinding(new Finding(yImport, ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES,
+                    "Module '" + importedModuleName + "' imported more than once - once without revision, once with explicit revision."));
+        }
+        if (importedModulesWithoutRevision.contains(importedModuleName)) {
+            context.addFinding(new Finding(yImport, ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES,
+                    "Module '" + importedModuleName + "' imported multiple times without revision."));
+        }
+
+        importedModulesWithoutRevision.add(importedModuleName);
+    }
+
+    private static void checkOneImportWithRevisionIsUnique(final ParserExecutionContext context, final YImport yImport,
+            final String importedModuleName, final String importedModuleRevision,
+            final Set<String> importedModulesUsingRevision, final Set<String> importedModulesWithoutRevision,
+            final Set<String> importedModulesNameAndRevision) {
+        /*
+         * Import with exact revision. Check not already imported without revision, and not doubly-imported.
+         */
+        if (importedModulesWithoutRevision.contains(importedModuleName)) {
+            context.addFinding(new Finding(yImport, ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES,
+                    "Module '" + importedModuleName + "' imported more than once - once without revision, once with explicit revision."));
+        }
+
+        final String key = importedModuleName + "/" + importedModuleRevision;
+
+        if (importedModulesNameAndRevision.contains(key)) {
+            context.addFinding(new Finding(yImport, ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES,
+                    "Module '" + key + "' imported more than once."));
+        }
+
+        importedModulesUsingRevision.add(importedModuleName);
+        importedModulesNameAndRevision.add(key);
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * For each YAM check that all "import" statements can be satisfied,
+     * i.e. the imported YAM is also available.
+     */
+    private static void checkImportsSatisfied(final ParserExecutionContext context, final ModuleRegistry moduleRegistry) {
+
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+            for (final YImport yImport : yangModel.getYangModelRoot().getImports()) {
+
+                final String importedModuleName = yImport.getImportedModuleName();
+                final String importedModuleRevision = yImport.getRevisionDate() == null ?
+                        null :
+                        yImport.getRevisionDate().getValue();
+
+                if (importedModuleName == null) {
+                    //No need for a finding, a invalid syntax finding would have previously issued.
+                    continue;
+                }
+
+                if (yangModel.getModuleIdentity().getModuleName().equals(importedModuleName)) {
+                    context.addFinding(new Finding(yImport, ParserFindingType.P034_UNRESOLVABLE_IMPORT,
+                            "Module '" + importedModuleName + "' imports itself."));
+                } else {
+                    if (importedModuleRevision == null) {
+                        checkOneImportWithoutRevision(context, moduleRegistry, yImport, importedModuleName);
+                    } else {
+                        checkOneImportWithExplicitRevision(context, moduleRegistry, yImport, importedModuleName,
+                                importedModuleRevision);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void checkOneImportWithoutRevision(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry, final YImport yImport, final String importedModuleName) {
+        /*
+         * The import does not have a revisions. So try to find exactly one module of the given name in the input.
+         */
+        final List<YangModel> foundModulesAnyRevision = moduleRegistry.byModuleName(importedModuleName);
+        switch (foundModulesAnyRevision.size()) {
+            case 0:
+                context.addFinding(new Finding(yImport, ParserFindingType.P034_UNRESOLVABLE_IMPORT,
+                        "Module '" + importedModuleName + "' not found in input."));
+                break;
+            case 1:
+                /*
+                 * OK, the import uses "any" revision and exactly one revision of the module was found in the registry.
+                 */
+                break;
+            default:
+                /*
+                 * This is ambiguous, so issue a finding.
+                 */
+                context.addFinding(new Finding(yImport, ParserFindingType.P035_AMBIGUOUS_IMPORT,
+                        "Module '" + importedModuleName + "' has multiple revisions in the input, but desired exact revision not specified in the 'import' statement."));
+        }
+    }
+
+    private static void checkOneImportWithExplicitRevision(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry, final YImport yImport, final String importedModuleName,
+            final String importedModuleRevision) {
+        /*
+         * The import has a revisions. So try to find exactly one module of the given name and given revision in the input.
+         */
+        final YangModel foundModulesExactRevision = moduleRegistry.exactMatch(importedModuleName, importedModuleRevision);
+        if (foundModulesExactRevision == null) {
+            /*
+             * That revision does not exist. Maybe a different revision is in the input?
+             */
+            final List<YangModel> foundModulesAnyRevision = moduleRegistry.byModuleName(importedModuleName);
+            if (foundModulesAnyRevision.isEmpty()) {
+                context.addFinding(new Finding(yImport, ParserFindingType.P034_UNRESOLVABLE_IMPORT,
+                        "Module '" + importedModuleName + "' with revision '" + importedModuleRevision + "' not found in input."));
+            } else {
+                context.addFinding(new Finding(yImport, ParserFindingType.P034_UNRESOLVABLE_IMPORT,
+                        "Module '" + importedModuleName + "' with revision '" + importedModuleRevision + "' not found in input, but a module with that name and revision '" + foundModulesAnyRevision
+                                .get(0).getModuleIdentity().getRevision() + "' has been found."));
+            }
+        }
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * For each submodule check that the "belongs-to" statement can be satisfied.
+     */
+    private static void checkBelongsTosSatisfied(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry) {
+
+        final List<YangModel> subModules = moduleRegistry.getAllYangModels().stream().filter(yangModel -> yangModel
+                .getYangModelRoot().isSubmodule()).collect(Collectors.toList());
+
+        for (final YangModel subModuleYangModel : subModules) {
+
+            final YBelongsTo belongsTo = subModuleYangModel.getYangModelRoot().getSubmodule().getBelongsTo();
+            if (belongsTo == null) {
+                /* No need for a finding, would have been previously issued as missing mandatory child statement. */
+                continue;
+            }
+
+            final String belongsToModuleName = belongsTo.getBelongsToModuleName();
+            if (belongsToModuleName == null) {
+                /* No need for a finding, a invalid syntax finding would have previously issued. */
+                continue;
+            }
+
+            final List<YangModel> modules = moduleRegistry.byModuleName(belongsToModuleName);
+            if (modules.isEmpty()) {
+                context.addFinding(new Finding(belongsTo, ParserFindingType.P039_UNRESOLVABLE_BELONGS_TO,
+                        "Owning module '" + belongsToModuleName + "' not found in input."));
+            } else {
+                checkBelongsToAgainstModule(context, belongsTo, subModuleYangModel, modules.get(0));
+            }
+        }
+    }
+
+    private static void checkBelongsToAgainstModule(final ParserExecutionContext context, final YBelongsTo belongsTo,
+            final YangModel subModuleModelInput, final YangModel owningModuleModelInput) {
+
+        /*
+         * Check the found module is actually a module, and that it actually references the submodule!
+         */
+        if (!owningModuleModelInput.getYangModelRoot().isModule()) {
+            context.addFinding(new Finding(belongsTo, ParserFindingType.P046_NOT_A_MODULE, "'" + belongsTo
+                    .getBelongsToModuleName() + "' is not a module."));
+        } else {
+            final String subModuleName = subModuleModelInput.getYangModelRoot().getModuleOrSubModuleName();
+            boolean owningModuleIncludesTheSubmodule = false;
+            for (final YInclude include : owningModuleModelInput.getYangModelRoot().getModule().getIncludes()) {
+                if (subModuleName.equals(include.getIncludedSubModuleName())) {
+                    owningModuleIncludesTheSubmodule = true;
+                    break;
+                }
+            }
+            if (!owningModuleIncludesTheSubmodule) {
+                context.addFinding(new Finding(subModuleModelInput, ParserFindingType.P048_ORPHAN_SUBMODULE,
+                        "Owning module '" + owningModuleModelInput.getYangModelRoot()
+                                .getModuleOrSubModuleName() + "' does not 'include' this submodule."));
+            }
+        }
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * Check up the usage of the Conformance Types.
+     */
+    private static void checkImplementsAndImports(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry) {
+
+        int nrYangFilesThatImplement = 0;
+
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+
+            if (yangModel.getConformanceType() == ConformanceType.IMPLEMENT) {
+                nrYangFilesThatImplement++;
+            }
+
+            if (yangModel.getYangModelRoot().isSubmodule()) {
+                final YBelongsTo belongsTo = yangModel.getYangModelRoot().getSubmodule().getBelongsTo();
+                if (belongsTo == null) {
+                    /* No need for a finding, a missing mandatory child statement would have issued already. */
+                    return;
+                }
+
+                final String belongsToModuleName = belongsTo.getBelongsToModuleName();
+                if (belongsToModuleName == null) {
+                    /* No need for a finding, an invalid syntax finding would have issued already. */
+                    return;
+                }
+
+                final List<YangModel> modules = moduleRegistry.byModuleName(belongsToModuleName);
+                if (!modules.isEmpty() && yangModel.getConformanceType() != modules.get(0).getConformanceType()) {
+                    context.addFinding(new Finding(belongsTo, ParserFindingType.P006_IMPLEMENT_IMPORT_MISMATCH,
+                            "Submodule is " + yangModel.getConformanceType().toString() + " but owning module is " + modules
+                                    .get(0).getConformanceType()));
+                }
+            }
+        }
+
+        if (nrYangFilesThatImplement == 0) {
+            context.addFinding(new Finding(ParserFindingType.P005_NO_IMPLEMENTS,
+                    "Need at least a single module that IMPLEMENTs."));
+        }
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * A module with the exact same name should not be more than once in the input as IMPLEMENT.
+     */
+    private static void checkForDuplicateModules(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry) {
+
+        final Set<String> implementingModules = new HashSet<>();
+        final Set<String> importedModules = new HashSet<>();
+
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+
+            final String moduleName = yangModel.getModuleIdentity().getModuleName();
+
+            if (yangModel.getConformanceType() == ConformanceType.IMPLEMENT) {
+
+                if (implementingModules.contains(moduleName)) {
+                    context.addFinding(new Finding(yangModel, ParserFindingType.P043_SAME_MODULE_IMPLEMENTS_MORE_THAN_ONCE,
+                            "Module '" + moduleName + "' multiple times in the input with conformance type IMPLEMENT."));
+                }
+                if (importedModules.contains(moduleName)) {
+                    context.addFinding(new Finding(yangModel, ParserFindingType.P044_SAME_MODULE_IMPLEMENTS_AND_IMPORTS,
+                            "Module '" + moduleName + "' multiple times in the input, with both conformance types IMPLEMENT and IMPORT."));
+                }
+                implementingModules.add(moduleName);
+
+            } else { // ConformanceType.IMPORT
+
+                if (implementingModules.contains(moduleName)) {
+                    context.addFinding(new Finding(yangModel, ParserFindingType.P044_SAME_MODULE_IMPLEMENTS_AND_IMPORTS,
+                            "Module '" + moduleName + "' multiple times in the input, with both conformance types IMPLEMENT and IMPORT."));
+                }
+                importedModules.add(moduleName);
+            }
+        }
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * A module should not have duplicate revisions.
+     */
+    private static void checkForDuplicateRevisions(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry) {
+
+        for (final YangModel yangModel : moduleRegistry.getAllYangModels()) {
+
+            final Set<String> uniqueRevisions = new HashSet<>();
+
+            for (final YRevision yRevision : yangModel.getYangModelRoot().getRevisions()) {
+                final String revision = yRevision.getValue();
+                if (uniqueRevisions.contains(revision)) {
+                    if (revision.equals(yangModel.getModuleIdentity().getRevision())) {
+                        context.addFinding(new Finding(yangModel, ParserFindingType.P050_DUPLICATE_LATEST_REVISION,
+                                "Latest revision '" + revision + "' exists more than once in the (sub-)module."));
+                    } else {
+                        context.addFinding(new Finding(yangModel, ParserFindingType.P049_DUPLICATE_REVISION,
+                                "Prior revision '" + revision + "' exists more than once in the (sub-)module."));
+                    }
+                }
+                uniqueRevisions.add(revision);
+            }
+        }
+    }
+
+    // ==============================================================================================================================================
+
+    /**
+     * For each module check that all "include" statements can be satisfied, i.e. are in the input. Also that the submodule
+     * belongs to the module.
+     */
+    private static void checkIncludesSatisfied(final ParserExecutionContext context, final ModuleRegistry moduleRegistry) {
+
+        final List<YangModel> modulesOnly = moduleRegistry.getAllYangModels().stream().filter(yangModel -> yangModel
+                .getYangModelRoot().isModule()).collect(Collectors.toList());
+
+        for (final YangModel yangModel : modulesOnly) {
+
+            for (final YInclude yInclude : yangModel.getYangModelRoot().getModule().getIncludes()) {
+
+                final String includedSubmoduleName = yInclude.getIncludedSubModuleName();
+                if (includedSubmoduleName == null) {
+                    // No need for a finding, an invalid syntax finding would have issued already.
+                    continue;
+                }
+
+                final String includedSubmoduleRevision = yInclude.getRevisionDate() == null ?
+                        null :
+                        yInclude.getRevisionDate().getValue();
+
+                if (includedSubmoduleRevision == null) {
+                    checkOneIncludeWithoutRevision(context, moduleRegistry, yangModel, yInclude, includedSubmoduleName);
+                } else {
+                    checkOneIncludeWithExplicitRevision(context, moduleRegistry, yangModel, yInclude, includedSubmoduleName,
+                            includedSubmoduleRevision);
+                }
+            }
+        }
+    }
+
+    private static void checkOneIncludeWithoutRevision(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry, final YangModel yangModel, final YInclude yInclude,
+            final String includedSubmoduleName) {
+        /*
+         * The include was done without revision, so try to find "any" revision.
+         */
+        final List<YangModel> subModulesFoundAnyRevision = moduleRegistry.byModuleName(includedSubmoduleName);
+
+        switch (subModulesFoundAnyRevision.size()) {
+            case 0:
+                context.addFinding(new Finding(yInclude, ParserFindingType.P037_UNRESOLVABLE_INCLUDE,
+                        "Submodule " + includedSubmoduleName + " not found in input."));
+                break;
+            case 1:
+                checkIncludedSubmoduleAgainstModule(context, yInclude, subModulesFoundAnyRevision.get(0), yangModel);
+                break;
+            default:
+                context.addFinding(new Finding(yInclude, ParserFindingType.P038_AMBIGUOUS_INCLUDE,
+                        "Multiple revisions of submodule " + includedSubmoduleName + " found in input."));
+                break;
+        }
+    }
+
+    private static void checkOneIncludeWithExplicitRevision(final ParserExecutionContext context,
+            final ModuleRegistry moduleRegistry, final YangModel yangModel, final YInclude yInclude,
+            final String includedSubmoduleName, final String includedSubmoduleRevision) {
+        /*
+         * The include was done with revision, so try to find the exact revision.
+         */
+        final String moduleNameAndRevision = StringHelper.getModuleNameAndRevision(includedSubmoduleName,
+                includedSubmoduleRevision);
+
+        final YangModel subModuleFoundWithExactRevision = moduleRegistry.exactMatch(includedSubmoduleName,
+                includedSubmoduleRevision);
+        if (subModuleFoundWithExactRevision == null) {
+            final List<YangModel> subModulesFoundAnyRevision = moduleRegistry.byModuleName(includedSubmoduleName);
+            if (subModulesFoundAnyRevision.isEmpty()) {
+                context.addFinding(new Finding(yInclude, ParserFindingType.P037_UNRESOLVABLE_INCLUDE,
+                        "Submodule " + moduleNameAndRevision + " not found in input."));
+            } else {
+                /*
+                 * Different revision found.
+                 */
+                context.addFinding(new Finding(yInclude, ParserFindingType.P037_UNRESOLVABLE_INCLUDE,
+                        "Submodule " + moduleNameAndRevision + " not found in the input, but a submodule with that name and with revision '" + subModulesFoundAnyRevision
+                                .get(0).getModuleIdentity().getRevision() + "' is in the input."));
+            }
+        } else {
+            checkIncludedSubmoduleAgainstModule(context, yInclude, subModuleFoundWithExactRevision, yangModel);
+        }
+    }
+
+    private static void checkIncludedSubmoduleAgainstModule(final ParserExecutionContext context,
+            final YInclude includeStatement, final YangModel subModuleModelInput, final YangModel moduleModelInput) {
+
+        final String yangVersionOfSubmodule = subModuleModelInput.getYangModelRoot().getYangVersion();
+        final String yangVersionOfModule = moduleModelInput.getYangModelRoot().getYangVersion();
+
+        /*
+         * Make sure the submodule is actually a submodule.
+         */
+        if (!subModuleModelInput.getYangModelRoot().isSubmodule()) {
+            context.addFinding(new Finding(includeStatement, ParserFindingType.P045_NOT_A_SUBMODULE,
+                    "'" + subModuleModelInput.getYangModelRoot()
+                            .getModuleOrSubModuleName() + "' is not a submodule and can therefore not be included."));
+            return;
+        }
+        /*
+         * YANG versions must match up between module and all its submodules.
+         */
+        if (!yangVersionOfModule.equals(yangVersionOfSubmodule)) {
+            context.addFinding(new Finding(includeStatement,
+                    ParserFindingType.P041_DIFFERENT_YANG_VERSIONS_BETWEEN_MODULE_AND_SUBMODULES,
+                    "The yang versions differ between module and submodule(s)."));
+        }
+        /*
+         * Make sure the submodule actually belongs to the module.
+         */
+        final YBelongsTo belongsTo = subModuleModelInput.getYangModelRoot().getSubmodule().getBelongsTo();
+        if (belongsTo == null) {
+            // No need for a finding, a missing mandatory child statement finding would have issued already.
+            return;
+        }
+
+        final String belongsToModuleName = belongsTo.getBelongsToModuleName();
+        if (belongsToModuleName == null) {
+            // No need for a finding, an invalid syntax finding would have issued already.
+            return;
+        }
+
+        if (!belongsToModuleName.equals(moduleModelInput.getYangModelRoot().getModuleOrSubModuleName())) {
+            context.addFinding(new Finding(includeStatement, ParserFindingType.P047_SUBMODULE_OWNERSHIP_MISMATCH,
+                    "The referenced submodule belongs to '" + belongsToModuleName + "', not this module here."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/SchemaProcessor.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/SchemaProcessor.java
new file mode 100644
index 0000000..cab50b3
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/schema/SchemaProcessor.java
@@ -0,0 +1,823 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.resolvers.Helper;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YCase;
+import org.oran.smo.yangtools.parser.model.statements.yang.YChoice;
+import org.oran.smo.yangtools.parser.model.statements.yang.YFeature;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIfFeature;
+import org.oran.smo.yangtools.parser.model.statements.yang.YInput;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YOutput;
+import org.oran.smo.yangtools.parser.model.statements.yang.YStatus;
+import org.oran.smo.yangtools.parser.model.statements.yang.YSubmodule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIfFeature.Token;
+import org.oran.smo.yangtools.parser.model.util.YangFeature;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+/**
+ * Processes the schema.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class SchemaProcessor {
+
+    // =================================== SUBMODULE HANDLING =====================================
+
+    public static void resolveSubmodules(final Schema schema) {
+
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            if (yangModelFile.getYangModelRoot().isSubmodule()) {
+                mergeInSubmodule(schema, yangModelFile);
+            }
+        }
+    }
+
+    /**
+     * Merges the content of submodules into their owning modules. This makes processing later on
+     * considerably easier (e.g. much easier to find the target node for an augment or deviation).
+     * <p/>
+     * Only the statement tree is manipulated, the DOM tree remains unchanged.
+     */
+    private static void mergeInSubmodule(final Schema schema, final YangModel yangModel) {
+
+        final YSubmodule submodule = yangModel.getYangModelRoot().getSubmodule();
+
+        final String belongsToModuleName = submodule.getBelongsToValue();
+        if (belongsToModuleName == null) {
+            // No need for a finding, an invalid syntax finding would have previously issued.
+            return;
+        }
+
+        final List<YangModel> moduleYangFiles = schema.getModuleRegistry().byModuleName(belongsToModuleName);
+        if (moduleYangFiles.size() != 1) {
+            // No need to record a finding - would have been caught previously.
+            return;
+        }
+
+        /*
+         * We are basically taking all the schema nodes and re-house them into the module. Note: The prefix-resolver
+         * of all of these statements will not be adjusted, i.e. they will keep the prefix resolver of the submodule.
+         * This is to handle a situation where the prefixes declared are different between those in the module and those
+         * in the submodule(s) - which is frequently the case.
+         */
+        final YModule owningModule = moduleYangFiles.get(0).getYangModelRoot().getModule();
+        if (owningModule == null) {
+            // submodule owned by submodule, which is wrong; no need to record a finding - would have been caught previously.
+            return;
+        }
+
+        owningModule.addChildren(submodule.getAnydata());
+        owningModule.addChildren(submodule.getAnyxmls());
+        owningModule.addChildren(submodule.getAugments());
+        owningModule.addChildren(submodule.getChoices());
+        owningModule.addChildren(submodule.getContainers());
+        owningModule.addChildren(submodule.getDeviations());
+        owningModule.addChildren(submodule.getExtensions());
+        owningModule.addChildren(submodule.getFeatures());
+        owningModule.addChildren(submodule.getGroupings());
+        owningModule.addChildren(submodule.getIdentities());
+        owningModule.addChildren(submodule.getLeafLists());
+        owningModule.addChildren(submodule.getLeafs());
+        owningModule.addChildren(submodule.getLists());
+        owningModule.addChildren(submodule.getNotifications());
+        owningModule.addChildren(submodule.getRpcs());
+        owningModule.addChildren(submodule.getTypedefs());
+        owningModule.addChildren(submodule.getUses());
+    }
+
+    // =================================== CASE HANDLING =====================================
+
+    @SuppressWarnings("unchecked")
+    public static void fixupOmittedCaseStatements(final Schema schema) {
+        final List<YChoice> allChoices = (List<YChoice>) Helper.findStatementsInSchema(CY.STMT_CHOICE, schema);
+        for (final YChoice oneChoice : allChoices) {
+            injectCaseForShorthandedStatements(oneChoice);
+        }
+    }
+
+    private static final Set<StatementModuleAndName> POSSIBLY_SHORTHANDED_STATEMENTS = new HashSet<>(Arrays.asList(
+            CY.STMT_ANYDATA, CY.STMT_ANYXML, CY.STMT_CHOICE, CY.STMT_CONTAINER, CY.STMT_LEAF_LIST, CY.STMT_LEAF,
+            CY.STMT_LIST));
+
+    /**
+     * Injects a 'case' statement above any data node-defining statement found directly under
+     * a 'choice'. In Yang, this is referred-to as "shorthand". Example:
+     * <p/>
+     * choice my-choice {
+     * container option1 { ... }
+     * container option2 { ... }
+     * }
+     * <p/>
+     * Usage of shorthand causes problems, as schema node paths referring to data nodes within
+     * the choice must also use the identity of the (omitted) case statement. To simplify
+     * navigation later on, we inject these missing case statements here. The above example is
+     * effectively modified to:
+     * <p/>
+     * choice my-choice {
+     * case option1 {
+     * container option1 { ... }
+     * }
+     * case option2 {
+     * container option2 { ... }
+     * }
+     * }
+     * <p/>
+     * Both the DOM tree and the statement tree are adjusted. The artificial 'case' statement
+     * will be given the same name and line number as the statement defining the data node.
+     * <p/>
+     * The parent statement is usually a 'choice', but could be an 'augment' or 'grouping',
+     * which inject into a 'choice'.
+     */
+    public static void injectCaseForShorthandedStatements(final AbstractStatement parentStatement) {
+
+        final List<AbstractStatement> shorthandedStatements = parentStatement.getChildren(POSSIBLY_SHORTHANDED_STATEMENTS);
+
+        for (final AbstractStatement shorthandedStatement : shorthandedStatements) {
+            /*
+             * The identifier of the case statement is equal to the identifier of the short-handed statement.
+             */
+            final String caseIdentifier = shorthandedStatement.getStatementIdentifier();
+            /*
+             * Create new DOM element for the 'case' statement first. It will sit below the parent
+             * statement and has no children (yet). As line number, we will give it the line number
+             * of the short-handed statement.
+             */
+            final YangDomElement caseDomElement = new YangDomElement(CY.CASE, caseIdentifier, parentStatement
+                    .getDomElement(), shorthandedStatement.getDomElement().getLineNumber());
+            /*
+             * Now create the 'case' statement under the parent statement, and then move
+             * the short-handed statement under the 'case'. That cleans up the statement tree.
+             */
+            final YCase newCase = new YCase(parentStatement, caseDomElement);
+            newCase.addChild(shorthandedStatement);
+            /*
+             * We still need to clean up the DOM tree - we do something very similar here,
+             * basically re-parenting the short-handed DOM element under the 'case' DOM element.
+             */
+            caseDomElement.reparent(shorthandedStatement.getDomElement());
+
+            /*
+             * The properties need to be copied over.
+             */
+            newCase.copyPropertiesFrom(shorthandedStatement);
+
+            /*
+             * Any 'if-feature' statements that sit under the shorthand statement also need to
+             * be cloned to make the newly-created case just as much dependent on those.
+             */
+            final List<YIfFeature> ifFeaturesOfShorthand = shorthandedStatement.getChildren(CY.STMT_IF_FEATURE);
+            for (final YIfFeature ifFeature : ifFeaturesOfShorthand) {
+                final YIfFeature clonedIfFeature = new YIfFeature(newCase, ifFeature.getDomElement());
+                clonedIfFeature.cloneFrom(ifFeature);
+            }
+
+            Helper.addGeneralInfoAppData(newCase, "originally omitted 'case' statement inserted for readability.");
+        }
+    }
+
+    // =================================== INPUT / OUTPUT HANDLING =====================================
+
+    public static void fixupMissingInputOutputStatements(final Schema schema) {
+        fixupMissingInputOutputStatements(schema, CY.STMT_ACTION);
+        fixupMissingInputOutputStatements(schema, CY.STMT_RPC);
+    }
+
+    /**
+     * Some RPCs or actions do not use any input or output. However, it is still possible for data nodes to
+     * be augmented-into RPCs and actions. For this to work, the targetNode path will list the input/output
+     * statement. We simplify our processing later on if we inject any missing input/output statements now.
+     */
+    @SuppressWarnings("unchecked")
+    private static <T extends AbstractStatement> void fixupMissingInputOutputStatements(final Schema schema,
+            final StatementModuleAndName actionOrRpcClazz) {
+
+        final List<T> statements = (List<T>) Helper.findStatementsInSchema(actionOrRpcClazz, schema);
+        for (final T actionOrRpc : statements) {
+
+            if (actionOrRpc.getChild(CY.STMT_INPUT) == null) {
+                /*
+                 * Create new DOM element for the 'input' statement. It will sit below the 'action' (or 'rpc')
+                 * statement and has no children. As line number, we will give it the line number of the parent.
+                 */
+                final YangDomElement inputDomElement = new YangDomElement(CY.INPUT, null, actionOrRpc.getDomElement(),
+                        actionOrRpc.getDomElement().getLineNumber());
+                /*
+                 * And create the statement.
+                 */
+                final YInput yInput = new YInput(actionOrRpc, inputDomElement);
+                /*
+                 * Copy over properties as well.
+                 */
+                yInput.copyPropertiesFrom(actionOrRpc);
+            }
+
+            /*
+             * Exact same now for the output.
+             */
+            if (actionOrRpc.getChild(CY.STMT_OUTPUT) == null) {
+                final YangDomElement outputDomElement = new YangDomElement(CY.OUTPUT, null, actionOrRpc.getDomElement(),
+                        actionOrRpc.getDomElement().getLineNumber());
+                final YOutput yOutput = new YOutput(actionOrRpc, outputDomElement);
+                yOutput.copyPropertiesFrom(actionOrRpc);
+            }
+        }
+    }
+
+    // =================================== DATA NODE HANDLING FOR IMPORT-ONLY MODULES =====================================
+
+    public static void removeProtocolAccessibleObjects(final Schema schema) {
+        /*
+         * According to RFC, any statement that "implements any protocol-accessible objects" cannot remain in the
+         * module, so we delete those. Such statements may have been augmented into a lower part of the tree, so we
+         * need to navigate down the tree.
+         */
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            removeProtocolAccessibleObjects(yangModelFile.getYangModelRoot().getModuleOrSubmodule());
+        }
+    }
+
+    private static final Set<StatementModuleAndName> PROTOCOL_ACCESSIBLE_STATEMENTS = new HashSet<>(Arrays.asList(
+            CY.STMT_ANYDATA, CY.STMT_ANYXML, CY.STMT_AUGMENT, CY.STMT_CHOICE, CY.STMT_CONTAINER, CY.STMT_DEVIATION,
+            CY.STMT_LEAF, CY.STMT_LEAF_LIST, CY.STMT_LIST, CY.STMT_NOTIFICATION, CY.STMT_RPC, CY.STMT_USES));
+
+    private static void removeProtocolAccessibleObjects(final AbstractStatement statement) {
+
+        final List<AbstractStatement> children = statement.getNonExtensionChildStatements();
+        for (final AbstractStatement child : children) {
+            if (child.getEffectiveConformanceType() == ConformanceType.IMPORT && PROTOCOL_ACCESSIBLE_STATEMENTS.contains(
+                    child.getStatementModuleAndName())) {
+                statement.removeChild(child);
+            } else if (child.definesSchemaNode()) {
+                removeProtocolAccessibleObjects(child);
+            }
+        }
+    }
+
+    // =================================== IF-FEATURE HANDLING =====================================
+
+    public static void removeDataNodesNotSatisfyingIfFeature(final ParserExecutionContext context, final Schema schema) {
+
+        /*
+         * There is a special case that requires some up-front logic: it is possible for
+         * a feature itself to be constrained by if-feature. This does not mean that the
+         * feature shall be removed. From the RFC:
+         *
+         * "In order for a server to support a feature that is dependent on any other
+         * features (i.e., the feature has one or more "if-feature" substatements), the
+         * server MUST also support all the dependent features."
+         *
+         * Consider this:
+         *
+         *   feature feature-abc;
+         *   feature feature-def;
+         *   feature feature-xyz {
+         *       if-feature "feature-abc and feature-def";
+         *   }
+         *
+         * What this means is that xyz can only be supported if both abc and def are
+         * supported. The client that has supplied the YANG library, however, could have
+         * gotten this wrong. So we need to check for that.
+         */
+        checkFeaturesConstrainedByIfFeatures(context, schema);
+
+        /*
+         * Now that this is done, remove statements as required...
+         */
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            removeFromModule(context, schema, yangModelFile);
+        }
+    }
+
+    private static void removeFromModule(final ParserExecutionContext context, final Schema schema,
+            final YangModel yangModelFile) {
+
+        final AbstractStatement moduleOrSubmodule = yangModelFile.getYangModelRoot().getModuleOrSubmodule();
+
+        /*
+         * We go through the statement tree and check each statement whether it's
+         * if-feature is fulfilled or not.
+         */
+        handleStatementPossiblyConstrainedByIfFeature(context, schema, moduleOrSubmodule);
+    }
+
+    private static void handleStatementPossiblyConstrainedByIfFeature(final ParserExecutionContext context,
+            final Schema schema, final AbstractStatement parent) {
+
+        final List<AbstractStatement> children = new ArrayList<>(parent.getChildStatements());		// deep copy required
+        for (final AbstractStatement child : children) {
+            if (!child.is(CY.STMT_FEATURE) && !ifFeaturesUnderStatementAreSatisfied(context, schema, child)) {
+                /*
+                 * Remove the statement and keep a note of it!
+                 */
+                addChildRemovedDueToIfFeatureAppData(parent, child.getDomElement().getNameValue());
+                if (child.getStatementIdentifier() != null && !child.getStatementIdentifier().isEmpty()) {
+                    addRemovedChildIdentifierDueToIfFeature(parent, child.getStatementIdentifier());
+                }
+
+                parent.removeChild(child);
+            } else {
+                /*
+                 * Go into the sub-tree.
+                 */
+                handleStatementPossiblyConstrainedByIfFeature(context, schema, child);
+            }
+        }
+    }
+
+    private static void checkFeaturesConstrainedByIfFeatures(final ParserExecutionContext context, final Schema schema) {
+
+        for (final YangModel yangModel : schema.getModuleRegistry().getAllYangModels()) {
+
+            final List<YFeature> featuresInYam = yangModel.getYangModelRoot().getModuleOrSubmodule().getChildren(
+                    CY.STMT_FEATURE);
+
+            for (final YFeature feature : featuresInYam) {
+                if (ifFeaturesUnderStatementAreSatisfied(context, schema, feature)) {
+                    continue;
+                }
+
+                /*
+                 * Some if-feature is not satisfied. This means that the feature itself MUST NOT
+                 * be supported. Better check!
+                 */
+                final String namespace = feature.getDomElement().getYangModel().getYangModelRoot().getNamespace();
+                final String moduleName = feature.getDomElement().getYangModel().getYangModelRoot().getOwningSchema()
+                        .getModuleNamespaceResolver().getModuleForNamespace(namespace);
+
+                final YangFeature yangFeature = new YangFeature(namespace, moduleName, feature.getFeatureName());
+                if (context.getSupportedFeatures().contains(yangFeature)) {
+                    context.addFinding(new Finding(feature, ParserFindingType.P086_FEATURE_CANNOT_BE_SUPPORTED,
+                            "Feature '" + feature
+                                    .getFeatureName() + "' has been supplied as supported, but it's 'if-feature' statement evaluates to false."));
+                }
+            }
+        }
+    }
+
+    private static boolean ifFeaturesUnderStatementAreSatisfied(final ParserExecutionContext context, final Schema schema,
+            final AbstractStatement statement) {
+
+        if (!statement.hasAtLeastOneChildOf(CY.STMT_IF_FEATURE)) {
+            return true;
+        }
+
+        final List<YIfFeature> ifFeatures = statement.getChildren(CY.STMT_IF_FEATURE);
+
+        /*
+         * There can be multiple if-feature statements under a statement. They all must
+         * be true for the overall result to be true.
+         */
+        for (final YIfFeature ifFeature : ifFeatures) {
+            if (!ifFeatureIsSatisfied(context, schema, ifFeature)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean ifFeatureIsSatisfied(final ParserExecutionContext context, final Schema schema,
+            final YIfFeature ifFeature) {
+
+        final List<Token> tokens = ifFeature.getTokens();
+
+        /*
+         * If the tokens are not valid the logic further below where we simplify the
+         * expression until we get a result will throw errors, so catch this problem
+         * here.
+         */
+        if (!ifFeature.areTokensValid(context, tokens)) {
+            return false;
+        }
+
+        if (tokens.size() == 1) {
+            /*
+             * Simple if-feature statement, just referring to a single feature, easy.
+             */
+            return isFeatureSupported(context, schema, ifFeature, tokens.get(0).name);
+        }
+
+        /*
+         * More than one token in the if-feature. This means we need to apply boolean
+         * logic to the string We build a logical expression first, and then simplify it
+         * bit-by-bit.
+         */
+        final List<Operand> expression = buildExpressionFromTokens(context, schema, ifFeature, tokens);
+
+        final Operand result = simplify(expression);
+        return result == Operand.TRUE;
+    }
+
+    private static boolean isFeatureSupported(final ParserExecutionContext context, final Schema schema,
+            final YIfFeature ifFeature, final String possiblyPrefixedFeatureName) {
+
+        final String featureName = QNameHelper.extractName(possiblyPrefixedFeatureName);
+        String namespace = null;
+
+        if (QNameHelper.hasPrefix(possiblyPrefixedFeatureName)) {
+            final String prefix = QNameHelper.extractPrefix(possiblyPrefixedFeatureName);
+            final ModuleIdentity moduleIdentityForPrefix = ifFeature.getPrefixResolver().getModuleForPrefix(prefix);
+            if (moduleIdentityForPrefix == null) {
+                context.addFinding(new Finding(ifFeature, ParserFindingType.P033_UNRESOLVEABLE_PREFIX,
+                        "Unresolvable prefix '" + prefix + "'."));
+                return false;
+            }
+
+            final YangModel yangModel = schema.getModuleRegistry().find(moduleIdentityForPrefix);
+            if (yangModel == null) {
+                context.addFinding(new Finding(ifFeature, ParserFindingType.P034_UNRESOLVABLE_IMPORT,
+                        "Cannot find '" + moduleIdentityForPrefix + "' in input."));
+                return false;
+            }
+
+            namespace = yangModel.getYangModelRoot().getNamespace();
+        } else {
+            /*
+             * No prefix, so refers to same module in which it was defined.
+             */
+            namespace = ifFeature.getDomElement().getYangModel().getYangModelRoot().getNamespace();
+        }
+
+        final String moduleName = ifFeature.getDomElement().getYangModel().getYangModelRoot().getOwningSchema()
+                .getModuleNamespaceResolver().getModuleForNamespace(namespace);
+
+        final YangFeature yangFeature = new YangFeature(namespace, moduleName, featureName);
+        return context.getSupportedFeatures().contains(yangFeature);
+    }
+
+    // -------------------------- All the expression handling stuff here -------------------------------
+
+    private enum Operand {
+        NOT,
+        OR,
+        AND,
+        TRUE,
+        FALSE,
+        LEFT_PARENTHESIS,
+        RIGHT_PARENTHESIS;
+    }
+
+    private static List<Operand> buildExpressionFromTokens(final ParserExecutionContext context, final Schema schema,
+            final YIfFeature ifFeature, final List<Token> tokens) {
+
+        final List<Operand> result = new ArrayList<>(tokens.size());
+
+        for (final Token token : tokens) {
+
+            switch (token.type) {
+                case NOT:
+                    result.add(Operand.NOT);
+                    break;
+                case AND:
+                    result.add(Operand.AND);
+                    break;
+                case OR:
+                    result.add(Operand.OR);
+                    break;
+                case LEFT_PARENTHESIS:
+                    result.add(Operand.LEFT_PARENTHESIS);
+                    break;
+                case RIGHT_PARENTHESIS:
+                    result.add(Operand.RIGHT_PARENTHESIS);
+                    break;
+                default:
+                    if (isFeatureSupported(context, schema, ifFeature, token.name)) {
+                        result.add(Operand.TRUE);
+                    } else {
+                        result.add(Operand.FALSE);
+                    }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * A bit of magic here. We keep simplifying the expression until there are no
+     * more operators left.
+     */
+    private static Operand simplify(final List<Operand> input) {
+
+        final List<Operand> result = new ArrayList<>(input);
+
+        /*
+         * The RFC gives as precedence: parenthesis, not, and, or. So that is the order in which we resolve things.
+         *
+         * To simplify the list, we simplify all sub-expressions (those in parenthesis) first.
+         */
+        while (result.contains(Operand.LEFT_PARENTHESIS)) {
+            /*
+             * Find first occurrence of LEFT, and last occurrence or RIGHT. The contents of
+             * that will be simplified and replaces the sub-expression.
+             */
+            final int indexOfLeft = result.indexOf(Operand.LEFT_PARENTHESIS);
+            int parenthesisCount = 1;
+            int indexOfRight = indexOfLeft;
+
+            while (parenthesisCount > 0) {
+                indexOfRight++;
+                if (result.get(indexOfRight) == Operand.LEFT_PARENTHESIS) {
+                    parenthesisCount++;
+                } else if (result.get(indexOfRight) == Operand.RIGHT_PARENTHESIS) {
+                    parenthesisCount--;
+                }
+            }
+
+            /*
+             * Get the content that is between the parenthesis. That content will be
+             * simplified in a moment and replaces the sub-expression.
+             */
+            final List<Operand> sublist = new ArrayList<>(result.subList(indexOfLeft + 1, indexOfRight));
+            final Operand replaceSubExpressionWith = simplify(sublist);
+
+            /*
+             * Remove the sub-expression and replace with the result of the simplification.
+             */
+            final int nrOfElementsToRemove = indexOfRight - indexOfLeft + 1;
+            for (int i = 0; i < nrOfElementsToRemove; ++i) {
+                result.remove(indexOfLeft);
+            }
+            result.add(indexOfLeft, replaceSubExpressionWith);
+        }
+
+        /*
+         * Next precedence is "NOT"
+         */
+        while (result.contains(Operand.NOT)) {
+
+            final int indexOfNot = result.indexOf(Operand.NOT);
+
+            /*
+             * We simply remove the 'NOT', and flip the next element.
+             */
+            result.remove(indexOfNot);
+            result.set(indexOfNot, result.get(indexOfNot) == Operand.TRUE ? Operand.FALSE : Operand.TRUE);
+        }
+
+        /*
+         * Next precedence is "AND"
+         */
+        while (result.contains(Operand.AND)) {
+
+            final int indexOfAnd = result.indexOf(Operand.AND);
+
+            /*
+             * We logically AND together the elements before and after. Then we remove all
+             * three elements and replace with the ANDed result.
+             */
+            final boolean resultOfAnd = (result.get(indexOfAnd - 1) == Operand.TRUE) && (result.get(
+                    indexOfAnd + 1) == Operand.TRUE);
+
+            result.remove(indexOfAnd - 1);
+            result.remove(indexOfAnd - 1);
+            result.remove(indexOfAnd - 1);
+            result.add(indexOfAnd - 1, resultOfAnd ? Operand.TRUE : Operand.FALSE);
+        }
+
+        /*
+         * And finally "OR"
+         */
+        while (result.contains(Operand.OR)) {
+
+            final int indexOfOr = result.indexOf(Operand.OR);
+
+            /*
+             * We logically OR together the elements before and after. Then we remove all
+             * three elements and replace with the ORed result.
+             */
+            final boolean resultOfOr = (result.get(indexOfOr - 1) == Operand.TRUE) || (result.get(
+                    indexOfOr + 1) == Operand.TRUE);
+
+            result.remove(indexOfOr - 1);
+            result.remove(indexOfOr - 1);
+            result.remove(indexOfOr - 1);
+            result.add(indexOfOr - 1, resultOfOr ? Operand.TRUE : Operand.FALSE);
+        }
+
+        /*
+         * At this point, there can only be a single entry left in the list.
+         */
+
+        return result.get(0);
+    }
+
+    private static final String IF_FEATURE_INFO = "IF_FEATURE_INFO";
+    private static final String IF_FEATURE_REMOVED_CHILD_IDENTIFIERS = "REMOVED_CHILD_IDENTIFIERS";
+
+    private static void addChildRemovedDueToIfFeatureAppData(final AbstractStatement parentStatement,
+            final String nameOfRemovedChild) {
+        Helper.addAppDataListInfo(parentStatement, IF_FEATURE_INFO,
+                "Child statement " + nameOfRemovedChild + " removed as it's if-feature condition evaluated to false.");
+    }
+
+    public static List<String> getChildRemovedDueToIfFeatureAppDataForStatement(final AbstractStatement statement) {
+        return Helper.getAppDataListInfo(statement, IF_FEATURE_INFO);
+    }
+
+    private static void addRemovedChildIdentifierDueToIfFeature(final AbstractStatement statement,
+            final String identifier) {
+        Helper.addAppDataListInfo(statement, IF_FEATURE_REMOVED_CHILD_IDENTIFIERS, identifier);
+    }
+
+    public static List<String> getRemovedChildIdentifiersDueToIfFeatureForStatement(final AbstractStatement statement) {
+        return Helper.getAppDataListInfo(statement, IF_FEATURE_REMOVED_CHILD_IDENTIFIERS);
+    }
+
+    // =================================== FINDING HANDLING ON UNUSED SCHEMA NODES =====================================
+
+    /**
+     * Certain parts of the YAMs may not make it into the final schema:
+     *
+     * - Unused typedefs
+     * - Unused groupings
+     *
+     * Also, the schema may be tweaked such that original schema nodes are not longer referenced when we do the following:
+     *
+     * - deviate replace
+     * - uses refine
+     * - if-feature evaluating to false
+     *
+     * So what we do is we go through the final schema, and jump back to the DOM nodes and record which of these are still
+     * referenced; whatever is not referenced will then be looked-at in terms of findings and the findings removed. This
+     * cuts down on "noise"
+     */
+    public static void removeFindingsOnUnusedSchemaNodes(final ParserExecutionContext context, final Schema schema) {
+
+        final Set<YangDomElement> usedDomNodes = new HashSet<>(500000, 0.75f);
+
+        /*
+         * Collect the DOM nodes first.
+         */
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            collectUsedDomNodes(yangModelFile, usedDomNodes);
+        }
+
+        /*
+         * Now go through the DOM and have a look.
+         */
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            removeFindingsFromUnusedDomNodes(context, yangModelFile, usedDomNodes);
+        }
+    }
+
+    private static void collectUsedDomNodes(final YangModel yangModelFile, final Set<YangDomElement> usedDomNodes) {
+
+        /*
+         * Start off with the YAM root, and then work recursively down.
+         */
+        final AbstractStatement moduleOrSubmodule = yangModelFile.getYangModelRoot().getModuleOrSubmodule();
+        usedDomNodes.add(moduleOrSubmodule.getDomElement());
+
+        collectUsedDomNodes(usedDomNodes, moduleOrSubmodule);
+    }
+
+    private final static Set<StatementModuleAndName> CHILDREN_OF_STATEMENTS_TO_IGNORE = new HashSet<>(Arrays.asList(
+            CY.STMT_GROUPING, CY.STMT_TYPEDEF));
+
+    private static void collectUsedDomNodes(final Set<YangDomElement> usedDomNodes,
+            final AbstractStatement parentStatement) {
+
+        for (final AbstractStatement child : parentStatement.getChildStatements()) {
+
+            usedDomNodes.add(child.getDomElement());
+
+            /*
+             * Certain statements we happily ignore when we encounter them in the schema. They
+             * would have been resolved / merged-in by this stage and have no further role to
+             * play in the schema..
+             */
+            if (CHILDREN_OF_STATEMENTS_TO_IGNORE.contains(child.getStatementModuleAndName())) {
+                continue;
+            }
+
+            collectUsedDomNodes(usedDomNodes, child);
+        }
+    }
+
+    private static void removeFindingsFromUnusedDomNodes(final ParserExecutionContext context,
+            final YangModel yangModelFile, final Set<YangDomElement> usedDomNodes) {
+        final YangDomElement moduleOrSubmodule = yangModelFile.getYangModelRoot().getModuleOrSubmodule().getDomElement();
+        removeFindingsFromUnusedDomNodes(context, usedDomNodes, moduleOrSubmodule);
+    }
+
+    private static void removeFindingsFromUnusedDomNodes(final ParserExecutionContext context,
+            final Set<YangDomElement> usedDomNodes, final YangDomElement parentDomElement) {
+
+        for (final YangDomElement child : parentDomElement.getChildren()) {
+
+            if (!usedDomNodes.contains(child)) {
+                /*
+                 * We have encountered a DOM node that is not referenced by the statement tree. Remove any findings on it.
+                 */
+                context.getFindingsManager().removeFindingsOnYangDomElement(child);
+            }
+
+            removeFindingsFromUnusedDomNodes(context, usedDomNodes, child);
+        }
+    }
+
+    // =================================== STATUS HANDLING =====================================
+
+    /**
+     * Each statement will be assigned the effective status.
+     */
+    public static void assignStatus(final Schema schema) {
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            final String implicitStatus = YStatus.CURRENT;
+            assignStatus(yangModelFile.getYangModelRoot().getModuleOrSubmodule(), implicitStatus);
+        }
+    }
+
+    private static void assignStatus(final AbstractStatement statement, final String statusOfParent) {
+
+        String statusToAssign = statusOfParent;
+
+        /*
+         * If there is a status statement that makes the status "more severe"
+         * we use that instead. If the status is less restrictive we ignore that.
+         */
+        final YStatus statusChild = statement.getChild(CY.STMT_STATUS);
+        if (statusChild != null) {
+            if (statusChild.isObsolete()) {
+                statusToAssign = YStatus.OBSOLETE;
+            } else if (statusChild.isDeprecated() && statusOfParent.equals(YStatus.CURRENT)) {
+                statusToAssign = YStatus.DEPRECATED;
+            }
+        }
+
+        statement.setEffectiveStatus(statusToAssign);
+
+        for (final AbstractStatement child : statement.getChildStatements()) {
+            assignStatus(child, statusToAssign);
+        }
+    }
+
+    // =================================== NAMESPACE HANDLING =====================================
+
+    /**
+     * Each statement within a YAM will get the namespace of the module.
+     */
+    public static void assignEffectiveNamespaces(final Schema schema) {
+        for (final YangModel yangModel : schema.getModuleRegistry().getAllYangModels()) {
+            final String namespace = yangModel.getYangModelRoot().getNamespace();
+            yangModel.getYangModelRoot().assignEffectiveNamespaceToStatementTree(namespace);
+        }
+    }
+
+    // =================================== CONFORMANCE TYPE HANDLING =====================================
+
+    /**
+     * The ConformanceType is applied to all statements within a YAM.
+     */
+    public static void assignEffectiveConformanceType(final Schema schema) {
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            final ConformanceType conformanceType = yangModelFile.getConformanceType();
+            yangModelFile.getYangModelRoot().assignEffectiveConformanceTypeToStatementTree(conformanceType);
+        }
+    }
+
+    /**
+     * The effective config is applied to all statements within a YAM.
+     */
+    public static void assignConfig(final Schema schema) {
+        for (final YangModel yangModelFile : schema.getModuleRegistry().getAllYangModels()) {
+            yangModelFile.getYangModelRoot().assignEffectiveConfigToStatementTree(true);
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/AbstractStatement.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/AbstractStatement.java
new file mode 100644
index 0000000..b0763b6
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/AbstractStatement.java
@@ -0,0 +1,1154 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.ModulePrefixResolver;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YConfig;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDescription;
+import org.oran.smo.yangtools.parser.model.statements.yang.YErrorMessage;
+import org.oran.smo.yangtools.parser.model.statements.yang.YReference;
+import org.oran.smo.yangtools.parser.model.statements.yang.YStatus;
+import org.oran.smo.yangtools.parser.model.util.GrammarHelper;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomDocumentRoot;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+/**
+ * Base class for all statements. Once a YAM has been parsed into a Yang DOM, the statement
+ * tree will be build. Every statement in the model, no matter if core or extension, is
+ * represented by an instance of this class.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class AbstractStatement {
+
+    /**
+     * The root of the model owning this statement.
+     */
+    protected YangModelRoot modelRoot;
+
+    /**
+     * The underlying DOM element
+     */
+    protected final YangDomElement domElement;
+
+    /**
+     * Parent and children of this statement, respectively. Both can change as result of various
+     * operations, such as augment, uses, deviate.
+     */
+    protected AbstractStatement parent;
+    protected final List<AbstractStatement> children = new ArrayList<>();
+
+    /**
+     * The module and statement name
+     */
+    private StatementModuleAndName statementModuleAndName = null;
+
+    /**
+     * The namespace in which this statement effectively sits. This is important for statements as
+     * part of groupings/typedef that get pulled-in (the effective namespace will be the namespace
+     * of the module using the grouping/typedef, not the namespace of the module in which the
+     * grouping/typedef is defined).
+     */
+    private String effectiveNamespace = null;
+
+    /**
+     * The effective status of this statement.
+     */
+    private String effectiveStatus = null;
+
+    /**
+     * The effective ConformanceType of this statement. Only of significant interest if protocol-
+     * accessible objects of conformance "import-only" are actually retained in the schema (which
+     * is usually undesirable)
+     */
+    private ConformanceType effectiveConformanceType = null;
+
+    /**
+     * The effective config value of this statement.
+     */
+    private boolean effectiveConfig = true;
+
+    /**
+     * Findings made in respect of this statement, if any.
+     */
+    private Set<Finding> findings = null;
+
+    /**
+     * Gives an app using the parser the possibility to attach custom data to this statement.
+     * May be used by tooling.
+     */
+    private Map<String, Object> customAppData = null;
+
+    /**
+     * Special constructor for root. Only the YangModelRoot constructor will invoke this.
+     */
+    protected AbstractStatement(final YangDomDocumentRoot domDocumentRoot) {
+        this.modelRoot = (YangModelRoot) this;
+        this.domElement = domDocumentRoot;
+
+        this.parent = null;
+    }
+
+    public AbstractStatement(final AbstractStatement parentStatement, final YangDomElement domElement) {
+        this.modelRoot = parentStatement.getYangModelRoot();
+        this.domElement = domElement;
+
+        this.parent = parentStatement;
+        parentStatement.children.add(this);
+    }
+
+    public YangModelRoot getYangModelRoot() {
+        return modelRoot;
+    }
+
+    public AbstractStatement getParentStatement() {
+        return parent;
+    }
+
+    /**
+     * Returns the child statements of this statement. Do not modify the returned list.
+     */
+    public List<AbstractStatement> getChildStatements() {
+        return children;
+    }
+
+    public boolean isExtension() {
+        return getStatementModuleAndName().isExtensionStatement();
+    }
+
+    /**
+     * Returns all child statements that are extensions.
+     */
+    public List<ExtensionStatement> getExtensionChildStatements() {
+
+        List<ExtensionStatement> result = null;
+
+        for (final AbstractStatement child : children) {
+            if (child.isExtension()) {
+                if (result == null) {
+                    result = new ArrayList<>(4);
+                }
+                result.add((ExtensionStatement) child);
+            }
+        }
+
+        return result != null ? result : Collections.emptyList();
+    }
+
+    /**
+     * Returns all child statements that are not extensions (ie. they are core YANG statements).
+     */
+    public List<AbstractStatement> getNonExtensionChildStatements() {
+
+        if (children.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final List<AbstractStatement> result = new ArrayList<>();
+        for (final AbstractStatement child : children) {
+            if (!child.isExtension()) {
+                result.add(child);
+            }
+        }
+
+        return result;
+    }
+
+    public YangDomElement getDomElement() {
+        return domElement;
+    }
+
+    /**
+     * Returns the prefix resolver for this statement. The prefix resolver is the exact same as that
+     * of the underlying DOM element. Different statements within the same schema tree may use a
+     * different prefix resolver - this is typically then the case where statements are augmented-into/
+     * used-by a module, and the original prefix context must be retained.
+     */
+    public ModulePrefixResolver getPrefixResolver() {
+        return domElement.getPrefixResolver();
+    }
+
+    /**
+     * Returns the name of the statement. If the statement is an extension, only the
+     * name of the extension will be returned, not the prefix.
+     */
+    public String getStatementName() {
+        return getStatementModuleAndName().getStatementName();
+    }
+
+    /**
+     * Returns the statement name and the module defining it.
+     */
+    public StatementModuleAndName getStatementModuleAndName() {
+
+        /*
+         * All type-safe classes representing YANG core language statements, and some extension classes,
+         * will override this. This logic should only ever fire if a client has manually created a YANG
+         * core statement, or a factory was not available for an extension statement.
+         */
+        if (statementModuleAndName == null) {
+
+            final String statementPrefix = QNameHelper.extractPrefix(domElement.getName());
+            final String statementName = QNameHelper.extractName(domElement.getName());
+
+            if (PrefixResolver.NO_PREFIX.equals(statementPrefix)) {
+                if (CY.isYangCoreStatementName(statementName)) {
+                    statementModuleAndName = CY.getStatementForName(statementName);
+                } else {
+                    /*
+                     * Probably a spelling mistake, or possibly the absolute root '/' which is not a real
+                     * statement. We still create a SMAN.
+                     */
+                    statementModuleAndName = new StatementModuleAndName(CY.YANG_CORE_MODULE_NAME, statementName);
+                }
+            } else {
+                /*
+                 * Extension
+                 */
+                final ModuleIdentity moduleForPrefix = getPrefixResolver().getModuleForPrefix(statementPrefix);
+                if (moduleForPrefix == null) {
+                    /*
+                     * Unresolvable prefix, would have been caught elsewhere. We use the prefix as module name
+                     * which is wrong, of course, but at least this method here will never return null and
+                     * cause a NPE somewhere else...
+                     */
+                    statementModuleAndName = new StatementModuleAndName(statementPrefix, statementName);
+                } else {
+                    /*
+                     * All is well.
+                     */
+                    statementModuleAndName = new StatementModuleAndName(moduleForPrefix.getModuleName(), statementName);
+                }
+            }
+        }
+
+        return statementModuleAndName;
+    }
+
+    public void addFinding(final Finding finding) {
+        if (findings == null) {
+            findings = new HashSet<>();
+        }
+        findings.add(finding);
+    }
+
+    public void removeFinding(final Finding finding) {
+        if (findings != null) {
+            findings.remove(finding);
+        }
+    }
+
+    /**
+     * Returns the findings for this statement. Returns an empty set if no findings found.
+     */
+    public Set<Finding> getFindings() {
+        return findings == null ? Collections.<Finding> emptySet() : findings;
+    }
+
+    /**
+     * Add arbitrary app-specific data to this statement. Typically used by tooling.
+     */
+    public void setCustomAppData(final String key) {
+        setCustomAppData(key, null);
+    }
+
+    /**
+     * Add arbitrary app-specific data to this statement. Typically used by tooling.
+     */
+    public void setCustomAppData(final String key, final Object value) {
+        if (customAppData == null) {
+            customAppData = new HashMap<>();
+        }
+        customAppData.put(key, value);
+    }
+
+    /**
+     * Returns the value, if any, for app-specific data. Where the application data value is
+     * null, hasCustomAppData() should be used instead.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T getCustomAppData(final String key) {
+        return customAppData == null ? null : (T) customAppData.get(key);
+    }
+
+    public boolean hasCustomAppData(final String key) {
+        return customAppData == null ? false : customAppData.containsKey(key);
+    }
+
+    /**
+     * Returns the identifier defined by the statement. Overridden by those statements that
+     * have an identifier.
+     */
+    public String getStatementIdentifier() {
+        return "";
+    }
+
+    /**
+     * Overridden by statements that define "schema nodes". See RFC, chapter 3 (terminology):
+     *
+     * "schema node: A node in the schema tree. One of action, container, leaf,
+     * leaf-list, list, choice, case, rpc, input, output, notification, anydata,
+     * and anyxml."
+     */
+    public boolean definesSchemaNode() {
+        return false;
+    }
+
+    /**
+     * Overridden by statements that define "data nodes". See RFC, chapter 3 (terminology):
+     *
+     * "data node: A node in the schema tree that can be instantiated in a
+     * data tree. One of container, leaf, leaf-list, list, anydata, and
+     * anyxml."
+     */
+    public boolean definesDataNode() {
+        return false;
+    }
+
+    /**
+     * The statement argument types. Values are similar to the ones shown in chapter 13.1, but do not align fully.
+     */
+    public enum StatementArgumentType {
+        /** The statement does not have an argument. */
+        NO_ARG,
+        /** The argument is a name; for example, the name of a leaf. */
+        NAME,
+        /** The argument is a value. */
+        VALUE,
+        /** The argument is free text. */
+        TEXT,
+        /** The argument is a condition */
+        CONDITION,
+        /** The argument is a (sub-)module name */
+        MODULE,
+        /** The argument is a URI */
+        URI,
+        /** The argument is a date. */
+        DATE,
+        /** The argument is a target node. */
+        TARGET_NODE,
+        /** The argument is a tag. */
+        TAG
+    }
+
+    /**
+     * Returns the argument type
+     */
+    public abstract StatementArgumentType getArgumentType();
+
+    /**
+     * Denotes whether the order of multiple statements of this type under the same parent
+     * matters - i.e., if the order was to be changed in the model, would this result in a
+     * semantic change? For the vast majority of statements this does not matter, but sometimes
+     * it does (think multiple default statements under a leaf-list).
+     */
+    public boolean orderUnderParentMatters() {
+        return false;
+    }
+
+    /**
+     * Returns the effective status of the statement. This value will be calculated once all
+     * groupings, deviations and augmentations have been processed.
+     */
+    public String getEffectiveStatus() {
+        return effectiveStatus == null ? YStatus.CURRENT : effectiveStatus;
+    }
+
+    public void setEffectiveStatus(final String effectiveStatus) {
+        this.effectiveStatus = effectiveStatus;
+    }
+
+    public boolean isEffectiveStatusCurrent() {
+        return YStatus.CURRENT.equals(getEffectiveStatus());
+    }
+
+    public boolean isEffectiveStatusDeprecated() {
+        return YStatus.DEPRECATED.equals(getEffectiveStatus());
+    }
+
+    public boolean isEffectiveStatusObsolete() {
+        return YStatus.OBSOLETE.equals(getEffectiveStatus());
+    }
+
+    public boolean isEffectiveConfigTrue() {
+        return effectiveConfig;
+    }
+
+    public boolean is(final StatementModuleAndName statementModuleAndName) {
+        return getStatementModuleAndName().equals(statementModuleAndName);
+    }
+
+    /**
+     * Returns the 'description' statement, if any, that is a child of this statement.
+     * Use getDescriptionValue() to get the actual value of the description.
+     */
+    public YDescription getDescription() {
+        return getChild(CY.STMT_DESCRIPTION);
+    }
+
+    /**
+     * Returns the value of the 'description' statement, if any, that is a child of this statement.
+     */
+    public String getDescriptionValue() {
+        final YDescription yDescription = getDescription();
+        return yDescription == null ? null : yDescription.getValue();
+    }
+
+    /**
+     * Returns the 'reference' statement, if any, that is a child of this statement.
+     */
+    public YReference getReference() {
+        return getChild(CY.STMT_REFERENCE);
+    }
+
+    /**
+     * Returns the value of the 'reference' statement, if any, that is a child of this statement.
+     */
+    public String getReferenceValue() {
+        final YReference yReference = getReference();
+        return yReference == null ? null : yReference.getValue();
+    }
+
+    /**
+     * Returns the error message text of this statement, or the value of a 'error-message'
+     * child statement. Otherwise returns null.
+     */
+    public String getErrorMessageText() {
+        if (is(CY.STMT_ERROR_MESSAGE)) {
+            return domElement.getValue();
+        }
+
+        final YErrorMessage child = getChild(CY.STMT_ERROR_MESSAGE);
+        return child != null ? child.getValue() : null;
+    }
+
+    /**
+     * Returns the statement names that are allowed as children of this statement according to the
+     * RFC. Extension classes should override this method.
+     */
+    public List<String> getStatementsAllowedAsChild() {
+        final List<String> allowedStatements = new ArrayList<>(20);
+        allowedStatements.addAll(getMandatorySingleChildStatementNames());
+        allowedStatements.addAll(getMandatoryMultipleChildStatementNames());
+        allowedStatements.addAll(getOptionalSingleChildStatementNames());
+        allowedStatements.addAll(getOptionalMultipleChildStatementNames());
+        return allowedStatements;
+    }
+
+    public final List<String> getOptionalSingleChildStatementNames() {
+        return CY.getOptionalSingleChildren(this.domElement.getName());
+    }
+
+    public final List<String> getOptionalMultipleChildStatementNames() {
+        return CY.getOptionalMultipleChildren(this.domElement.getName());
+    }
+
+    public final List<String> getMandatorySingleChildStatementNames() {
+        return CY.getMandatorySingleChildren(this.domElement.getName());
+    }
+
+    public final List<String> getMandatoryMultipleChildStatementNames() {
+        return CY.getMandatoryMultipleChildren(this.domElement.getName());
+    }
+
+    /**
+     * Processes this statement by recursively creating child statements.
+     */
+    protected void process(final ParserExecutionContext context) {
+
+        /*
+         * The normal case is that this statement is a build-in YANG statement.
+         * However, it could very well also be an extension statement.
+         */
+
+        if (isExtension()) {
+            /*
+             * If it is an extension, then really any statement can be below it. There is no RFC-defined way
+             * how this can be expressed in YANG, so really we must be able to handle everything. Hence,
+             * extract whatever is underneath the extension - if it makes sense or not is a different issue,
+             * and a problem of the extension.
+             */
+            extractAllChildStatementsFromDomExceptExtensions(context);
+            extractChildExtensions(context);
+
+            validate(context);
+
+        } else {
+            /*
+             * It is a build-in YANG statement. We extract all possible (optional, mandatory) child statements.
+             */
+            final List<String> mandatoryChildSingletonStatementNames = getMandatorySingleChildStatementNames();
+            final List<String> mandatoryChildMultipleStatementNames = getMandatoryMultipleChildStatementNames();
+            final List<String> optionalChildSingletonStatementNames = getOptionalSingleChildStatementNames();
+            final List<String> optionalChildMultipleStatementNames = getOptionalMultipleChildStatementNames();
+
+            extractMandatorySingletonChildStatementsFromDom(context, mandatoryChildSingletonStatementNames);
+            extractMandatoryMultipleChildStatementsFromDom(context, mandatoryChildMultipleStatementNames);
+            extractOptionalSingletonChildStatementsFromDom(context, optionalChildSingletonStatementNames);
+            extractOptionalMultipleChildStatementsFromDom(context, optionalChildMultipleStatementNames);
+
+            extractChildExtensions(context);
+
+            validate(context);
+
+            /*
+             * Check at this point that there are not any statements here that are not expected according to RFC.
+             */
+            for (final YangDomElement childDomElement : domElement.getChildren()) {
+                final String childName = childDomElement.getName();
+
+                if (optionalChildSingletonStatementNames.contains(childName) || optionalChildMultipleStatementNames
+                        .contains(childName) || mandatoryChildSingletonStatementNames.contains(
+                                childName) || mandatoryChildMultipleStatementNames.contains(childName)) {
+                    /*
+                     * All ok, it is a statement that we are expecting and according to the RFC is fine to be here.
+                     */
+                } else if (childName.contains(":")) {
+                    /*
+                     * That's ok as well, it is an extension statement, ignore.
+                     */
+                } else {
+                    /*
+                     * Some other in-build YANG statement that should not be a child of this statement.
+                     */
+                    if (CY.isYangCoreStatementName(childName)) {
+                        context.addFinding(new Finding(childDomElement, ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT
+                                .toString(), "Statement '" + childName + "' is not allowed under '" + domElement
+                                        .getName() + "'."));
+                    } else {
+                        context.addFinding(new Finding(childDomElement, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                                .toString(), "'" + childName + "' is not part of the core YANG language."));
+                    }
+                }
+            }
+        }
+
+        /*
+         * Indicate that processing of this statement, and all sub-statements, is finished.
+         */
+        subtreeProcessed(context);
+    }
+
+    /**
+     * Performs statement-specific validation. Statements sometimes override.
+     */
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * The vast majority of statements require some kind of
+         * argument, so check that. For the few statements that
+         * don't require this, the method will be overridden.
+         */
+        validateArgumentNotNullNotEmpty(context);
+    }
+
+    /**
+     * May be overriden by subclasses if they wish to perform any further processing after the
+     * statement and all its children have been fully processed.
+     */
+    protected void subtreeProcessed(final ParserExecutionContext context) {
+    }
+
+    /**
+     * Extracts from the DOM tree all statements no matter what they are, except extensions
+     */
+    private void extractAllChildStatementsFromDomExceptExtensions(final ParserExecutionContext context) {
+        for (final YangDomElement childDomElement : domElement.getChildren()) {
+            if (!childDomElement.getName().contains(":")) {
+                final AbstractStatement childStatement = StatementFactory.createYangCoreStatement(context, childDomElement,
+                        this);
+                childStatement.process(context);
+            }
+        }
+    }
+
+    /**
+     * Extracts from the DOM all child nodes of the specified statement names. Each of these
+     * may be present 0..1, i.e. once-only.
+     */
+    private void extractOptionalSingletonChildStatementsFromDom(final ParserExecutionContext context,
+            final List<String> optionalSingletonChildStatementNames) {
+
+        if (optionalSingletonChildStatementNames.isEmpty()) {
+            return;
+        }
+
+        final Set<String> namesOfStatementsAlreadyExtracted = new HashSet<>();
+
+        for (final YangDomElement childDomElement : domElement.getChildren()) {
+            final String domElementName = childDomElement.getName();
+
+            if (optionalSingletonChildStatementNames.contains(domElementName)) {
+
+                if (!namesOfStatementsAlreadyExtracted.contains(domElementName)) {
+                    namesOfStatementsAlreadyExtracted.add(domElementName);
+                    final AbstractStatement childStatement = StatementFactory.createYangCoreStatement(context,
+                            childDomElement, this);
+                    childStatement.process(context);
+                } else {
+                    /*
+                     * The same statement exists more than once, but is only allowed once. We generate the
+                     * finding on the parent.
+                     */
+                    context.addFinding(new Finding(domElement, ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString(),
+                            "Child statement '" + domElementName + "' cannot exist more than once under '" + domElement
+                                    .getName() + "'."));
+                }
+            }
+        }
+    }
+
+    /**
+     * Extracts from the DOM all child nodes of the specified statement names. Each of these may be
+     * present 0..n, i.e. multiple times (or not at all).
+     */
+    private void extractOptionalMultipleChildStatementsFromDom(final ParserExecutionContext context,
+            final List<String> optionalMultipleChildStatementNames) {
+
+        if (optionalMultipleChildStatementNames.isEmpty()) {
+            return;
+        }
+
+        for (final YangDomElement childDomElement : domElement.getChildren()) {
+            final String domElementNode = childDomElement.getName();
+
+            if (optionalMultipleChildStatementNames.contains(domElementNode)) {
+                final AbstractStatement childStatement = StatementFactory.createYangCoreStatement(context, childDomElement,
+                        this);
+                childStatement.process(context);
+            }
+        }
+    }
+
+    /**
+     * Extracts from the DOM all child nodes of the specified statement names. Each of these must be
+     * present 1..1, i.e. exactly once.
+     */
+    private void extractMandatorySingletonChildStatementsFromDom(final ParserExecutionContext context,
+            final List<String> mandatorySingletonChildStatementNames) {
+
+        if (mandatorySingletonChildStatementNames.isEmpty()) {
+            return;
+        }
+
+        final Set<String> namesOfStatementsYetToExtract = new HashSet<>(mandatorySingletonChildStatementNames);
+
+        for (final YangDomElement childDomElement : domElement.getChildren()) {
+            final String domElementName = childDomElement.getName();
+
+            if (mandatorySingletonChildStatementNames.contains(domElementName)) {
+
+                if (namesOfStatementsYetToExtract.contains(domElementName)) {
+                    namesOfStatementsYetToExtract.remove(domElementName);
+                    final AbstractStatement childStatement = StatementFactory.createYangCoreStatement(context,
+                            childDomElement, this);
+                    childStatement.process(context);
+                } else {
+                    /*
+                     * The same statement exists more than once, but is only allowed once. We generate the
+                     * finding on the parent.
+                     */
+                    context.addFinding(new Finding(domElement, ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString(),
+                            "Child statement '" + domElementName + "' cannot exist more than once under '" + domElement
+                                    .getName() + "'."));
+                }
+            }
+        }
+
+        if (!namesOfStatementsYetToExtract.isEmpty()) {
+            for (final String notSuppliedStatement : namesOfStatementsYetToExtract) {
+                context.addFinding(new Finding(this, ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString(),
+                        "Statement '" + notSuppliedStatement + "' required under '" + domElement.getName() + "'."));
+            }
+        }
+    }
+
+    /**
+     * Extracts from the DOM all child nodes of the specified statement names. Each of these must be
+     * present 1..n, i.e. at least once, but possibly more often.
+     */
+    private void extractMandatoryMultipleChildStatementsFromDom(final ParserExecutionContext context,
+            final List<String> mandatoryMultipleChildStatementNames) {
+
+        if (mandatoryMultipleChildStatementNames.isEmpty()) {
+            return;
+        }
+
+        final Set<String> namesOfStatementsYetToExtract = new HashSet<>(mandatoryMultipleChildStatementNames);
+
+        for (final YangDomElement childDomElement : domElement.getChildren()) {
+            final String domElementNode = childDomElement.getName();
+
+            if (mandatoryMultipleChildStatementNames.contains(domElementNode)) {
+                namesOfStatementsYetToExtract.remove(domElementNode);
+                final AbstractStatement childStatement = StatementFactory.createYangCoreStatement(context, childDomElement,
+                        this);
+                childStatement.process(context);
+            }
+        }
+
+        if (!namesOfStatementsYetToExtract.isEmpty()) {
+            for (final String notSuppliedStatement : namesOfStatementsYetToExtract) {
+                context.addFinding(new Finding(this, ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT,
+                        "Statement '" + notSuppliedStatement + "' required at least once under '" + domElement
+                                .getName() + "'."));
+            }
+        }
+    }
+
+    /**
+     * Extract any extension statement.
+     */
+    private void extractChildExtensions(final ParserExecutionContext context) {
+
+        for (final YangDomElement childDomElement : domElement.getChildren()) {
+            if (childDomElement.getName().contains(":")) {
+                final AbstractStatement extensionStatement = StatementFactory.createYangExtensionStatement(context,
+                        childDomElement, this);
+                if (extensionStatement != null) {
+                    extensionStatement.process(context);
+                }
+            }
+        }
+    }
+
+    /**
+     * Assigns the supplied namespace to all statements in this sub-tree. A namespace is really
+     * only relevant for data nodes, but w simply apply the namespace to all statements to make
+     * our life easier.
+     */
+    public void assignEffectiveNamespaceToStatementTree(final String namespace) {
+        effectiveNamespace = namespace;
+        for (final AbstractStatement child : children) {
+            child.assignEffectiveNamespaceToStatementTree(namespace);
+        }
+    }
+
+    /**
+     * Returns the effective namespace of the statement. Statements (usually data nodes) within a
+     * type-safe statement tree may have different namespaces due to augmentations having been
+     * merged in.
+     */
+    public final String getEffectiveNamespace() {
+        return effectiveNamespace;
+    }
+
+    /**
+     * Assigns the supplied ConformanceType to all statements in this sub-tree. Again, really
+     * only of interest of data nodes, but we simply assign it to all statements.
+     */
+    public void assignEffectiveConformanceTypeToStatementTree(final ConformanceType conformanceType) {
+        effectiveConformanceType = conformanceType;
+        for (final AbstractStatement child : children) {
+            child.assignEffectiveConformanceTypeToStatementTree(conformanceType);
+        }
+    }
+
+    /**
+     * Returns the effective conformance type of the statement. Statements (usually data nodes)
+     * within a type-safe statement tree may have different conformance due to augmentations
+     * having been merged in.
+     */
+    public ConformanceType getEffectiveConformanceType() {
+        return effectiveConformanceType;
+    }
+
+    /**
+     * Assigns the config value of the parent to this statement, unless the statement has
+     * a 'config' statement itself as child, in which case that will be used from now on.
+     */
+    public void assignEffectiveConfigToStatementTree(final boolean configValueOfParent) {
+
+        /*
+         * Config value may switch.
+         */
+        boolean configValueToUse = configValueOfParent;
+
+        final YConfig yConfig = getChild(CY.STMT_CONFIG);
+        if (yConfig != null && configValueToUse == true) {
+            /*
+             * This statement has a config statement. So use this value from now on for this statement
+             * and all statements below. Note that switching back from 'config false' to 'config true' is
+             * not allowed, and we will effectively ignore that.
+             */
+            configValueToUse = yConfig.isConfigTrue();
+        }
+
+        /*
+         * Certain statements can never carry configuration data. For those statements,
+         * the config value will always be forced to false, no matter if they have an
+         * explicit 'config' underneath.
+         */
+        if (is(CY.STMT_ACTION) || is(CY.STMT_RPC) || is(CY.STMT_NOTIFICATION)) {
+            configValueToUse = false;
+        }
+
+        effectiveConfig = configValueToUse;
+
+        for (final AbstractStatement child : children) {
+            child.assignEffectiveConfigToStatementTree(configValueToUse);
+        }
+    }
+
+    /**
+     * Returns whether this statement has at least one child instance of the specified statement.
+     */
+    public boolean hasAtLeastOneChildOf(final StatementModuleAndName statementModuleAndName) {
+        for (final AbstractStatement child : children) {
+            if (child.getStatementModuleAndName().equals(statementModuleAndName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns all children of this statement of the specified module and statement name.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends AbstractStatement> List<T> getChildren(final StatementModuleAndName soughtSman) {
+        final List<T> result = new ArrayList<>();
+        for (final AbstractStatement child : children) {
+            if (child.getStatementModuleAndName().equals(soughtSman)) {
+                result.add((T) child);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns all children of the specified statement module/names.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends AbstractStatement> List<T> getChildren(
+            final Set<StatementModuleAndName> soughtStatementModulesAndNames) {
+        final List<T> result = new ArrayList<>();
+        for (final AbstractStatement child : children) {
+            if (soughtStatementModulesAndNames.contains(child.getStatementModuleAndName())) {
+                result.add((T) child);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the first child of this statement of the specified module and statement name, or null if not found.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends AbstractStatement> T getChild(final StatementModuleAndName soughtStatementModuleAndName) {
+        for (final AbstractStatement child : children) {
+            if (child.getStatementModuleAndName().equals(soughtStatementModuleAndName)) {
+                return (T) child;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Clones the children of this statement. Will result in a recursive invocation, i.e.
+     * clones the complete subtree. The cloning keeps the original prefix resolvers in place.
+     * Note that findings on the statements will not be cloned.
+     */
+    public void cloneFrom(final AbstractStatement orig) {
+
+        copyPropertiesFrom(orig);
+
+        /*
+         * Clone the children. This will also clone extensions.
+         */
+        for (final AbstractStatement childToClone : orig.children) {
+            final AbstractStatement clonedStatement = StatementFactory.cloneYangStatement(childToClone, this);
+            clonedStatement.cloneFrom(childToClone);
+        }
+    }
+
+    /**
+     * Copies the statement properties from the supplied statement into this statement.
+     */
+    public void copyPropertiesFrom(final AbstractStatement orig) {
+
+        /*
+         * Clone-over the contents of any app data.
+         */
+        if (orig.customAppData != null) {
+            for (final Entry<String, Object> origEntry : orig.customAppData.entrySet()) {
+                if (origEntry.getValue() instanceof List) {
+                    this.setCustomAppData(origEntry.getKey(), new ArrayList<>((List<?>) origEntry.getValue()));		// deep copy
+                } else {
+                    this.setCustomAppData(origEntry.getKey(), origEntry.getValue());
+                }
+            }
+        }
+
+        this.effectiveConformanceType = orig.effectiveConformanceType;
+        this.effectiveConfig = orig.effectiveConfig;
+        this.effectiveNamespace = orig.effectiveNamespace;
+        this.effectiveStatus = orig.effectiveStatus;
+    }
+
+    /**
+     * All existing children of the same type of statement are removed, and replaced by the supplied statement.
+     */
+    public <T extends AbstractStatement> void replaceChildrenWith(final T replaceWith) {
+        removeAllChildrenOfStatement(replaceWith.getStatementModuleAndName());
+        addChild(replaceWith);
+    }
+
+    /**
+     * All existing children of the same statement are removed, and replaced by the supplied statements.
+     */
+    public <T extends AbstractStatement> void replaceChildrenWith(final List<T> replaceWith) {
+        if (!replaceWith.isEmpty()) {
+            removeAllChildrenOfStatement(replaceWith.get(0).getStatementModuleAndName());
+        }
+        addChildren(replaceWith);
+    }
+
+    /**
+     * All existing children of the supplied type of statement are removed
+     */
+    @SuppressWarnings("unchecked")
+    private <T extends AbstractStatement> void removeAllChildrenOfStatement(
+            final StatementModuleAndName statementModuleAndName) {
+        for (final T child : (List<T>) getChildren(statementModuleAndName)) {
+            removeChild(child);
+        }
+    }
+
+    /**
+     * Replace one specific child statement with another.
+     */
+    public <T extends AbstractStatement> void replaceChild(final T toBeReplaced, final T replaceWith) {
+        removeChild(toBeReplaced);
+        addChild(replaceWith);
+    }
+
+    /**
+     * Replace one specific child statement with another at the exact same place in the statement tree.
+     */
+    public <T extends AbstractStatement> void replaceChildInPlace(final T toBeReplaced, final T replaceWith) {
+        final int oldPos = removeChild(toBeReplaced);
+        addChild(replaceWith, oldPos);
+    }
+
+    /**
+     * Removes a number of statements as children from this statement.
+     */
+    public <T extends AbstractStatement> void removeChildren(final List<T> statementsToRemove) {
+        for (final T statementToRemove : statementsToRemove) {
+            removeChild(statementToRemove);
+        }
+    }
+
+    /**
+     * Removes a specific child statement. Returns the index position at which the child was placed in the statement tree.
+     */
+    public <T extends AbstractStatement> int removeChild(final T statementToRemove) {
+
+        final int indexOf = this.children.indexOf(statementToRemove);
+
+        /*
+         * The child is unlinked from this object here. The child becomes in effect detached from the tree and is
+         * not-reachable anymore. (It should also be GC'ed fairly soon.)
+         */
+        statementToRemove.parent = null;
+        this.children.remove(statementToRemove);
+
+        return indexOf;
+    }
+
+    /**
+     * Add a number of statements as children to this statement. If the statements are part of the
+     * statement tree they will be detached from their parent first (i.e. will be effectively
+     * re-parented).
+     */
+    public <T extends AbstractStatement> void addChildren(final List<T> statementsToAdd) {
+        for (final T statementToAdd : statementsToAdd) {
+            addChild(statementToAdd);
+        }
+    }
+
+    /**
+     * Add a statement as child to this statement. If the statement is part of the statement tree
+     * it will be detached from its parent first (i.e. will be effectively re-parented).
+     */
+    public <T extends AbstractStatement> void addChild(final T statementToAdd) {
+        addChild(statementToAdd, this.children.size());
+    }
+
+    /**
+     * Add a statement as child to this statement at the specified position in the statement tree.
+     * If the statement is part of the statement tree it will be detached from its parent first
+     * (i.e. will be effectively re-parented).
+     */
+    public <T extends AbstractStatement> void addChild(final T statementToAdd, final int pos) {
+        /*
+         * Unlink the statement that is being added from it's current parent and hook it under "this" here.
+         * The YangModelRoot must be likewise updated, as ownership in the tree has changed. Note: The
+         * prefix resolver is NOT modified, as the prefixes may be different between the original definition
+         * and this tree here.
+         */
+        if (statementToAdd.parent != null) {
+            statementToAdd.parent.children.remove(statementToAdd);
+        }
+        this.children.add(pos, statementToAdd);
+        statementToAdd.parent = this;
+        statementToAdd.modelRoot = this.modelRoot;
+    }
+
+    /**
+     * A result of TRUE means validation succeeded (all ok).
+     */
+    protected boolean validateArgumentIsTrueOrFalse(final ParserExecutionContext context) {
+        final boolean validateNotNull = validateNotNull(context, domElement.getValue(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                "statement '" + getStatementName() + "' requires 'true' or 'false' as argument.");
+        final boolean validateIsTrueOrFalse = validateIsTrueOrFalse(context, domElement.getValue(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                "statement '" + getStatementName() + "' requires 'true' or 'false' as argument.");
+        return (validateNotNull && validateIsTrueOrFalse);
+    }
+
+    /**
+     * A result of TRUE means validation succeeded (all ok).
+     */
+    protected boolean validateArgumentNotNullNotEmpty(final ParserExecutionContext context) {
+        final boolean validateNotNull = validateNotNull(context, domElement.getValue(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                "statement '" + getStatementName() + "' requires an argument.");
+        final boolean validateNotEmpty = validateNotEmpty(context, domElement.getValue(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                "The argument for statement '" + getStatementName() + "' cannot be empty.");
+        return (validateNotNull && validateNotEmpty);
+    }
+
+    /**
+     * A result of TRUE means validation succeeded (all ok).
+     */
+    protected boolean validateArgumentNotNull(final ParserExecutionContext context) {
+        return validateNotNull(context, domElement.getValue(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                "statement '" + getStatementName() + "' requires an argument.");
+    }
+
+    /**
+     * A result of TRUE means validation succeeded (all ok).
+     */
+    protected boolean validateArgumentIsNull(final ParserExecutionContext context) {
+        return validateIsNull(context, domElement.getValue(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                "statement '" + getStatementName() + "' does not take an argument.");
+    }
+
+    /**
+     * A result of TRUE means validation succeeded (all ok).
+     */
+    protected boolean validateDocumentationArgumentNotEmpty(final ParserExecutionContext context) {
+        return validateNotEmpty(context, domElement.getValue(), ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE,
+                "statement '" + getStatementName() + "' requires some text as argument.");
+    }
+
+    private boolean validateNotNull(final ParserExecutionContext context, final String valueToCheck,
+            final ParserFindingType findingType, final String message) {
+        if (valueToCheck == null) {
+            issueFinding(context, findingType, message);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean validateIsNull(final ParserExecutionContext context, final String valueToCheck,
+            final ParserFindingType findingType, final String message) {
+        if (valueToCheck != null) {
+            issueFinding(context, findingType, message);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean validateNotEmpty(final ParserExecutionContext context, final String valueToCheck,
+            final ParserFindingType findingType, final String message) {
+        if (valueToCheck != null && valueToCheck.trim().isEmpty()) {
+            issueFinding(context, findingType, message);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean validateIsTrueOrFalse(final ParserExecutionContext context, final String valueToCheck,
+            final ParserFindingType findingType, final String message) {
+        if (valueToCheck != null && !valueToCheck.equals("true") && !valueToCheck.equals("false")) {
+            issueFinding(context, findingType, message);
+            return false;
+        }
+        return true;
+    }
+
+    protected void validateIsYangIdentifier(final ParserExecutionContext context, final String valueToCheck) {
+
+        if (valueToCheck == null || valueToCheck.isEmpty()) {
+            return;
+        }
+
+        final boolean isYangIdentifier = GrammarHelper.isYangIdentifier(valueToCheck);
+        if (!isYangIdentifier) {
+            issueFinding(context, ParserFindingType.P052_INVALID_YANG_IDENTIFIER,
+                    "'" + valueToCheck + "' is not a valid YANG identifier.");
+        }
+    }
+
+    protected void validateIsYangIdentifierReference(final ParserExecutionContext context, final String valueToCheck) {
+
+        if (valueToCheck == null || valueToCheck.isEmpty()) {
+            return;
+        }
+
+        final boolean isYangIdentifierReference = GrammarHelper.isYangIdentifierReference(valueToCheck);
+        if (!isYangIdentifierReference) {
+            issueFinding(context, ParserFindingType.P052_INVALID_YANG_IDENTIFIER,
+                    "'" + valueToCheck + "' is not a valid YANG identifier-reference.");
+        }
+    }
+
+    private void issueFinding(final ParserExecutionContext context, final ParserFindingType findingType,
+            final String message) {
+        context.addFinding(new Finding(this, findingType, message));
+    }
+
+    @Override
+    public String toString() {
+        return domElement.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/AbstractStatementClassSupplier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/AbstractStatementClassSupplier.java
new file mode 100644
index 0000000..6b7f353
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/AbstractStatementClassSupplier.java
@@ -0,0 +1,77 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+/**
+ * Convenience base class containing a utility method for constructing java class names for
+ * type-safe statement classes.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class AbstractStatementClassSupplier implements StatementClassSupplier {
+
+    /**
+     * Given a Java package name, a class name prefix and the name of a statement, returns the Java class
+     * representing the statement. The YANG statement name (possibly the name of an extension statement)
+     * will be translated to CamelCase.
+     */
+    @SuppressWarnings("unchecked")
+    protected static <T extends AbstractStatement> Class<T> getJavaClazzForStatement(final String javaPackage,
+            final String clazzPrefix, final String statementName) {
+
+        final StringBuilder sb = new StringBuilder(100);
+        sb.append(javaPackage);
+        sb.append(".");
+        sb.append(clazzPrefix);
+        appendStatementNameInCamelCase(sb, statementName);
+
+        try {
+            final Class<?> forName = Class.forName(sb.toString());
+            return (Class<T>) forName;
+        } catch (final Exception ex) {
+            /* no-op */ }
+
+        return null;
+    }
+
+    /**
+     * Takes a statement name (which, by YANG convention, is all lowercase and contains hyphens) and converts it to
+     * CamelCase:
+     *
+     * "choice" -> "Choice"
+     * "belongs-to" -> "BelongsTo"
+     */
+    private static void appendStatementNameInCamelCase(final StringBuilder sb, final String statementName) {
+
+        boolean upperCaseNextChar = true;
+        for (int i = 0; i < statementName.length(); ++i) {
+            final char c = statementName.charAt(i);
+            if (c == '-') {
+                upperCaseNextChar = true;
+            } else if (upperCaseNextChar) {
+                sb.append(Character.toUpperCase(c));
+                upperCaseNextChar = false;
+            } else {
+                sb.append(c);
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ExtensionStatement.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ExtensionStatement.java
new file mode 100644
index 0000000..8e8e07d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ExtensionStatement.java
@@ -0,0 +1,150 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YExtension;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Represents an instance of an extension statement; that is, <i>usage</i> of an extension (as
+ * opposed to <i>definition</i> of an extension - extensions are defined by means of the
+ * {@link YExtension} class).
+ * <p/>
+ * This is a generic catch-all class for extension instances. Implementations of {@link StatementClassSupplier}
+ * are typically used to create instances of type-safe classes representing extensions.
+ *
+ * @author Mark Hollmann
+ */
+public class ExtensionStatement extends SimpleStatement {
+
+    public ExtensionStatement(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    /**
+     * Returns the prefix of the extension.
+     */
+    public String getExtensionModulePrefix() {
+        return domElement.getName().split(":")[0];
+    }
+
+    /**
+     * Returns the name of the extension
+     */
+    public String getExtensionStatementName() {
+        return domElement.getName().split(":")[1];
+    }
+
+    /**
+     * Returns the value (argument) of the extension, if any (ie. can be null).
+     */
+    public String getValue() {
+        return domElement.getValue();
+    }
+
+    /**
+     * Denotes whether a possible argument to the extension is mandatory to be supplied.
+     * By default this method this method will return FALSE as it is not possible to
+     * predict the semantics of each extensions. Sub-classes that require their argument
+     * to be present should override this method accordingly.
+     */
+    public boolean argumentIsMandatory() {
+        return false;
+    }
+
+    /**
+     * Returns the number of instances this extension can possible have under its parent
+     * statement. By default, this method will return ONE as this is typically the case
+     * with extensions. Sub-types may override.
+     */
+    public MaxCardinality getMaxCardinalityUnderParent() {
+        return MaxCardinality.ONE;
+    }
+
+    public enum MaxCardinality {
+        ONE,
+        MULTIPLE
+    }
+
+    /**
+     * Returns whether the extension can be a valid child of the supplied parent statement
+     * (which is usually a core Yang statement, but could be another extension). Type-safe
+     * extension subclasses should override this method.
+     * <p/>
+     * Since we don't know any better here, the default assumption is that the extension can
+     * sit anywhere.
+     */
+    public boolean canBeChildOf(final StatementModuleAndName parentStatement) {
+        return true;
+    }
+
+    @Override
+    protected void validate(ParserExecutionContext context) {
+        /*
+         * Validation will always be extension-specific. The assumption
+         * that these all need arguments is wrong, of course.
+         */
+    }
+
+    protected void checkParent(final ParserExecutionContext context) {
+        final AbstractStatement parent = getParentStatement();
+
+        if (!canBeChildOf(parent.getStatementModuleAndName())) {
+            context.addFinding(new Finding(this, ParserFindingType.P025_INVALID_EXTENSION,
+                    "Extension statement '" + getExtensionStatementName() + "' is not allowed under '" + parent
+                            .getStatementName()));
+        }
+    }
+
+    protected void checkParentAlsoAllowDeviateOrRefine(final ParserExecutionContext context) {
+        final AbstractStatement parent = getParentStatement();
+
+        if (parent.is(CY.STMT_DEVIATE) || parent.is(CY.STMT_REFINE)) {
+            return;
+        }
+        if (!canBeChildOf(parent.getStatementModuleAndName())) {
+            context.addFinding(new Finding(this, ParserFindingType.P025_INVALID_EXTENSION,
+                    "Extension statement '" + getExtensionStatementName() + "' is not allowed under '" + parent
+                            .getStatementName()));
+        }
+    }
+
+    protected void checkCardinalityUnderParent(final ParserExecutionContext context, final int max) {
+        final AbstractStatement parentStatement = getParentStatement();
+        final List<? extends AbstractStatement> childrenOfThisType = parentStatement.getChildren(this
+                .getStatementModuleAndName());
+        if (childrenOfThisType.size() > max) {
+            context.addFinding(new Finding(this, ParserFindingType.P025_INVALID_EXTENSION,
+                    "The allowed maximum cardinality for this extension statement is " + max + "."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/SimpleStatement.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/SimpleStatement.java
new file mode 100644
index 0000000..e68f12b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/SimpleStatement.java
@@ -0,0 +1,39 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Represents a simple statement in YANG (one that one has a single identifier / value)
+ *
+ * @author Mark Hollmann
+ */
+public abstract class SimpleStatement extends AbstractStatement {
+
+    public SimpleStatement(final AbstractStatement parentStatement, final YangDomElement domElement) {
+        super(parentStatement, domElement);
+    }
+
+    public String getValue() {
+        return domElement.getValue();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementClassSupplier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementClassSupplier.java
new file mode 100644
index 0000000..11eb9c1
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementClassSupplier.java
@@ -0,0 +1,67 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.yang.YangCoreClassSupplier;
+
+/**
+ * Implementations of this interface can supply type-safe classes for statements. Implementation
+ * classes are typically invoked when the YANG statement tree is being built from the YANG DOM tree.
+ * For YANG core statements as defined in RFC 7950, {@link YangCoreClassSupplier} will be used. Other
+ * implementations typically handle extensions.
+ *
+ * @author Mark Hollmann
+ */
+public interface StatementClassSupplier {
+
+    /**
+     * Returns information about the statements that this implementation can handle.
+     * <p>
+     * The map keys are the names of modules. The map value is a list of statement names
+     * that are defined within that module, and which the implementation can handle.
+     */
+    Map<String, List<String>> getHandledStatements();
+
+    /**
+     * Returns the Java class that represents the YANG statement.
+     * <p/>
+     * Implementations will return either a specific class that can handle the statement or null.
+     * <p/>
+     * If the statement represents an extension, either {@link ExtensionStatement} or a subclass of
+     * {@link ExtensionStatement} must be returned. Failure to do so will lead to parse errors.
+     * <p/>
+     * The supplied method <b>must</b> have a constructor as follows, and invoke super:
+     * <p/>
+     * <pre>
+     * public class MyStatement extends ExtensionStatement {
+     *
+     * public MyStatement(final AbstractStatement parentStatement, final YangDomElement domElement) {
+     * super(parentStatement, domElement);
+     * ...
+     * }
+     * }
+     * </pre>
+     */
+    <T extends AbstractStatement> Class<T> getJavaClazzForStatement(String moduleName, String statementName);
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementFactory.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementFactory.java
new file mode 100644
index 0000000..d1746e3
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementFactory.java
@@ -0,0 +1,157 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.statements.yang.YangCoreClassSupplier;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.util.StackTraceHelper;
+
+/**
+ * Factory for creating instances of type-safe classes representing Yang statements.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class StatementFactory {
+
+    private static final Map<String, Constructor<? extends AbstractStatement>> CoreTypesConstructors = new HashMap<>();
+
+    private static final YangCoreClassSupplier yangCoreClassSupplier = new YangCoreClassSupplier();
+
+    /**
+     * Creates an instance of a core Yang statement.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends AbstractStatement> T createYangCoreStatement(final ParserExecutionContext context,
+            final YangDomElement domElement, final AbstractStatement parentStatement) {
+
+        final String yangStatementName = domElement.getName();
+        try {
+            if (!CoreTypesConstructors.containsKey(yangStatementName)) {
+                final Class<? extends AbstractStatement> clazz = yangCoreClassSupplier.getJavaClazzForStatement(null,
+                        yangStatementName);
+                final Constructor<? extends AbstractStatement> constructor = clazz.getConstructor(AbstractStatement.class,
+                        YangDomElement.class);
+                CoreTypesConstructors.put(yangStatementName, constructor);
+            }
+
+            final Constructor<? extends AbstractStatement> constructor = CoreTypesConstructors.get(yangStatementName);
+            final AbstractStatement newInstance = constructor.newInstance(parentStatement, domElement);
+
+            return (T) newInstance;
+
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(domElement, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                    "Not a valid YANG statement: " + yangStatementName));
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates an instance of an extension statement.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends ExtensionStatement> T createYangExtensionStatement(final ParserExecutionContext context,
+            final YangDomElement domNode, final AbstractStatement parentStatement) {
+
+        final String[] prefixAndStatement = domNode.getName().split(":");
+        final String prefix = prefixAndStatement[0];
+        final String extStatementName = prefixAndStatement[1];
+
+        final ModuleIdentity moduleIdentity = parentStatement.getPrefixResolver().getModuleForPrefix(prefix);
+        if (moduleIdentity == null) {
+            context.addFinding(new Finding(domNode, ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString(),
+                    "Prefix '" + prefixAndStatement[0] + "' for the extension statement not resolvable."));
+            return null;
+        }
+
+        final String extModuleName = moduleIdentity.getModuleName();
+
+        try {
+            final Class<? extends ExtensionStatement> clazz = getClassForYangExtension(context, extModuleName,
+                    extStatementName);
+            final Constructor<? extends ExtensionStatement> constructor = clazz.getConstructor(AbstractStatement.class,
+                    YangDomElement.class);
+
+            final ExtensionStatement newInstance = constructor.newInstance(parentStatement, domNode);
+
+            return (T) newInstance;
+        } catch (final NoSuchMethodException nsmex) {
+            context.addFinding(new Finding(domNode, ParserFindingType.P002_INVALID_EXTENSION_STATEMENT_CLASS.toString(),
+                    "Extension statement class constructor wrong."));
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(domNode, ParserFindingType.P000_UNSPECIFIED_ERROR.toString(),
+                    "During instantiation of extension statement: " + ex.getMessage() + " - trace: " + StackTraceHelper
+                            .getStackTraceInfo(ex)));
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends AbstractStatement> T cloneYangStatement(final T statementToClone,
+            final AbstractStatement parentOfClone) {
+
+        final YangDomElement domElementOfStatementToClone = statementToClone.getDomElement();
+        final Class<? extends AbstractStatement> clazz = statementToClone.getClass();
+
+        try {
+            final Constructor<? extends AbstractStatement> constructor = clazz.getConstructor(AbstractStatement.class,
+                    YangDomElement.class);
+            final AbstractStatement newInstance = constructor.newInstance(parentOfClone, domElementOfStatementToClone);
+
+            return (T) newInstance;
+
+        } catch (final Exception ex) {
+            // no-op, cannot happen
+            return null;
+        }
+    }
+
+    /**
+     * Given the module name where an extension is defined, and the extension name, returns either a dedicated
+     * class that can handle the statement, or the catch-all {@link ExtensionStatement} class.
+     */
+    @SuppressWarnings("unchecked")
+    private static <T extends ExtensionStatement> Class<T> getClassForYangExtension(final ParserExecutionContext context,
+            final String moduleName, final String statementName) {
+
+        for (final StatementClassSupplier supplier : context.getExtensionCreators()) {
+            final Class<ExtensionStatement> extensionClazz = supplier.getJavaClazzForStatement(moduleName, statementName);
+            if (extensionClazz != null) {
+                return (Class<T>) extensionClazz;
+            }
+        }
+
+        /*
+         * No supplier found that can handle the extensions, we return extension catch-all base class.
+         */
+        return (Class<T>) ExtensionStatement.class;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementModuleAndName.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementModuleAndName.java
new file mode 100644
index 0000000..afe2a58
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/StatementModuleAndName.java
@@ -0,0 +1,103 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+
+/**
+ * Holds information about the name of a statement, and the module where the statement has
+ * been defined.
+ *
+ * @author Mark Hollmann
+ */
+public class StatementModuleAndName {
+
+    private final String moduleName;
+    private final String statementName;
+    private final boolean isYangCoreStatement;
+
+    /**
+     * Creates a new SMAN. The module name is the name of the module defining the statement.
+     */
+    public StatementModuleAndName(final String moduleName, final String statementName) {
+        this.moduleName = Objects.requireNonNull(moduleName);
+        this.statementName = Objects.requireNonNull(statementName);
+        this.isYangCoreStatement = CY.YANG_CORE_MODULE_NAME.equals(moduleName);
+    }
+
+    /**
+     * Returns the module in which the statement has been defined. If the statement is part of
+     * the core YANG language, the constant {@link CY.YANG_CORE_MODULE_NAME} will be returned.
+     */
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    /**
+     * Returns whether this statement is part of the YANG core language.
+     */
+    public boolean isYangCoreStatement() {
+        return isYangCoreStatement;
+    }
+
+    /**
+     * Returns whether this statement is an extension statement.
+     */
+    public boolean isExtensionStatement() {
+        return !isYangCoreStatement;
+    }
+
+    /**
+     * Returns the statement name. Note that different modules may define
+     * extensions having the same (statement-) name.
+     */
+    public String getStatementName() {
+        return statementName;
+    }
+
+    @Override
+    public int hashCode() {
+        return statementName.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return isYangCoreStatement() ? statementName : moduleName + ":" + statementName;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof StatementModuleAndName)) {
+            return false;
+        }
+
+        final StatementModuleAndName other = (StatementModuleAndName) obj;
+
+        return this.statementName.equals(other.statementName) && this.moduleName.equals(other.moduleName);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/YangModelRoot.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/YangModelRoot.java
new file mode 100644
index 0000000..d4122b6
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/YangModelRoot.java
@@ -0,0 +1,249 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ModulePrefixResolver;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+import org.oran.smo.yangtools.parser.model.statements.yang.YImport;
+import org.oran.smo.yangtools.parser.model.statements.yang.YInclude;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YNamespace;
+import org.oran.smo.yangtools.parser.model.statements.yang.YPrefix;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRevision;
+import org.oran.smo.yangtools.parser.model.statements.yang.YSubmodule;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomDocumentRoot;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Root element for a YANG statement tree. Every YAM will result in a tree of type-safe statements.
+ * Usages of groupings and typedefs, augmentations and deviations, and merge-in of submodule content,
+ * will all be performed on the tree (depending on settings in the context).
+ * <p/>
+ * For each YAM, there will be both a Yang DOM element tree (see {@link YangDomDocumentRoot}) and a
+ * YANG statement tree. However, these are not the exact same, and it is important to understand the
+ * difference:
+ * <p/>
+ * <ul>
+ * <li>The Yang DOM element tree is an exact 1:1 representation of the original YAM. It is the result
+ * of the parse of the YAM. During runtime of the parser it does not change, with some marked
+ * exceptions (see {@link YangDomDocumentRoot}).</li>
+ * <li>The YANG statement tree is the end result of applying various Yang statements (such as augment)
+ * to the YAM. This means that the YANG statement tree for a given YAM may end up pointing to DOM
+ * elements located in a different YAM (eg. the YAM that contains the 'augment' statement).</li>
+ * </ul>
+ * <p/>
+ * For compliant YAMs, an instance of this class will only ever have a single child statement (of type
+ * YModule or YSubmodule).
+ *
+ * @author Mark Hollmann
+ */
+public class YangModelRoot extends AbstractStatement {
+
+    /**
+     * Pointer to the root of the corresponding Yang DOM element tree.
+     */
+    private final YangDomDocumentRoot domDocumentRoot;
+
+    private final Schema owningSchema;
+
+    private YModule module = null;
+    private YSubmodule submodule = null;
+
+    /**
+     * This is the model root of the owner of this YAM. This is either the module itself (i.e. "this")
+     * or the module owning this submodule.
+     */
+    private YangModelRoot owningYangModelRoot = this;
+
+    /**
+     * The submodules owned by this module here, if any.
+     */
+    private List<YangModelRoot> ownedSubmodules = new ArrayList<>();
+
+    public YangModelRoot(final YangDomDocumentRoot domDocumentRoot, final Schema owningSchema) {
+        super(domDocumentRoot);
+        this.domDocumentRoot = domDocumentRoot;
+        this.owningSchema = owningSchema;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    public YangDomDocumentRoot getDomDocumentRoot() {
+        return domDocumentRoot;
+    }
+
+    public Schema getOwningSchema() {
+        return owningSchema;
+    }
+
+    public YangModel getYangModel() {
+        return domDocumentRoot.getYangModel();
+    }
+
+    /**
+     * Will tweak the pointer to point at the module that owns this module here.
+     */
+    public void setOwningYangModelRoot(final YangModelRoot owningYangModelRoot) {
+        this.owningYangModelRoot = owningYangModelRoot;
+        if (owningYangModelRoot != null) {
+            this.owningYangModelRoot.ownedSubmodules.add(this);
+        }
+    }
+
+    /**
+     * Returns the module owning this submodule. Returns "this" if this YAM is a module.
+     */
+    public YangModelRoot getOwningYangModelRoot() {
+        return owningYangModelRoot;
+    }
+
+    /**
+     * Returns the submodules owned by this module. Will be empty if this YAM here is a
+     * submodule, or if this module has no submodules.
+     */
+    public List<YangModelRoot> getOwnedSubmodules() {
+        return ownedSubmodules;
+    }
+
+    /**
+     * The namespace of the module, or the namespace of the owning module if this here is a submodule.
+     * May return null if a namespace has not been defined on the module, or the submodule is orphaned.
+     */
+    public String getNamespace() {
+
+        if (isModule()) {
+            final YNamespace yNamespace = module.getNamespace();
+            return yNamespace != null ? yNamespace.getValue() : null;
+        }
+
+        return owningYangModelRoot != null ? owningYangModelRoot.getNamespace() : null;
+    }
+
+    @Override
+    public ModulePrefixResolver getPrefixResolver() {
+        return getYangModel().getPrefixResolver();
+    }
+
+    @Override
+    protected void validate(ParserExecutionContext context) {
+        // nothing to validate
+    }
+
+    public YModule getModule() {
+        return module;
+    }
+
+    public YSubmodule getSubmodule() {
+        return submodule;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends AbstractStatement> T getModuleOrSubmodule() {
+        return module != null ? (T) module : (T) submodule;
+    }
+
+    /**
+     * Processes the DOM and starts building the statement tree in accordance with the DOM.
+     */
+    public void processYangDom(final ParserExecutionContext context, final YangDomDocumentRoot domDocRoot) {
+
+        final List<YangDomElement> childrenOfDocRoot = domDocRoot.getChildren();
+        if (childrenOfDocRoot.size() != 1) {
+            context.addFinding(new Finding(getYangModel(), ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
+                    "Expected single statement ('module' or 'submodule')."));
+            return;
+        }
+
+        final YangDomElement moduleElement = childrenOfDocRoot.get(0).getName().equals("module") ?
+                childrenOfDocRoot.get(0) :
+                null;
+        final YangDomElement submoduleElement = childrenOfDocRoot.get(0).getName().equals("submodule") ?
+                childrenOfDocRoot.get(0) :
+                null;
+
+        if (moduleElement != null) {
+            module = new YModule(this, moduleElement);
+            module.process(context);
+        } else if (submoduleElement != null) {
+            submodule = new YSubmodule(this, submoduleElement);
+            submodule.process(context);
+        } else {
+            context.addFinding(new Finding(getYangModel(), ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
+                    "Expected either 'module' or 'submodule' as root-statement in the document."));
+        }
+    }
+
+    public boolean isModule() {
+        return module != null;
+    }
+
+    public boolean isSubmodule() {
+        return submodule != null;
+    }
+
+    /**
+     * The module / submodule name will always be non-null.
+     */
+    public String getModuleOrSubModuleName() {
+        return isModule() ? module.getModuleName() : submodule.getSubmoduleName();
+    }
+
+    public List<YRevision> getRevisions() {
+        return isModule() ? module.getRevisions() : submodule.getRevisions();
+    }
+
+    public List<YImport> getImports() {
+        return isModule() ? module.getImports() : submodule.getImports();
+    }
+
+    public List<YInclude> getIncludes() {
+        return isModule() ? module.getIncludes() : submodule.getIncludes();
+    }
+
+    /**
+     * Returns the prefix statement of the module, or the prefix statement underneath the 'belongs-to' if
+     * it is a submodule. May return null if the prefix statement does not exist (which would be a very
+     * basic error).
+     */
+    public YPrefix getPrefix() {
+        return isModule() ?
+                module.getPrefix() :
+                submodule.getBelongsTo() != null ? submodule.getBelongsTo().getPrefix() : null;
+    }
+
+    public String getYangVersion() {
+        if (isModule()) {
+            return module.getYangVersion() == null ? "1" : module.getYangVersion().getValue();
+        }
+
+        return submodule.getYangVersion() == null ? "1" : submodule.getYangVersion().getValue();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/CIETF.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/CIETF.java
new file mode 100644
index 0000000..c660666
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/CIETF.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.ietf;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+
+/**
+ * Constants relating to IETF modules.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class CIETF {
+
+    public static final String IETF_YANG_SCHEMA_MOUNT_MODULE_NAME = "ietf-yang-schema-mount";
+    public static final String IETF_YANG_METADATA_MODULE_NAME = "ietf-yang-metadata";
+    public static final String IETF_NETCONF_ACM_MODULE_NAME = "ietf-netconf-acm";
+
+    public static final String MOUNT_POINT = "mount-point";
+    public static final String ANNOTATION = "annotation";
+    public static final String DEFAULT_DENY_WRITE = "default-deny-write";
+    public static final String DEFAULT_DENY_ALL = "default-deny-all";
+
+    private static final List<String> FROM_MODULE_IETF_YANG_SCHEMA_MOUNT = Arrays.asList(MOUNT_POINT);
+    private static final List<String> FROM_MODULE_IETF_YANG_METADATA = Arrays.asList(ANNOTATION);
+    private static final List<String> FROM_MODULE_IETF_NETCONF_ACM = Arrays.asList(DEFAULT_DENY_WRITE, DEFAULT_DENY_ALL);
+
+    public static final StatementModuleAndName IETF_YANG_SCHEMA_MOUNT__MOUNT_POINT = new StatementModuleAndName(
+            IETF_YANG_SCHEMA_MOUNT_MODULE_NAME, MOUNT_POINT);
+    public static final StatementModuleAndName IETF_YANG_METADATA__ANNOTATION = new StatementModuleAndName(
+            IETF_YANG_METADATA_MODULE_NAME, ANNOTATION);
+    public static final StatementModuleAndName IETF_NETCONF_ACM__DEFAULT_DENY_WRITE = new StatementModuleAndName(
+            IETF_NETCONF_ACM_MODULE_NAME, DEFAULT_DENY_WRITE);
+    public static final StatementModuleAndName IETF_NETCONF_ACM__DEFAULT_DENY_ALL = new StatementModuleAndName(
+            IETF_NETCONF_ACM_MODULE_NAME, DEFAULT_DENY_ALL);
+
+    public static final Map<String, List<String>> HANDLED_STATEMENTS = new HashMap<>();
+
+    static {
+        HANDLED_STATEMENTS.put(IETF_YANG_SCHEMA_MOUNT_MODULE_NAME, FROM_MODULE_IETF_YANG_SCHEMA_MOUNT);
+        HANDLED_STATEMENTS.put(IETF_YANG_METADATA_MODULE_NAME, FROM_MODULE_IETF_YANG_METADATA);
+        HANDLED_STATEMENTS.put(IETF_NETCONF_ACM_MODULE_NAME, FROM_MODULE_IETF_NETCONF_ACM);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/IetfExtensionsClassSupplier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/IetfExtensionsClassSupplier.java
new file mode 100644
index 0000000..1ad3b0a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/IetfExtensionsClassSupplier.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.ietf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatementClassSupplier;
+
+/**
+ * Class supplier for extensions defined in various IETF RFCs.
+ *
+ * @author Mark Hollmann
+ */
+public class IetfExtensionsClassSupplier extends AbstractStatementClassSupplier {
+
+    @Override
+    public Map<String, List<String>> getHandledStatements() {
+        return CIETF.HANDLED_STATEMENTS;
+    }
+
+    @Override
+    public <T extends AbstractStatement> Class<T> getJavaClazzForStatement(final String moduleName,
+            final String extStatementName) {
+
+        if (CIETF.IETF_YANG_SCHEMA_MOUNT_MODULE_NAME.equals(moduleName)) {
+            return handleIetfYangSchemaMountExtensions(extStatementName);
+        }
+
+        if (CIETF.IETF_YANG_METADATA_MODULE_NAME.equals(moduleName)) {
+            return handleIetfYangMetadataExtensions(extStatementName);
+        }
+
+        if (CIETF.IETF_NETCONF_ACM_MODULE_NAME.equals(moduleName)) {
+            return handleIetfNetconfAcmExtensions(extStatementName);
+        }
+
+        return null;
+    }
+
+    private static final String IETF_EXTENSIONS_JAVA_PACKAGE = YIetfMountPoint.class.getPackage().getName();
+    private static final String IETF_EXTENSIONS_JAVA_CLASS_PREFIX = "YIetf";
+
+    private <T extends AbstractStatement> Class<T> handleIetfYangSchemaMountExtensions(final String extStatementName) {
+        return getJavaClazzForStatement(IETF_EXTENSIONS_JAVA_PACKAGE, IETF_EXTENSIONS_JAVA_CLASS_PREFIX, extStatementName);
+    }
+
+    private <T extends AbstractStatement> Class<T> handleIetfYangMetadataExtensions(final String extStatementName) {
+        return getJavaClazzForStatement(IETF_EXTENSIONS_JAVA_PACKAGE, IETF_EXTENSIONS_JAVA_CLASS_PREFIX, extStatementName);
+    }
+
+    private <T extends AbstractStatement> Class<T> handleIetfNetconfAcmExtensions(final String extStatementName) {
+        return getJavaClazzForStatement(IETF_EXTENSIONS_JAVA_PACKAGE, IETF_EXTENSIONS_JAVA_CLASS_PREFIX, extStatementName);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfAnnotation.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfAnnotation.java
new file mode 100644
index 0000000..3996134
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfAnnotation.java
@@ -0,0 +1,127 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.ietf;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * From module ietf-yang-metadata:
+ *
+ * This extension allows for defining metadata annotations in
+ * YANG modules. The 'md:annotation' statement can appear only
+ * at the top level of a YANG module or submodule, i.e., it
+ * becomes a new alternative in the ABNF production rule for
+ * 'body-stmts' (Section 14 in RFC 7950).
+ *
+ * The argument of the 'md:annotation' statement defines the name
+ * of the annotation. Syntactically, it is a YANG identifier as
+ * defined in Section 6.2 of RFC 7950.
+ *
+ * An annotation defined with this 'extension' statement inherits
+ * the namespace and other context from the YANG module in which
+ * it is defined.
+ *
+ * The data type of the annotation value is specified in the same
+ * way as for a leaf data node using the 'type' statement.
+ *
+ * The semantics of the annotation and other documentation can be
+ * specified using the following standard YANG substatements (all
+ * are optional): 'description', 'if-feature', 'reference',
+ * 'status', and 'units'.
+ *
+ * A server announces support for a particular annotation by
+ * including the module in which the annotation is defined among
+ * the advertised YANG modules, e.g., in a NETCONF <hello>
+ * message or in the YANG library (RFC 7950). The annotation can
+ * then be attached to any instance of a data node defined in any
+ * YANG module that is advertised by the server.
+ *
+ * XML encoding and JSON encoding of annotations are defined in
+ * RFC 7952.;
+ *
+ * @author Mark Hollmann
+ */
+public class YIetfAnnotation extends ExtensionStatement {
+
+    public YIetfAnnotation(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CIETF.IETF_YANG_METADATA__ANNOTATION;
+    }
+
+    @Override
+    public boolean argumentIsMandatory() {
+        return true;
+    }
+
+    public String getAnnotationName() {
+        return getValue() != null ? getValue() : "";
+    }
+
+    @Override
+    public MaxCardinality getMaxCardinalityUnderParent() {
+        return MaxCardinality.MULTIPLE;
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_MODULE, CY.STMT_SUBMODULE);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        checkParent(context);
+
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getValue());
+    }
+
+    @Override
+    protected void subtreeProcessed(final ParserExecutionContext context) {
+        /*
+         * There must be exactly a single type statement under the annotation.
+         */
+        if (getChildren(CY.STMT_TYPE).size() != 1) {
+            context.addFinding(new Finding(this, ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString(),
+                    "A 'type' statement is required for the annotation."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfDefaultDenyAll.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfDefaultDenyAll.java
new file mode 100644
index 0000000..833be94
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfDefaultDenyAll.java
@@ -0,0 +1,88 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.ietf;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe IETF statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YIetfDefaultDenyAll extends ExtensionStatement {
+
+    public YIetfDefaultDenyAll(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CIETF.IETF_NETCONF_ACM__DEFAULT_DENY_ALL;
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_RPC, CY.STMT_NOTIFICATION,
+            CY.STMT_LEAF, CY.STMT_LEAF_LIST, CY.STMT_LIST, CY.STMT_CONTAINER, CY.STMT_ANYDATA, CY.STMT_ANYXML);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From module ietf-netconf-acm:
+         *
+         * Used to indicate that the data model node
+         * controls a very sensitive security system parameter.
+         *
+         * If present, the NETCONF server will only allow the designated
+         * 'recovery session' to have read, write, or execute access to
+         * the node.  An explicit access control rule is required for all
+         * other users.
+         *
+         * If the NACM module is used, then it must be enabled (i.e.,
+         * /nacm/enable-nacm object equals 'true'), or this extension
+         * is ignored.
+         *
+         * The 'default-deny-all' extension MAY appear within a data
+         * definition statement, 'rpc' statement, or 'notification'
+         * statement. It is ignored otherwise.
+         */
+        validateArgumentIsNull(context);
+
+        checkParentAlsoAllowDeviateOrRefine(context);
+        checkCardinalityUnderParent(context, 1);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfDefaultDenyWrite.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfDefaultDenyWrite.java
new file mode 100644
index 0000000..db52d9a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfDefaultDenyWrite.java
@@ -0,0 +1,86 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.ietf;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe IETF statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YIetfDefaultDenyWrite extends ExtensionStatement {
+
+    public YIetfDefaultDenyWrite(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CIETF.IETF_NETCONF_ACM__DEFAULT_DENY_WRITE;
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_LEAF, CY.STMT_LEAF_LIST,
+            CY.STMT_LIST, CY.STMT_CONTAINER, CY.STMT_ANYDATA, CY.STMT_ANYXML);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From module ietf-netconf-acm:
+         *
+         * Used to indicate that the data model node
+         * represents a sensitive security system parameter.
+         *
+         * If present, the NETCONF server will only allow the designated
+         * 'recovery session' to have write access to the node.  An
+         * explicit access control rule is required for all other users.
+         *
+         * If the NACM module is used, then it must be enabled (i.e.,
+         * /nacm/enable-nacm object equals 'true'), or this extension
+         * is ignored.
+         *
+         * The 'default-deny-write' extension MAY appear within a data
+         * definition statement.  It is ignored otherwise.
+         */
+        validateArgumentIsNull(context);
+
+        checkParentAlsoAllowDeviateOrRefine(context);
+        checkCardinalityUnderParent(context, 1);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfMountPoint.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfMountPoint.java
new file mode 100644
index 0000000..fefb885
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/ietf/YIetfMountPoint.java
@@ -0,0 +1,103 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.ietf;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe IETF statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YIetfMountPoint extends ExtensionStatement {
+
+    public YIetfMountPoint(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CIETF.IETF_YANG_SCHEMA_MOUNT__MOUNT_POINT;
+    }
+
+    @Override
+    public boolean argumentIsMandatory() {
+        return true;
+    }
+
+    public String getLabel() {
+        return getValue() != null ? getValue() : "";
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_LIST, CY.STMT_CONTAINER);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From module ietf-yang-schema-mount:
+         *
+         * The argument 'label' is a YANG identifier, i.e., it is of the
+         * type 'yang:yang-identifier'.
+         *
+         * The 'mount-point' statement MUST NOT be used in a YANG
+         * version 1 module, neither explicitly nor via a 'uses'
+         * statement.
+         * The 'mount-point' statement MAY be present as a substatement
+         * of 'container' and 'list' and MUST NOT be present elsewhere.
+         * There MUST NOT be more than one 'mount-point' statement in a
+         * given 'container' or 'list' statement.
+         *
+         * If a mount point is defined within a grouping, its label is
+         * bound to the module where the grouping is used.
+         *
+         * A mount point defines a place in the node hierarchy where
+         * other data models may be attached.  A server that implements a
+         * module with a mount point populates the
+         * '/schema-mounts/mount-point' list with detailed information on
+         * which data models are mounted at each mount point.
+         *
+         * Note that the 'mount-point' statement does not define a new
+         * data node.
+         */
+        validateArgumentNotNullNotEmpty(context);
+
+        checkParentAlsoAllowDeviateOrRefine(context);
+        checkCardinalityUnderParent(context, 1);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/CORAN.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/CORAN.java
new file mode 100644
index 0000000..47bc0bb
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/CORAN.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.oran;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+
+/**
+ * Constants relating to ORAN modules.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class CORAN {
+
+    public static final String ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME = "o-ran-smo-teiv-common-yang-extensions";
+
+    public static final String SMO_TEIV_BI_DIRECTIONAL_TOPOLOGY_RELATIONSHIP = "biDirectionalTopologyRelationship";
+    public static final String SMO_TEIV_A_SIDE = "aSide";
+    public static final String SMO_TEIV_B_SIDE = "bSide";
+    public static final String SMO_TEIV_DOMAIN = "domain";
+    public static final String SMO_TEIV_LABEL = "label";
+
+    private static final List<String> FROM_MODULE_ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS = Arrays.asList(
+            SMO_TEIV_BI_DIRECTIONAL_TOPOLOGY_RELATIONSHIP, SMO_TEIV_A_SIDE, SMO_TEIV_B_SIDE, SMO_TEIV_DOMAIN,
+            SMO_TEIV_LABEL);
+
+    public static final StatementModuleAndName ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__BI_DIRECTIONAL_TOPOLOGY_RELATIONSHIP = new StatementModuleAndName(
+            ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME, SMO_TEIV_BI_DIRECTIONAL_TOPOLOGY_RELATIONSHIP);
+    public static final StatementModuleAndName ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__A_SIDE = new StatementModuleAndName(
+            ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME, SMO_TEIV_A_SIDE);
+    public static final StatementModuleAndName ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__B_SIDE = new StatementModuleAndName(
+            ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME, SMO_TEIV_B_SIDE);
+    public static final StatementModuleAndName ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__DOMAIN = new StatementModuleAndName(
+            ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME, SMO_TEIV_DOMAIN);
+    public static final StatementModuleAndName ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__LABEL = new StatementModuleAndName(
+            ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME, SMO_TEIV_LABEL);
+
+    public static final Map<String, List<String>> HANDLED_STATEMENTS = new HashMap<>();
+
+    static {
+        HANDLED_STATEMENTS.put(ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME,
+                FROM_MODULE_ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/OranExtensionsClassSupplier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/OranExtensionsClassSupplier.java
new file mode 100644
index 0000000..04a350d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/OranExtensionsClassSupplier.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.oran;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatementClassSupplier;
+
+/**
+ * Class supplier for extension statements defined by ORAN
+ *
+ * @author Mark Hollmann
+ */
+public class OranExtensionsClassSupplier extends AbstractStatementClassSupplier {
+
+    @Override
+    public Map<String, List<String>> getHandledStatements() {
+        return CORAN.HANDLED_STATEMENTS;
+    }
+
+    @Override
+    public <T extends AbstractStatement> Class<T> getJavaClazzForStatement(final String moduleName,
+            final String extStatementName) {
+
+        if (CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS_MODULE_NAME.equals(moduleName)) {
+            return handleSmoTeivExtensions(extStatementName);
+        }
+
+        return null;
+    }
+
+    private static final String ORAN_EXTENSIONS_JAVA_PACKAGE = OranExtensionsClassSupplier.class.getPackage().getName();
+    private static final String ORAN_SMO_TEIV_EXTENSIONS_JAVA_CLASS_PREFIX = "YOranSmoTeiv";
+
+    private <T extends AbstractStatement> Class<T> handleSmoTeivExtensions(final String extStatementName) {
+        return getJavaClazzForStatement(ORAN_EXTENSIONS_JAVA_PACKAGE, ORAN_SMO_TEIV_EXTENSIONS_JAVA_CLASS_PREFIX,
+                extStatementName);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivASide.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivASide.java
new file mode 100644
index 0000000..2b6143c
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivASide.java
@@ -0,0 +1,99 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.oran;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+public class YOranSmoTeivASide extends ExtensionStatement {
+
+    public YOranSmoTeivASide(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__A_SIDE;
+    }
+
+    @Override
+    public boolean argumentIsMandatory() {
+        return true;
+    }
+
+    public String getTeivTypeName() {
+        return getValue() != null ? getValue() : "";
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_LEAF, CY.STMT_LEAF_LIST);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From o-ran-smo-teiv-common-yang-extensions:
+         *
+         * Defines the A-side of a relationship.
+         *
+         * The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+         * statement, which itself must be a substatement of the
+         * 'uni-directional-topology-relationship' statement.
+         *
+         * The data type of the parent 'leaf' or 'leaf-list' MUST be
+         * 'instance-identifier'. Constraints MAY be used as part of the parent
+         * 'leaf' or 'leaf-list' to enforce cardinality.
+         *
+         * The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+         * the role of the A-side of the relationship. The name of the role is
+         * scoped to the type on which the A-side is defined and MUST be unique
+         * within the scope.
+         *
+         * While the parent 'leaf' or 'leaf-list' does not result in a property of
+         * the relationship, it is RECOMMENDED to avoid using the name of an
+         * existing type property as role name to avoid potential ambiguities
+         * between properties of a type, and roles of a relationship on the type.
+         *
+         * The argument is the name of the type on which the A-side resides. If the
+         * type is declared in another module, the type must be prefixed, and a
+         * corresponding 'import' statement be used to declare the prefix.";
+         */
+        validateArgumentNotNullNotEmpty(context);
+
+        checkParent(context);
+        checkCardinalityUnderParent(context, 1);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivBSide.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivBSide.java
new file mode 100644
index 0000000..a6aeaa7
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivBSide.java
@@ -0,0 +1,99 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.oran;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+public class YOranSmoTeivBSide extends ExtensionStatement {
+
+    public YOranSmoTeivBSide(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__B_SIDE;
+    }
+
+    @Override
+    public boolean argumentIsMandatory() {
+        return true;
+    }
+
+    public String getTeivTypeName() {
+        return getValue() != null ? getValue() : "";
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_LEAF, CY.STMT_LEAF_LIST);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From o-ran-smo-teiv-common-yang-extensions:
+         *
+         * Defines the B-side of a relationship.
+         *
+         * The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+         * statement, which itself must be a substatement of the
+         * 'uni-directional-topology-relationship' statement.
+         *
+         * The data type of the parent 'leaf' or 'leaf-list' MUST be
+         * 'instance-identifier'. Constraints MAY be used as part of the parent
+         * 'leaf' or 'leaf-list' to enforce cardinality.
+         *
+         * The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+         * the role of the B-side of the relationship. The name of the role is
+         * scoped to the type on which the B-side is defined and MUST be unique
+         * within the scope.
+         *
+         * While the parent 'leaf' or 'leaf-list' does not result in a property of
+         * the relationship, it is RECOMMENDED to avoid using the name of an
+         * existing type property as role name to avoid potential ambiguities
+         * between properties of a type, and roles of a relationship on the type.
+         *
+         * The argument is the name of the type on which the B-side resides. If the
+         * type is declared in another module, the type must be prefixed, and a
+         * corresponding 'import' statement be used to declare the prefix.";
+         */
+        validateArgumentNotNullNotEmpty(context);
+
+        checkParent(context);
+        checkCardinalityUnderParent(context, 1);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivBiDirectionalTopologyRelationship.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivBiDirectionalTopologyRelationship.java
new file mode 100644
index 0000000..0b2b42e
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivBiDirectionalTopologyRelationship.java
@@ -0,0 +1,131 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.oran;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+public class YOranSmoTeivBiDirectionalTopologyRelationship extends ExtensionStatement {
+
+    public YOranSmoTeivBiDirectionalTopologyRelationship(final AbstractStatement parentStatement,
+            final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__BI_DIRECTIONAL_TOPOLOGY_RELATIONSHIP;
+    }
+
+    @Override
+    public boolean argumentIsMandatory() {
+        return true;
+    }
+
+    @Override
+    public MaxCardinality getMaxCardinalityUnderParent() {
+        return MaxCardinality.MULTIPLE;
+    }
+
+    public String getRelationshipName() {
+        return getValue() != null ? getValue() : "";
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_MODULE);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From o-ran-smo-teiv-common-yang-extensions:
+         *
+         * Defines a bi-directional relationship in the topology.
+         *
+         * A bi-directional-association (UDA) is a relationship comprising of an
+         * A-side and a B-side. The A-side is considered the originating side of
+         * the relationship; the B-side is considered the terminating side of the
+         * relationship. The order of A-side and B-side is of importance and MUST
+         * NOT be changed once defined.
+         *
+         * Both A-side and B-side are defined on a type, and are given a role. A
+         * type may have multiple originating and/or terminating sides of a
+         * relationship, all distinguished by role name.
+         *
+         * The statement MUST only be a substatement of the 'module' statement.
+         * Multiple 'bi-directional-topology-relationship' statements are allowed
+         * per parent statement.
+         *
+         * Substatements to the 'bi-directional-topology-relationship' define the
+         * A-side and the B-side, respectively, and optionally properties of the
+         * relationship. Data nodes of types 'leaf' and 'leaf-list' are used for
+         * this purpose. One of the data nodes MUST be annotated with the 'aSide'
+         * extension; another data node MUST be annotated with the 'bSide'
+         * extension. Other data nodes define properties of the relationship.
+         *
+         * The argument is the name of the relationship. The relationship name is
+         * scoped to the namespace of the declaring module and MUST be unique
+         * within the scope.";
+         */
+        validateArgumentNotNullNotEmpty(context);
+
+        checkParent(context);
+    }
+
+    @Override
+    protected void subtreeProcessed(final ParserExecutionContext context) {
+        /*
+         * We are checking that we have an a-side and a b-side.
+         */
+        final long aSides = getChildStatements().stream().filter(stmt -> stmt.is(CY.STMT_LEAF) || stmt.is(
+                CY.STMT_LEAF_LIST)).filter(stmt -> stmt.hasAtLeastOneChildOf(
+                        CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__A_SIDE)).count();
+        final long bSides = getChildStatements().stream().filter(stmt -> stmt.is(CY.STMT_LEAF) || stmt.is(
+                CY.STMT_LEAF_LIST)).filter(stmt -> stmt.hasAtLeastOneChildOf(
+                        CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__B_SIDE)).count();
+
+        if (aSides != 1) {
+            context.addFinding(new Finding(this, ParserFindingType.P025_INVALID_EXTENSION,
+                    "A 'bi-directional relationship' must have as child exactly a single leaf or leaf-list annotated with 'aSide'."));
+        }
+        if (bSides != 1) {
+            context.addFinding(new Finding(this, ParserFindingType.P025_INVALID_EXTENSION,
+                    "A 'bi-directional relationship' must have as child exactly a single leaf or leaf-list annotated with 'bSide'."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivLabel.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivLabel.java
new file mode 100644
index 0000000..53c60d1
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/oran/YOranSmoTeivLabel.java
@@ -0,0 +1,115 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.oran;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+public class YOranSmoTeivLabel extends ExtensionStatement {
+
+    private int version;
+    private int release;
+    private int correction;
+
+    public YOranSmoTeivLabel(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__LABEL;
+    }
+
+    @Override
+    public boolean argumentIsMandatory() {
+        return true;
+    }
+
+    public String getLabel() {
+        return getValue() != null ? getValue() : "";
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public int getRelease() {
+        return release;
+    }
+
+    public int getCorrection() {
+        return correction;
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_REVISION);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    private static final Pattern VALID_PATTERN = Pattern.compile("[0-9]+\\.[0-9]+\\.[0-9]+");
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From o-ran-smo-teiv-common-yang-extensions:
+         *
+         * The label can be used to give modules and submodules a semantic version, in addition to their revision.
+         *
+         * The format of the label is 'x.y.z' – expressed as pattern, it is [0-9]+\.[0-9]+\.[0-9]+
+         *
+         * The statement MUST only be a substatement of the revision statement.  Zero or one revision label statements
+         * per parent statement are allowed.
+         *
+         * Revision labels MUST be unique amongst all revisions of a module or submodule.
+         */
+        validateArgumentNotNullNotEmpty(context);
+
+        final String label = getLabel();
+        if (!VALID_PATTERN.matcher(label).matches()) {
+            context.addFinding(new Finding(this, ParserFindingType.P025_INVALID_EXTENSION,
+                    "Label value must be in 'version.release.correction' format."));
+        } else {
+            version = Integer.parseInt(label.substring(0, label.indexOf('.')));
+            release = Integer.parseInt(label.substring(label.indexOf('.') + 1, label.lastIndexOf('.')));
+            correction = Integer.parseInt(label.substring(label.lastIndexOf('.') + 1));
+        }
+
+        checkParent(context);
+        checkCardinalityUnderParent(context, 1);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/C3GPP.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/C3GPP.java
new file mode 100644
index 0000000..3095565
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/C3GPP.java
@@ -0,0 +1,58 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.threegpp;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+
+/**
+ * Constants relating to 3GPP modules.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class C3GPP {
+
+    public static final String THREEGPP_COMMON_YANG_EXTENSIONS_MODULE_NAME = "_3gpp-common-yang-extensions";
+
+    public static final String INITIAL_VALUE = "initial-value";
+    public static final String IN_VARIANT = "inVariant";
+    public static final String NOT_NOTIFYABLE = "notNotifyable";
+
+    private static final List<String> FROM_MODULE_THREEGPP_COMMON_YANG_EXTENSIONS = Arrays.asList(INITIAL_VALUE, IN_VARIANT,
+            NOT_NOTIFYABLE);
+
+    public static final StatementModuleAndName THREEGPP_COMMON_YANG_EXTENSIONS__INITIAL_VALUE = new StatementModuleAndName(
+            THREEGPP_COMMON_YANG_EXTENSIONS_MODULE_NAME, INITIAL_VALUE);
+    public static final StatementModuleAndName THREEGPP_COMMON_YANG_EXTENSIONS__IN_VARIANT = new StatementModuleAndName(
+            THREEGPP_COMMON_YANG_EXTENSIONS_MODULE_NAME, IN_VARIANT);
+    public static final StatementModuleAndName THREEGPP_COMMON_YANG_EXTENSIONS__NOT_NOTIFYABLE = new StatementModuleAndName(
+            THREEGPP_COMMON_YANG_EXTENSIONS_MODULE_NAME, NOT_NOTIFYABLE);
+
+    public static final Map<String, List<String>> HANDLED_STATEMENTS = new HashMap<>();
+
+    static {
+        HANDLED_STATEMENTS.put(THREEGPP_COMMON_YANG_EXTENSIONS_MODULE_NAME, FROM_MODULE_THREEGPP_COMMON_YANG_EXTENSIONS);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/ThreeGppExtensionsClassSupplier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/ThreeGppExtensionsClassSupplier.java
new file mode 100644
index 0000000..dd0086d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/ThreeGppExtensionsClassSupplier.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.threegpp;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatementClassSupplier;
+
+/**
+ * Class supplier for extension statements defined by 3GPP
+ *
+ * @author Mark Hollmann
+ */
+public class ThreeGppExtensionsClassSupplier extends AbstractStatementClassSupplier {
+
+    @Override
+    public Map<String, List<String>> getHandledStatements() {
+        return C3GPP.HANDLED_STATEMENTS;
+    }
+
+    @Override
+    public <T extends AbstractStatement> Class<T> getJavaClazzForStatement(final String moduleName,
+            final String extStatementName) {
+
+        if (C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS_MODULE_NAME.equals(moduleName)) {
+            return handle3gppExtensions(extStatementName);
+        }
+
+        return null;
+    }
+
+    private static final String THREEGPP_EXTENSIONS_JAVA_PACKAGE = Y3gppInVariant.class.getPackage().getName();
+    private static final String THREEGPP_EXTENSIONS_JAVA_CLASS_PREFIX = "Y3gpp";
+
+    private <T extends AbstractStatement> Class<T> handle3gppExtensions(final String extStatementName) {
+        return getJavaClazzForStatement(THREEGPP_EXTENSIONS_JAVA_PACKAGE, THREEGPP_EXTENSIONS_JAVA_CLASS_PREFIX,
+                extStatementName);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppInVariant.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppInVariant.java
new file mode 100644
index 0000000..a2bb490
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppInVariant.java
@@ -0,0 +1,91 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.threegpp;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe 3GPP statement.
+ *
+ * @author Mark Hollmann
+ */
+public class Y3gppInVariant extends ExtensionStatement {
+
+    public Y3gppInVariant(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__IN_VARIANT;
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_LEAF, CY.STMT_LEAF_LIST,
+            CY.STMT_LIST);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From module _3gpp-common-yang-extensions:
+         *
+         * Indicates that the value for the data node can only be set when its
+         * parent data node is being created. To change the value after that, the
+         * parent data node must be deleted and recreated with the data node
+         * having the new value.
+         *
+         * It is unnecessary to use and MUST NOT be used for key leafs.
+         *
+         * The statement MUST only be a substatement of a leaf, leaf-list, list
+         * statements that is config=true.
+         * Zero or one inVariant statement is allowed per parent statement.
+         * NO substatements are allowed.
+         *
+         * Adding this statement is an NBC change, removing it is BC.
+         */
+        checkParentAlsoAllowDeviateOrRefine(context);
+        checkCardinalityUnderParent(context, 1);
+
+        if (getValue() != null) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "'inVariant' extension does not allow for an argument."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppInitialValue.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppInitialValue.java
new file mode 100644
index 0000000..9045b2d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppInitialValue.java
@@ -0,0 +1,119 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.threegpp;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe 3GPP statement.
+ *
+ * @author Mark Hollmann
+ */
+public class Y3gppInitialValue extends ExtensionStatement {
+
+    public Y3gppInitialValue(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__INITIAL_VALUE;
+    }
+
+    @Override
+    public boolean argumentIsMandatory() {
+        return true;
+    }
+
+    @Override
+    public boolean orderUnderParentMatters() {
+        return true;
+    }
+
+    public String getInitialValue() {
+        return getValue() != null ? getValue() : "";
+    }
+
+    @Override
+    public MaxCardinality getMaxCardinalityUnderParent() {
+        return getParentStatement().is(CY.STMT_LEAF) ? MaxCardinality.ONE : MaxCardinality.MULTIPLE;
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_LEAF, CY.STMT_LEAF_LIST);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From module _3gpp-common-yang-extensions:
+         *
+         * Specifies a value that the system will set for a leaf
+         * leaf-list if a value is not specified for it when its parent list
+         * or container is created. The value has no effect in any other
+         * modification e.g. changing or removing the value.
+         *
+         * The description statement of the parent statement SHOULD contain
+         * the label 'Initial-value: ' followed by the text from the argument.
+         *
+         * The statement MUST only be a substatement of a leaf or leaf-list.
+         * The statement MUST NOT be present if the leaf or the leaf-list
+         * has a default statement or the type used for the data node
+         * has a default value.
+         * The statement MUST NOT be used for config=false data or in an
+         * action, rpc or notification.
+         * Zero or one initial-value statements are allowed for a leaf parent
+         * statement. Zero or more initial-value statements are allowed for a
+         * leaf-list parent statement. If the leaf-list is ordered-by user, the
+         * initial values are stored in the order they appear in the YANG definition.
+         * NO substatements are allowed.
+         *
+         * Always consider using a YANG-default statement instead.
+         *
+         * Modification of the initial-value is a non-backwards-compatible change.
+         *
+         * The argument specifies a single initial value for a leaf or leaf-list.
+         * The value MUST be part of the valuespace of the leaf/leaf-list.
+         * It follows the same rules as the argument of the default statement.
+         */
+        validateArgumentNotNull(context);
+        checkParentAlsoAllowDeviateOrRefine(context);
+
+        if (getParentStatement().is(CY.STMT_LEAF)) {
+            checkCardinalityUnderParent(context, 1);
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppNotNotifyable.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppNotNotifyable.java
new file mode 100644
index 0000000..ed6308b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/threegpp/Y3gppNotNotifyable.java
@@ -0,0 +1,93 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.threegpp;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe 3GPP statement.
+ *
+ * @author Mark Hollmann
+ */
+public class Y3gppNotNotifyable extends ExtensionStatement {
+
+    public Y3gppNotNotifyable(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__NOT_NOTIFYABLE;
+    }
+
+    private static final List<StatementModuleAndName> REQUIRED_PARENTS = Arrays.asList(CY.STMT_LEAF, CY.STMT_LEAF_LIST,
+            CY.STMT_LIST, CY.STMT_CONTAINER, CY.STMT_ANYDATA, CY.STMT_ANYXML);
+
+    @Override
+    public boolean canBeChildOf(final StatementModuleAndName parentSman) {
+        return REQUIRED_PARENTS.contains(parentSman);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * From module _3gpp-common-yang-extensions:
+         *
+         * Indicates that data change notifications shall not be sent
+         * for this attribute. If the extension is not present and other
+         * conditions are fulfilled data change notification should be sent.
+         * If a list or container already has the notNotifyable
+         * extension, that is also valid for all contained data nodes.
+         *
+         * The statement MUST only be a substatement of a leaf, leaf-list, list,
+         * container statement that is contained within the 'attributes'
+         * container of an IOC and that represents an attribute or sub-parts of
+         * an attribute .
+         *
+         * Zero or one notNotifyable statement is allowed per parent statement.
+         * NO substatements are allowed.
+         *
+         * Adding this statement is an NBC change, removing it is BC.";
+         */
+        checkParentAlsoAllowDeviateOrRefine(context);
+        checkCardinalityUnderParent(context, 1);
+
+        if (getValue() != null) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "'notNotifyable' extension does not allow for an argument."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/CY.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/CY.java
new file mode 100644
index 0000000..d49a6b7
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/CY.java
@@ -0,0 +1,1009 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+
+/**
+ * A class containing a number of constants in relation to the YANG core language.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class CY {
+
+    /*
+     * ----------- core language statement names ---------------
+     */
+
+    public static final String ACTION = "action";
+    public static final String ANYDATA = "anydata";
+    public static final String ANYXML = "anyxml";
+    public static final String ARGUMENT = "argument";
+    public static final String AUGMENT = "augment";
+    public static final String BASE = "base";
+    public static final String BELONGS_TO = "belongs-to";
+    public static final String BIT = "bit";
+    public static final String CASE = "case";
+    public static final String CHOICE = "choice";
+    public static final String CONFIG = "config";
+    public static final String CONTACT = "contact";
+    public static final String CONTAINER = "container";
+    public static final String DEFAULT = "default";
+    public static final String DESCRIPTION = "description";
+    public static final String DEVIATE = "deviate";
+    public static final String DEVIATION = "deviation";
+    public static final String ENUM = "enum";
+    public static final String ERROR_APP_TAG = "error-app-tag";
+    public static final String ERROR_MESSAGE = "error-message";
+    public static final String EXTENSION = "extension";
+    public static final String FEATURE = "feature";
+    public static final String FRACTION_DIGITS = "fraction-digits";
+    public static final String GROUPING = "grouping";
+    public static final String IDENTITY = "identity";
+    public static final String IF_FEATURE = "if-feature";
+    public static final String IMPORT = "import";
+    public static final String INCLUDE = "include";
+    public static final String INPUT = "input";
+    public static final String KEY = "key";
+    public static final String LEAF = "leaf";
+    public static final String LEAF_LIST = "leaf-list";
+    public static final String LENGTH = "length";
+    public static final String LIST = "list";
+    public static final String MANDATORY = "mandatory";
+    public static final String MAX_ELEMENTS = "max-elements";
+    public static final String MIN_ELEMENTS = "min-elements";
+    public static final String MODIFIER = "modifier";
+    public static final String MODULE = "module";
+    public static final String MUST = "must";
+    public static final String NAMESPACE = "namespace";
+    public static final String NOTIFICATION = "notification";
+    public static final String ORDERED_BY = "ordered-by";
+    public static final String ORGANIZATION = "organization";
+    public static final String OUTPUT = "output";
+    public static final String PATH = "path";
+    public static final String PATTERN = "pattern";
+    public static final String POSITION = "position";
+    public static final String PREFIX = "prefix";
+    public static final String PRESENCE = "presence";
+    public static final String RANGE = "range";
+    public static final String REFERENCE = "reference";
+    public static final String REFINE = "refine";
+    public static final String REQUIRE_INSTANCE = "require-instance";
+    public static final String REVISION = "revision";
+    public static final String REVISION_DATE = "revision-date";
+    public static final String RPC = "rpc";
+    public static final String STATUS = "status";
+    public static final String SUBMODULE = "submodule";
+    public static final String TYPE = "type";
+    public static final String TYPEDEF = "typedef";
+    public static final String UNIQUE = "unique";
+    public static final String UNITS = "units";
+    public static final String USES = "uses";
+    public static final String VALUE = "value";
+    public static final String WHEN = "when";
+    public static final String YANG_VERSION = "yang-version";
+    public static final String YIN_ELEMENT = "yin-element";
+
+    public static final Set<String> ALL_YANG_CORE_STATEMENT_NAMES = new HashSet<>(Arrays.asList(ACTION, ANYDATA, ANYXML,
+            ARGUMENT, AUGMENT, BASE, BELONGS_TO, BIT, CASE, CHOICE, CONFIG, CONTACT, CONTAINER, DEFAULT, DESCRIPTION,
+            DEVIATE, DEVIATION, ENUM, ERROR_APP_TAG, ERROR_MESSAGE, EXTENSION, FEATURE, FRACTION_DIGITS, GROUPING, IDENTITY,
+            IF_FEATURE, IMPORT, INCLUDE, INPUT, KEY, LEAF, LEAF_LIST, LENGTH, LIST, MANDATORY, MAX_ELEMENTS, MIN_ELEMENTS,
+            MODIFIER, MODULE, MUST, NAMESPACE, NOTIFICATION, ORDERED_BY, ORGANIZATION, OUTPUT, PATH, PATTERN, POSITION,
+            PREFIX, PRESENCE, RANGE, REFERENCE, REFINE, REQUIRE_INSTANCE, REVISION, REVISION_DATE, RPC, STATUS, SUBMODULE,
+            TYPE, TYPEDEF, UNIQUE, UNITS, USES, VALUE, WHEN, YANG_VERSION, YIN_ELEMENT));
+
+    /**
+     * Returns whether the supplied statement name is defined by the Yang core language.
+     */
+    public static boolean isYangCoreStatementName(final String statementName) {
+        return ALL_YANG_CORE_STATEMENT_NAMES.contains(statementName);
+    }
+
+    /*
+     * --------- core YANG statements encoded as module-name/statements -------------
+     */
+
+    /**
+     * There is no module name for YANG. The name chosen here is a fictitious, but illegal,
+     * module name (as it contains a space character), to avoid a potential clash with an actual,
+     * real, YANG module name.
+     */
+    public static final String YANG_CORE_MODULE_NAME = "YANG CORE";
+
+    public static final StatementModuleAndName STMT_ACTION = new StatementModuleAndName(YANG_CORE_MODULE_NAME, ACTION);
+    public static final StatementModuleAndName STMT_ANYDATA = new StatementModuleAndName(YANG_CORE_MODULE_NAME, ANYDATA);
+    public static final StatementModuleAndName STMT_ANYXML = new StatementModuleAndName(YANG_CORE_MODULE_NAME, ANYXML);
+    public static final StatementModuleAndName STMT_ARGUMENT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, ARGUMENT);
+    public static final StatementModuleAndName STMT_AUGMENT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, AUGMENT);
+    public static final StatementModuleAndName STMT_BASE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, BASE);
+    public static final StatementModuleAndName STMT_BELONGS_TO = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            BELONGS_TO);
+    public static final StatementModuleAndName STMT_BIT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, BIT);
+    public static final StatementModuleAndName STMT_CASE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, CASE);
+    public static final StatementModuleAndName STMT_CHOICE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, CHOICE);
+    public static final StatementModuleAndName STMT_CONFIG = new StatementModuleAndName(YANG_CORE_MODULE_NAME, CONFIG);
+    public static final StatementModuleAndName STMT_CONTACT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, CONTACT);
+    public static final StatementModuleAndName STMT_CONTAINER = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            CONTAINER);
+    public static final StatementModuleAndName STMT_DEFAULT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, DEFAULT);
+    public static final StatementModuleAndName STMT_DESCRIPTION = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            DESCRIPTION);
+    public static final StatementModuleAndName STMT_DEVIATE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, DEVIATE);
+    public static final StatementModuleAndName STMT_DEVIATION = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            DEVIATION);
+    public static final StatementModuleAndName STMT_ENUM = new StatementModuleAndName(YANG_CORE_MODULE_NAME, ENUM);
+    public static final StatementModuleAndName STMT_ERROR_APP_TAG = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            ERROR_APP_TAG);
+    public static final StatementModuleAndName STMT_ERROR_MESSAGE = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            ERROR_MESSAGE);
+    public static final StatementModuleAndName STMT_EXTENSION = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            EXTENSION);
+    public static final StatementModuleAndName STMT_FEATURE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, FEATURE);
+    public static final StatementModuleAndName STMT_FRACTION_DIGITS = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            FRACTION_DIGITS);
+    public static final StatementModuleAndName STMT_GROUPING = new StatementModuleAndName(YANG_CORE_MODULE_NAME, GROUPING);
+    public static final StatementModuleAndName STMT_IDENTITY = new StatementModuleAndName(YANG_CORE_MODULE_NAME, IDENTITY);
+    public static final StatementModuleAndName STMT_IF_FEATURE = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            IF_FEATURE);
+    public static final StatementModuleAndName STMT_IMPORT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, IMPORT);
+    public static final StatementModuleAndName STMT_INCLUDE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, INCLUDE);
+    public static final StatementModuleAndName STMT_INPUT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, INPUT);
+    public static final StatementModuleAndName STMT_KEY = new StatementModuleAndName(YANG_CORE_MODULE_NAME, KEY);
+    public static final StatementModuleAndName STMT_LEAF = new StatementModuleAndName(YANG_CORE_MODULE_NAME, LEAF);
+    public static final StatementModuleAndName STMT_LEAF_LIST = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            LEAF_LIST);
+    public static final StatementModuleAndName STMT_LENGTH = new StatementModuleAndName(YANG_CORE_MODULE_NAME, LENGTH);
+    public static final StatementModuleAndName STMT_LIST = new StatementModuleAndName(YANG_CORE_MODULE_NAME, LIST);
+    public static final StatementModuleAndName STMT_MANDATORY = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            MANDATORY);
+    public static final StatementModuleAndName STMT_MAX_ELEMENTS = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            MAX_ELEMENTS);
+    public static final StatementModuleAndName STMT_MIN_ELEMENTS = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            MIN_ELEMENTS);
+    public static final StatementModuleAndName STMT_MODIFIER = new StatementModuleAndName(YANG_CORE_MODULE_NAME, MODIFIER);
+    public static final StatementModuleAndName STMT_MODULE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, MODULE);
+    public static final StatementModuleAndName STMT_MUST = new StatementModuleAndName(YANG_CORE_MODULE_NAME, MUST);
+    public static final StatementModuleAndName STMT_NAMESPACE = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            NAMESPACE);
+    public static final StatementModuleAndName STMT_NOTIFICATION = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            NOTIFICATION);
+    public static final StatementModuleAndName STMT_ORDERED_BY = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            ORDERED_BY);
+    public static final StatementModuleAndName STMT_ORGANIZATION = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            ORGANIZATION);
+    public static final StatementModuleAndName STMT_OUTPUT = new StatementModuleAndName(YANG_CORE_MODULE_NAME, OUTPUT);
+    public static final StatementModuleAndName STMT_PATH = new StatementModuleAndName(YANG_CORE_MODULE_NAME, PATH);
+    public static final StatementModuleAndName STMT_PATTERN = new StatementModuleAndName(YANG_CORE_MODULE_NAME, PATTERN);
+    public static final StatementModuleAndName STMT_POSITION = new StatementModuleAndName(YANG_CORE_MODULE_NAME, POSITION);
+    public static final StatementModuleAndName STMT_PREFIX = new StatementModuleAndName(YANG_CORE_MODULE_NAME, PREFIX);
+    public static final StatementModuleAndName STMT_PRESENCE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, PRESENCE);
+    public static final StatementModuleAndName STMT_RANGE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, RANGE);
+    public static final StatementModuleAndName STMT_REFERENCE = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            REFERENCE);
+    public static final StatementModuleAndName STMT_REFINE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, REFINE);
+    public static final StatementModuleAndName STMT_REQUIRE_INSTANCE = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            REQUIRE_INSTANCE);
+    public static final StatementModuleAndName STMT_REVISION = new StatementModuleAndName(YANG_CORE_MODULE_NAME, REVISION);
+    public static final StatementModuleAndName STMT_REVISION_DATE = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            REVISION_DATE);
+    public static final StatementModuleAndName STMT_RPC = new StatementModuleAndName(YANG_CORE_MODULE_NAME, RPC);
+    public static final StatementModuleAndName STMT_STATUS = new StatementModuleAndName(YANG_CORE_MODULE_NAME, STATUS);
+    public static final StatementModuleAndName STMT_SUBMODULE = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            SUBMODULE);
+    public static final StatementModuleAndName STMT_TYPE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, TYPE);
+    public static final StatementModuleAndName STMT_TYPEDEF = new StatementModuleAndName(YANG_CORE_MODULE_NAME, TYPEDEF);
+    public static final StatementModuleAndName STMT_UNIQUE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, UNIQUE);
+    public static final StatementModuleAndName STMT_UNITS = new StatementModuleAndName(YANG_CORE_MODULE_NAME, UNITS);
+    public static final StatementModuleAndName STMT_USES = new StatementModuleAndName(YANG_CORE_MODULE_NAME, USES);
+    public static final StatementModuleAndName STMT_VALUE = new StatementModuleAndName(YANG_CORE_MODULE_NAME, VALUE);
+    public static final StatementModuleAndName STMT_WHEN = new StatementModuleAndName(YANG_CORE_MODULE_NAME, WHEN);
+    public static final StatementModuleAndName STMT_YANG_VERSION = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            YANG_VERSION);
+    public static final StatementModuleAndName STMT_YIN_ELEMENT = new StatementModuleAndName(YANG_CORE_MODULE_NAME,
+            YIN_ELEMENT);
+
+    public static final Set<StatementModuleAndName> ALL_YANG_CORE_STATEMENTS = new HashSet<>(Arrays.asList(STMT_ACTION,
+            STMT_ANYDATA, STMT_ANYXML, STMT_ARGUMENT, STMT_AUGMENT, STMT_BASE, STMT_BELONGS_TO, STMT_BIT, STMT_CASE,
+            STMT_CHOICE, STMT_CONFIG, STMT_CONTACT, STMT_CONTAINER, STMT_DEFAULT, STMT_DESCRIPTION, STMT_DEVIATE,
+            STMT_DEVIATION, STMT_ENUM, STMT_ERROR_APP_TAG, STMT_ERROR_MESSAGE, STMT_EXTENSION, STMT_FEATURE,
+            STMT_FRACTION_DIGITS, STMT_GROUPING, STMT_IDENTITY, STMT_IF_FEATURE, STMT_IMPORT, STMT_INCLUDE, STMT_INPUT,
+            STMT_KEY, STMT_LEAF, STMT_LEAF_LIST, STMT_LENGTH, STMT_LIST, STMT_MANDATORY, STMT_MAX_ELEMENTS,
+            STMT_MIN_ELEMENTS, STMT_MODIFIER, STMT_MODULE, STMT_MUST, STMT_NAMESPACE, STMT_NOTIFICATION, STMT_ORDERED_BY,
+            STMT_ORGANIZATION, STMT_OUTPUT, STMT_PATH, STMT_PATTERN, STMT_POSITION, STMT_PREFIX, STMT_PRESENCE, STMT_RANGE,
+            STMT_REFERENCE, STMT_REFINE, STMT_REQUIRE_INSTANCE, STMT_REVISION, STMT_REVISION_DATE, STMT_RPC, STMT_STATUS,
+            STMT_SUBMODULE, STMT_TYPE, STMT_TYPEDEF, STMT_UNIQUE, STMT_UNITS, STMT_USES, STMT_VALUE, STMT_WHEN,
+            STMT_YANG_VERSION, STMT_YIN_ELEMENT));
+
+    public static boolean isYangCoreStatement(final StatementModuleAndName statementModuleAndName) {
+        return ALL_YANG_CORE_STATEMENTS.contains(statementModuleAndName);
+    }
+
+    private static final Map<String, StatementModuleAndName> STATEMENT_NAME_TO_STATEMENT = new HashMap<>();
+
+    static {
+        ALL_YANG_CORE_STATEMENTS.forEach(sman -> STATEMENT_NAME_TO_STATEMENT.put(sman.getStatementName(), sman));
+    }
+
+    /**
+     * Given the statement name, will return the corresponding statement. Will return null if the statement
+     * is not one of the core YANG statements.
+     */
+    public static StatementModuleAndName getStatementForName(final String statementName) {
+        return STATEMENT_NAME_TO_STATEMENT.get(statementName);
+    }
+
+    /*
+     * -------- children handling, i.e. the statements that can occur under other statements --------
+     */
+
+    private static final List<String> NO_CHILDREN = Collections.<String> emptyList();
+    private static final List<String> DESCRIPTION_AND_REFERENCE_CHILDREN = Arrays.asList(DESCRIPTION, REFERENCE);
+
+    private static final Map<String, List<String>> optionalSingleChildren = new HashMap<>();
+    private static final Map<String, List<String>> optionalMultipleChildren = new HashMap<>();
+    private static final Map<String, List<String>> mandatorySingleChildren = new HashMap<>();
+    private static final Map<String, List<String>> mandatoryMultipleChildren = new HashMap<>();
+
+    /**
+     * Returns a list of statements that may occur 0..1 under the supplied statement.
+     */
+    public static final List<String> getOptionalSingleChildren(final String forYangCoreStatement) {
+
+        final List<String> result = optionalSingleChildren.get(forYangCoreStatement);
+        /*
+         * We are kind and explicitly allow both 'description' and 'reference' on any statement
+         * that does not have an explicit list of children. According to RFC this isn't really
+         * syntactically correct, but sometimes model designers will add descriptions and
+         * references although they don't have to (or where they shouldn't) and we are lenient
+         * towards that.
+         */
+        return result == null ? DESCRIPTION_AND_REFERENCE_CHILDREN : result;
+    }
+
+    /**
+     * Returns a list of statements that may occur 0..n under the supplied statement.
+     */
+    public static final List<String> getOptionalMultipleChildren(final String forYangCoreStatement) {
+        final List<String> result = optionalMultipleChildren.get(forYangCoreStatement);
+        return result == null ? NO_CHILDREN : result;
+    }
+
+    /**
+     * Returns a list of statements that must occur exactly once under the supplied statement.
+     */
+    public static final List<String> getMandatorySingleChildren(final String forYangCoreStatement) {
+        final List<String> result = mandatorySingleChildren.get(forYangCoreStatement);
+        return result == null ? NO_CHILDREN : result;
+    }
+
+    /**
+     * Returns a list of statements that must occur once or more under the supplied statement.
+     */
+    public static final List<String> getMandatoryMultipleChildren(final String forYangCoreStatement) {
+        final List<String> result = mandatoryMultipleChildren.get(forYangCoreStatement);
+        return result == null ? NO_CHILDREN : result;
+    }
+
+    static {
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| description  | 7.21.3  | 0..1 |
+        	| grouping     | 7.12    | 0..n |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| input        | 7.14.2  | 0..1 |
+        	| output       | 7.14.3  | 0..1 |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| typedef      | 7.3     | 0..n |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(ACTION, Arrays.asList(DESCRIPTION, INPUT, OUTPUT, REFERENCE, STATUS));
+        optionalMultipleChildren.put(ACTION, Arrays.asList(GROUPING, IF_FEATURE, TYPEDEF));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| config       | 7.21.1  | 0..1 |
+        	| description  | 7.21.3  | 0..1 |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| mandatory    | 7.6.5   | 0..1 |
+        	| must         | 7.5.3   | 0..n |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| when         | 7.21.5  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(ANYDATA, Arrays.asList(CONFIG, DESCRIPTION, MANDATORY, REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(ANYDATA, Arrays.asList(IF_FEATURE, MUST));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| config       | 7.21.1  | 0..1 |
+        	| description  | 7.21.3  | 0..1 |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| mandatory    | 7.6.5   | 0..1 |
+        	| must         | 7.5.3   | 0..n |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| when         | 7.21.5  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(ANYXML, Arrays.asList(CONFIG, DESCRIPTION, MANDATORY, REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(ANYXML, Arrays.asList(IF_FEATURE, MUST));
+
+        /*
+        	+--------------+----------+-------------+
+        	| substatement | section  | cardinality |
+        	+--------------+----------+-------------+
+        	| yin-element  | 7.19.2.2 | 0..1 |
+        	+--------------+----------+-------------+
+         */
+        optionalSingleChildren.put(ARGUMENT, Arrays.asList(DESCRIPTION, REFERENCE, YIN_ELEMENT));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| action       | 7.15    | 0..n |
+        	| anydata      | 7.10    | 0..n |
+        	| anyxml       | 7.11    | 0..n |
+        	| case         | 7.9.2   | 0..n |
+        	| choice       | 7.9     | 0..n |
+        	| container    | 7.5     | 0..n |
+        	| description  | 7.21.3  | 0..1 |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| leaf         | 7.6     | 0..n |
+        	| leaf-list    | 7.7     | 0..n |
+        	| list         | 7.8     | 0..n |
+        	| notification | 7.16    | 0..n |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| uses         | 7.13    | 0..n |
+        	| when         | 7.21.5  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(AUGMENT, Arrays.asList(DESCRIPTION, REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(AUGMENT, Arrays.asList(ACTION, ANYDATA, ANYXML, CASE, CHOICE, CONTAINER, IF_FEATURE,
+                LEAF, LEAF_LIST, LIST, NOTIFICATION, USES));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| prefix       | 7.1.4   |    1        |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(BELONGS_TO, DESCRIPTION_AND_REFERENCE_CHILDREN);
+        mandatorySingleChildren.put(BELONGS_TO, Arrays.asList(PREFIX));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| description  | 7.21.3  | 0..1 |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| position     | 9.7.4.2 | 0..1 |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(BIT, Arrays.asList(DESCRIPTION, POSITION, REFERENCE, STATUS));
+        optionalMultipleChildren.put(BIT, Arrays.asList(IF_FEATURE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| anydata      | 7.10    | 0..n |
+        	| anyxml       | 7.11    | 0..n |
+        	| choice       | 7.9     | 0..n |
+        	| container    | 7.5     | 0..n |
+        	| description  | 7.21.3  | 0..1 |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| leaf         | 7.6     | 0..n |
+        	| leaf-list    | 7.7     | 0..n |
+        	| list         | 7.8     | 0..n |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| uses         | 7.13    | 0..n |
+        	| when         | 7.21.5  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(CASE, Arrays.asList(DESCRIPTION, REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(CASE, Arrays.asList(ANYDATA, ANYXML, CHOICE, CONTAINER, IF_FEATURE, LEAF, LEAF_LIST,
+                LIST, USES));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| anydata      | 7.10    | 0..n |
+        	| anyxml       | 7.11    | 0..n |
+        	| case         | 7.9.2   | 0..n |
+        	| choice       | 7.9     | 0..n |
+        	| config       | 7.21.1  | 0..1 |
+        	| container    | 7.5     | 0..n |
+        	| default      | 7.9.3   | 0..1 |
+        	| description  | 7.21.3  | 0..1 |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| leaf         | 7.6     | 0..n |
+        	| leaf-list    | 7.7     | 0..n |
+        	| list         | 7.8     | 0..n |
+        	| mandatory    | 7.9.4   | 0..1 |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| when         | 7.21.5  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(CHOICE, Arrays.asList(CONFIG, DEFAULT, DESCRIPTION, MANDATORY, REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(CHOICE, Arrays.asList(ANYDATA, ANYXML, CASE, CHOICE, CONTAINER, IF_FEATURE, LEAF,
+                LEAF_LIST, LIST));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| action       | 7.15    | 0..n |
+        	| anydata      | 7.10    | 0..n |
+        	| anyxml       | 7.11    | 0..n |
+        	| choice       | 7.9     | 0..n |
+        	| config       | 7.21.1  | 0..1 |
+        	| container    | 7.5     | 0..n |
+        	| description  | 7.21.3  | 0..1 |
+        	| grouping     | 7.12    | 0..n |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| leaf         | 7.6     | 0..n |
+        	| leaf-list    | 7.7     | 0..n |
+        	| list         | 7.8     | 0..n |
+        	| must         | 7.5.3   | 0..n |
+        	| notification | 7.16    | 0..n |
+        	| presence     | 7.5.5   | 0..1 |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| typedef      | 7.3     | 0..n |
+        	| uses         | 7.13    | 0..n |
+        	| when         | 7.21.5  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(CONTAINER, Arrays.asList(CONFIG, DESCRIPTION, PRESENCE, REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(CONTAINER, Arrays.asList(ACTION, ANYDATA, ANYXML, CHOICE, CONTAINER, GROUPING,
+                IF_FEATURE, LEAF, LEAF_LIST, LIST, MUST, NOTIFICATION, TYPEDEF, USES));
+
+        /*
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(DESCRIPTION, NO_CHILDREN);
+
+        /*
+        	+--------------+--------------+-------------+
+        	| substatement | section      | cardinality |
+        	+--------------+--------------+-------------+
+        	| config       | 7.21.1       |  0..1  |
+        	| default      | 7.6.4, 7.7.4 |  0..n  |
+        	| mandatory    | 7.6.5        |  0..1  |
+        	| max-elements | 7.7.6        |  0..1  |
+        	| min-elements | 7.7.5        |  0..1  |
+        	| must         | 7.5.3        |  0..n  |
+        	| type         | 7.4          |  0..1  |
+        	| unique       | 7.8.3        |  0..n  |
+        	| units        | 7.3.3        |  0..1  |
+        	+--------------+--------------+-------------+
+         */
+        optionalSingleChildren.put(DEVIATE, Arrays.asList(CONFIG, DESCRIPTION, MANDATORY, MAX_ELEMENTS, MIN_ELEMENTS,
+                REFERENCE, TYPE, UNITS));
+        optionalMultipleChildren.put(DEVIATE, Arrays.asList(DEFAULT, MUST, UNIQUE));
+
+        /*
+        	+--------------+----------+-------------+
+        	| substatement | section  | cardinality |
+        	+--------------+----------+-------------+
+        	| description  | 7.21.3   |  0..1  |
+        	| deviate      | 7.20.3.2 |  1..n  |
+        	| reference    | 7.21.4   |  0..1  |
+        	+--------------+----------+-------------+
+         */
+        optionalSingleChildren.put(DEVIATION, Arrays.asList(DESCRIPTION, REFERENCE));
+        mandatoryMultipleChildren.put(DEVIATION, Arrays.asList(DEVIATE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| description  | 7.21.3  |  0..1  |
+        	| if-feature   | 7.20.2  |  0..n  |
+        	| reference    | 7.21.4  |  0..1  |
+        	| status       | 7.21.2  |  0..1  |
+        	| value        | 9.6.4.2 |  0..1  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(ENUM, Arrays.asList(DESCRIPTION, REFERENCE, STATUS, VALUE));
+        optionalMultipleChildren.put(ENUM, Arrays.asList(IF_FEATURE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| argument     | 7.19.2  |  0..1  |
+        	| description  | 7.21.3  |  0..1  |
+        	| reference    | 7.21.4  |  0..1  |
+        	| status       | 7.21.2  |  0..1  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(EXTENSION, Arrays.asList(ARGUMENT, DESCRIPTION, REFERENCE, STATUS));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| description  | 7.21.3  |  0..1  |
+        	| if-feature   | 7.20.2  |  0..n  |
+        	| reference    | 7.21.4  |  0..1  |
+        	| status       | 7.21.2  |  0..1  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(FEATURE, Arrays.asList(DESCRIPTION, REFERENCE, STATUS));
+        optionalMultipleChildren.put(FEATURE, Arrays.asList(IF_FEATURE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| action       | 7.15    |  0..n  |
+        	| anydata      | 7.10    |  0..n  |
+        	| anyxml       | 7.11    |  0..n  |
+        	| choice       | 7.9     |  0..n  |
+        	| container    | 7.5     |  0..n  |
+        	| description  | 7.21.3  |  0..1  |
+        	| grouping     | 7.12    |  0..n  |
+        	| leaf         | 7.6     |  0..n  |
+        	| leaf-list    | 7.7     |  0..n  |
+        	| list         | 7.8     |  0..n  |
+        	| notification | 7.16    |  0..n  |
+        	| reference    | 7.21.4  |  0..1  |
+        	| status       | 7.21.2  |  0..1  |
+        	| typedef      | 7.3     |  0..n  |
+        	| uses         | 7.13    |  0..n  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(GROUPING, Arrays.asList(DESCRIPTION, REFERENCE, STATUS));
+        optionalMultipleChildren.put(GROUPING, Arrays.asList(ACTION, ANYDATA, ANYXML, CHOICE, CONTAINER, GROUPING, LEAF,
+                LEAF_LIST, LIST, NOTIFICATION, TYPEDEF, USES));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| base         | 7.18.2  |  0..n  |
+        	| description  | 7.21.3  |  0..1  |
+        	| if-feature   | 7.20.2  |  0..n  |
+        	| reference    | 7.21.4  |  0..1  |
+        	| status       | 7.21.2  |  0..1  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(IDENTITY, Arrays.asList(DESCRIPTION, REFERENCE, STATUS));
+        optionalMultipleChildren.put(IDENTITY, Arrays.asList(BASE, IF_FEATURE));
+
+        /*
+        	+---------------+---------+-------------+
+        	| substatement  | section | cardinality |
+        	+---------------+---------+-------------+
+        	| description   | 7.21.3  |  0..1  |
+        	| prefix        | 7.1.4   |    1   |
+        	| reference     | 7.21.4  |  0..1  |
+        	| revision-date | 7.1.5.1 |  0..1  |
+        	+---------------+---------+-------------+
+         */
+        optionalSingleChildren.put(IMPORT, Arrays.asList(DESCRIPTION, REFERENCE, REVISION_DATE));
+        mandatorySingleChildren.put(IMPORT, Arrays.asList(PREFIX));
+
+        /*
+        	+---------------+---------+-------------+
+        	| substatement  | section | cardinality |
+        	+---------------+---------+-------------+
+        	| description   | 7.21.3  |  0..1  |
+        	| reference     | 7.21.4  |  0..1  |
+        	| revision-date | 7.1.5.1 |  0..1  |
+        	+---------------+---------+-------------+
+         */
+        optionalSingleChildren.put(INCLUDE, Arrays.asList(DESCRIPTION, REFERENCE, REVISION_DATE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| anydata      | 7.10    |  0..n  |
+        	| anyxml       | 7.11    |  0..n  |
+        	| choice       | 7.9     |  0..n  |
+        	| container    | 7.5     |  0..n  |
+        	| grouping     | 7.12    |  0..n  |
+        	| leaf         | 7.6     |  0..n  |
+        	| leaf-list    | 7.7     |  0..n  |
+        	| list         | 7.8     |  0..n  |
+        	| must         | 7.5.3   |  0..n  |
+        	| typedef      | 7.3     |  0..n  |
+        	| uses         | 7.13    |  0..n  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(INPUT, Arrays.asList(DESCRIPTION, REFERENCE));
+        optionalMultipleChildren.put(INPUT, Arrays.asList(ANYDATA, ANYXML, CHOICE, CONTAINER, GROUPING, LEAF, LEAF_LIST,
+                LIST, MUST, TYPEDEF, USES));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| config       | 7.21.1  |  0..1  |
+        	| default      | 7.6.4   |  0..1  |
+        	| description  | 7.21.3  |  0..1  |
+        	| if-feature   | 7.20.2  |  0..n  |
+        	| mandatory    | 7.6.5   |  0..1  |
+        	| must         | 7.5.3   |  0..n  |
+        	| reference    | 7.21.4  |  0..1  |
+        	| status       | 7.21.2  |  0..1  |
+        	| type         | 7.6.3   |    1   |
+        	| units        | 7.3.3   |  0..1  |
+        	| when         | 7.21.5  |  0..1  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(LEAF, Arrays.asList(CONFIG, DEFAULT, DESCRIPTION, MANDATORY, REFERENCE, STATUS, UNITS,
+                WHEN));
+        optionalMultipleChildren.put(LEAF, Arrays.asList(IF_FEATURE, MUST));
+        mandatorySingleChildren.put(LEAF, Arrays.asList(TYPE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| config       | 7.21.1  |  0..1  |
+        	| default      | 7.7.4   |  0..n  |
+        	| description  | 7.21.3  |  0..1  |
+        	| if-feature   | 7.20.2  |  0..n  |
+        	| max-elements | 7.7.6   |  0..1  |
+        	| min-elements | 7.7.5   |  0..1  |
+        	| must         | 7.5.3   |  0..n  |
+        	| ordered-by   | 7.7.7   |  0..1  |
+        	| reference    | 7.21.4  |  0..1  |
+        	| status       | 7.21.2  |  0..1  |
+        	| type         | 7.4     |    1   |
+        	| units        | 7.3.3   |  0..1  |
+        	| when         | 7.21.5  |  0..1  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(LEAF_LIST, Arrays.asList(CONFIG, DESCRIPTION, MAX_ELEMENTS, MIN_ELEMENTS, ORDERED_BY,
+                REFERENCE, STATUS, UNITS, WHEN));
+        optionalMultipleChildren.put(LEAF_LIST, Arrays.asList(DEFAULT, IF_FEATURE, MUST));
+        mandatorySingleChildren.put(LEAF_LIST, Arrays.asList(TYPE));
+
+        /*
+        	+---------------+---------+-------------+
+        	| substatement  | section | cardinality |
+        	+---------------+---------+-------------+
+        	| description   | 7.19.3  | 0..1 |
+        	| error-app-tag | 7.5.4.2 | 0..1 |
+        	| error-message | 7.5.4.1 | 0..1 |
+        	| reference     | 7.19.4  | 0..1 |
+        	+---------------+---------+-------------+
+         */
+        optionalSingleChildren.put(LENGTH, Arrays.asList(DESCRIPTION, ERROR_APP_TAG, ERROR_MESSAGE, REFERENCE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| action       | 7.15    |  0..n  |
+        	| anydata      | 7.10    |  0..n  |
+        	| anyxml       | 7.11    |  0..n  |
+        	| choice       | 7.9     |  0..n  |
+        	| config       | 7.19.1  |  0..1  |
+        	| container    | 7.5     |  0..n  |
+        	| description  | 7.19.3  |  0..1  |
+        	| grouping     | 7.11    |  0..n  |
+        	| if-feature   | 7.18.2  |  0..n  |
+        	| key          | 7.8.2   |  0..1  |
+        	| leaf         | 7.6     |  0..n  |
+        	| leaf-list    | 7.7     |  0..n  |
+        	| list         | 7.8     |  0..n  |
+        	| max-elements | 7.7.4   |  0..1  |
+        	| min-elements | 7.7.3   |  0..1  |
+        	| must         | 7.5.3   |  0..n  |
+        	| notification | 7.5.3   |  0..n  |
+        	| ordered-by   | 7.7.5   |  0..1  |
+        	| reference    | 7.19.4  |  0..1  |
+        	| status       | 7.19.2  |  0..1  |
+        	| typedef      | 7.3     |  0..n  |
+        	| unique       | 7.8.3   |  0..n  |
+        	| uses         | 7.12    |  0..n  |
+        	| when         | 7.19.5  |  0..1  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(LIST, Arrays.asList(CONFIG, DESCRIPTION, KEY, MAX_ELEMENTS, MIN_ELEMENTS, ORDERED_BY,
+                REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(LIST, Arrays.asList(ACTION, ANYDATA, ANYXML, CHOICE, CONTAINER, GROUPING, IF_FEATURE,
+                LEAF, LEAF_LIST, LIST, MUST, NOTIFICATION, TYPEDEF, UNIQUE, USES));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| anydata      | 7.10    |  0..n  |
+        	| anyxml       | 7.11    |  0..n  |
+        	| augment      | 7.17    |  0..n  |
+        	| choice       | 7.9     |  0..n  |
+        	| contact      | 7.1.8   |  0..1  |
+        	| container    | 7.5     |  0..n  |
+        	| description  | 7.21.3  |  0..1  |
+        	| deviation    | 7.20.3  |  0..n  |
+        	| extension    | 7.19    |  0..n  |
+        	| feature      | 7.20.1  |  0..n  |
+        	| grouping     | 7.12    |  0..n  |
+        	| identity     | 7.18    |  0..n  |
+        	| import       | 7.1.5   |  0..n  |
+        	| include      | 7.1.6   |  0..n  |
+        	| leaf         | 7.6     |  0..n  |
+        	| leaf-list    | 7.7     |  0..n  |
+        	| list         | 7.8     |  0..n  |
+        	| namespace    | 7.1.3   |    1   |
+        	| notification | 7.16    |  0..n  |
+        	| organization | 7.1.7   |  0..1  |
+        	| prefix       | 7.1.4   |    1   |
+        	| reference    | 7.21.4  |  0..1  |
+        	| revision     | 7.1.9   |  0..n  |
+        	| rpc          | 7.14    |  0..n  |
+        	| typedef      | 7.3     |  0..n  |
+        	| uses         | 7.13    |  0..n  |
+        	| yang-version | 7.1.2   |    1   |
+        	+--------------+---------+-------------+
+
+        	Note that in YANG 1.0 the cardinality for the 'yang-version' statement is '0..1'. To remain
+        	backwards-compatible, this statement remains optional during parsing.
+         */
+        optionalSingleChildren.put(MODULE, Arrays.asList(CONTACT, DESCRIPTION, ORGANIZATION, REFERENCE, YANG_VERSION));
+        optionalMultipleChildren.put(MODULE, Arrays.asList(ANYDATA, ANYXML, AUGMENT, CHOICE, CONTAINER, DEVIATION,
+                EXTENSION, FEATURE, GROUPING, IDENTITY, IMPORT, INCLUDE, LEAF, LEAF_LIST, LIST, NOTIFICATION, REVISION, RPC,
+                TYPEDEF, USES));
+        mandatorySingleChildren.put(MODULE, Arrays.asList(NAMESPACE, PREFIX));
+
+        /*
+        	+---------------+---------+-------------+
+        	| substatement  | section | cardinality |
+        	+---------------+---------+-------------+
+        	| description   | 7.21.3  | 0..1 |
+        	| error-app-tag | 7.5.4.2 | 0..1 |
+        	| error-message | 7.5.4.1 | 0..1 |
+        	| reference     | 7.21.4  | 0..1 |
+        	+---------------+---------+-------------+
+         */
+        optionalSingleChildren.put(MUST, Arrays.asList(DESCRIPTION, ERROR_APP_TAG, ERROR_MESSAGE, REFERENCE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| anydata      | 7.10    | 0..n |
+        	| anyxml       | 7.11    | 0..n |
+        	| choice       | 7.9     | 0..n |
+        	| container    | 7.5     | 0..n |
+        	| description  | 7.21.3  | 0..1 |
+        	| grouping     | 7.12    | 0..n |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| leaf         | 7.6     | 0..n |
+        	| leaf-list    | 7.7     | 0..n |
+        	| list         | 7.8     | 0..n |
+        	| must         | 7.5.3   | 0..n |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| typedef      | 7.3     | 0..n |
+        	| uses         | 7.13    | 0..n |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(NOTIFICATION, Arrays.asList(DESCRIPTION, REFERENCE, STATUS));
+        optionalMultipleChildren.put(NOTIFICATION, Arrays.asList(ANYDATA, ANYXML, CHOICE, CONTAINER, GROUPING, IF_FEATURE,
+                LEAF, LEAF_LIST, LIST, MUST, TYPEDEF, USES));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| anydata      | 7.10    |  0..n  |
+        	| anyxml       | 7.11    |  0..n  |
+        	| choice       | 7.9     |  0..n  |
+        	| container    | 7.5     |  0..n  |
+        	| grouping     | 7.12    |  0..n  |
+        	| leaf         | 7.6     |  0..n  |
+        	| leaf-list    | 7.7     |  0..n  |
+        	| list         | 7.8     |  0..n  |
+        	| must         | 7.5.3   |  0..n  |
+        	| typedef      | 7.3     |  0..n  |
+        	| uses         | 7.13    |  0..n  |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(OUTPUT, Arrays.asList(DESCRIPTION, REFERENCE));
+        optionalMultipleChildren.put(OUTPUT, Arrays.asList(ANYDATA, ANYXML, CHOICE, CONTAINER, GROUPING, LEAF, LEAF_LIST,
+                LIST, MUST, TYPEDEF, USES));
+
+        /*
+        	+---------------+---------+-------------+
+        	| substatement  | section | cardinality |
+        	+---------------+---------+-------------+
+        	| description   | 7.21.3  |  0..1  |
+        	| error-app-tag | 7.5.4.2 |  0..1  |
+        	| error-message | 7.5.4.1 |  0..1  |
+        	| modifier      | 9.4.6   |  0..1  |
+        	| reference     | 7.21.4  |  0..1  |
+        	+---------------+---------+-------------+
+         */
+        optionalSingleChildren.put(PATTERN, Arrays.asList(DESCRIPTION, ERROR_APP_TAG, ERROR_MESSAGE, MODIFIER, REFERENCE));
+
+        /*
+        	+---------------+---------+-------------+
+        	| substatement  | section | cardinality |
+        	+---------------+---------+-------------+
+        	| description   | 7.21.3  |  0..1  |
+        	| error-app-tag | 7.5.4.2 |  0..1  |
+        	| error-message | 7.5.4.1 |  0..1  |
+        	| reference     | 7.21.4  |  0..1  |
+        	+---------------+---------+-------------+
+         */
+        optionalSingleChildren.put(RANGE, Arrays.asList(DESCRIPTION, ERROR_APP_TAG, ERROR_MESSAGE, REFERENCE));
+
+        /*
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(REFERENCE, NO_CHILDREN);
+
+        /*
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(REFINE, Arrays.asList(CONFIG, DESCRIPTION, MANDATORY, MAX_ELEMENTS, MIN_ELEMENTS,
+                PRESENCE, REFERENCE));
+        optionalMultipleChildren.put(REFINE, Arrays.asList(DEFAULT, IF_FEATURE, MUST));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| description  | 7.21.3  | 0..1 |
+        	| grouping     | 7.12    | 0..n |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| input        | 7.14.2  | 0..1 |
+        	| output       | 7.14.3  | 0..1 |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| typedef      | 7.3     | 0..n |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(RPC, Arrays.asList(DESCRIPTION, INPUT, OUTPUT, REFERENCE, STATUS));
+        optionalMultipleChildren.put(RPC, Arrays.asList(GROUPING, IF_FEATURE, TYPEDEF));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| anydata      | 7.10    | 0..n |
+        	| anyxml       | 7.11    | 0..n |
+        	| augment      | 7.17    | 0..n |
+        	| belongs-to   | 7.2.2   |   1  |
+        	| choice       | 7.9     | 0..n |
+        	| contact      | 7.1.8   | 0..1 |
+        	| container    | 7.5     | 0..n |
+        	| description  | 7.21.3  | 0..1 |
+        	| deviation    | 7.20.3  | 0..n |
+        	| extension    | 7.19    | 0..n |
+        	| feature      | 7.20.1  | 0..n |
+        	| grouping     | 7.12    | 0..n |
+        	| identity     | 7.18    | 0..n |
+        	| import       | 7.1.5   | 0..n |
+        	| include      | 7.1.6   | 0..n |
+        	| leaf         | 7.6     | 0..n |
+        	| leaf-list    | 7.7     | 0..n |
+        	| list         | 7.8     | 0..n |
+        	| notification | 7.16    | 0..n |
+        	| organization | 7.1.7   | 0..1 |
+        	| reference    | 7.21.4  | 0..1 |
+        	| revision     | 7.1.9   | 0..n |
+        	| rpc          | 7.14    | 0..n |
+        	| typedef      | 7.3     | 0..n |
+        	| uses         | 7.13    | 0..n |
+        	| yang-version | 7.1.2   |  1   |
+        	+--------------+---------+-------------+
+
+        	Note that in YANG 1.0 the cardinality for the 'yang-version' statement is '0..1'. To remain
+        	backwards-compatible, this statement remains optional during parsing.
+         */
+        optionalSingleChildren.put(SUBMODULE, Arrays.asList(CONTACT, DESCRIPTION, ORGANIZATION, REFERENCE, YANG_VERSION));
+        optionalMultipleChildren.put(SUBMODULE, Arrays.asList(ANYDATA, ANYXML, AUGMENT, CHOICE, CONTAINER, DEVIATION,
+                EXTENSION, FEATURE, GROUPING, IDENTITY, IMPORT, INCLUDE, LEAF, LEAF_LIST, LIST, NOTIFICATION, REVISION, RPC,
+                TYPEDEF, USES));
+        mandatorySingleChildren.put(SUBMODULE, Arrays.asList(BELONGS_TO));
+
+        /*
+        	+------------------+---------+-------------+
+        	| substatement     | section | cardinality |
+        	+------------------+---------+-------------+
+        	| base             | 7.18.2  | 0..n |
+        	| bit              | 9.7.4   | 0..n |
+        	| enum             | 9.6.4   | 0..n |
+        	| fraction-digits  | 9.3.4   | 0..1 |
+        	| length           | 9.4.4   | 0..1 |
+        	| path             | 9.9.2   | 0..1 |
+        	| pattern          | 9.4.5   | 0..n |
+        	| range            | 9.2.4   | 0..1 |
+        	| require-instance | 9.9.3   | 0..1 |
+        	| type             | 7.4     | 0..n |
+        	+------------------+---------+-------------+
+         */
+        optionalSingleChildren.put(TYPE, Arrays.asList(DESCRIPTION, FRACTION_DIGITS, LENGTH, PATH, RANGE,
+                REQUIRE_INSTANCE));
+        optionalMultipleChildren.put(TYPE, Arrays.asList(BASE, BIT, ENUM, PATTERN, TYPE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| default      | 7.3.4   | 0..1 |
+        	| description  | 7.21.3  | 0..1 |
+        	| reference    | 7.21.4  | 0..1 |
+        	| status       | 7.21.2  | 0..1 |
+        	| type         | 7.3.2   |   1  |
+        	| units        | 7.3.3   | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(TYPEDEF, Arrays.asList(DEFAULT, DESCRIPTION, REFERENCE, STATUS, UNITS));
+        mandatorySingleChildren.put(TYPEDEF, Arrays.asList(TYPE));
+
+        /*
+        	+--------------+---------+-------------+
+        	| substatement | section | cardinality |
+        	+--------------+---------+-------------+
+        	| augment      | 7.17    | 0..n |
+        	| description  | 7.21.3  | 0..1 |
+        	| if-feature   | 7.20.2  | 0..n |
+        	| reference    | 7.21.4  | 0..1 |
+        	| refine       | 7.13.2  | 0..n |
+        	| status       | 7.21.2  | 0..1 |
+        	| when         | 7.21.5  | 0..1 |
+        	+--------------+---------+-------------+
+         */
+        optionalSingleChildren.put(USES, Arrays.asList(DESCRIPTION, REFERENCE, STATUS, WHEN));
+        optionalMultipleChildren.put(USES, Arrays.asList(AUGMENT, IF_FEATURE, REFINE));
+    }
+
+    public static final Map<String, List<String>> HANDLED_STATEMENTS = new HashMap<>();
+
+    static {
+        HANDLED_STATEMENTS.put(YANG_CORE_MODULE_NAME, new ArrayList<>(ALL_YANG_CORE_STATEMENT_NAMES));
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAction.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAction.java
new file mode 100644
index 0000000..4947564
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAction.java
@@ -0,0 +1,93 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YAction extends AbstractStatement {
+
+    public YAction(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getActionName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ACTION;
+    }
+
+    public String getActionName() {
+        return domElement.getValue();
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YInput getInput() {
+        return getChild(CY.STMT_INPUT);
+    }
+
+    public YOutput getOutput() {
+        return getChild(CY.STMT_OUTPUT);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getActionName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAnydata.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAnydata.java
new file mode 100644
index 0000000..d84ec07
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAnydata.java
@@ -0,0 +1,98 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YAnydata extends AbstractStatement {
+
+    public YAnydata(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public boolean definesDataNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ANYDATA;
+    }
+
+    public String getName() {
+        return domElement.getValue();
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YMandatory getMandatory() {
+        return getChild(CY.STMT_MANDATORY);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAnyxml.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAnyxml.java
new file mode 100644
index 0000000..c78ab2b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAnyxml.java
@@ -0,0 +1,98 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YAnyxml extends AbstractStatement {
+
+    public YAnyxml(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public boolean definesDataNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ANYXML;
+    }
+
+    public String getName() {
+        return domElement.getValue();
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YMandatory getMandatory() {
+        return getChild(CY.STMT_MANDATORY);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YArgument.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YArgument.java
new file mode 100644
index 0000000..818f86c
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YArgument.java
@@ -0,0 +1,61 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YArgument extends AbstractStatement {
+
+    public YArgument(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    public String getArgumentName() {
+        return domElement.getValue();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ARGUMENT;
+    }
+
+    public YYinElement getYinElement() {
+        return getChild(CY.STMT_YIN_ELEMENT);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getArgumentName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAugment.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAugment.java
new file mode 100644
index 0000000..e8acd59
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YAugment.java
@@ -0,0 +1,131 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YAugment extends AbstractStatement {
+
+    public YAugment(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    public String getAugmentTargetNode() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TARGET_NODE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_AUGMENT;
+    }
+
+    public List<YAction> getActions() {
+        return getChildren(CY.STMT_ACTION);
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YCase> getCases() {
+        return getChildren(CY.STMT_CASE);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public List<YNotification> getNotifications() {
+        return getChildren(CY.STMT_NOTIFICATION);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    public YWhen getWhen() {
+        return getChild(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        /*
+         * Depending on where the 'augment' sits, the path has to be either absolute or relative.
+         */
+        if ((getParentStatement().is(CY.STMT_MODULE) || getParentStatement().is(
+                CY.STMT_SUBMODULE)) && !getAugmentTargetNode().startsWith("/")) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "The augment's schema node identifier '" + getAugmentTargetNode() + "' is relative (it must be absolute, i.e. start with '/')"));
+        } else if (getParentStatement().is(CY.STMT_USES) && getAugmentTargetNode().startsWith("/")) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "The augment's schema node identifier '" + getAugmentTargetNode() + "' is absolute (it must be relative, i.e. not start with '/')"));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBase.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBase.java
new file mode 100644
index 0000000..cf102ff
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBase.java
@@ -0,0 +1,54 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YBase extends SimpleStatement {
+
+    public YBase(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_BASE;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifierReference(context, getValue());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBelongsTo.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBelongsTo.java
new file mode 100644
index 0000000..1b9c6ea
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBelongsTo.java
@@ -0,0 +1,73 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YBelongsTo extends AbstractStatement {
+
+    public YBelongsTo(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    public String getBelongsToModuleName() {
+        return domElement.getValue();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.MODULE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_BELONGS_TO;
+    }
+
+    /**
+     * Returns the 'prefix' statement, if any, under the 'belongs-to'. To get the actual value of the belong-to's
+     * prefix, invoke myBelongsTo.getPrefixValue();
+     */
+    public YPrefix getPrefix() {
+        return getChild(CY.STMT_PREFIX);
+    }
+
+    /**
+     * Returns the value, if any, of the 'prefix' statement under the 'belong-to'.
+     */
+    public String getPrefixValue() {
+        final YPrefix yPrefix = getPrefix();
+        return yPrefix == null ? null : yPrefix.getPrefix();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getBelongsToModuleName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBit.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBit.java
new file mode 100644
index 0000000..d684a33
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YBit.java
@@ -0,0 +1,87 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YBit extends AbstractStatement {
+
+    public YBit(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getBitName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_BIT;
+    }
+
+    public String getBitName() {
+        return domElement.getValue();
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YPosition getPosition() {
+        return getChild(CY.STMT_POSITION);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getBitName());
+    }
+
+    @Override
+    protected void subtreeProcessed(final ParserExecutionContext context) {
+        if (getPosition() == null) {
+            context.addFinding(new Finding(this, ParserFindingType.P144_BIT_WITHOUT_POSITION,
+                    "bit '" + getBitName() + "' does not have a position (bad practice)."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YCase.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YCase.java
new file mode 100644
index 0000000..ee1b459
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YCase.java
@@ -0,0 +1,113 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YCase extends AbstractStatement {
+
+    public YCase(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getCaseName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_CASE;
+    }
+
+    public String getCaseName() {
+        return domElement.getValue();
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getCaseName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YChoice.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YChoice.java
new file mode 100644
index 0000000..442253b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YChoice.java
@@ -0,0 +1,155 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YChoice extends AbstractStatement {
+
+    public YChoice(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getChoiceName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_CHOICE;
+    }
+
+    public String getChoiceName() {
+        return domElement.getValue();
+    }
+
+    /**
+     * This method will always return an empty list after parsing has completed, as any
+     * shorthand case-notation will cause a case statement to be injected between the
+     * choice and the shorthand statement.
+     */
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    /**
+     * This method will always return an empty list after parsing has completed, as any
+     * shorthand case-notation will cause a case statement to be injected between the
+     * choice and the shorthand statement.
+     */
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YCase> getCases() {
+        return getChildren(CY.STMT_CASE);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    /**
+     * This method will always return an empty list after parsing has completed, as any
+     * shorthand case-notation will cause a case statement to be injected between the
+     * choice and the shorthand statement.
+     */
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public YDefault getDefault() {
+        return getChild(CY.STMT_DEFAULT);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    /**
+     * This method will always return an empty list after parsing has completed, as any
+     * shorthand case-notation will cause a case statement to be injected between the
+     * choice and the shorthand statement.
+     */
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    /**
+     * This method will always return an empty list after parsing has completed, as any
+     * shorthand case-notation will cause a case statement to be injected between the
+     * choice and the shorthand statement.
+     */
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    /**
+     * This method will always return an empty list after parsing has completed, as any
+     * shorthand case-notation will cause a case statement to be injected between the
+     * choice and the shorthand statement.
+     */
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public YMandatory getMandatory() {
+        return getChild(CY.STMT_MANDATORY);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getChoiceName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YConfig.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YConfig.java
new file mode 100644
index 0000000..d4791e9
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YConfig.java
@@ -0,0 +1,61 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YConfig extends SimpleStatement {
+
+    public YConfig(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_CONFIG;
+    }
+
+    public boolean isConfigTrue() {
+        return "true".equals(getValue());
+    }
+
+    public boolean isConfigFalse() {
+        return "false".equals(getValue());
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentIsTrueOrFalse(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YContact.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YContact.java
new file mode 100644
index 0000000..930000d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YContact.java
@@ -0,0 +1,54 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YContact extends SimpleStatement {
+
+    public YContact(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TEXT;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_CONTACT;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNull(context);
+        validateDocumentationArgumentNotEmpty(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YContainer.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YContainer.java
new file mode 100644
index 0000000..c39d973
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YContainer.java
@@ -0,0 +1,150 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YContainer extends AbstractStatement {
+
+    public YContainer(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getContainerName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public boolean definesDataNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_CONTAINER;
+    }
+
+    public String getContainerName() {
+        return domElement.getValue();
+    }
+
+    public List<YAction> getActions() {
+        return getChildren(CY.STMT_ACTION);
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public List<YNotification> getNotifications() {
+        return getChildren(CY.STMT_NOTIFICATION);
+    }
+
+    public YPresence getPresence() {
+        return getChild(CY.STMT_PRESENCE);
+    }
+
+    public boolean isPresenceContainer() {
+        return getPresence() != null;
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getContainerName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDefault.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDefault.java
new file mode 100644
index 0000000..bac05d6
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDefault.java
@@ -0,0 +1,79 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.util.NumberHelper;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YDefault extends SimpleStatement {
+
+    public YDefault(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_DEFAULT;
+    }
+
+    @Override
+    public boolean orderUnderParentMatters() {
+        return true;
+    }
+
+    public BigInteger getIntegerDefaultValue() {
+        return NumberHelper.getIntegerDefaultValue(getValue());
+    }
+
+    public BigDecimal getDecimalDefaultValue() {
+        return NumberHelper.getDecimalValue(getValue());
+    }
+
+    public boolean canTranslateToIntegerValue() {
+        return NumberHelper.getIntegerDefaultValue(getValue()) != null;
+    }
+
+    public boolean canTranslateToDecimalValue() {
+        return NumberHelper.getDecimalValue(getValue()) != null;
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNull(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDescription.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDescription.java
new file mode 100644
index 0000000..7ab3fb2
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDescription.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YDescription extends SimpleStatement {
+
+    public YDescription(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TEXT;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_DESCRIPTION;
+    }
+
+    public YDescription getDescription() {
+        throw new RuntimeException(
+                "Wrong invocation. Invoke getValue() or getDescriptionValue() to get the value of a description statement.");
+    }
+
+    public String getDescriptionValue() {
+        return getValue();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNull(context);
+        validateDocumentationArgumentNotEmpty(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDeviate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDeviate.java
new file mode 100644
index 0000000..152118e
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDeviate.java
@@ -0,0 +1,189 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YDeviate extends AbstractStatement {
+
+    public YDeviate(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    public String getDeviateOperation() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_DEVIATE;
+    }
+
+    /**
+     * Returns the deviate type or null if the deviate type is unknown / wrong.
+     */
+    public DeviateType getDeviateType() {
+
+        switch (getDeviateOperation()) {
+            case "not-supported":
+                return DeviateType.NOT_SUPPORTED;
+            case "add":
+                return DeviateType.ADD;
+            case "replace":
+                return DeviateType.REPLACE;
+            case "delete":
+                return DeviateType.DELETE;
+            default:
+        }
+
+        return null;
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public List<YDefault> getDefaults() {
+        return getChildren(CY.STMT_DEFAULT);
+    }
+
+    public YMandatory getMandatory() {
+        return getChild(CY.STMT_MANDATORY);
+    }
+
+    public YMaxElements getMaxElements() {
+        return getChild(CY.STMT_MAX_ELEMENTS);
+    }
+
+    public YMinElements getMinElements() {
+        return getChild(CY.STMT_MIN_ELEMENTS);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public YType getType() {
+        return getChild(CY.STMT_TYPE);
+    }
+
+    public List<YUnique> getUniques() {
+        return getChildren(CY.STMT_UNIQUE);
+    }
+
+    public YUnits getUnits() {
+        return getChild(CY.STMT_UNITS);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        final DeviateType deviateType = getDeviateType();
+        if (deviateType == null) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT, "'" + domElement
+                    .getValue() + "' is not valid as argument for deviate. Use one of: not-supported, add, replace, delete."));
+        }
+    }
+
+    private static final Set<String> NOT_ALLOWED_FOR_ADD_OR_DELETE = new HashSet<>(Arrays.asList(CY.CONFIG, CY.MANDATORY,
+            CY.TYPE, CY.MAX_ELEMENTS, CY.MIN_ELEMENTS));
+
+    @Override
+    protected void subtreeProcessed(final ParserExecutionContext context) {
+
+        final DeviateType deviateType = getDeviateType();
+        if (deviateType == null) {
+            return;
+        }
+
+        final List<AbstractStatement> nonExtensionChildStatements = getNonExtensionChildStatements();
+
+        switch (deviateType) {
+            case NOT_SUPPORTED:
+                if (!nonExtensionChildStatements.isEmpty()) {
+                    for (final AbstractStatement child : nonExtensionChildStatements) {
+                        context.addFinding(new Finding(child, ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT,
+                                "Statement '" + child
+                                        .getStatementName() + "' cannot occur under 'deviate not-supported'."));
+                    }
+                }
+                break;
+            case ADD:
+            case REPLACE:
+            case DELETE:
+                if (getChildStatements().isEmpty()) {
+                    context.addFinding(new Finding(this, ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT,
+                            "Statements are required under " + this.getDomElement().getNameValue() + "."));
+                }
+                break;
+        }
+
+        /*
+         * After some discussion on the IETF netmod mailing list, a decision was made that some
+         * properties always exist and hence can never be ADDed or DELETEd:
+         *
+         * "I think that config, mandatory, type, max-elements, min-elements cannot be added or
+         *  deleted, only replaced, because they always exist."
+         *
+         * "default, must, unique, units are all optional, and hence may be added, replaced,
+         *  or deleted"
+         */
+        if (deviateType == DeviateType.ADD || deviateType == DeviateType.DELETE) {
+            for (final AbstractStatement nonExtensionChild : nonExtensionChildStatements) {
+                if (NOT_ALLOWED_FOR_ADD_OR_DELETE.contains(nonExtensionChild.getStatementName())) {
+                    context.addFinding(new Finding(nonExtensionChild,
+                            ParserFindingType.P167_CANNOT_USE_UNDER_DEVIATE_ADD_OR_DELETE,
+                            "This statement cannot be used under 'deviate add/delete' as it refers to a property that always exists. Use a 'deviate replace' instead."));
+                }
+            }
+        }
+    }
+
+    public enum DeviateType {
+        NOT_SUPPORTED,
+        ADD,
+        REPLACE,
+        DELETE
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDeviation.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDeviation.java
new file mode 100644
index 0000000..b7e3b28
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YDeviation.java
@@ -0,0 +1,72 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YDeviation extends AbstractStatement {
+
+    public YDeviation(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    public String getDeviationTargetNode() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TARGET_NODE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_DEVIATION;
+    }
+
+    public List<YDeviate> getDeviates() {
+        return getChildren(CY.STMT_DEVIATE);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        if (!getDeviationTargetNode().startsWith("/")) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "The deviation's schema node identifier is not absolute (it must start with '/')."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YEnum.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YEnum.java
new file mode 100644
index 0000000..f253938
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YEnum.java
@@ -0,0 +1,119 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.util.GrammarHelper;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YEnum extends AbstractStatement {
+
+    public YEnum(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getEnumName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ENUM;
+    }
+
+    public String getEnumName() {
+        return domElement.getValue();
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public YValue getValue() {
+        return getChild(CY.STMT_VALUE);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        /*
+         * Note that the RFC states that an enum can be "any string". Not sure how much this makes
+         * sense, as this would allow spaces...we check for that as this would cause problems
+         * somewhere, no doubt.
+         */
+        if (GrammarHelper.containsYangWhitespace(getEnumName())) {
+            context.addFinding(new Finding(this, ParserFindingType.P141_WHITESPACE_IN_ENUM,
+                    "Usage of whitespace character(s) in enum '" + getEnumName() + "'."));
+        } else if (containsWeirdCharacters(getEnumName())) {
+            context.addFinding(new Finding(this, ParserFindingType.P142_UNUSUAL_CHARACTERS_IN_ENUM,
+                    "enum '" + getEnumName() + "' contains unusual characters."));
+        }
+    }
+
+    private static boolean containsWeirdCharacters(final String enumName) {
+
+        if (enumName == null) {
+            return false;
+        }
+
+        for (final char c : enumName.toCharArray()) {
+            if (c == '_' || c == '.' || c == '-' || (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122)) {
+                // all ok
+            } else {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    protected void subtreeProcessed(final ParserExecutionContext context) {
+        if (getValue() == null) {
+            context.addFinding(new Finding(this, ParserFindingType.P143_ENUM_WITHOUT_VALUE,
+                    "enum '" + getEnumName() + "' does not have a value (bad practice)."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YErrorAppTag.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YErrorAppTag.java
new file mode 100644
index 0000000..60e8a27
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YErrorAppTag.java
@@ -0,0 +1,54 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YErrorAppTag extends SimpleStatement {
+
+    public YErrorAppTag(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TEXT;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ERROR_APP_TAG;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNull(context);
+        validateDocumentationArgumentNotEmpty(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YErrorMessage.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YErrorMessage.java
new file mode 100644
index 0000000..d42ddc8
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YErrorMessage.java
@@ -0,0 +1,54 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YErrorMessage extends SimpleStatement {
+
+    public YErrorMessage(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TEXT;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ERROR_MESSAGE;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNull(context);
+        validateDocumentationArgumentNotEmpty(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YExtension.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YExtension.java
new file mode 100644
index 0000000..632389d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YExtension.java
@@ -0,0 +1,70 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YExtension extends AbstractStatement {
+
+    public YExtension(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getExtensionName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_EXTENSION;
+    }
+
+    public String getExtensionName() {
+        return domElement.getValue();
+    }
+
+    public YArgument getArgument() {
+        return getChild(CY.STMT_ARGUMENT);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getExtensionName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YFeature.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YFeature.java
new file mode 100644
index 0000000..11c6d17
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YFeature.java
@@ -0,0 +1,73 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YFeature extends SimpleStatement {
+
+    public YFeature(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getFeatureName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_FEATURE;
+    }
+
+    public String getFeatureName() {
+        return getValue();
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getFeatureName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YFractionDigits.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YFractionDigits.java
new file mode 100644
index 0000000..3e55c67
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YFractionDigits.java
@@ -0,0 +1,79 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YFractionDigits extends SimpleStatement {
+
+    public YFractionDigits(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_FRACTION_DIGITS;
+    }
+
+    public int getFractionDigits() {
+
+        int fractionDigits = 0;
+
+        try {
+            fractionDigits = Integer.parseInt(getValue());
+            if (fractionDigits < 1 || fractionDigits > 18) {
+                fractionDigits = 0;
+            }
+        } catch (final Exception ex) {
+            /* no-op */ }
+
+        return fractionDigits;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        final int fractionDigits = getFractionDigits();
+        if (fractionDigits == 0) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + getValue() + "' not valid for fraction-digits."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YGrouping.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YGrouping.java
new file mode 100644
index 0000000..82faf6e
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YGrouping.java
@@ -0,0 +1,116 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YGrouping extends AbstractStatement {
+
+    public YGrouping(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getGroupingName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_GROUPING;
+    }
+
+    public String getGroupingName() {
+        return domElement.getValue();
+    }
+
+    public List<YAction> getActions() {
+        return getChildren(CY.STMT_ACTION);
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public List<YNotification> getNotifications() {
+        return getChildren(CY.STMT_NOTIFICATION);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getGroupingName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YIdentity.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YIdentity.java
new file mode 100644
index 0000000..d7afaee
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YIdentity.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YIdentity extends AbstractStatement {
+
+    public YIdentity(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getIdentityName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_IDENTITY;
+    }
+
+    public String getIdentityName() {
+        return domElement.getValue();
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public List<YBase> getBases() {
+        return getChildren(CY.STMT_BASE);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getIdentityName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YIfFeature.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YIfFeature.java
new file mode 100644
index 0000000..df93439
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YIfFeature.java
@@ -0,0 +1,282 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YIfFeature extends SimpleStatement {
+
+    public YIfFeature(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_IF_FEATURE;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        /*
+         * The 'if-feature' is either simply the (possibly prefixed) name of a feature, or it has special syntax, which the RFC defines as:
+         *
+         * if-feature-expr = if-feature-term [sep or-keyword sep if-feature-expr]
+         * if-feature-term = if-feature-factor [sep and-keyword sep if-feature-term]
+         * if-feature-factor = not-keyword sep if-feature-factor / "(" optsep if-feature-expr optsep ")" / identifier-ref-arg
+         *
+         * (This actually looks wrong - basically, the (possibly prefixed) names of features, with 'and' 'or' 'not' thrown in, possibly in parenthesis)
+         */
+        final List<Token> tokens = parseIfFeatureValueIntoTokens(getValue());
+        validateTokens(context, tokens, true);
+    }
+
+    public boolean areTokensValid(final ParserExecutionContext context, final List<Token> tokens) {
+        return validateTokens(context, tokens, false);
+    }
+
+    private boolean validateTokens(final ParserExecutionContext context, final List<Token> tokens,
+            final boolean issueFindings) {
+
+        if (tokens == null || tokens.isEmpty()) {
+            if (issueFindings) {
+                context.addFinding(new Finding(this, ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString(),
+                        "Missing feature name."));
+            }
+            return false;
+        }
+
+        /*
+         * Check the tokens - usually only a single token will exist (old Yang 1.0 syntax), but we never know...
+         */
+        int parenthesisOpenCount = 0;
+        int featureNameCount = 0;
+
+        Type previousTokenType = null;
+
+        for (final Token token : tokens) {
+
+            if (token.type == Type.LEFT_PARENTHESIS) {
+                parenthesisOpenCount++;
+            } else if (token.type == Type.RIGHT_PARENTHESIS) {
+                parenthesisOpenCount--;
+                if (parenthesisOpenCount < 0) {
+                    if (issueFindings) {
+                        context.addFinding(new Finding(this, ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString(),
+                                "Unexpected closing parenthesis."));
+                    }
+                    return false;
+                }
+            } else if (token.type == Type.FEATURE_NAME) {
+                featureNameCount++;
+            }
+
+            if (previousTokenType == null) {
+                checkToken(context, token, VALID_TOKENS_AT_START, issueFindings);
+            } else if (previousTokenType == Type.FEATURE_NAME) {
+                checkToken(context, token, VALID_TOKENS_AFTER_FEATURE_NAME, issueFindings);
+            } else if (previousTokenType == Type.AND || previousTokenType == Type.OR) {
+                checkToken(context, token, VALID_TOKENS_AFTER_AND_OR, issueFindings);
+            } else if (previousTokenType == Type.NOT) {
+                checkToken(context, token, VALID_TOKENS_AFTER_NOT, issueFindings);
+            } else if (previousTokenType == Type.LEFT_PARENTHESIS) {
+                checkToken(context, token, VALID_TOKENS_AFTER_LEFT_PARENTHESIS, issueFindings);
+            } else { // (previousTokenType == Type.RIGHT_PARENTHESIS) {
+                checkToken(context, token, VALID_TOKENS_AFTER_RIGHT_PARENTHESIS, issueFindings);
+            }
+
+            previousTokenType = token.type;
+        }
+
+        /*
+         * Last token must be either a feature-name or a right parenthesis.
+         */
+        final Token lastToken = tokens.get(tokens.size() - 1);
+        if (lastToken.type != Type.FEATURE_NAME && lastToken.type != Type.RIGHT_PARENTHESIS) {
+            if (issueFindings) {
+                context.addFinding(new Finding(this, ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString(),
+                        "Unexpected end of if-feature expression."));
+            }
+            return false;
+        }
+
+        /*
+         * There must be at least one feature, and opening/closing parenthesis must be balanced.
+         */
+        if (featureNameCount == 0) {
+            if (issueFindings) {
+                context.addFinding(new Finding(this, ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString(),
+                        "Missing feature name."));
+            }
+            return false;
+        }
+        if (parenthesisOpenCount != 0) {
+            if (issueFindings) {
+                context.addFinding(new Finding(this, ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString(),
+                        "Parenthesis not balanced."));
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    private static final List<Type> VALID_TOKENS_AT_START = Arrays.asList(Type.FEATURE_NAME, Type.LEFT_PARENTHESIS,
+            Type.NOT);
+    private static final List<Type> VALID_TOKENS_AFTER_FEATURE_NAME = Arrays.asList(Type.AND, Type.OR,
+            Type.RIGHT_PARENTHESIS);
+    private static final List<Type> VALID_TOKENS_AFTER_AND_OR = Arrays.asList(Type.FEATURE_NAME, Type.NOT,
+            Type.LEFT_PARENTHESIS);
+    private static final List<Type> VALID_TOKENS_AFTER_NOT = Arrays.asList(Type.FEATURE_NAME, Type.LEFT_PARENTHESIS);
+    private static final List<Type> VALID_TOKENS_AFTER_LEFT_PARENTHESIS = Arrays.asList(Type.FEATURE_NAME, Type.NOT,
+            Type.LEFT_PARENTHESIS);
+    private static final List<Type> VALID_TOKENS_AFTER_RIGHT_PARENTHESIS = Arrays.asList(Type.AND, Type.OR,
+            Type.RIGHT_PARENTHESIS);
+
+    private void checkToken(final ParserExecutionContext context, final Token token, final List<Type> mustBeOfType,
+            final boolean issueFindings) {
+        if (!mustBeOfType.contains(token.type) && issueFindings) {
+            context.addFinding(new Finding(this, ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString(),
+                    "Illegal syntax '" + token.name + "'."));
+        }
+    }
+
+    public List<Token> getTokens() {
+        return parseIfFeatureValueIntoTokens(this.getValue());
+    }
+
+    public static List<Token> parseIfFeatureValueIntoTokens(final String input) {
+
+        if (input == null) {
+            return Collections.<Token> emptyList();
+        }
+
+        boolean inString = false;
+        StringBuilder sb = null;
+        final List<Token> nodes = new ArrayList<>();
+
+        for (final char c : input.toCharArray()) {
+
+            if (inString) {
+                if (c == ' ' || c == '\t' || c == '\n' || c == '(' || c == ')') {
+                    // String is over
+                    inString = false;
+                    nodes.add(tokenFromString(sb.toString()));
+                    if (c == '(') {
+                        nodes.add(new Token(Type.LEFT_PARENTHESIS, "("));
+                    } else if (c == ')') {
+                        nodes.add(new Token(Type.RIGHT_PARENTHESIS, ")"));
+                    }
+                } else {
+                    // still in string, so add to it.
+                    sb.append(c);
+                }
+            } else {
+                // currently not in string
+
+                if (c == ' ' || c == '\t' || c == '\n') {
+                    // Have encountered whitespace, ignore.
+                } else if (c == '(') {
+                    nodes.add(new Token(Type.LEFT_PARENTHESIS, "("));
+                } else if (c == ')') {
+                    nodes.add(new Token(Type.RIGHT_PARENTHESIS, ")"));
+                } else {
+                    // some other character, so start of some string
+                    inString = true;
+                    sb = new StringBuilder(100);
+                    sb.append(c);
+                }
+            }
+        }
+
+        if (inString) {
+            nodes.add(tokenFromString(sb.toString()));
+        }
+
+        return nodes;
+    }
+
+    public enum Type {
+        FEATURE_NAME,
+        AND,
+        OR,
+        NOT,
+        LEFT_PARENTHESIS,
+        RIGHT_PARENTHESIS
+    }
+
+    public static class Token {
+        public final Type type;
+        public final String name;
+
+        public Token(final Type type, final String name) {
+            this.type = type;
+            this.name = name;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            return obj instanceof Token && (((Token) obj).type == this.type) && (((Token) obj).name.equals(this.name));
+        }
+    }
+
+    private static Token tokenFromString(final String string) {
+        switch (string) {
+            case "and":
+                return new Token(Type.AND, "and");
+            case "or":
+                return new Token(Type.OR, "or");
+            case "not":
+                return new Token(Type.NOT, "not");
+            default:
+        }
+        return new Token(Type.FEATURE_NAME, string);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YImport.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YImport.java
new file mode 100644
index 0000000..8dd24c5
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YImport.java
@@ -0,0 +1,89 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YImport extends AbstractStatement {
+
+    public YImport(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.MODULE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_IMPORT;
+    }
+
+    public String getImportedModuleName() {
+        return domElement.getValue();
+    }
+
+    /**
+     * Returns the 'prefix' statement, if any, under the 'import'. To get the actual value of the import's
+     * prefix, invoke myImport.getPrefixValue();
+     */
+    public YPrefix getPrefix() {
+        return getChild(CY.STMT_PREFIX);
+    }
+
+    /**
+     * Returns the value, if any, of the 'prefix' statement under the 'import'.
+     */
+    public String getPrefixValue() {
+        final YPrefix yPrefix = getPrefix();
+        return yPrefix == null ? null : yPrefix.getPrefix();
+    }
+
+    /**
+     * Returns the 'revision-date' statement, if any, under the 'import'. To get the actual value of the import's
+     * revision-date, invoke myImport.getRevisionDateValue();
+     */
+    public YRevisionDate getRevisionDate() {
+        return getChild(CY.STMT_REVISION_DATE);
+    }
+
+    /**
+     * Returns the value, if any, of the 'revision-date' statement under the 'import'.
+     */
+    public String getRevisionDateValue() {
+        final YRevisionDate yRevisionDate = getRevisionDate();
+        return yRevisionDate == null ? null : yRevisionDate.getRevisionDateValue();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getImportedModuleName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YInclude.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YInclude.java
new file mode 100644
index 0000000..9841ff5
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YInclude.java
@@ -0,0 +1,73 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YInclude extends AbstractStatement {
+
+    public YInclude(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.MODULE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_INCLUDE;
+    }
+
+    public String getIncludedSubModuleName() {
+        return domElement.getValue();
+    }
+
+    /**
+     * Returns the 'revision-date' statement, if any, under the 'include'. To get the actual value of the include's
+     * revision-date, invoke myInclude.getRevisionDateValue();
+     */
+    public YRevisionDate getRevisionDate() {
+        return getChild(CY.STMT_REVISION_DATE);
+    }
+
+    /**
+     * Returns the value, if any, of the 'revision-date' statement under the 'include'.
+     */
+    public String getRevisionDateValue() {
+        final YRevisionDate yRevisionDate = getRevisionDate();
+        return yRevisionDate == null ? null : yRevisionDate.getRevisionDateValue();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getIncludedSubModuleName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YInput.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YInput.java
new file mode 100644
index 0000000..eabe3af
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YInput.java
@@ -0,0 +1,108 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YInput extends AbstractStatement {
+
+    public YInput(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return "input";
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_INPUT;
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentIsNull(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YKey.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YKey.java
new file mode 100644
index 0000000..c67f653
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YKey.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.util.GrammarHelper;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YKey extends SimpleStatement {
+
+    public YKey(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_KEY;
+    }
+
+    @Override
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+    }
+
+    public List<String> getKeys() {
+        final String value = getValue();
+        return value == null ? Collections.<String> emptyList() : GrammarHelper.parseToStringList(value);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLeaf.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLeaf.java
new file mode 100644
index 0000000..b18106c
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLeaf.java
@@ -0,0 +1,118 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YLeaf extends AbstractStatement {
+
+    public YLeaf(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getLeafName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public boolean definesDataNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_LEAF;
+    }
+
+    public String getLeafName() {
+        return domElement.getValue();
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public YDefault getDefault() {
+        return getChild(CY.STMT_DEFAULT);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YMandatory getMandatory() {
+        return getChild(CY.STMT_MANDATORY);
+    }
+
+    /**
+     * Returns whether the leaf is mandatory.
+     */
+    public boolean isMandatory() {
+        final YMandatory yMandatory = getMandatory();
+        return yMandatory == null ? false : yMandatory.isMandatoryTrue();
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public YType getType() {
+        return getChild(CY.STMT_TYPE);
+    }
+
+    public YUnits getUnits() {
+        return getChild(CY.STMT_UNITS);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getLeafName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLeafList.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLeafList.java
new file mode 100644
index 0000000..9ea44c4
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLeafList.java
@@ -0,0 +1,118 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YLeafList extends AbstractStatement {
+
+    public YLeafList(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getLeafListName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public boolean definesDataNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_LEAF_LIST;
+    }
+
+    public String getLeafListName() {
+        return domElement.getValue();
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public List<YDefault> getDefaults() {
+        return getChildren(CY.STMT_DEFAULT);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YMaxElements getMaxElements() {
+        return getChild(CY.STMT_MAX_ELEMENTS);
+    }
+
+    public YMinElements getMinElements() {
+        return getChild(CY.STMT_MIN_ELEMENTS);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public YOrderedBy getOrderedBy() {
+        return getChild(CY.STMT_ORDERED_BY);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public YType getType() {
+        return getChild(CY.STMT_TYPE);
+    }
+
+    public YUnits getUnits() {
+        return getChild(CY.STMT_UNITS);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getLeafListName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLength.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLength.java
new file mode 100644
index 0000000..d433e4a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YLength.java
@@ -0,0 +1,229 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YLength extends AbstractStatement {
+
+    private static final long MIN_VALUE_FOR_LENGTH = 0;
+    private static final long MAX_VALUE_FOR_LENGTH = Long.MAX_VALUE;
+
+    public YLength(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_LENGTH;
+    }
+
+    public String getLengthValue() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    public YErrorAppTag getErrorAppTag() {
+        return getChild(CY.STMT_ERROR_APP_TAG);
+    }
+
+    public YErrorMessage getErrorMessage() {
+        return getChild(CY.STMT_ERROR_MESSAGE);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        validateBoundaries(context);
+    }
+
+    public void validateBoundaries(final ParserExecutionContext context) {
+        final List<BoundaryPair> boundaries = getBoundaries();
+        checkBoundaries(context, boundaries);
+    }
+
+    /**
+     * Returns the boundaries for this length. "min" and "max" are zero / Long.MAX respectively.
+     */
+    public List<BoundaryPair> getBoundaries() {
+        /*
+         * From the RFC:
+         *
+         * "A length range consists of an explicit value, or a lower bound, two
+         * consecutive dots "..", and an upper bound. Multiple values or ranges
+         * can be given, separated by "|". Length-restricting values MUST NOT
+         * be negative. If multiple values or ranges are given, they all MUST
+         * be disjoint and MUST be in ascending order.
+         *
+         * Official definition is:
+         *
+         * length-boundary = min-keyword / max-keyword / non-negative-integer-value
+        // From the RFC:
+        //
+        // length-arg = length-part *(optsep "|" optsep length-part)
+        //
+        // length-part = length-boundary [optsep ".." optsep length-boundary]
+        //
+        // length-boundary = min-keyword / max-keyword / non-negative-integer-value
+        //
+        // max-keyword = "max"
+        // min-keyword = "min"
+         */
+
+        try {
+            final List<BoundaryPair> boundaries = new ArrayList<>();
+            final String stringefiedLengthValues = getLengthValue().trim();
+            if (stringefiedLengthValues.isEmpty() || stringefiedLengthValues.startsWith("|") || stringefiedLengthValues
+                    .endsWith("|")) {
+                return Collections.<BoundaryPair> emptyList();
+            }
+
+            final String[] lengths = stringefiedLengthValues.contains("|") ?
+                    stringefiedLengthValues.split("\\|") :
+                    new String[] { stringefiedLengthValues };
+            for (final String oneLength : lengths) {
+
+                if (oneLength.trim().startsWith("..") || oneLength.trim().endsWith("..")) {
+                    return Collections.<BoundaryPair> emptyList();
+                }
+
+                final String[] boundary = oneLength.contains("..") ?
+                        oneLength.split("\\.\\.") :
+                        new String[] { oneLength, oneLength };
+
+                final String lowerBoundary = boundary[0].trim();
+                final String upperBoundary = boundary[1].trim();
+
+                long lowerValue = 0;
+                if (lowerBoundary.equals("min")) {
+                    lowerValue = MIN_VALUE_FOR_LENGTH;
+                } else if (lowerBoundary.equals("max")) {
+                    lowerValue = MAX_VALUE_FOR_LENGTH;
+                } else {
+                    lowerValue = Long.parseLong(lowerBoundary);		// this may throw
+                }
+
+                long upperValue = 0;
+                if (upperBoundary.equals("min")) {
+                    upperValue = MIN_VALUE_FOR_LENGTH;
+                } else if (upperBoundary.equals("max")) {
+                    upperValue = MAX_VALUE_FOR_LENGTH;
+                } else {
+                    upperValue = Long.parseLong(upperBoundary);		// this may throw
+                }
+
+                boundaries.add(new BoundaryPair(lowerValue, upperValue));
+            }
+
+            return boundaries;
+
+        } catch (final Exception ex) {
+            /* no-op */
+        }
+
+        /*
+         * If we get here then an issue has occurred somewhere. We return empty boundaries
+         * as these cannot be reliably established.
+         */
+        return Collections.<BoundaryPair> emptyList();
+    }
+
+    public void checkBoundaries(final ParserExecutionContext context, final List<BoundaryPair> boundaries) {
+
+        if (boundaries.isEmpty()) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + getLengthValue() + "' not valid for length."));
+            return;
+        }
+
+        /*
+         * Rules:
+         * - Each value must be >= 0
+         * - In each pair, upper must be >= lower.
+         * - The lower of a pair must be >= the upper of the previous pair.
+         */
+        for (int i = 0; i < boundaries.size(); ++i) {
+            boolean allOk = true;
+
+            if (boundaries.get(i).lower < 0) {
+                allOk = false;
+            }
+            if (boundaries.get(i).upper < 0) {
+                allOk = false;
+            }
+
+            // lower <= upper ?
+            if (boundaries.get(i).lower > boundaries.get(i).upper) {
+                allOk = false;
+            }
+
+            if (i > 0 && boundaries.get(i).lower <= boundaries.get(i - 1).upper) {
+                allOk = false;
+            }
+
+            if (!allOk) {
+                context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                        "value '" + getLengthValue() + "' not valid for 'length'."));
+                return;
+            }
+        }
+    }
+
+    public boolean isWithinLengthBoundaries(final long toCheck) {
+        for (final BoundaryPair boundaryPair : getBoundaries()) {
+            if (toCheck >= boundaryPair.lower && toCheck <= boundaryPair.upper) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static class BoundaryPair {
+        public final long lower;
+        public final long upper;
+
+        public BoundaryPair(final long lower, final long upper) {
+            this.lower = lower;
+            this.upper = upper;
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YList.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YList.java
new file mode 100644
index 0000000..3653e7d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YList.java
@@ -0,0 +1,162 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YList extends AbstractStatement {
+
+    public YList(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getListName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public boolean definesDataNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_LIST;
+    }
+
+    public String getListName() {
+        return domElement.getValue();
+    }
+
+    public List<YAction> getActions() {
+        return getChildren(CY.STMT_ACTION);
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YKey getKey() {
+        return getChild(CY.STMT_KEY);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public YMaxElements getMaxElements() {
+        return getChild(CY.STMT_MAX_ELEMENTS);
+    }
+
+    public YMinElements getMinElements() {
+        return getChild(CY.STMT_MIN_ELEMENTS);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public List<YNotification> getNotifications() {
+        return getChildren(CY.STMT_NOTIFICATION);
+    }
+
+    public YOrderedBy getOrderedBy() {
+        return getChild(CY.STMT_ORDERED_BY);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUnique> getUniques() {
+        return getChildren(CY.STMT_UNIQUE);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getListName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMandatory.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMandatory.java
new file mode 100644
index 0000000..be6112b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMandatory.java
@@ -0,0 +1,61 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YMandatory extends SimpleStatement {
+
+    public YMandatory(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_MANDATORY;
+    }
+
+    public boolean isMandatoryTrue() {
+        return "true".equals(getValue());
+    }
+
+    public boolean isMandatoryFalse() {
+        return "false".equals(getValue());
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentIsTrueOrFalse(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMaxElements.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMaxElements.java
new file mode 100644
index 0000000..7e8d985
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMaxElements.java
@@ -0,0 +1,82 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YMaxElements extends SimpleStatement {
+
+    public YMaxElements(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_MAX_ELEMENTS;
+    }
+
+    public boolean isUnbounded() {
+        return "unbounded".equals(getValue());
+    }
+
+    public long getMaxValue() {
+
+        long maxValue = -1;
+
+        try {
+            maxValue = Long.parseLong(getValue());
+            if (maxValue <= 0) {
+                maxValue = -1;
+            }
+        } catch (final Exception nfex) {
+            /* no-op */ }
+
+        return maxValue;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        if (!isUnbounded() && getMaxValue() < 0) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + getValue() + "' not valid for max-elements."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMinElements.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMinElements.java
new file mode 100644
index 0000000..a2f7641
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMinElements.java
@@ -0,0 +1,75 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YMinElements extends SimpleStatement {
+
+    public YMinElements(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_MIN_ELEMENTS;
+    }
+
+    public long getMinValue() {
+
+        long minValue = -1;
+
+        try {
+            minValue = Long.parseLong(getValue());
+        } catch (final Exception nfex) {
+            /* no-op */ }
+
+        return minValue;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        if (getMinValue() < 0) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + getValue() + "' not valid for min-elements."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YModifier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YModifier.java
new file mode 100644
index 0000000..fd5ffff
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YModifier.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YModifier extends SimpleStatement {
+
+    public YModifier(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_MODIFIER;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        if (!"invert-match".equals(getValue())) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "modifier value invalid."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YModule.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YModule.java
new file mode 100644
index 0000000..d6d422f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YModule.java
@@ -0,0 +1,201 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YModule extends AbstractStatement {
+
+    public YModule(final AbstractStatement modelRoot, final YangDomElement domNode) {
+        super(modelRoot, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getModuleName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_MODULE;
+    }
+
+    /**
+     * The module name will always be non-null.
+     */
+    public String getModuleName() {
+        return domElement.getValue();
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YAugment> getAugments() {
+        return getChildren(CY.STMT_AUGMENT);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public YContact getContact() {
+        return getChild(CY.STMT_CONTACT);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YDeviation> getDeviations() {
+        return getChildren(CY.STMT_DEVIATION);
+    }
+
+    public List<YExtension> getExtensions() {
+        return getChildren(CY.STMT_EXTENSION);
+    }
+
+    public List<YFeature> getFeatures() {
+        return getChildren(CY.STMT_FEATURE);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YIdentity> getIdentities() {
+        return getChildren(CY.STMT_IDENTITY);
+    }
+
+    public List<YImport> getImports() {
+        return getChildren(CY.STMT_IMPORT);
+    }
+
+    public List<YInclude> getIncludes() {
+        return getChildren(CY.STMT_INCLUDE);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    /**
+     * Returns the 'namespace' statement, if any, under the 'module'. To get the actual value of the module's
+     * namespace, invoke myModule.getNamespaceValue();
+     */
+    public YNamespace getNamespace() {
+        return getChild(CY.STMT_NAMESPACE);
+    }
+
+    /**
+     * Returns the value, if any, of the 'namespace' statement under the 'module'.
+     */
+    public String getNamespaceValue() {
+        final YNamespace yNamespace = getNamespace();
+        return yNamespace == null ? null : yNamespace.getNamespace();
+    }
+
+    public List<YNotification> getNotifications() {
+        return getChildren(CY.STMT_NOTIFICATION);
+    }
+
+    public YOrganization getOrganization() {
+        return getChild(CY.STMT_ORGANIZATION);
+    }
+
+    /**
+     * Returns the 'prefix' statement, if any, under the 'module'. To get the actual value of the module's
+     * prefix, invoke myModule.getPrefixValue();
+     */
+    public YPrefix getPrefix() {
+        return getChild(CY.STMT_PREFIX);
+    }
+
+    /**
+     * Returns the value, if any, of the 'prefix' statement under the module.
+     */
+    public String getPrefixValue() {
+        final YPrefix yPrefix = getPrefix();
+        return yPrefix == null ? null : yPrefix.getPrefix();
+    }
+
+    public List<YRevision> getRevisions() {
+        return getChildren(CY.STMT_REVISION);
+    }
+
+    public List<YRpc> getRpcs() {
+        return getChildren(CY.STMT_RPC);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    public YYangVersion getYangVersion() {
+        return getChild(CY.STMT_YANG_VERSION);
+    }
+
+    public boolean is10Version() {
+        final YYangVersion yYangVersion = getYangVersion();
+        return yYangVersion == null ? false : yYangVersion.is10Version();
+    }
+
+    public boolean is11Version() {
+        final YYangVersion yYangVersion = getYangVersion();
+        return yYangVersion == null ? false : yYangVersion.is11Version();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getModuleName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMust.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMust.java
new file mode 100644
index 0000000..6da3e52
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YMust.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YMust extends AbstractStatement {
+
+    public YMust(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.CONDITION;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_MUST;
+    }
+
+    public String getXpathExpression() {
+        return domElement.getValue();
+    }
+
+    public YErrorAppTag getErrorAppTag() {
+        return getChild(CY.STMT_ERROR_APP_TAG);
+    }
+
+    public YErrorMessage getErrorMessage() {
+        return getChild(CY.STMT_ERROR_MESSAGE);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YNamespace.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YNamespace.java
new file mode 100644
index 0000000..300f814
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YNamespace.java
@@ -0,0 +1,52 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YNamespace extends SimpleStatement {
+
+    public YNamespace(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.URI;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_NAMESPACE;
+    }
+
+    public String getNamespace() {
+        return getValue();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YNotification.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YNotification.java
new file mode 100644
index 0000000..4a0101b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YNotification.java
@@ -0,0 +1,125 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YNotification extends AbstractStatement {
+
+    public YNotification(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getNotificationName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_NOTIFICATION;
+    }
+
+    public String getNotificationName() {
+        return domElement.getValue();
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    public List<YWhen> getWhens() {
+        return getChildren(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getNotificationName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOrderedBy.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOrderedBy.java
new file mode 100644
index 0000000..d2261d0
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOrderedBy.java
@@ -0,0 +1,71 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YOrderedBy extends SimpleStatement {
+
+    public YOrderedBy(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ORDERED_BY;
+    }
+
+    public boolean isOrderedByUser() {
+        return "user".equals(getValue());
+    }
+
+    public boolean isOrderedBySystem() {
+        return "system".equals(getValue());
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        if (!isOrderedByUser() && !isOrderedBySystem()) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "value '" + getValue() + "' not valid for ordered-by."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOrganization.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOrganization.java
new file mode 100644
index 0000000..627162c
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOrganization.java
@@ -0,0 +1,54 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YOrganization extends SimpleStatement {
+
+    public YOrganization(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TEXT;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_ORGANIZATION;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNull(context);
+        validateDocumentationArgumentNotEmpty(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOutput.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOutput.java
new file mode 100644
index 0000000..9ec60d8
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YOutput.java
@@ -0,0 +1,108 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YOutput extends AbstractStatement {
+
+    public YOutput(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return "output";
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NO_ARG;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_OUTPUT;
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentIsNull(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPath.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPath.java
new file mode 100644
index 0000000..119dab4
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPath.java
@@ -0,0 +1,52 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YPath extends SimpleStatement {
+
+    public YPath(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_PATH;
+    }
+
+    final String getPath() {
+        return getValue();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPattern.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPattern.java
new file mode 100644
index 0000000..c8914fa
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPattern.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YPattern extends AbstractStatement {
+
+    public YPattern(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_PATTERN;
+    }
+
+    public String getPattern() {
+        return domElement.getValue();
+    }
+
+    public YErrorAppTag getErrorAppTag() {
+        return getChild(CY.STMT_ERROR_APP_TAG);
+    }
+
+    public YErrorMessage getErrorMessage() {
+        return getChild(CY.STMT_ERROR_MESSAGE);
+    }
+
+    public YModifier getModifier() {
+        return getChild(CY.STMT_MODIFIER);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPosition.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPosition.java
new file mode 100644
index 0000000..ff847cb
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPosition.java
@@ -0,0 +1,81 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YPosition extends SimpleStatement {
+
+    public static final long MAX_POSITION_VALUE = 4294967295L;
+
+    public YPosition(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_POSITION;
+    }
+
+    public long getPosition() {
+
+        long position = -1;
+
+        try {
+            position = Long.parseLong(getValue());
+            if (position < 0 || position > MAX_POSITION_VALUE) {
+                position = -1;
+            }
+        } catch (final Exception ex) {
+            /* no-op */ }
+
+        return position;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        final long position = getPosition();
+        if (position < 0) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + getValue() + "' not valid for position."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPrefix.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPrefix.java
new file mode 100644
index 0000000..5416b17
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPrefix.java
@@ -0,0 +1,58 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YPrefix extends SimpleStatement {
+
+    public YPrefix(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_PREFIX;
+    }
+
+    public String getPrefix() {
+        return getValue();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getPrefix());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPresence.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPresence.java
new file mode 100644
index 0000000..ef7fdc2
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YPresence.java
@@ -0,0 +1,57 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YPresence extends SimpleStatement {
+
+    public YPresence(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_PRESENCE;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        /*
+         * Happens quite often that the value is omitted for 'presence', or it is "".
+         *
+         * We don't do a check as it simply results in a lot of findings that are of no value to the user.
+         */
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRange.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRange.java
new file mode 100644
index 0000000..b0d3f65
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRange.java
@@ -0,0 +1,389 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper.YangDataType;
+import org.oran.smo.yangtools.parser.model.util.NumberHelper;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YRange extends AbstractStatement {
+
+    public YRange(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_RANGE;
+    }
+
+    public String getRangeValues() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    public YErrorAppTag getErrorAppTag() {
+        return getChild(CY.STMT_ERROR_APP_TAG);
+    }
+
+    public YErrorMessage getErrorMessage() {
+        return getChild(CY.STMT_ERROR_MESSAGE);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        checkUsedUnderIntegerOrDecimal64(context);
+        validateBoundaries(context);
+    }
+
+    public void validateBoundaries(final ParserExecutionContext context) {
+        final List<BoundaryPair> boundaries = getBoundaries();
+        checkBoundaries(context, boundaries);
+    }
+
+    /**
+     * Returns the boundaries for this range. "min" and "max" are resolved to the
+     * minimum / maximum values for the data type.
+     * <p>
+     * The returned list contains pairings for each boundary part of the range.
+     * Both upper and lower boundary are expressed as BigDecimal. Where the type
+     * owning this range statement is integer, a client should invoke toBigInteger
+     * to get the boundaries as integer values.
+     */
+    public List<BoundaryPair> getBoundaries() {
+        /*
+         * A range can only sit under type, so it's safe to do the typecast below.
+         */
+        return getBoundaries((YType) getParentStatement());
+    }
+
+    public List<BoundaryPair> getBoundaries(final YType forType) {
+        final YangDataType yangDataType = DataTypeHelper.getYangDataType(forType.getDataType());
+        final int fractionDigits = forType.hasAtLeastOneChildOf(CY.STMT_FRACTION_DIGITS) ?
+                ((YFractionDigits) forType.getChild(CY.STMT_FRACTION_DIGITS)).getFractionDigits() :
+                0;
+        return getBoundaries(yangDataType, fractionDigits);
+    }
+
+    private List<BoundaryPair> getBoundaries(final YangDataType forDataType, final int fractionDigits) {
+
+        /*
+         * From the RFC:
+         *
+         * "A range consists of an explicit value, or a lower-inclusive bound,
+         * two consecutive dots "..", and an upper-inclusive bound. Multiple
+         * values or ranges can be given, separated by "|". If multiple values
+         * or ranges are given, they all MUST be disjoint and MUST be in
+         * ascending order. If a range restriction is applied to a type that is
+         * already range-restricted, the new restriction MUST be equally
+         * limiting or more limiting, i.e., raising the lower bounds, reducing
+         * the upper bounds, removing explicit values or ranges, or splitting
+         * ranges into multiple ranges with intermediate gaps. Each explicit
+         * value and range boundary value given in the range expression MUST
+         * match the type being restricted or be one of the special values "min"
+         * or "max". "min" and "max" mean the minimum and maximum values
+         * accepted for the type being restricted, respectively."
+         *
+         * Official definition is:
+         *
+         * range-boundary = min-keyword / max-keyword / integer-value / decimal-value
+         */
+
+        /*
+         * The first problem that we are faced with is to know what actual values we
+         * should use for min and max. That solely depends on the data type of the
+         * parent 'type' statement. If this cannot be resolved for whatever reason we
+         * return empty boundaries so that a client doesn't have to worry about null values.
+         */
+        final BigDecimal minValueForRange = getMinValueForRange(forDataType, fractionDigits);
+        final BigDecimal maxValueForRange = getMaxValueForRange(forDataType, fractionDigits);
+
+        if (minValueForRange == null || maxValueForRange == null) {
+            return Collections.<BoundaryPair> emptyList();
+        }
+
+        /*
+         * Now parse the range values string. This may very well throw somewhere if
+         * the syntax has not been adhered to.
+         */
+        try {
+
+            final List<BoundaryPair> result = new ArrayList<>();
+            final String stringefiedRangeValues = getRangeValues().trim();
+
+            if (stringefiedRangeValues.isEmpty() || stringefiedRangeValues.startsWith("|") || stringefiedRangeValues
+                    .endsWith("|")) {
+                // syntax error
+                return Collections.<BoundaryPair> emptyList();
+            }
+
+            final String[] ranges = stringefiedRangeValues.contains("|") ?
+                    stringefiedRangeValues.split("\\|") :
+                    new String[] { stringefiedRangeValues };
+            for (final String oneRange : ranges) {
+
+                if (oneRange.trim().startsWith("..") || oneRange.trim().endsWith("..")) {
+                    // syntax error
+                    return Collections.<BoundaryPair> emptyList();
+                }
+
+                final String[] boundary = oneRange.contains("..") ?
+                        oneRange.split("\\.\\.") :
+                        new String[] { oneRange, oneRange };
+
+                final String lowerBoundary = boundary[0].trim();
+                final String upperBoundary = boundary[1].trim();
+
+                BigDecimal lowerValue = null;
+                if (lowerBoundary.equals("min")) {
+                    lowerValue = minValueForRange;
+                } else if (lowerBoundary.equals("max")) {
+                    lowerValue = maxValueForRange;
+                } else {
+                    lowerValue = NumberHelper.extractYangIntegerValueOrDecimalValue(lowerBoundary);		// Note: May throw
+                }
+
+                BigDecimal upperValue = null;
+                if (upperBoundary.equals("min")) {
+                    upperValue = minValueForRange;
+                } else if (upperBoundary.equals("max")) {
+                    upperValue = maxValueForRange;
+                } else {
+                    upperValue = NumberHelper.extractYangIntegerValueOrDecimalValue(upperBoundary);		// Note: May throw
+                }
+
+                result.add(new BoundaryPair(lowerValue, upperValue));
+            }
+
+            return result;
+
+        } catch (final Exception ex) {
+            /* no-op */
+        }
+
+        /*
+         * If we get here then an issue has occurred somewhere. We return empty boundaries
+         * as these cannot be reliably established.
+         */
+        return Collections.<BoundaryPair> emptyList();
+    }
+
+    /**
+     * Returns the data type of the parent 'type' statement.
+     */
+    private YangDataType getParentTypeDataType() {
+        final AbstractStatement parentStatement = getParentStatement();
+        return DataTypeHelper.getYangDataType(((YType) parentStatement).getDataType());
+    }
+
+    public void checkBoundaries(final ParserExecutionContext context, final List<BoundaryPair> boundaries) {
+        /*
+         * A range can only sit under type, so it's safe to do the typecast below.
+         */
+        checkBoundaries(context, boundaries, (YType) getParentStatement());
+    }
+
+    public void checkBoundaries(final ParserExecutionContext context, final List<BoundaryPair> boundaries,
+            final YType forType) {
+
+        final YangDataType yangDataType = DataTypeHelper.getYangDataType(forType.getDataType());
+        final int fractionDigits = forType.hasAtLeastOneChildOf(CY.STMT_FRACTION_DIGITS) ?
+                ((YFractionDigits) forType.getChild(CY.STMT_FRACTION_DIGITS)).getFractionDigits() :
+                0;
+        checkBoundaries(context, boundaries, yangDataType, fractionDigits);
+    }
+
+    private void checkBoundaries(final ParserExecutionContext context, final List<BoundaryPair> boundaries,
+            final YangDataType forDataType, final int fractionDigits) {
+
+        /*
+         * Establish min/max values for the data type. If this cannot be done for whatever reason
+         * (e.g. non-numeric data type) then the boundaries cannot be checked, and we return out.
+         */
+        final BigDecimal minValueForRange = getMinValueForRange(forDataType, fractionDigits);
+        final BigDecimal maxValueForRange = getMaxValueForRange(forDataType, fractionDigits);
+
+        if (minValueForRange == null || maxValueForRange == null) {
+            return;
+        }
+
+        /*
+         * If we don't have boundaries that would be a finding.
+         */
+        if (boundaries.isEmpty()) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + getRangeValues() + "' not valid for range."));
+            return;
+        }
+
+        final boolean isIntegerType = DataTypeHelper.isYangIntegerType(getParentTypeDataType());
+
+        /*
+         * Rules:
+         * - Each value must be within min/max values
+         * - In each pair, upper must be >= lower.
+         * - The lower of a pair must be >= the upper of the previous pair.
+         */
+        for (int i = 0; i < boundaries.size(); ++i) {
+            boolean allOk = true;
+
+            if (isIntegerType && boundaries.get(i).lower.stripTrailingZeros().scale() > 0) {
+                allOk = false;
+            }
+            if (isIntegerType && boundaries.get(i).upper.stripTrailingZeros().scale() > 0) {
+                allOk = false;
+            }
+
+            if (boundaries.get(i).lower.compareTo(minValueForRange) < 0) {
+                allOk = false;
+            }
+            if (boundaries.get(i).upper.compareTo(minValueForRange) < 0) {
+                allOk = false;
+            }
+            if (boundaries.get(i).lower.compareTo(maxValueForRange) > 0) {
+                allOk = false;
+            }
+            if (boundaries.get(i).upper.compareTo(maxValueForRange) > 0) {
+                allOk = false;
+            }
+
+            // lower <= upper ?
+            if (boundaries.get(i).lower.compareTo(boundaries.get(i).upper) > 0) {
+                allOk = false;
+            }
+
+            if (i > 0) {
+                if (boundaries.get(i).lower.compareTo(boundaries.get(i - 1).upper) <= 0) {
+                    allOk = false;
+                }
+            }
+
+            if (!allOk) {
+                context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                        "value '" + getRangeValues() + "' not valid for range."));
+                return;
+            }
+        }
+    }
+
+    private void checkUsedUnderIntegerOrDecimal64(final ParserExecutionContext context) {
+        final YangDataType dataType = getParentTypeDataType();
+
+        if (dataType != YangDataType.DERIVED____TYPE && !dataTypeIsIntegerOrDecimal64(dataType)) {
+            context.addFinding(new Finding(this, ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT,
+                    "'range' statement not allowed under type '" + dataType + "'."));
+        }
+    }
+
+    private static boolean dataTypeIsIntegerOrDecimal64(final YangDataType dataType) {
+        switch (dataType) {
+            case INT8:
+            case INT16:
+            case INT32:
+            case INT64:
+            case UINT8:
+            case UINT16:
+            case UINT32:
+            case UINT64:
+            case DECIMAL64:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    public boolean isWithinRangeBoundaries(final BigDecimal toCheck) {
+        for (final BoundaryPair boundaryPair : getBoundaries()) {
+            if (toCheck.compareTo(boundaryPair.lower) >= 0 && toCheck.compareTo(boundaryPair.upper) <= 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the smallest possible value for the data type. May return null if this cannot be resolved.
+     */
+    private static BigDecimal getMinValueForRange(final YangDataType forDataType, final int fractionDigits) {
+
+        if (DataTypeHelper.isYangIntegerType(forDataType)) {
+
+            return (NumberHelper.getMinValueForYangIntegerDataType(forDataType));
+
+        } else if (DataTypeHelper.isYangDecimal64Type(forDataType)) {
+            /*
+             * Type is decimal64.
+             */
+            return NumberHelper.getMinValueForYangDecimalDataType(fractionDigits);
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the largest possible value for the data type. May return null if this cannot be resolved.
+     */
+    private static BigDecimal getMaxValueForRange(final YangDataType forDataType, final int fractionDigits) {
+
+        if (DataTypeHelper.isYangIntegerType(forDataType)) {
+
+            return (NumberHelper.getMaxValueForYangIntegerDataType(forDataType));
+
+        } else if (DataTypeHelper.isYangDecimal64Type(forDataType)) {
+            /*
+             * Type is decimal64.
+             */
+            return NumberHelper.getMaxValueForYangDecimalDataType(fractionDigits);
+        }
+
+        return null;
+    }
+
+    public static class BoundaryPair {
+        public final BigDecimal lower;
+        public final BigDecimal upper;
+
+        public BoundaryPair(final BigDecimal lower, final BigDecimal upper) {
+            this.lower = lower;
+            this.upper = upper;
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YReference.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YReference.java
new file mode 100644
index 0000000..95223b1
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YReference.java
@@ -0,0 +1,58 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YReference extends SimpleStatement {
+
+    public YReference(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TEXT;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_REFERENCE;
+    }
+
+    public YReference getReference() {
+        throw new RuntimeException("Wrong invocation. Use getValue() to get the value of a reference statement.");
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNull(context);
+        validateDocumentationArgumentNotEmpty(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRefine.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRefine.java
new file mode 100644
index 0000000..5b73f21
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRefine.java
@@ -0,0 +1,100 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YRefine extends AbstractStatement {
+
+    public YRefine(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TARGET_NODE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_REFINE;
+    }
+
+    public String getRefineTargetNode() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    public YConfig getConfig() {
+        return getChild(CY.STMT_CONFIG);
+    }
+
+    public List<YDefault> getDefaults() {
+        return getChildren(CY.STMT_DEFAULT);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YMandatory getMandatory() {
+        return getChild(CY.STMT_MANDATORY);
+    }
+
+    public YMinElements getMinElements() {
+        return getChild(CY.STMT_MIN_ELEMENTS);
+    }
+
+    public YMaxElements getMaxElements() {
+        return getChild(CY.STMT_MAX_ELEMENTS);
+    }
+
+    public List<YMust> getMusts() {
+        return getChildren(CY.STMT_MUST);
+    }
+
+    public YPresence getPresence() {
+        return getChild(CY.STMT_PRESENCE);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        if (getRefineTargetNode().startsWith("/")) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "The identifier for the refine's target node is not relative (it must not start with '/')."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRequireInstance.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRequireInstance.java
new file mode 100644
index 0000000..c827b4b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRequireInstance.java
@@ -0,0 +1,61 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YRequireInstance extends SimpleStatement {
+
+    public YRequireInstance(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_REQUIRE_INSTANCE;
+    }
+
+    public boolean isRequireInstanceTrue() {
+        return "true".equals(getValue());
+    }
+
+    public boolean isRequireInstanceFalse() {
+        return "false".equals(getValue());
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentIsTrueOrFalse(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRevision.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRevision.java
new file mode 100644
index 0000000..9282974
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRevision.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YRevision extends SimpleStatement {
+
+    public YRevision(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.DATE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_REVISION;
+    }
+
+    public String getRevision() {
+        return getValue() == null ? "" : getValue();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        final String value = getValue();
+        if (value.length() != 10) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "value '" + value + "' not valid for revision date (must be YYYY-MM-DD)."));
+        } else {
+            if (!Character.isDigit(value.charAt(0)) || !Character.isDigit(value.charAt(1)) || !Character.isDigit(value
+                    .charAt(2)) || !Character.isDigit(value.charAt(3)) || value.charAt(4) != '-' || !Character.isDigit(value
+                            .charAt(5)) || !Character.isDigit(value.charAt(6)) || value.charAt(7) != '-' || !Character
+                                    .isDigit(value.charAt(8)) || !Character.isDigit(value.charAt(9))) {
+                context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                        "value '" + value + "' not valid for revision date (must be YYYY-MM-DD)."));
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRevisionDate.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRevisionDate.java
new file mode 100644
index 0000000..c3f158f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRevisionDate.java
@@ -0,0 +1,76 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YRevisionDate extends SimpleStatement {
+
+    public YRevisionDate(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.DATE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_REVISION_DATE;
+    }
+
+    public String getRevisionDateValue() {
+        return getValue();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        final String value = getRevisionDateValue();
+        if (value.length() != 10) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + value + "' not valid for revision date (must be YYYY-MM-DD)."));
+        } else {
+            if (!Character.isDigit(value.charAt(0)) || !Character.isDigit(value.charAt(1)) || !Character.isDigit(value
+                    .charAt(2)) || !Character.isDigit(value.charAt(3)) || value.charAt(4) != '-' || !Character.isDigit(value
+                            .charAt(5)) || !Character.isDigit(value.charAt(6)) || value.charAt(7) != '-' || !Character
+                                    .isDigit(value.charAt(8)) || !Character.isDigit(value.charAt(9))) {
+                context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                        "value '" + value + "' not valid for revision date (must be YYYY-MM-DD)."));
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRpc.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRpc.java
new file mode 100644
index 0000000..e50c4d4
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YRpc.java
@@ -0,0 +1,93 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YRpc extends AbstractStatement {
+
+    public YRpc(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getRpcName();
+    }
+
+    @Override
+    public boolean definesSchemaNode() {
+        return true;
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_RPC;
+    }
+
+    public String getRpcName() {
+        return domElement.getValue();
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public YInput getInput() {
+        return getChild(CY.STMT_INPUT);
+    }
+
+    public YOutput getOutput() {
+        return getChild(CY.STMT_OUTPUT);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getRpcName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YStatus.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YStatus.java
new file mode 100644
index 0000000..3489025
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YStatus.java
@@ -0,0 +1,110 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YStatus extends SimpleStatement {
+
+    public static final String CURRENT = "current";
+    public static final String DEPRECATED = "deprecated";
+    public static final String OBSOLETE = "obsolete";
+
+    public YStatus(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_STATUS;
+    }
+
+    public boolean isCurrent() {
+        return CURRENT.equals(getValue());
+    }
+
+    public boolean isDeprecated() {
+        return DEPRECATED.equals(getValue());
+    }
+
+    public boolean isObsolete() {
+        return OBSOLETE.equals(getValue());
+    }
+
+    /**
+     * Returns an integer that may be used to compare the status value for two data nodes.
+     * The general rules are: CURRENT &lt; DEPRECATED &lt; OBSOLETE. The value returned
+     * has no meaning in itself and especially should not be used to identity a certain
+     * status value; it is only meaningful when compared to another value returned from
+     * this method.
+     */
+    public int getStatusOrder() {
+        return getStatusOrder(getValue());
+    }
+
+    /**
+     * Returns an integer that may be used to compare the status value for two data nodes.
+     * The general rules are: CURRENT &lt; DEPRECATED &lt; OBSOLETE. The value returned
+     * has no meaning in itself and especially should not be used to identity a certain
+     * status value; it is only meaningful when compared to another value returned from
+     * this method.
+     */
+    public static int getStatusOrder(final String status) {
+        switch (status) {
+            case CURRENT:
+                return 20;
+            case DEPRECATED:
+                return 30;
+            case OBSOLETE:
+                return 40;
+        }
+
+        return 0;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        if (!isCurrent() && !isDeprecated() && !isObsolete()) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "'" + getValue() + "' is not a valid status. Use one of: current, deprecated, obsolete."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YSubmodule.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YSubmodule.java
new file mode 100644
index 0000000..101fc4b
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YSubmodule.java
@@ -0,0 +1,185 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YSubmodule extends AbstractStatement {
+
+    public YSubmodule(final AbstractStatement modelRoot, final YangDomElement domNode) {
+        super(modelRoot, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getSubmoduleName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_SUBMODULE;
+    }
+
+    /**
+     * The submodule name will always be non-null.
+     */
+    public String getSubmoduleName() {
+        return domElement.getValue();
+    }
+
+    public List<YAnydata> getAnydata() {
+        return getChildren(CY.STMT_ANYDATA);
+    }
+
+    public List<YAnyxml> getAnyxmls() {
+        return getChildren(CY.STMT_ANYXML);
+    }
+
+    public List<YAugment> getAugments() {
+        return getChildren(CY.STMT_AUGMENT);
+    }
+
+    /**
+     * Returns the 'belongs-to' statement, if any, under the 'submodule'. To get the actual value of the submodule's
+     * belongs-to, invoke mySubmodule.getBelongsToValue();
+     */
+    public YBelongsTo getBelongsTo() {
+        return getChild(CY.STMT_BELONGS_TO);
+    }
+
+    /**
+     * Returns the value, if any, of the 'belongs-to' statement under the 'submodule'.
+     */
+    public String getBelongsToValue() {
+        final YBelongsTo yBelongsTo = getBelongsTo();
+        return yBelongsTo == null ? null : yBelongsTo.getBelongsToModuleName();
+    }
+
+    public List<YChoice> getChoices() {
+        return getChildren(CY.STMT_CHOICE);
+    }
+
+    public YContact getContact() {
+        return getChild(CY.STMT_CONTACT);
+    }
+
+    public List<YContainer> getContainers() {
+        return getChildren(CY.STMT_CONTAINER);
+    }
+
+    public List<YDeviation> getDeviations() {
+        return getChildren(CY.STMT_DEVIATION);
+    }
+
+    public List<YExtension> getExtensions() {
+        return getChildren(CY.STMT_EXTENSION);
+    }
+
+    public List<YFeature> getFeatures() {
+        return getChildren(CY.STMT_FEATURE);
+    }
+
+    public List<YGrouping> getGroupings() {
+        return getChildren(CY.STMT_GROUPING);
+    }
+
+    public List<YIdentity> getIdentities() {
+        return getChildren(CY.STMT_IDENTITY);
+    }
+
+    public List<YImport> getImports() {
+        return getChildren(CY.STMT_IMPORT);
+    }
+
+    public List<YInclude> getIncludes() {
+        return getChildren(CY.STMT_INCLUDE);
+    }
+
+    public List<YLeaf> getLeafs() {
+        return getChildren(CY.STMT_LEAF);
+    }
+
+    public List<YLeafList> getLeafLists() {
+        return getChildren(CY.STMT_LEAF_LIST);
+    }
+
+    public List<YList> getLists() {
+        return getChildren(CY.STMT_LIST);
+    }
+
+    public List<YNotification> getNotifications() {
+        return getChildren(CY.STMT_NOTIFICATION);
+    }
+
+    public YOrganization getOrganization() {
+        return getChild(CY.STMT_ORGANIZATION);
+    }
+
+    public List<YRevision> getRevisions() {
+        return getChildren(CY.STMT_REVISION);
+    }
+
+    public List<YRpc> getRpcs() {
+        return getChildren(CY.STMT_RPC);
+    }
+
+    public List<YTypedef> getTypedefs() {
+        return getChildren(CY.STMT_TYPEDEF);
+    }
+
+    public List<YUses> getUses() {
+        return getChildren(CY.STMT_USES);
+    }
+
+    public YYangVersion getYangVersion() {
+        return getChild(CY.STMT_YANG_VERSION);
+    }
+
+    public boolean is10Version() {
+        final YYangVersion yYangVersion = getYangVersion();
+        return yYangVersion == null ? false : yYangVersion.is10Version();
+    }
+
+    public boolean is11Version() {
+        final YYangVersion yYangVersion = getYangVersion();
+        return yYangVersion == null ? false : yYangVersion.is11Version();
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifier(context, getSubmoduleName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YType.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YType.java
new file mode 100644
index 0000000..6e3be06
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YType.java
@@ -0,0 +1,98 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YType extends AbstractStatement {
+
+    public YType(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_TYPE;
+    }
+
+    @Override
+    public boolean orderUnderParentMatters() {
+        return true;
+    }
+
+    public String getDataType() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    public List<YBase> getBases() {
+        return getChildren(CY.STMT_BASE);
+    }
+
+    public List<YBit> getBits() {
+        return getChildren(CY.STMT_BIT);
+    }
+
+    public List<YEnum> getEnums() {
+        return getChildren(CY.STMT_ENUM);
+    }
+
+    public YFractionDigits getFractionDigits() {
+        return getChild(CY.STMT_FRACTION_DIGITS);
+    }
+
+    public YLength getLength() {
+        return getChild(CY.STMT_LENGTH);
+    }
+
+    public YPath getPath() {
+        return getChild(CY.STMT_PATH);
+    }
+
+    public List<YPattern> getPatterns() {
+        return getChildren(CY.STMT_PATTERN);
+    }
+
+    public YRange getRange() {
+        return getChild(CY.STMT_RANGE);
+    }
+
+    public YRequireInstance getRequireInstance() {
+        return getChild(CY.STMT_REQUIRE_INSTANCE);
+    }
+
+    public List<YType> getTypes() {
+        return getChildren(CY.STMT_TYPE);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YTypedef.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YTypedef.java
new file mode 100644
index 0000000..7cee01f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YTypedef.java
@@ -0,0 +1,93 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YTypedef extends AbstractStatement {
+
+    public YTypedef(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public String getStatementIdentifier() {
+        return getTypedefName();
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_TYPEDEF;
+    }
+
+    public String getTypedefName() {
+        return domElement.getValue();
+    }
+
+    public YDefault getDefault() {
+        return getChild(CY.STMT_DEFAULT);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public YType getType() {
+        return getChild(CY.STMT_TYPE);
+    }
+
+    public YUnits getUnits() {
+        return getChild(CY.STMT_UNITS);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        validateIsYangIdentifier(context, getTypedefName());
+
+        /*
+         * The name of the typedef cannot be one of the built-in types, so check for that as well.
+         */
+        if (DataTypeHelper.isBuiltInType(getTypedefName())) {
+            context.addFinding(new Finding(this, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT,
+                    "The name of the typedef cannot be one of the built-in YANG data type names."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUnique.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUnique.java
new file mode 100644
index 0000000..e6d2857
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUnique.java
@@ -0,0 +1,48 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YUnique extends SimpleStatement {
+
+    public YUnique(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.TAG;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_UNIQUE;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUnits.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUnits.java
new file mode 100644
index 0000000..ad18b41
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUnits.java
@@ -0,0 +1,48 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YUnits extends SimpleStatement {
+
+    public YUnits(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_UNITS;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUses.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUses.java
new file mode 100644
index 0000000..6a98ff1
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YUses.java
@@ -0,0 +1,79 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YUses extends AbstractStatement {
+
+    public YUses(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.NAME;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_USES;
+    }
+
+    public String getUsesGroupingName() {
+        return domElement.getTrimmedValueOrEmpty();
+    }
+
+    public List<YAugment> getAugments() {
+        return getChildren(CY.STMT_AUGMENT);
+    }
+
+    public List<YIfFeature> getIfFeatures() {
+        return getChildren(CY.STMT_IF_FEATURE);
+    }
+
+    public List<YRefine> getRefines() {
+        return getChildren(CY.STMT_REFINE);
+    }
+
+    public YStatus getStatus() {
+        return getChild(CY.STMT_STATUS);
+    }
+
+    public YWhen getWhen() {
+        return getChild(CY.STMT_WHEN);
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentNotNullNotEmpty(context);
+        validateIsYangIdentifierReference(context, getUsesGroupingName());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YValue.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YValue.java
new file mode 100644
index 0000000..2d796c6
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YValue.java
@@ -0,0 +1,75 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YValue extends SimpleStatement {
+
+    public YValue(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_VALUE;
+    }
+
+    public int getEnumValue() {
+
+        try {
+            return Integer.parseInt(getValue());
+        } catch (final Exception ex) {
+            /* no-op */ }
+
+        return 0;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (!validateArgumentNotNullNotEmpty(context)) {
+            /* no point trying to perform more validation */
+            return;
+        }
+
+        try {
+            Integer.parseInt(getValue());
+        } catch (final Exception ex) {
+            context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                    "value '" + getValue() + "' not valid for value."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YWhen.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YWhen.java
new file mode 100644
index 0000000..29669ce
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YWhen.java
@@ -0,0 +1,68 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YWhen extends SimpleStatement {
+
+    private boolean appliesToParentSchemaNode = false;
+
+    public YWhen(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.CONDITION;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_WHEN;
+    }
+
+    public String getXpathExpression() {
+        return getValue();
+    }
+
+    public void setAppliesToParentSchemaNode() {
+        appliesToParentSchemaNode = true;
+    }
+
+    public boolean appliesToParentSchemaNode() {
+        return appliesToParentSchemaNode;
+    }
+
+    @Override
+    public void cloneFrom(final AbstractStatement orig) {
+        this.appliesToParentSchemaNode = ((YWhen) orig).appliesToParentSchemaNode;
+        super.cloneFrom(orig);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YYangVersion.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YYangVersion.java
new file mode 100644
index 0000000..f9af21a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YYangVersion.java
@@ -0,0 +1,68 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YYangVersion extends SimpleStatement {
+
+    public YYangVersion(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_YANG_VERSION;
+    }
+
+    public boolean is10Version() {
+        return "1".equals(getValue()) || "1.0".equals(getValue());		// being lenient here - 1.0 is really wrong...
+    }
+
+    public boolean is11Version() {
+        return "1.1".equals(getValue());
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        if (validateArgumentNotNullNotEmpty(context)) {
+            if (!is10Version() && !is11Version()) {
+                context.addFinding(new Finding(this, ParserFindingType.P053_INVALID_VALUE,
+                        "value '" + getValue() + "' not valid for yang-version."));
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YYinElement.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YYinElement.java
new file mode 100644
index 0000000..cff61b2
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YYinElement.java
@@ -0,0 +1,53 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.SimpleStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+/**
+ * Type-safe Yang core statement.
+ *
+ * @author Mark Hollmann
+ */
+public class YYinElement extends SimpleStatement {
+
+    public YYinElement(final AbstractStatement parentStatement, final YangDomElement domNode) {
+        super(parentStatement, domNode);
+    }
+
+    @Override
+    public StatementArgumentType getArgumentType() {
+        return StatementArgumentType.VALUE;
+    }
+
+    @Override
+    public StatementModuleAndName getStatementModuleAndName() {
+        return CY.STMT_YIN_ELEMENT;
+    }
+
+    protected void validate(final ParserExecutionContext context) {
+        validateArgumentIsTrueOrFalse(context);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YangCoreClassSupplier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YangCoreClassSupplier.java
new file mode 100644
index 0000000..517bde5
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/statements/yang/YangCoreClassSupplier.java
@@ -0,0 +1,49 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang;
+
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatementClassSupplier;
+
+/**
+ * Class supplier for core YANG statements.
+ *
+ * @author Mark Hollmann
+ */
+public class YangCoreClassSupplier extends AbstractStatementClassSupplier {
+
+    @Override
+    public Map<String, List<String>> getHandledStatements() {
+        return CY.HANDLED_STATEMENTS;
+    }
+
+    private static final String YANG_CORE_JAVA_PACKAGE = YModule.class.getPackage().getName();
+    private static final String YANG_CORE_JAVA_CLASS_PREFIX = "Y";
+
+    @Override
+    public <T extends AbstractStatement> Class<T> getJavaClazzForStatement(final String ignoredModuleName,
+            final String statementName) {
+        return getJavaClazzForStatement(YANG_CORE_JAVA_PACKAGE, YANG_CORE_JAVA_CLASS_PREFIX, statementName);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/DataTypeHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/DataTypeHelper.java
new file mode 100644
index 0000000..9a590ab
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/DataTypeHelper.java
@@ -0,0 +1,573 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YBit;
+import org.oran.smo.yangtools.parser.model.statements.yang.YEnum;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLength;
+import org.oran.smo.yangtools.parser.model.statements.yang.YPattern;
+import org.oran.smo.yangtools.parser.model.statements.yang.YPosition;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRange.BoundaryPair;
+import org.oran.smo.yangtools.parser.model.statements.yang.YType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YValue;
+
+/**
+ * Utility class handling data types.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class DataTypeHelper {
+
+    public static boolean isYangNumericType(final String dataType) {
+        return isYangNumericType(getYangDataType(dataType));
+    }
+
+    public static boolean isYangNumericType(final YangDataType yangDataType) {
+        return isYangIntegerType(yangDataType) || isYangDecimal64Type(yangDataType);
+    }
+
+    public static boolean isYangIntegerType(final String dataType) {
+        return isYangIntegerType(getYangDataType(dataType));
+    }
+
+    public static boolean isYangIntegerType(final YangDataType yangDataType) {
+        return isYangSignedIntegerType(yangDataType) || isYangUnsignedIntegerType(yangDataType);
+    }
+
+    public static boolean isYangSignedIntegerType(final String dataType) {
+        return isYangSignedIntegerType(getYangDataType(dataType));
+    }
+
+    public static boolean isYangSignedIntegerType(final YangDataType yangDataType) {
+        switch (yangDataType) {
+            case INT8:
+            case INT16:
+            case INT32:
+            case INT64:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    public static boolean isYangUnsignedIntegerType(final String dataType) {
+        return isYangUnsignedIntegerType(getYangDataType(dataType));
+    }
+
+    public static boolean isYangUnsignedIntegerType(final YangDataType yangDataType) {
+        switch (yangDataType) {
+            case UINT8:
+            case UINT16:
+            case UINT32:
+            case UINT64:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    public static boolean isYangDecimal64Type(final String dataType) {
+        return isYangDecimal64Type(getYangDataType(dataType));
+    }
+
+    public static boolean isYangDecimal64Type(final YangDataType yangDataType) {
+        return yangDataType == YangDataType.DECIMAL64;
+    }
+
+    /**
+     * Returns whether the datatype is one of the built-in YANG data types.
+     */
+    public static boolean isBuiltInType(final String dataType) {
+        return getYangDataType(dataType) != YangDataType.DERIVED____TYPE;
+    }
+
+    /**
+     * Returns whether the datatype is a derived type.
+     */
+    public static boolean isDerivedType(final String dataType) {
+        return getYangDataType(dataType) == YangDataType.DERIVED____TYPE;
+    }
+
+    public static boolean isUnionType(final String dataType) {
+        return isUnionType(getYangDataType(dataType));
+    }
+
+    public static boolean isUnionType(final YangDataType yangDataType) {
+        return yangDataType == YangDataType.UNION;
+    }
+
+    public static boolean isEmptyType(final String dataType) {
+        return isEmptyType(getYangDataType(dataType));
+    }
+
+    public static boolean isEmptyType(final YangDataType yangDataType) {
+        return yangDataType == YangDataType.EMPTY;
+    }
+
+    public static boolean isStringType(final String dataType) {
+        return isStringType(getYangDataType(dataType));
+    }
+
+    public static boolean isStringType(final YangDataType yangDataType) {
+        return yangDataType == YangDataType.STRING;
+    }
+
+    public static boolean isBinaryType(final String dataType) {
+        return isBinaryType(getYangDataType(dataType));
+    }
+
+    public static boolean isBinaryType(final YangDataType yangDataType) {
+        return yangDataType == YangDataType.BINARY;
+    }
+
+    /**
+     * Returns the YANG datatype, which can be one of the build-in data types, or a
+     * derived data type.
+     */
+    public static YangDataType getYangDataType(final String dataType) {
+
+        if (dataType.equals("instance-identifier")) {
+            return YangDataType.INSTANCE_IDENTIFIER;
+        }
+
+        if (dataType.contains(":")) {
+            return YangDataType.DERIVED____TYPE;
+        }
+
+        try {
+            return YangDataType.valueOf(dataType.toUpperCase());
+        } catch (final Exception ex) {
+            /* no-op */
+        }
+
+        /*
+         * Derived type being used without prefix. According to RFC this seems to be
+         * allowed...? Really?
+         */
+        return YangDataType.DERIVED____TYPE;
+    }
+
+    public enum YangDataType {
+        INT8,
+        INT16,
+        INT32,
+        INT64,
+        UINT8,
+        UINT16,
+        UINT32,
+        UINT64,
+        DECIMAL64,
+        STRING,
+        BOOLEAN,
+        ENUMERATION,
+        BITS,
+        BINARY,
+        LEAFREF,
+        IDENTITYREF,
+        EMPTY,
+        UNION,
+        INSTANCE_IDENTIFIER,
+        DERIVED____TYPE
+    }
+
+    /**
+     * Given a 'type' statement, computes the position for each of the bits within.
+     * The rules as outlined in chapter 9.7.4.2 of the RFC are applied.
+     * <p>
+     * This method allows a pre-defined mapping to be supplied. This may be used in
+     * a situation where a bits data type has been restricted, and the numeric
+     * position has to be used from the typedef where the bits have been defined.
+     * <p>
+     * The returned value maps bit names to their position value.
+     *
+     * @param predefinedMapping
+     *     may be null
+     */
+    public static Map<String, Long> calculatePositionOfBits(final FindingsManager findingsManager, final YType type,
+            final Map<String, Long> predefinedMapping) {
+
+        final Map<String, Long> result = new HashMap<>();
+
+        /*
+         * Calculate the numeric position of each bit in the type.
+         */
+        long nextImplicitBitPosition = 0;
+        for (final YBit bit : type.getBits()) {
+
+            final String bitName = bit.getBitName();
+
+            /*
+             * Position can be either explicit or implicit. If it is implicit, then it is
+             * "one higher than the previous value". If it is explicit, then there is a
+             * 'position' statement under the bit statement. If neither is the case, it will
+             * be taken from the predefined mapping, if possible.
+             */
+            Long positionOfThisBit = Long.valueOf(nextImplicitBitPosition);
+
+            if (bit.getPosition() != null) {
+                final YPosition yPosition = bit.getPosition();
+                positionOfThisBit = Long.valueOf(yPosition.getPosition());
+            } else if (predefinedMapping != null && predefinedMapping.containsKey(bitName)) {
+                positionOfThisBit = predefinedMapping.get(bitName);
+            }
+
+            if (positionOfThisBit.longValue() > YPosition.MAX_POSITION_VALUE && findingsManager != null) {
+                findingsManager.addFinding(new Finding(bit, ParserFindingType.P053_INVALID_VALUE,
+                        "bit position value larger than '" + YPosition.MAX_POSITION_VALUE + "'."));
+            }
+
+            if (result.containsValue(positionOfThisBit) && findingsManager != null) {
+                findingsManager.addFinding(new Finding(bit, ParserFindingType.P053_INVALID_VALUE,
+                        "Duplicate bit position value '" + positionOfThisBit + "'."));
+            }
+
+            result.put(bitName, positionOfThisBit);
+
+            nextImplicitBitPosition = positionOfThisBit.longValue() + 1;
+        }
+
+        return result;
+    }
+
+    /**
+     * Does the exact same thing as the previous method, but for data type
+     * enumeration.
+     *
+     * @param predefinedMapping
+     *     may be null
+     */
+    public static Map<String, Long> calculateValuesOfEnums(final FindingsManager findingsManager, final YType type,
+            final Map<String, Long> predefinedMapping) {
+
+        final Map<String, Long> result = new HashMap<>();
+
+        /*
+         * Calculate the numeric value of each enum in the type.
+         */
+        long nextImplicitEnumValue = 0;
+        for (final YEnum oneEnum : type.getEnums()) {
+
+            final String enumName = oneEnum.getEnumName();
+
+            /*
+             * Value can be either explicit or implicit. If it is implicit, then it is "one
+             * higher than the previous value". If it is explicit, then there is a 'value'
+             * statement under the enum statement. If neither is the case, it will be taken
+             * from the predefined mapping, if possible.
+             */
+            Long valueOfThisEnum = Long.valueOf(nextImplicitEnumValue);
+
+            if (oneEnum.getValue() != null) {
+                final YValue value = oneEnum.getValue();
+                valueOfThisEnum = Long.valueOf(value.getEnumValue());
+            } else if (predefinedMapping != null && predefinedMapping.containsKey(enumName)) {
+                valueOfThisEnum = predefinedMapping.get(enumName);
+            }
+
+            if ((valueOfThisEnum.longValue() < (long) Integer.MIN_VALUE || valueOfThisEnum
+                    .longValue() > (long) Integer.MAX_VALUE) && findingsManager != null) {
+                findingsManager.addFinding(new Finding(oneEnum, ParserFindingType.P053_INVALID_VALUE,
+                        "enum value outside allowed range."));
+            }
+
+            if (result.containsValue(valueOfThisEnum) && findingsManager != null) {
+                findingsManager.addFinding(new Finding(oneEnum, ParserFindingType.P053_INVALID_VALUE,
+                        "Duplicate enum value '" + valueOfThisEnum + "'."));
+            }
+
+            result.put(enumName, valueOfThisEnum);
+
+            nextImplicitEnumValue = valueOfThisEnum.longValue() + 1;
+        }
+
+        return result;
+    }
+
+    /**
+     * Given a value as string, is this value a valid value in respect of the
+     * non-union data type supplied, considering constraints?
+     */
+    public static boolean isStringefiedValueValid(final String stringefiedValue, final YType yType) {
+
+        final YangDataType yangDataType = DataTypeHelper.getYangDataType(yType.getDataType());
+
+        if (yangDataType == YangDataType.UNION) {
+            throw new RuntimeException("This method does not handle union.");
+        }
+
+        switch (yangDataType) {
+            case UINT8:
+            case UINT16:
+            case UINT32:
+            case UINT64:
+            case INT8:
+            case INT16:
+            case INT32:
+            case INT64:
+                return isValidIntegerValue(stringefiedValue, yType);
+            case DECIMAL64:
+                return isValidDecimalValue(stringefiedValue, yType);
+            case BOOLEAN:
+                return isValidBooleanValue(stringefiedValue, yType);
+            case ENUMERATION:
+                return isValidEnumerationValue(stringefiedValue, yType);
+            case BITS:
+                return isValidBitsValue(stringefiedValue, yType);
+            case STRING:
+                return isValidStringValue(stringefiedValue, yType);
+            case EMPTY:
+                return isValidEmptyValue(stringefiedValue, yType);
+            default:
+                break;
+        }
+
+        return true;
+    }
+
+    public static boolean isValidIntegerValue(final String stringefiedValue, final YType yType) {
+
+        if (stringefiedValue == null) {
+            return false;
+        }
+
+        final BigInteger integerValue = NumberHelper.getIntegerDefaultValue(stringefiedValue);
+        if (integerValue == null) {
+            return false;
+        }
+
+        if (!isIntegerValueCorrectInRespectOfSize(integerValue, yType)) {
+            return false;
+        }
+
+        return isIntegerValueCorrectInRespectOfConstrainedRange(integerValue, yType);
+    }
+
+    public static boolean isIntegerValueCorrectInRespectOfSize(final BigInteger integerValue, final YType yType) {
+
+        final YangDataType yangDataType = DataTypeHelper.getYangDataType(yType.getDataType());
+        final BigInteger integerMinValue = NumberHelper.getMinValueForYangIntegerDataType(yangDataType).toBigIntegerExact();
+        final BigInteger integerMaxValue = NumberHelper.getMaxValueForYangIntegerDataType(yangDataType).toBigIntegerExact();
+
+        return (integerValue.compareTo(integerMinValue) >= 0 && integerValue.compareTo(integerMaxValue) <= 0);
+    }
+
+    public static boolean isIntegerValueCorrectInRespectOfConstrainedRange(final BigInteger integerValue,
+            final YType yType) {
+
+        if (yType.getRange() == null) {
+            return true;
+        }
+
+        boolean withinOneOfTheBoundaries = false;
+        for (final BoundaryPair boundary : yType.getRange().getBoundaries()) {
+            if (integerValue.compareTo(boundary.lower.toBigIntegerExact()) >= 0 && integerValue.compareTo(boundary.upper
+                    .toBigIntegerExact()) <= 0) {
+                withinOneOfTheBoundaries = true;
+                break;
+            }
+        }
+        return withinOneOfTheBoundaries;
+    }
+
+    public static boolean isValidDecimalValue(final String stringefiedValue, final YType yType) {
+
+        if (stringefiedValue == null) {
+            return false;
+        }
+
+        if (yType.getFractionDigits() == null) {
+            /*
+             * We cannot ascertain if the default value is ok, as the fraction-digits
+             * statement is missing. That would have caused a separate finding anyway.
+             */
+            return true;
+        }
+
+        final BigDecimal decimalValue = NumberHelper.getDecimalValue(stringefiedValue);
+        if (decimalValue == null) {
+            return false;
+        }
+
+        if (!isDecimalValueCorrectInRespectOfSize(decimalValue, yType)) {
+            return false;
+        }
+
+        return isDecimalValueCorrectInRespectOfConstrainedRange(decimalValue, yType);
+    }
+
+    public static boolean isDecimalValueCorrectInRespectOfSize(final BigDecimal decimalValue, final YType yType) {
+
+        final int fractionDigits = yType.getFractionDigits().getFractionDigits();
+        final BigDecimal decimalMinValue = NumberHelper.getMinValueForYangDecimalDataType(fractionDigits);
+        final BigDecimal decimalMaxValue = NumberHelper.getMaxValueForYangDecimalDataType(fractionDigits);
+        if (decimalValue.compareTo(decimalMinValue) < 0 || decimalValue.compareTo(decimalMaxValue) > 0) {
+            return false;
+        }
+
+        return (decimalValue.stripTrailingZeros().scale() <= yType.getFractionDigits().getFractionDigits());
+    }
+
+    public static boolean isDecimalValueCorrectInRespectOfConstrainedRange(final BigDecimal decimalValue,
+            final YType yType) {
+
+        if (yType.getRange() == null) {
+            return true;
+        }
+
+        boolean withinOneOfTheBoundaries = false;
+        for (final BoundaryPair boundary : yType.getRange().getBoundaries()) {
+            if (decimalValue.compareTo(boundary.lower) >= 0 && decimalValue.compareTo(boundary.upper) <= 0) {
+                withinOneOfTheBoundaries = true;
+                break;
+            }
+        }
+
+        return withinOneOfTheBoundaries;
+    }
+
+    public static boolean isValidBooleanValue(final String stringefiedValue, final YType yType) {
+        return ("true".equals(stringefiedValue) || "false".equals(stringefiedValue));
+    }
+
+    public static boolean isValidEnumerationValue(final String stringefiedValue, final YType yType) {
+
+        if (stringefiedValue == null) {
+            return false;
+        }
+
+        return findEnum(stringefiedValue, yType) != null;
+    }
+
+    public static YEnum findEnum(final String stringefiedValue, final YType yType) {
+        for (final YEnum enumStatement : yType.getEnums()) {
+            if (enumStatement.getEnumName().equals(stringefiedValue)) {
+                return enumStatement;
+            }
+        }
+        return null;
+    }
+
+    public static boolean isValidBitsValue(final String stringefiedValue, final YType yType) {
+
+        if (stringefiedValue == null) {
+            return false;
+        }
+
+        if (!isBitsValueCorrectInRespectOfUniqueness(stringefiedValue, yType)) {
+            return false;
+        }
+
+        return isBitsValueCorrectInRespectOfNames(stringefiedValue, yType);
+    }
+
+    public static boolean isBitsValueCorrectInRespectOfUniqueness(final String stringefiedValue, final YType yType) {
+        final List<String> stringList = GrammarHelper.parseToStringList(stringefiedValue);
+        return stringList.size() == new HashSet<>(stringList).size();
+    }
+
+    public static boolean isBitsValueCorrectInRespectOfNames(final String stringefiedValue, final YType yType) {
+
+        final Set<String> bitsValue = new HashSet<>(GrammarHelper.parseToStringList(stringefiedValue));
+        final Set<String> bitNames = yType.getBits().stream().map(bit -> bit.getBitName()).collect(Collectors.toSet());
+
+        bitsValue.removeAll(bitNames);
+        return bitsValue.isEmpty();
+    }
+
+    private static boolean isValidStringValue(final String stringefiedValue, final YType yType) {
+
+        if (stringefiedValue == null) {
+            return false;
+        }
+
+        if (!isStringValueCorrectInRespectOfConstrainedLength(stringefiedValue, yType)) {
+            return false;
+        }
+
+        return isStringValueCorrectInRespectOfPatterns(stringefiedValue, yType);
+    }
+
+    public static boolean isStringValueCorrectInRespectOfConstrainedLength(final String stringValue, final YType yType) {
+
+        if (yType.getLength() == null) {
+            return true;
+        }
+
+        boolean withinOneOfTheBoundaries = false;
+        for (final YLength.BoundaryPair boundary : yType.getLength().getBoundaries()) {
+            if (stringValue.length() >= boundary.lower && stringValue.length() <= boundary.upper) {
+                withinOneOfTheBoundaries = true;
+                break;
+            }
+        }
+
+        return withinOneOfTheBoundaries;
+    }
+
+    private static final String COMPILED_PATTERN = "COMPILED_PATTERN";
+
+    public static boolean isStringValueCorrectInRespectOfPatterns(final String stringValue, final YType yType) {
+
+        for (final YPattern yPattern : yType.getPatterns()) {
+
+            try {
+                /*
+                 * Performance improvement to re-use a compiled pattern.
+                 */
+                Pattern compiledPattern = yPattern.getCustomAppData(COMPILED_PATTERN);
+                if (compiledPattern == null) {
+                    compiledPattern = Pattern.compile(yPattern.getPattern());
+                    yPattern.setCustomAppData(COMPILED_PATTERN, compiledPattern);
+                }
+
+                if (!compiledPattern.matcher(stringValue).matches()) {
+                    return false;
+                }
+            } catch (final PatternSyntaxException ignored) {
+                /* ignore - a finding would have been issued on this already */
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean isValidEmptyValue(final String stringefiedValue, final YType yType) {
+        /*
+         * An empty value is represented as empty element in XML when transferred
+         * over NETCONF, so we need to handle it.
+         */
+        return stringefiedValue == null || stringefiedValue.isEmpty();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/GrammarHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/GrammarHelper.java
new file mode 100644
index 0000000..da1234d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/GrammarHelper.java
@@ -0,0 +1,214 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Utility class to help with Yang grammar.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class GrammarHelper {
+
+    /**
+     * Returns whether the supplied string contains a white-space according to the RFC.
+     * White space characters are SPACE (0x20) and HORIZONTAL TAB (0x09).
+     */
+    public static boolean containsYangWhitespace(final String value) {
+        if (value == null || value.isEmpty()) {
+            return false;
+        }
+
+        for (int i = 0; i < value.length(); ++i) {
+            if (value.charAt(i) == 32 || value.charAt(i) == 9) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether the supplied string is a valid YANG identifier according to the RFC.
+     * <p>
+     * A valid identifier must:
+     * <p>
+     * Start with '_' or 'A-Z' or 'a-z'
+     * Followed by '_' or '-' or '.' or 'A-Z' or 'a-z' or '0-9'
+     * <p>
+     * Note especially that other unicode characters are not allowed, and that an identifier MUST NOT start with a digit.
+     */
+    public static boolean isYangIdentifier(final String stringToCheck) {
+
+        if (stringToCheck == null || stringToCheck.isEmpty()) {
+            return false;
+        }
+
+        final char firstChar = stringToCheck.charAt(0);
+        if (!firstCharacterOkForYangIdentifier(firstChar)) {
+            return false;
+        }
+
+        for (int i = 1; i < stringToCheck.length(); ++i) {
+            final char c = stringToCheck.charAt(i);
+            if (!otherCharacterOkForYangIdentifier(c)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean firstCharacterOkForYangIdentifier(final char c) {
+        return (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c == 95;			// A-Z a-z _
+    }
+
+    private static boolean otherCharacterOkForYangIdentifier(final char c) {
+        return (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || (c >= 48 && c <= 57) || c == '_' || c == '-' || c == '.';
+    }
+
+    /**
+     * Returns whether the supplied string is an identifier reference according to the RFC.
+     *
+     * An identifier is either prefix:identifier or just an identifier.
+     *
+     * The rules for prefix are the same as for identifier.
+     */
+    public static boolean isYangIdentifierReference(final String stringToCheck) {
+
+        if (stringToCheck == null || stringToCheck.isEmpty()) {
+            return false;
+        }
+
+        if (stringToCheck.charAt(0) == ':' || stringToCheck.charAt(stringToCheck.length() - 1) == ':') {
+            return false;
+        }
+
+        if (stringToCheck.contains(":")) {
+            final String[] split = stringToCheck.split(":");
+            if (split.length != 2) {
+                return false;
+            }
+            return isYangIdentifier(split[0]) && isYangIdentifier(split[1]);
+        } else {
+            return isYangIdentifier(stringToCheck);
+        }
+    }
+
+    /**
+     * Given a string containing white-space separated strings, extracts those. Typically used where an
+     * argument allows for a "space"-separated list of data node names, such as the 'key' or 'unique'
+     * statements.
+     * <p>
+     * The RFC is contradictory: In chapter 7.8.2 it says that leaf names are separated by "space character",
+     * but the official grammar definition in chapter 14 allows any whitespace (and line break). We err
+     * on the side of caution and align with the official grammar.
+     */
+    public static List<String> parseToStringList(final String value) {
+
+        if (value == null || value.trim().isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final char[] asChars = value.toCharArray();
+
+        if (!containsWhitespace(asChars)) {
+            return Collections.singletonList(value);
+        }
+
+        final List<String> result = new ArrayList<>();
+
+        StringBuilder sb = null;
+
+        for (final char c : asChars) {
+            if (sb != null) {
+                if (isWhitespace(c)) {						// end of a single string reached
+                    result.add(sb.toString());
+                    sb = null;
+                } else {
+                    sb.append(c);							// add to the single string
+                }
+            } else {
+                if (!isWhitespace(c)) {						// new string starts
+                    sb = new StringBuilder(20);
+                    sb.append(c);
+                }
+            }
+        }
+
+        if (sb != null) {					// value did not end with whitespace (it rarely does), so add remainder
+            result.add(sb.toString());
+        }
+
+        return result;
+    }
+
+    private static boolean containsWhitespace(final char[] chars) {
+        for (final char c : chars) {
+            if (isWhitespace(c)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isWhitespace(final char c) {
+        return (c == ' ' || c == '\t' || c == '\n');
+    }
+
+    /**
+     * Returns whether the supplied string can be legally used in YANG unquoted.
+     * <p>
+     * In general, any string can be expressed quoted, but for readability this is
+     * omitted where possible.
+     * <p>
+     * From the RFC:
+     *
+     * An unquoted string is any sequence of characters that does not contain any space,
+     * tab, carriage return, or line feed characters, a single or double quote character,
+     * a semicolon (";"), braces ("{" or "}"), or comment sequences (double-slash,
+     * slash-star, star-slash)
+     *
+     * Note that any keyword can legally appear as an unquoted string. Within an unquoted
+     * string, every character is preserved. Note that this means that the backslash
+     * character does not have any special meaning in an unquoted string.
+     */
+    public static boolean isUnquotableString(final String valueToCheck) {
+
+        if (valueToCheck.isEmpty()) {
+            return false;	// correct - empty string must always be represented as "" in YANG.
+        }
+
+        if (valueToCheck.contains("//") || valueToCheck.contains("/*") || valueToCheck.contains("*/")) {
+            return false;
+        }
+
+        for (final char c : valueToCheck.toCharArray()) {
+            if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\'' || c == '"' || c == ';' || c == '{' || c == '}' || c == '+') {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/NumberHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/NumberHelper.java
new file mode 100644
index 0000000..4b8ed60
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/NumberHelper.java
@@ -0,0 +1,205 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper.YangDataType;
+
+/**
+ * Utility class to deal with numbers in Yang.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class NumberHelper {
+
+    /*
+     * integer-value = ("-" non-negative-integer-value) / non-negative-integer-value
+     * non-negative-integer-value = "0" / positive-integer-value
+     * positive-integer-value = (non-zero-digit *DIGIT)
+     * non-zero-digit = %x31-39
+     * decimal-value = integer-value ("." zero-integer-value)
+     * zero-integer-value = 1*DIGIT
+     */
+
+    /**
+     * Extracts a decimal number representing a yang "integer-value" or "decimal-value". Note that a BigDecimal
+     * will be returned even if the underlying number is mathematically integer.
+     */
+    public static BigDecimal extractYangIntegerValueOrDecimalValue(final String string) {
+        return new BigDecimal(string);
+    }
+
+    public static final BigDecimal INT8_MIN_VALUE = new BigDecimal("-128");
+    public static final BigDecimal INT16_MIN_VALUE = new BigDecimal("-32768");
+    public static final BigDecimal INT32_MIN_VALUE = new BigDecimal("-2147483648");
+    public static final BigDecimal INT64_MIN_VALUE = new BigDecimal("-9223372036854775808");
+
+    public static final BigDecimal UINT8_MAX_VALUE = new BigDecimal("255");
+    public static final BigDecimal UINT16_MAX_VALUE = new BigDecimal("65535");
+    public static final BigDecimal UINT32_MAX_VALUE = new BigDecimal("4294967295");
+    public static final BigDecimal UINT64_MAX_VALUE = new BigDecimal("18446744073709551615");
+
+    public static final BigDecimal INT8_MAX_VALUE = new BigDecimal("127");
+    public static final BigDecimal INT16_MAX_VALUE = new BigDecimal("32767");
+    public static final BigDecimal INT32_MAX_VALUE = new BigDecimal("2147483647");
+    public static final BigDecimal INT64_MAX_VALUE = new BigDecimal("9223372036854775807");
+
+    public static BigDecimal getMinValueForYangIntegerDataType(final YangDataType yangDataType) {
+
+        switch (yangDataType) {
+            case UINT8:
+            case UINT16:
+            case UINT32:
+            case UINT64:
+                return BigDecimal.ZERO;
+            case INT8:
+                return INT8_MIN_VALUE;
+            case INT16:
+                return INT16_MIN_VALUE;
+            case INT32:
+                return INT32_MIN_VALUE;
+            case INT64:
+                return INT64_MIN_VALUE;
+            default:
+                throw new RuntimeException("Not an integer data type");
+        }
+    }
+
+    public static BigDecimal getMaxValueForYangIntegerDataType(final YangDataType yangDataType) {
+
+        switch (yangDataType) {
+            case UINT8:
+                return UINT8_MAX_VALUE;
+            case UINT16:
+                return UINT16_MAX_VALUE;
+            case UINT32:
+                return UINT32_MAX_VALUE;
+            case UINT64:
+                return UINT64_MAX_VALUE;
+            case INT8:
+                return INT8_MAX_VALUE;
+            case INT16:
+                return INT16_MAX_VALUE;
+            case INT32:
+                return INT32_MAX_VALUE;
+            case INT64:
+                return INT64_MAX_VALUE;
+            default:
+                throw new RuntimeException("Not an integer data type");
+        }
+    }
+
+    public static BigDecimal getMinValueForYangDecimalDataType(final int digits) {
+        return (digits >= 1 && digits <= 18) ?
+                new BigDecimal("-9223372036854775808").divide(BigDecimal.valueOf(10L).pow(digits)) :
+                null;
+    }
+
+    public static BigDecimal getMaxValueForYangDecimalDataType(final int digits) {
+        return (digits >= 1 && digits <= 18) ?
+                new BigDecimal("9223372036854775807").divide(BigDecimal.valueOf(10L).pow(digits)) :
+                null;
+    }
+
+    /**
+     * Returns the integer value (in a BigInteger) of a default value. Will return null
+     * if the supplied string cannot be translated to a BigInteger.
+     * <p>
+     * Special handling applies as follows (taken from the RFC):
+     * <p>
+     * "For convenience, when specifying a default value for an integer in a
+     * YANG module, an alternative lexical representation can be used that
+     * represents the value in a hexadecimal or octal notation. The
+     * hexadecimal notation consists of an optional sign ("+" or "-"),
+     * followed by the characters "0x", followed by a number of hexadecimal
+     * digits where letters may be uppercase or lowercase. The octal
+     * notation consists of an optional sign ("+" or "-"), followed by the
+     * character "0", followed by a number of octal digits.
+     * <p>
+     * Note that if a default value in a YANG module has a leading zero
+     * ("0"), it is interpreted as an octal number. In the XML encoding, an
+     * integer is always interpreted as a decimal number, and leading zeros
+     * are allowed."
+     */
+    public static BigInteger getIntegerDefaultValue(final String stringefiedValue) {
+
+        try {
+            if (stringefiedValue.equals("0") || stringefiedValue.equals("+0") || stringefiedValue.equals("-0")) {
+                return BigInteger.ZERO;
+            } else if (stringefiedValue.startsWith("-0x")) {
+                return new BigInteger(stringefiedValue.substring(3), 16).negate();
+            } else if (stringefiedValue.startsWith("+0x")) {
+                return new BigInteger(stringefiedValue.substring(3), 16);
+            } else if (stringefiedValue.startsWith("0x")) {
+                return new BigInteger(stringefiedValue.substring(2), 16);
+            } else if (stringefiedValue.startsWith("-0")) {
+                return new BigInteger(stringefiedValue.substring(2), 8).negate();
+            } else if (stringefiedValue.startsWith("+0")) {
+                return new BigInteger(stringefiedValue.substring(2), 8);
+            } else if (stringefiedValue.startsWith("0")) {
+                return new BigInteger(stringefiedValue.substring(1), 8);
+            }
+
+            return getIntegerValue(stringefiedValue);
+
+        } catch (final Exception ignored) {
+            /* no-op */
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the integer value (in a BigInteger) of a value. Will return null
+     * if the supplied string cannot be translated to a BigInteger.
+     * <p>
+     * Note that special default value handling is <b>not</b> applied by this
+     * method, i.e. a leading zero is interpreted as the number zero.
+     */
+    public static BigInteger getIntegerValue(final String stringefiedValue) {
+        try {
+            return new BigInteger(stringefiedValue);
+        } catch (final Exception ignored) {
+            /* no-op */
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the decimal value (in a BigDecimal) of a value. Will return null
+     * if the supplied string cannot be translated to a BigDecimal.
+     * <p>
+     * Note that special handling (as for integers above) does NOT apply for
+     * decimal values.
+     */
+    public static BigDecimal getDecimalValue(final String stringefiedValue) {
+        try {
+            return new BigDecimal(stringefiedValue);
+        } catch (final Exception ex) {
+            /* no-op */
+        }
+
+        return null;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/PatternHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/PatternHelper.java
new file mode 100644
index 0000000..1d76c39
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/PatternHelper.java
@@ -0,0 +1,106 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+public abstract class PatternHelper {
+
+    /**
+     * Does a basic translation of a YANG REGEX (which is of XML schema flavour) to a Java REGEX flavour.
+     * Does not handle category escape \p{X} or block escape \p{Is}
+     * <p/>
+     * See annex F of https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/
+     */
+    public static String toJavaPatternString(final String input) {
+
+        /*
+         * Notable differences between XSD REGEX syntax and Java REGEX syntax:
+         *
+         * The '^' and '$' are not used as head/tail anchors, so are interpreted as literals. But the ^ is
+         * used as negation in character classes.
+         *
+         * In XSD REGEX, meta-characters are either . \ ? * + { } ( ) [ ]
+         *
+         * All of these must be escaped with the backslash \ to use these as literals. The following must
+         * also be escaped to arrive at a literal:
+         *
+         * \n \r \t \\ \| \- \^
+         *
+         * Note that . refers to any character BUT NOT \n \r - this is markedly different from Java.
+         */
+
+        String result = cleanDollar(input);
+        result = cleanRoof(result);
+
+        /*
+         * We are not handling all of the category escape \p{X} or block escape \p{Is} - this is quite complex
+         * and so far these have never been seen in Yang 'pattern' statement.
+         */
+
+        return result;
+    }
+
+    protected static String cleanDollar(final String input) {
+
+        if (!input.contains("$")) {
+            return input;
+        }
+
+        /*
+         * The $ character has no special meaning in XSD REGEX syntax. It is a literal. It should never be encountered
+         * in escaped form in YANG.
+         *
+         * In Java, it denotes line-end - so we need to escape any $ character that we find to make it a literal.
+         */
+
+        return input.replace("$", "\\$");
+    }
+
+    protected static String cleanRoof(final String input) {
+
+        if (!input.contains("^")) {
+            return input;
+        }
+
+        /*
+         * The ^ character has special meaning in XSD REGEX syntax only inside character classes, for example:
+         *
+         * [^a-f]
+         *
+         * In all other cases, it is a literal.
+         *
+         * In Java, it is also used inside character classes, but is also used to denote line-start. So if we
+         * encounter the ^ character we escape it (unless at the start of a character class).
+         */
+
+        final StringBuilder sb = new StringBuilder(input.length());
+
+        for (int i = 0, len = input.length(); i < len; ++i) {
+            final char c = input.charAt(i);
+            if (c == '^' && (i == 0 || (i > 0 && input.charAt(i - 1) != '['))) {
+                sb.append("\\^");
+            } else {
+                sb.append(c);
+            }
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/StringHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/StringHelper.java
new file mode 100644
index 0000000..d947254
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/StringHelper.java
@@ -0,0 +1,111 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+
+/**
+ * Some utility methods used in various places, mostly for info texts.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class StringHelper {
+
+    public static String getModuleNameAndRevision(final String moduleName, final String revision) {
+
+        final StringBuilder sb = new StringBuilder();
+
+        sb.append("'");
+        sb.append(Objects.requireNonNull(moduleName));
+
+        if (revision != null && !revision.isEmpty()) {
+            sb.append('/');
+            sb.append(revision);
+        }
+        sb.append("'");
+
+        return sb.toString();
+    }
+
+    public static String getModuleLineString(final AbstractStatement statement) {
+
+        final StringBuilder sb = new StringBuilder();
+
+        if (statement.getDomElement().getYangModel().getYangModelRoot().isModule()) {
+            sb.append("module '");
+        } else {
+            sb.append("submodule '");
+        }
+
+        sb.append(statement.getDomElement().getYangModel().getYangModelRoot().getModuleOrSubModuleName());
+        sb.append("' (line ");
+        sb.append(statement.getDomElement().getLineNumber());
+        sb.append(')');
+
+        return sb.toString();
+    }
+
+    /**
+     * Utility to assemble from a collection a nicely formatted string based on some separation sequences.
+     * The order of elements will be taken from the collection iterator.
+     */
+    public static <T extends Object> String toString(final Collection<T> list, final String start, final String end,
+            final String elemSep, final String elemStart, final String elemEnd) {
+
+        final StringBuilder sb = new StringBuilder();
+
+        if (start != null) {
+            sb.append(start);
+        }
+
+        boolean first = true;
+        final Iterator<T> iter = list.iterator();
+
+        while (iter.hasNext()) {
+
+            if (!first && elemSep != null) {
+                sb.append(elemSep);
+            }
+
+            if (elemStart != null) {
+                sb.append(elemStart);
+            }
+
+            sb.append(iter.next().toString());
+
+            if (elemEnd != null) {
+                sb.append(elemEnd);
+            }
+
+            first = false;
+        }
+
+        if (end != null) {
+            sb.append(end);
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangAnnotation.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangAnnotation.java
new file mode 100644
index 0000000..8e03d91
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangAnnotation.java
@@ -0,0 +1,74 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+/**
+ * Denotes a single annotation declared in a module. The annotation has been declared in accordance with RFC 7952. It
+ * has special significance as it likely to become part of the YANG core language at some stage.
+ *
+ * @author Mark Hollmann
+ */
+public class YangAnnotation extends NamespaceModuleIdentifier {
+
+    public YangAnnotation(final String owningModuleNamespace, final String owningModule, final String annotationName) {
+        super(Objects.requireNonNull(owningModuleNamespace), Objects.requireNonNull(owningModule), Objects.requireNonNull(
+                annotationName));
+    }
+
+    /**
+     * The name of the annotation
+     */
+    public String getAnnotationName() {
+        return getIdentifier();
+    }
+
+    /**
+     * The module owning the annotation. If the annotation has been declared in a
+     * submodule, this is the name of the module that owns the submodule.
+     */
+    public String getAnnotationModuleName() {
+        return getModuleName();
+    }
+
+    /**
+     * The namespace of the module in which the annotation has been declared. If the
+     * annotation has been declared in a submodule, this is the namespace of the
+     * module that owns the submodule.
+     */
+    public String getAnnotationNamespace() {
+        return getNamespace();
+    }
+
+    @Override
+    public String toString() {
+        return "Annotation " + getAnnotationNamespace() + "/" + getAnnotationModuleName() + "/" + getAnnotationName();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+        return other != null && other.getClass().getName().equals(YangAnnotation.class.getName()) && this.toString().equals(
+                other.toString());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangFeature.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangFeature.java
new file mode 100644
index 0000000..25af84e
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangFeature.java
@@ -0,0 +1,73 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+/**
+ * Represents a YANG feature. An YANG feature is uniquely identified by its
+ * namespace / module name and identifier.
+ *
+ * @author Mark Hollmann
+ */
+public class YangFeature extends NamespaceModuleIdentifier {
+
+    public YangFeature(final String namespace, final String moduleName, final String identifier) {
+        super(Objects.requireNonNull(namespace), Objects.requireNonNull(moduleName), Objects.requireNonNull(identifier));
+    }
+
+    /**
+     * The name of the feature
+     */
+    public String getFeatureName() {
+        return getIdentifier();
+    }
+
+    /**
+     * The name of the module that owns the feature. If the feature has been
+     * declared in a submodule, this is the name of the module that owns the submodule.
+     */
+    public String getFeatureModuleName() {
+        return getIdentifier();
+    }
+
+    /**
+     * The namespace of the module in which the feature has been declared. If the
+     * feature has been declared in a submodule, this is the namespace of the
+     * module that owns the submodule.
+     */
+    public String getFeatureNamespace() {
+        return getNamespace();
+    }
+
+    @Override
+    public String toString() {
+        return "Feature " + getFeatureNamespace() + "/" + getFeatureModuleName() + "/" + getIdentifier();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+        return other != null && other.getClass().getName().equals(YangFeature.class.getName()) && this.toString().equals(
+                other.toString());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangIdentity.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangIdentity.java
new file mode 100644
index 0000000..b654d6f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/util/YangIdentity.java
@@ -0,0 +1,75 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+/**
+ * Represents a YANG identity. An YANG identity is uniquely identified by its
+ * namespace/module name and identifier. A YANG identity may have one or more "bases"
+ * ("super-identities") and/or may have 0..n derived identities.
+ *
+ * @author Mark Hollmann
+ */
+public class YangIdentity extends NamespaceModuleIdentifier {
+
+    public YangIdentity(final String namespace, final String moduleName, final String identifier) {
+        super(Objects.requireNonNull(namespace), Objects.requireNonNull(moduleName), Objects.requireNonNull(identifier));
+    }
+
+    /**
+     * The name of the identity
+     */
+    public String getIdentityName() {
+        return getIdentifier();
+    }
+
+    /**
+     * The name of the module in which the identity has been declared. If the
+     * identity has been declared in a submodule, this is the name of the
+     * module that owns the submodule.
+     */
+    public String getIdentityModuleName() {
+        return getModuleName();
+    }
+
+    /**
+     * The namespace of the module in which the identity has been declared. If the
+     * identity has been declared in a submodule, this is the namespace of the
+     * module that owns the submodule.
+     */
+    public String getIdentityNamespace() {
+        return getNamespace();
+    }
+
+    @Override
+    public String toString() {
+        return "Identity " + getNamespace() + "/" + getModuleName() + "/" + getIdentifier();
+    }
+
+    @Override
+    public boolean equals(final Object other) {
+        return other != null && other.getClass().getName().equals(YangIdentity.class.getName()) && this.toString().equals(
+                other.toString());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/DefaultOutputFileNameResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/DefaultOutputFileNameResolver.java
new file mode 100644
index 0000000..e9f2a65
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/DefaultOutputFileNameResolver.java
@@ -0,0 +1,51 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom;
+
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.YangModel;
+
+/**
+ * The default implementation returns as file name the concatenation of the module
+ * name and the module revision.
+ *
+ * @author Mark Hollmann
+ */
+public class DefaultOutputFileNameResolver implements OutputFileNameResolver {
+
+    @Override
+    public String getOutputFileNameForYangInput(final YangModel yangModel) {
+
+        final ModuleIdentity moduleIdentity = yangModel.getModuleIdentity();
+
+        final StringBuilder fileName = new StringBuilder(100);
+
+        fileName.append(moduleIdentity.getModuleName());
+        if (moduleIdentity.getRevision() != null) {
+            fileName.append('-');
+            fileName.append(moduleIdentity.getRevision());
+        }
+        fileName.append(".yang");
+
+        return fileName.toString();
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OriginalFileNameOutputFileNameResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OriginalFileNameOutputFileNameResolver.java
new file mode 100644
index 0000000..7b6b0af
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OriginalFileNameOutputFileNameResolver.java
@@ -0,0 +1,39 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom;
+
+import org.oran.smo.yangtools.parser.model.YangModel;
+
+/**
+ * This implementation returns as file name the original file used for the YANG input.
+ * Note that this only works if the original input was actually a file (as opposed to,
+ * for example, an stream).
+ *
+ * @author Mark Hollmann
+ */
+public class OriginalFileNameOutputFileNameResolver implements OutputFileNameResolver {
+
+    @Override
+    public String getOutputFileNameForYangInput(final YangModel yangModel) {
+        return yangModel.getYangInput().getFile().getName();
+    }
+
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OutputFileNameResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OutputFileNameResolver.java
new file mode 100644
index 0000000..421ebda
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OutputFileNameResolver.java
@@ -0,0 +1,37 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom;
+
+import org.oran.smo.yangtools.parser.model.YangModel;
+
+/**
+ * Implementations of this interface can resolve the name of the file that a DOM tree shall be written to.
+ *
+ * @author Mark Hollmann
+ */
+public interface OutputFileNameResolver {
+
+    /**
+     * Given the YANG input representing the original file, returns the name the file
+     * that the DOM tree for that YANG input shall be written-to.
+     */
+    String getOutputFileNameForYangInput(YangModel yangModel);
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OutputStreamResolver.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OutputStreamResolver.java
new file mode 100644
index 0000000..7aaf3ca
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/OutputStreamResolver.java
@@ -0,0 +1,42 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom;
+
+import java.io.OutputStream;
+
+import org.oran.smo.yangtools.parser.model.YangModel;
+
+/**
+ * Implementations of this interface can resolve an output stream into which the contents of a YANG DOM tree
+ * shall be written to.
+ *
+ * @author Mark Hollmann
+ */
+public interface OutputStreamResolver {
+
+    /**
+     * Given the YANG input representing the original input, returns an output stream into which the DOM
+     * tree for that YANG input shall be written-to.
+     * <p>
+     * It is the responsibility of the client to close the stream once done.
+     */
+    OutputStream getOutputStreamForYangInput(YangModel yangModel);
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomDocumentRoot.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomDocumentRoot.java
new file mode 100644
index 0000000..7e114af
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomDocumentRoot.java
@@ -0,0 +1,131 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.parser.Token;
+import org.oran.smo.yangtools.parser.model.parser.TokenIterator;
+import org.oran.smo.yangtools.parser.model.parser.Token.TokenType;
+import org.oran.smo.yangtools.parser.model.schema.Schema;
+
+/**
+ * Root element for a YANG DOM. Serves as entry point into the DOM and has no
+ * representation in the YAM.
+ * <p/>
+ * For compliant YAMs, will only ever have a single child DOM element (with a name
+ * of 'module' or 'submodule').
+ *
+ * @author Mark Hollmann
+ */
+public class YangDomDocumentRoot extends YangDomElement {
+
+    private final YangModel yangModel;
+
+    /**
+     * The schema that owns this YANG DOM.
+     */
+    private final Schema owningSchema;
+
+    /**
+     * Indicates that a change has been made to the DOM (perhaps due to modifications being made).
+     */
+    private boolean domModified;
+
+    public YangDomDocumentRoot(final YangModel yangModel, final Schema owningSchema) {
+        super("/", "/", null, 0);
+        this.yangModel = yangModel;
+        this.owningSchema = owningSchema;
+    }
+
+    @Override
+    public YangModel getYangModel() {
+        return yangModel;
+    }
+
+    public Schema getOwningSchema() {
+        return owningSchema;
+    }
+
+    public void setDomHasBeenModified() {
+        domModified = true;
+    }
+
+    public boolean domHasBeenModified() {
+        return domModified;
+    }
+
+    /**
+     * Processes the token stream and recursively builds the DOM tree.
+     */
+    @Override
+    public void processTokens(final ParserExecutionContext context, final TokenIterator iter) {
+        /*
+         * Document root is a special case. It does not start or end with a brace. The expected format is:
+         *
+         * <statement> <argument> { ... stuff ... }
+         *
+         * And the only statement there should ever be is a "module" or "sub-module" statement.
+         */
+
+        if (iter.done()) {
+            context.addFinding(new Finding(yangModel, ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
+                    "Document seems empty."));
+            return;
+        }
+
+        final Token token1 = iter.getToken(0);
+        final Token token2 = iter.getToken(1);
+        final Token token3 = iter.getToken(2);
+
+        if (token2 == null || token3 == null) {
+            context.addFinding(new Finding(yangModel, ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
+                    "Missing content at the beginning of the document."));
+            return;
+        }
+
+        if (!token1.value.equals("module") && !token1.value.equals("submodule")) {
+            context.addFinding(new Finding(yangModel, ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT,
+                    "Expected 'module' or 'submodule' at the beginning of the document."));
+            return;
+        }
+
+        if (token3.type == TokenType.LEFT_BRACE) {
+            final YangDomElement newYangDomNode = new YangDomElement(token1.value, token2.value, this, token1.lineNumber);
+            iter.advance(2);
+            newYangDomNode.processTokens(context, iter);
+        } else {
+            context.addFinding(new Finding(yangModel, token3.lineNumber,
+                    ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString(),
+                    "Expected opening brace '{' after (sub)module name."));
+            return;
+        }
+
+        if (!iter.done()) {
+            final Token leftoverToken = iter.getToken(0);
+            context.addFinding(new Finding(yangModel, leftoverToken.lineNumber,
+                    ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString(),
+                    "Unexpected content at end of document. Check curly braces balance throughout document."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomElement.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomElement.java
new file mode 100644
index 0000000..75bf88a
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomElement.java
@@ -0,0 +1,371 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ModulePrefixResolver;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.parser.Token;
+import org.oran.smo.yangtools.parser.model.parser.TokenIterator;
+import org.oran.smo.yangtools.parser.model.parser.Token.TokenType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+
+/**
+ * Represents a single schema node in the schema tree for a single YAM. Conceptually, a Yang DOM
+ * can be compared to an XML DOM; that is, a structured file is broken up into a tree-representation
+ * of the content.
+ * <p/>
+ * Every YANG statement is represented as DOM element. Every DOM element is comprised of two parts:
+ * the name and the value.
+ * <ul>
+ * <li>The name-part is always the name of a YANG statement. Where the statement is part of the core
+ * YANG language (as defined in RFC 7950) the name-part is simply the statement name (for example,
+ * "leaf-list"). Where the statement is <i>usage</i> of an extension (as opposed to the <i>definition</i>
+ * of an extension), the name-part is always a combination of a prefix and the name of the extension
+ * (for example, "md:annotation" (see RFC 7952)).</li>
+ * <li>The value-part depends on the statement; to be more precise, the semantics of the statement.
+ * Most core YANG language statements require an argument, and the value-part will be the argument value.
+ * For example, for a "leaf-list" statement, the value-part would be the name of the leaf-list (so,
+ * for a "leaf-list my-super-leaf-list" the value-part of the DOM element would be "my-super-leaf-list").
+ * However, not all statements support arguments (for example, the "input" statement), and for those
+ * the value-part will be null. Also, not all extensions support arguments, and for those the value-part
+ * will typically be null as well.</li>
+ * </ul>
+ *
+ * @author Mark Hollmann
+ */
+public class YangDomElement {
+
+    private final String name;
+    private final String value;		// possibly null
+    private String nameValue;
+
+    private final int lineNumber;
+
+    private YangDomElement parentElement;
+    private final List<YangDomElement> children = new ArrayList<>();
+
+    private final YangDomDocumentRoot documentRoot;
+
+    public YangDomElement(final String name, final String value, final YangDomElement parentElement, final int lineNumber) {
+        /*
+         * We intern the name. Saves quite a bit of memory.
+         */
+        this.name = name.intern();
+        this.value = value;
+        this.parentElement = parentElement;
+        this.lineNumber = lineNumber;
+
+        if (parentElement != null) {
+            parentElement.children.add(this);
+            this.documentRoot = parentElement.getDocumentRoot();
+        } else {
+            this.documentRoot = (YangDomDocumentRoot) this;
+        }
+    }
+
+    /**
+     * Returns the name of the statement. This will be the name of a statement part of the
+     * core YANG language, or the name of a prefixed extension.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the argument of the statement. The semantics of the returned value depend
+     * on the statement. May return null.
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Returns null if the value is null, otherwise the trimmed value.
+     */
+    public String getTrimmedValueOrNull() {
+        return value == null ? null : value.trim();
+    }
+
+    /**
+     * Returns empty string if the value is null, otherwise the trimmed value.
+     */
+    public String getTrimmedValueOrEmpty() {
+        return value == null ? "" : value.trim();
+    }
+
+    public String getNameValue() {
+
+        if (nameValue == null) {
+            final StringBuilder sb = new StringBuilder();
+
+            sb.append('\'');
+            sb.append(name);
+            if (value != null) {
+                sb.append(' ');
+                sb.append(value);
+            }
+            sb.append('\'');
+
+            nameValue = sb.toString();
+        }
+
+        return nameValue;
+    }
+
+    public YangDomElement getParentElement() {
+        return parentElement;
+    }
+
+    /**
+     * Returns the list of child DOM elements, in the order in which they are in the YAM.
+     * The returned must not be modified.
+     */
+    public List<YangDomElement> getChildren() {
+        return children;
+    }
+
+    public YangDomDocumentRoot getDocumentRoot() {
+        return documentRoot;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public YangModel getYangModel() {
+        return getDocumentRoot().getYangModel();
+    }
+
+    public ModulePrefixResolver getPrefixResolver() {
+        return getYangModel().getPrefixResolver();
+    }
+
+    /**
+     * The given DOM element is added as child to this element, and removed from its previous parent. This is typically
+     * done when injecting additional statements into the statement tree.
+     */
+    public void reparent(final YangDomElement childElement) {
+        if (childElement.parentElement != null) {
+            childElement.parentElement.children.remove(childElement);
+        }
+        this.children.add(childElement);
+        childElement.parentElement = this;
+    }
+
+    /**
+     * Removes this DOM element from under its parent. This in effect detaches the DOM element, and its complete
+     * sub-tree, from the parent.
+     */
+    public void remove() {
+        if (parentElement == null) {
+            return;
+        }
+
+        parentElement.children.remove(this);
+        parentElement = null;
+    }
+
+    /**
+     * Processes the token stream and recursively builds the DOM tree.
+     */
+    void processTokens(final ParserExecutionContext context, final TokenIterator iter) {
+
+        /*
+         * We are at the beginning of an element, hence there is a left-bracket to start. We don't
+         * need to explicitly check that, other code logic will makes sure that this method is
+         * invoked such that the next token is a left brace. We can safely skip it and advance
+         * the iterator.
+         */
+        iter.advance(1);
+
+        /*
+         * It's possible (though unlikely) that we have encountered a sequence "{}" - which
+         * doesn't really make sense, but we are nice about it and handle it leniently.
+         */
+        if (!iter.done() && iter.getToken(0).type == TokenType.RIGHT_BRACE) {
+            context.addFinding(new Finding(getYangModel(), iter.getToken(0).lineNumber,
+                    ParserFindingType.P055_SUPERFLUOUS_STATEMENT.toString(),
+                    "Encountered '{}', which does nothing. Replace with ';' or un-comment the contents."));
+            iter.advance(1);
+            return;
+        }
+
+        while (true) {
+
+            /*
+             * Wups - iterator exhausted? Thats wrong.
+             */
+            if (iter.done()) {
+                context.addFinding(new Finding(getYangModel(), ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END,
+                        "Unexpected end of document. A closing curly brace is probably missing."));
+                return;
+            }
+
+            final Token token1 = iter.getToken(0);
+
+            /*
+             * Are we at the end of this element, i.e have processed all statements
+             * underneath (denoted by closing curly brace)? Then exit out here.
+             */
+            if (token1.type == TokenType.RIGHT_BRACE) {
+                iter.advance(1);
+                return;
+            }
+
+            final Token token2 = iter.getToken(1);
+            final Token token3 = iter.getToken(2);
+
+            /**
+             * The following can be the case now (all valid):
+             *
+             * A.) <statement> <argument> ;
+             * B.) <statement> <argument> { ... stuff ... }
+             * C.) <statement> ;
+             * D.) <statement> { ... stuff ... }
+             * E.) ;
+             *
+             * We could also have this here (all invalid):
+             * F.) {
+             * G.) <statement> }
+             */
+            if (token1.type == TokenType.STRING && token2 != null && token2.type == TokenType.STRING && token3 != null && token3.type == TokenType.SEMI_COLON) {
+                /*
+                 * Case A) Simple statement with argument and finished with ; so no nesting. We consume all
+                 * three tokens.
+                 *
+                 * Example: "max-elements 100 ;"
+                 */
+                iter.advance(3);
+                new YangDomElement(token1.value, token2.value, this, token1.lineNumber);
+
+            } else if (token1.type == TokenType.STRING && token2 != null && token2.type == TokenType.STRING && token3 != null && token3.type == TokenType.LEFT_BRACE) {
+                /*
+                 * Case B) Statement and argument followed by curly opening braces. Only consume two tokens
+                 * (not the opening brace). Recurse down the tree.
+                 *
+                 * Example: "leaf my-leaf { type string; }"
+                 */
+                iter.advance(2);
+                final YangDomElement newYangDomElement = new YangDomElement(token1.value, token2.value, this,
+                        token1.lineNumber);
+                newYangDomElement.processTokens(context, iter);
+
+            } else if (token1.type == TokenType.STRING && token2 != null && token2.type == TokenType.SEMI_COLON) {
+                /*
+                 * Case C) Simple statement without argument, no nesting. We consume the two tokens.
+                 *
+                 * Example: "input ;"        (lame example, one wouldn't usually see this in a model...)
+                 */
+                iter.advance(2);
+                new YangDomElement(token1.value, null, this, token1.lineNumber);
+
+            } else if (token1.type == TokenType.STRING && token2 != null && token2.type == TokenType.LEFT_BRACE) {
+                /*
+                 * Case D) Statement only, followed by curly opening braces with more content. No argument
+                 * so we only consume first token only (not the opening brace). Recurse down the tree.
+                 *
+                 * Example: "input { leaf my-leaf { ... }}"
+                 */
+                iter.advance(1);
+                final YangDomElement newYangDomElement = new YangDomElement(token1.value, null, this, token1.lineNumber);
+                newYangDomElement.processTokens(context, iter);
+
+            } else if (token1.type == TokenType.SEMI_COLON) {
+                /*
+                 * Case E) - unnecessary semicolon, swallow it - technically it is invalid syntax,
+                 * but we are lenient.
+                 */
+                iter.advance(1);
+                context.addFinding(new Finding(getYangModel(), token1.lineNumber,
+                        ParserFindingType.P055_SUPERFLUOUS_STATEMENT.toString(), "The extra semicolon is unnecessary."));
+
+            } else if (token1.type == TokenType.LEFT_BRACE) {
+                /*
+                 * Case F) - unexpected left-brace - should not be here.
+                 */
+                iter.advance(1);
+                context.addFinding(new Finding(getYangModel(), token1.lineNumber,
+                        ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(), "Unexpected opening curly brace."));
+
+            } else {
+
+                context.addFinding(new Finding(getYangModel(), token1.lineNumber,
+                        ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                        "Unexpected content '" + token1.value + "'."));
+                return;
+            }
+        }
+    }
+
+    public String getSimplifiedPath() {
+        final StringBuilder sb = new StringBuilder(200);
+        prependPath(sb);
+        return sb.toString();
+    }
+
+    private void prependPath(final StringBuilder sb) {
+        if (!name.equals(CY.MODULE) && !name.equals(CY.SUBMODULE) && parentElement != null) {
+            parentElement.prependPath(sb);
+        }
+
+        sb.append('/');
+        sb.append(name);
+        if (value != null) {
+
+            sb.append('=');
+
+            final boolean isPath = name.equals(CY.AUGMENT) || name.equals(CY.DEVIATION) || name.equals(CY.USES) || name
+                    .equals(CY.WHEN) || name.equals(CY.MUST);
+            if (isPath) {
+                sb.append('(');
+                sb.append(value);
+                sb.append(')');
+            } else {
+                sb.append(value);
+            }
+        }
+    }
+
+    /*
+     * This is really not needed as it is the same as in Object - however, created to
+     * enforce that equality check always operates based on objects, and nothing else.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return (this == obj);
+    }
+
+    @Override
+    public String toString() {
+        return value == null ? name : name + " " + value;
+    }
+
+    @Override
+    public int hashCode() {
+        return getNameValue().hashCode();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomWriter.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomWriter.java
new file mode 100644
index 0000000..71256ab
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/model/yangdom/YangDomWriter.java
@@ -0,0 +1,175 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.util.GrammarHelper;
+
+/**
+ * Use this class to write out a Yang DOM to a file or output stream. This is typically used where
+ * a YAM is parsed into a DOM, the DOM is manipulated (for example, statements added or removed),
+ * and the result is written out again.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class YangDomWriter {
+
+    /**
+     * Writes the DOM into a file as denoted by the resolver.
+     */
+    public static void writeOut(final YangModel yangModel, final OutputFileNameResolver resolver,
+            final File targetDirectory) throws IOException {
+
+        final String fileName = resolver.getOutputFileNameForYangInput(yangModel);
+        final File outFile = new File(targetDirectory, fileName);
+        targetDirectory.mkdirs();
+        outFile.createNewFile();
+
+        final FileOutputStream fileOutputStream = new FileOutputStream(outFile);
+        writeOut(yangModel, fileOutputStream);
+        fileOutputStream.close();
+    }
+
+    /**
+     * Writes the DOM into an output stream as denoted by the resolver. Note the stream will
+     * not be automatically closed afterwards - it is up to the client to do so.
+     */
+    public static void writeOut(final YangModel yangModel, final OutputStreamResolver resolver) throws IOException {
+        final OutputStream outputStream = resolver.getOutputStreamForYangInput(yangModel);
+        writeOut(yangModel, outputStream);
+    }
+
+    /**
+     * Writes the DOM into an output stream, using UTF-8 character set.
+     */
+    public static void writeOut(final YangModel yangModel, final OutputStream outputStream) throws IOException {
+
+        final Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
+
+        final YangDomDocumentRoot domDocumentRoot = yangModel.getYangModelRoot().getDomDocumentRoot();
+        writeDomNode(writer, domDocumentRoot.getChildren().get(0), "");
+
+        writer.flush();
+        writer.close();
+    }
+
+    private static final Set<String> ADD_COMMENT_AT_END_FOR = new HashSet<>(Arrays.asList(CY.CONTAINER, CY.LIST,
+            CY.GROUPING));
+
+    private static void writeDomNode(final Writer writer, final YangDomElement domElement, final String indent)
+            throws IOException {
+
+        writer.write(indent);
+        writer.write(domElement.getName());
+
+        if (domElement.getValue() != null) {
+            writer.write(' ');
+            writeString(writer, domElement.getValue());
+        }
+
+        final List<YangDomElement> children = domElement.getChildren();
+        if (children.isEmpty()) {
+            writer.write(";\n");
+        } else {
+            writer.write(" {\n");
+            final String newIndent = indent + "  ";
+            for (final YangDomElement child : children) {
+                writeDomNode(writer, child, newIndent);
+            }
+            writer.write(indent);
+
+            if (ADD_COMMENT_AT_END_FOR.contains(domElement.getName())) {
+                writer.write("} // end '");
+                writer.write(domElement.getName());
+                writer.write(' ');
+                writer.write(domElement.getValue());
+                writer.write("'\n");
+            } else {
+                writer.write("}\n");
+            }
+        }
+    }
+
+    private static void writeString(final Writer writer, final String value) throws IOException {
+
+        if (GrammarHelper.isUnquotableString(value)) {
+            /*
+             * If there are no characters in the string that might need special handling we can simply write
+             * out the string. And no, we don't care about this stupid stipulation about wrapping at 80 characters.
+             */
+            writer.write(value);
+            return;
+        }
+
+        /*
+         * The string contains characters that must be escaped. Write as double-quoted string, with escaping
+         * where required.
+         */
+        writer.write(convertToDoubleQuotedString(value));
+    }
+
+    /**
+     * The supplied string is converted to a double-quoted string in accordance with the YANG rules.
+     */
+    private static String convertToDoubleQuotedString(final String input) {
+
+        final StringBuilder sb = new StringBuilder();
+
+        sb.append('"');
+
+        for (final char c : Objects.requireNonNull(input).toCharArray()) {
+            switch (c) {
+                case '\n':
+                    sb.append('\\').append('n');
+                    break;
+                case '\t':
+                    sb.append('\\').append('t');
+                    break;
+                case '"':
+                    sb.append('\\').append('"');
+                    break;
+                case '\\':
+                    sb.append('\\').append('\\');
+                    break;
+                default:
+                    sb.append(c);
+            }
+        }
+        sb.append('"');
+
+        return sb.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/InstanceIdentifier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/InstanceIdentifier.java
new file mode 100644
index 0000000..c200da1
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/InstanceIdentifier.java
@@ -0,0 +1,733 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+
+/**
+ * Represents instance-identifiers as specified in RFC7950, clause 9.13
+ *
+ * @author Mark Hollmann
+ */
+public class InstanceIdentifier {
+
+    /**
+     * Given an II encoded as specified in RFC7950, clause 9.13, returns the II. More specifically,
+     * each part of the II must have a prefix that is resolvable to a namespace given the supplied
+     * prefix resolver.
+     * <p/>
+     * Note especially this bit from the RFC: "All node names in an instance-identifier value MUST
+     * be qualified with explicit namespace prefixes, and these prefixes MUST be declared in the
+     * XML namespace scope in the instance-identifier's XML element."
+     * <p/>
+     * Since the input is XML, the module name for each step will remain unresolved. Use method
+     * resolveModuleOrNamespace() to resolve the module names for each step. Not doing so may cause
+     * problems when comparing II objects at a later stage.
+     * <p/>
+     * Will throw a RuntimeException if the syntax of the supplied string is wrong.
+     */
+    public static InstanceIdentifier parseXmlEncodedString(final String input, final PrefixResolver prefixResolver) {
+        return parseEncodedString(Objects.requireNonNull(input), Objects.requireNonNull(prefixResolver));
+    }
+
+    /**
+     * Given an II encoded as specified in RFC7951, clause 6.11, returns the II.
+     * <p/>
+     * Note especially this bit from the RFC: "The leftmost (top-level) data node
+     * name is always in the namespace-qualified form. Any subsequent data node
+     * name is in the namespace-qualified form if the node is defined in a module
+     * other than its parent node, and the simple form is used otherwise. This
+     * rule also holds for node names appearing in predicates."
+     * <p/>
+     * Since the input is JSON, the module namespace for each step will remain unresolved. Use method
+     * resolveModuleOrNamespace() to resolve the namespace for each step. Not doing so may cause
+     * problems when comparing II objects at a later stage.
+     * <p/>
+     * Will throw a RuntimeException if the syntax of the supplied string is wrong.
+     */
+    public static InstanceIdentifier parseJsonEncodedString(final String input) {
+        return parseEncodedString(Objects.requireNonNull(input), null);
+    }
+
+    /**
+     * Parses the supplied input string into an instance-identifier. If a prefix resolver
+     * is supplied, this method will assume that the source of the input was XML, and will
+     * treat data node prefixes as XML prefixes - otherwise, data node prefixes are assumed
+     * to be module names.
+     * <p/>
+     * Will throw a RuntimeException if the syntax of the supplied string is wrong.
+     */
+    public static InstanceIdentifier parseEncodedString(final String input, final PrefixResolver prefixResolver) {
+
+        try {
+            final List<IiXPathToken> tokens = tokenize(input);
+            final List<Step> steps = extractSteps(tokens, prefixResolver);
+            return new InstanceIdentifier(steps);
+        } catch (final IndexOutOfBoundsException ioobex) {
+            throw new RuntimeException(
+                    "Syntax error in input string. Check for incorrect syntax towards the end of the XPath expression, and missing brackets / quotes.");
+        }
+    }
+
+    private static List<Step> extractSteps(final List<IiXPathToken> tokens, final PrefixResolver prefixResolver) {
+
+        final List<Step> steps = new ArrayList<>();
+
+        /*
+         * Each part of the path is in the form:
+         *
+         * <slash><optional-prefix-and-colon><data-node-name><optional-predicate(s)>
+         */
+
+        int index = 0;
+        while (true) {
+
+            if (index == tokens.size()) {		// Nothing left to consume, we are done.
+                return steps;
+            }
+
+            if (tokens.get(index).type != IiXPathToken.Type.SLASH) {
+                throw new RuntimeException("Expected a slash at pos " + tokens.get(index).pos);
+            }
+
+            index++;
+
+            /*
+             * We extract the data node identifier. This will create a new Part object.
+             */
+            index = extractStepDataNodeIdentifier(tokens, index, prefixResolver, steps);
+
+            /*
+             * Extract the predicates, if any.
+             */
+            index = extractPredicates(tokens, index, prefixResolver, steps);
+        }
+    }
+
+    private static int extractStepDataNodeIdentifier(final List<IiXPathToken> tokens, final int index,
+            final PrefixResolver prefixResolver, final List<Step> steps) {
+
+        final NamespaceModuleIdentifier unprefixedName = getUnprefixedName(tokens, index, steps,
+                STEP_DATA_NODE_ALLOWED_TERMINATING_TOKENS);
+        final NamespaceModuleIdentifier prefixedName = unprefixedName != null ?
+                null :
+                getPrefixedName(tokens, index, prefixResolver, steps, STEP_DATA_NODE_ALLOWED_TERMINATING_TOKENS);
+
+        if (unprefixedName == null && prefixedName == null) {
+            throw new RuntimeException("Unresolvable data node name at pos " + tokens.get(index).pos);
+        }
+
+        steps.add(new Step(unprefixedName != null ? unprefixedName : prefixedName));
+
+        return index + (unprefixedName != null ? 1 : 3);
+    }
+
+    private static int extractPredicates(final List<IiXPathToken> tokens, int index, final PrefixResolver prefixResolver,
+            final List<Step> steps) {
+
+        /*
+         * A predicate may refer to:
+         *
+         * - A list entry, and the list is identified by one or more keys.
+         *   Example: /ex:system/ex:server[ex:ip='192.0.2.1'][ex:port='80']
+         *
+         * - A list entry, and the entry is identified by its position (since the list does not have keys):
+         *   Example: /ex:stats/ex:port[3]
+         *
+         * - A leaf-list entry, identified by value (since configurable leaf-lists must be unique).
+         *   Example: /ex:system/ex:services/ex:ssh/ex:cipher[.='blowfish-cbc']
+         *
+         * - A leaf-list entry, identified by position (since state leaf-lists may be non-unique).
+         *   Example: /ex:stats/ex:cpuLoad[3]
+         */
+
+        if (index == tokens.size()) {		// end of tokens
+            return index;
+        }
+        if (tokens.get(index).type != IiXPathToken.Type.SQUARE_BRACKET_OPEN) {		// there is no predicate
+            return index;
+        }
+
+        final Step step = steps.get(steps.size() - 1);
+
+        /*
+         * Figure out the kind of predicate - keys, value or position
+         */
+
+        if (tokens.get(index + 1).type == IiXPathToken.Type.UNQUOTED_STRING && tokens.get(
+                index + 2).type == IiXPathToken.Type.SQUARE_BRACKET_CLOSE) {
+            /*
+             * Position. The string must be parseable to an integer.
+             *
+             * NOTE that according to the XPath spec, position indexes start at 1, and not 0 as is customary in programming languages.
+             */
+            try {
+                final int pos = Integer.parseInt(tokens.get(index + 1).value);
+                if (pos < 1) {
+                    throw new RuntimeException("Position '" + pos + "' is illegal. Position must be larger/equal to 1.");
+                }
+                step.setPredicateListEntryOrLeafListMemberIndex(pos);
+                return index + 3;
+            } catch (final NumberFormatException nfex) {
+                throw new RuntimeException("Predicate '" + tokens.get(
+                        index + 1).value + "' not parseable to a position value.");
+            }
+        }
+
+        if (tokens.get(index + 1).type == IiXPathToken.Type.DOT && tokens.get(
+                index + 2).type == IiXPathToken.Type.EQUALS && (tokens.get(
+                        index + 3).type == IiXPathToken.Type.QUOTED_STRING || tokens.get(
+                                index + 3).type == IiXPathToken.Type.UNQUOTED_STRING) && tokens.get(
+                                        index + 4).type == IiXPathToken.Type.SQUARE_BRACKET_CLOSE) {
+            /*
+             * A value.
+             */
+            step.setPredicateLeafListMemberValue(tokens.get(index + 3).value);
+            return index + 5;
+        }
+
+        /*
+         * Must be one or more key values
+         */
+        while (true) {
+
+            if (index == tokens.size()) {		// end of tokens
+                return index;
+            }
+            if (tokens.get(index).type != IiXPathToken.Type.SQUARE_BRACKET_OPEN) {		// done with predicates
+                return index;
+            }
+
+            index++;		// consume the [
+
+            /*
+             * The data node may be prefixed or not...
+             */
+            final NamespaceModuleIdentifier unprefixedName = getUnprefixedName(tokens, index, steps,
+                    PREDICATE_DATA_NODE_ALLOWED_TERMINATING_TOKENS);
+            final NamespaceModuleIdentifier prefixedName = unprefixedName != null ?
+                    null :
+                    getPrefixedName(tokens, index, prefixResolver, steps, PREDICATE_DATA_NODE_ALLOWED_TERMINATING_TOKENS);
+
+            if (unprefixedName == null && prefixedName == null) {
+                throw new RuntimeException("Unresolvable data node name at pos " + tokens.get(index).pos);
+            }
+
+            index += (unprefixedName != null ? 1 : 3);		// consume the data node name
+
+            index++;		// consume the =    // note no need to check that the token is a =, as this is used as terminating token when extracting the data node name.
+
+            /*
+             * We are being lenient here. XPath spec says that LITERAL must be enclosed by single or double quotes.
+             * We will allow unquoted strings as well, as a lot of people will get this wrong. For the instance-identifier
+             * data type we can safely do this, as functions cannot be used inside an II.
+             */
+            if (tokens.get(index).type != IiXPathToken.Type.UNQUOTED_STRING && tokens.get(
+                    index).type != IiXPathToken.Type.QUOTED_STRING) {
+                throw new RuntimeException("Expected a single- or double-quoted string at pos " + tokens.get(index).pos);
+            }
+
+            final String stringefiedKeyValue = tokens.get(index).value;
+
+            step.addPredicateKeyValue(unprefixedName != null ? unprefixedName : prefixedName, stringefiedKeyValue);
+
+            index++;		// consume the value
+
+            if (tokens.get(index).type != IiXPathToken.Type.SQUARE_BRACKET_CLOSE) {
+                throw new RuntimeException("Expected a closing square brace ']' at pos " + tokens.get(index).pos);
+            }
+
+            index++;		// consume the ]
+        }
+    }
+
+    private static final List<IiXPathToken.Type> STEP_DATA_NODE_ALLOWED_TERMINATING_TOKENS = Arrays.asList(
+            IiXPathToken.Type.SQUARE_BRACKET_OPEN, IiXPathToken.Type.SLASH);
+    private static final List<IiXPathToken.Type> PREDICATE_DATA_NODE_ALLOWED_TERMINATING_TOKENS = Arrays.asList(
+            IiXPathToken.Type.EQUALS);
+
+    private static NamespaceModuleIdentifier getUnprefixedName(final List<IiXPathToken> tokens, final int index,
+            final List<Step> steps, final List<IiXPathToken.Type> allowedTerminatingToken) {
+
+        /*
+         * An unprefixed name simply has a name, followed by either nothing, or a predicate, or the next step.
+         */
+        final boolean unprefixedName = (tokens.get(
+                index).type == IiXPathToken.Type.UNQUOTED_STRING) && ((index + 1 == tokens
+                        .size()) || allowedTerminatingToken.contains(tokens.get(index + 1).type));
+        if (!unprefixedName) {
+            return null;
+        }
+
+        if (steps.isEmpty()) {
+            throw new RuntimeException("The first step of the path must have a prefix / module-name.");
+        }
+
+        final String dataNodeIdentifier = tokens.get(index).value;
+
+        /*
+         * We need to take the module name/namespace from the parent data node, i.e. the preceding step.
+         */
+        final NamespaceModuleIdentifier parentDataNodeNsmi = steps.get(steps.size() - 1).getDataNodeNsai();
+        return new NamespaceModuleIdentifier(parentDataNodeNsmi.getNamespace(), parentDataNodeNsmi.getModuleName(),
+                dataNodeIdentifier);
+    }
+
+    private static NamespaceModuleIdentifier getPrefixedName(final List<IiXPathToken> tokens, final int index,
+            final PrefixResolver prefixResolver, final List<Step> steps,
+            final List<IiXPathToken.Type> allowedTerminatingToken) {
+
+        /*
+         * An prefixed name is in the form <string><colon><string>, followed by either nothing, or a predicate, or the next step.
+         */
+        final boolean prefixedName = (tokens.get(index).type == IiXPathToken.Type.UNQUOTED_STRING) && (tokens.get(
+                index + 1).type == IiXPathToken.Type.COLON) && (tokens.get(
+                        index + 2).type == IiXPathToken.Type.UNQUOTED_STRING) && ((index + 3 == tokens
+                                .size()) || allowedTerminatingToken.contains(tokens.get(index + 3).type));
+        if (!prefixedName) {
+            return null;
+        }
+
+        final String prefixOrModuleName = tokens.get(index).value;
+        final String dataNodeIdentifier = tokens.get(index + 2).value;
+
+        /*
+         * The prefix can be either a module name (input was JSON) or an actual XML prefix (input was XML).
+         */
+        final String moduleName = prefixResolver == null ? prefixOrModuleName : null;
+        final String namespace = prefixResolver != null ? prefixResolver.resolveNamespaceUri(prefixOrModuleName) : null;
+
+        if (moduleName == null && namespace == null) {
+            throw new RuntimeException("Unresolvable prefix '" + prefixOrModuleName + "' at pos " + tokens.get(index).pos);
+        }
+
+        return new NamespaceModuleIdentifier(namespace, moduleName, dataNodeIdentifier);
+    }
+
+    /**
+     * A step in an Instance Identifier. A step is identified by a data node (itself identified through a
+     * module-name/namespace, and a data node identifier), and possibly a predicate.
+     */
+    public static class Step {
+
+        private final NamespaceModuleIdentifier nsai;
+
+        private Map<NamespaceModuleIdentifier, String> predicateKeyValues;
+
+        private String predicateLeafListMemberValue;
+
+        private Integer predicateListEntryOrLeafListMemberIndex;
+
+        public Step(final NamespaceModuleIdentifier nsai) {
+            this.nsai = Objects.requireNonNull(nsai);
+        }
+
+        /**
+         * Returns the NSAI of the data node. Note that depending on the input, either the module name or
+         * namespace may be null, unless resolved (see method resolveModuleOrNamespace() in InstanceIdentifier).
+         */
+        public NamespaceModuleIdentifier getDataNodeNsai() {
+            return nsai;
+        }
+
+        public Step addPredicateKeyValue(final NamespaceModuleIdentifier nsai, final String value) {
+            if (predicateLeafListMemberValue != null || predicateListEntryOrLeafListMemberIndex != null) {
+                throw new RuntimeException(
+                        "A step can only, at most, contain either: predicate(s), or leaf-list value, or list entry index.");
+            }
+
+            if (predicateKeyValues == null) {
+                predicateKeyValues = new HashMap<>();
+            }
+            predicateKeyValues.put(Objects.requireNonNull(nsai), Objects.requireNonNull(value));
+            return this;
+        }
+
+        /**
+         * Returns the predicate key values. Each predicate is identified by the data node NSAI, and a value.
+         * When comparing values, data conversion may have to be performed by a client. Note that depending
+         * on the input, either the module name or namespace of the data node NSAI may be null, unless
+         * resolved (see method resolveModuleOrNamespace() in InstanceIdentifier).
+         * <p>
+         * Returns null if there are no key values as predicate.
+         */
+        public Map<NamespaceModuleIdentifier, String> getPredicateKeyValues() {
+            return predicateKeyValues;
+        }
+
+        public Step setPredicateLeafListMemberValue(final String leafListMemberValue) {
+            if (predicateKeyValues != null || predicateListEntryOrLeafListMemberIndex != null) {
+                throw new RuntimeException(
+                        "A step can only, at most, contain either: predicate(s), or leaf-list value, or list entry index.");
+            }
+
+            this.predicateLeafListMemberValue = Objects.requireNonNull(leafListMemberValue);
+            return this;
+        }
+
+        /**
+         * Returns the value, if any, of a leaf-list member tested for as part of the predicate. When comparing
+         * values, data conversion may have to be performed by a client.
+         */
+        public String getPredicateLeafListMemberValue() {
+            return predicateLeafListMemberValue;
+        }
+
+        public Step setPredicateListEntryOrLeafListMemberIndex(final int listEntryOrLeafListMemberIndex) {
+            if (predicateLeafListMemberValue != null || predicateKeyValues != null) {
+                throw new RuntimeException(
+                        "A step can only, at most, contain either: predicate(s), or leaf-list value, or list entry index.");
+            }
+
+            if (listEntryOrLeafListMemberIndex < 1) {
+                throw new RuntimeException(
+                        "The index value must be >= 1 (in XPath, the index of the first element is 1, not 0).");
+            }
+
+            this.predicateListEntryOrLeafListMemberIndex = listEntryOrLeafListMemberIndex;
+            return this;
+        }
+
+        /**
+         * Returns the index, if any, of the list entry or leaf-list entry. Returns null if there is no
+         * index defined as part of the predicate.
+         * <p/>
+         * <b>NOTE that according to the XPath spec position indexes start at 1, and not 0 as is customary
+         * in programming languages.</b> When testing against arrays or lists in Java, the returned value
+         * must therefore be reduced by one.
+         */
+        public Integer getPredicateListEntryOrLeafListMemberIndex() {
+            return predicateListEntryOrLeafListMemberIndex;
+        }
+
+        public void resolveModuleOrNamespace(final ModuleAndNamespaceResolver namespaceResolver) {
+            nsai.resolveModuleOrNamespace(namespaceResolver);
+            if (predicateKeyValues != null) {
+                predicateKeyValues.keySet().forEach(k -> k.resolveModuleOrNamespace(namespaceResolver));
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return toString().hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Step)) {
+                return false;
+            }
+
+            final Step other = (Step) obj;
+
+            if (!this.nsai.equals(other.nsai)) {
+                return false;
+            }
+
+            if (!Objects.equals(this.predicateKeyValues, other.predicateKeyValues)) {
+                return false;
+            }
+
+            if (!Objects.equals(this.predicateLeafListMemberValue, other.predicateLeafListMemberValue)) {
+                return false;
+            }
+
+            return Objects.equals(this.predicateListEntryOrLeafListMemberIndex,
+                    other.predicateListEntryOrLeafListMemberIndex);
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("step node=").append(nsai);
+            if (predicateKeyValues != null) {
+                sb.append("; keys/values=").append(predicateKeyValues);
+            }
+            if (predicateLeafListMemberValue != null) {
+                sb.append("; value=").append(predicateLeafListMemberValue);
+            }
+            if (predicateListEntryOrLeafListMemberIndex != null) {
+                sb.append("; index=").append(predicateListEntryOrLeafListMemberIndex);
+            }
+            return sb.toString();
+        }
+    }
+
+    private static List<IiXPathToken> tokenize(final String s) {
+
+        final List<IiXPathToken> result = new ArrayList<>(50);
+
+        int charPos = 0;
+        char c;
+        while (charPos < s.length()) {
+
+            c = s.charAt(charPos);
+
+            switch (c) {
+                case '/':
+                    result.add(IiXPathToken.newSlash(charPos));
+                    break;
+                case ':':
+                    result.add(IiXPathToken.newColon(charPos));
+                    break;
+                case '[':
+                    result.add(IiXPathToken.newSquareBracketOpen(charPos));
+                    break;
+                case ']':
+                    result.add(IiXPathToken.newSquareBracketClose(charPos));
+                    break;
+                case '=':
+                    result.add(IiXPathToken.newEquals(charPos));
+                    break;
+                case '.':
+                    result.add(IiXPathToken.newDot(charPos));
+                    break;
+                case ' ':
+                case '\t':
+                    /*
+                     * We really don't expect whitespaces in the II, but according to XPath spec these are actually allowed.
+                     */
+                    break;
+                default:
+                    charPos = tokenizeExtractString(s, charPos, result);
+                    break;
+            }
+
+            charPos++;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the last character consumed.
+     */
+    private static int tokenizeExtractString(final String s, int charPos, final List<IiXPathToken> result) {
+
+        /*
+         * The production for LITERAL is quite clear in the XPath spec - it is either single-quoted-enclosed text,
+         * or double-quoted-enclosed text. No escaping is applied/allowed within the LITERAL.
+         *
+         * This method also extracts QNames, so we also allow unquoted strings. Different tokens are produced thus.
+         */
+
+        final boolean stringIsSingleQuoted = (s.charAt(charPos) == '\'');
+        final boolean stringIsDoubleQuoted = (s.charAt(charPos) == '"');
+
+        if (stringIsSingleQuoted || stringIsDoubleQuoted) {
+            charPos++;
+        }
+
+        char c;
+        final StringBuilder sb = new StringBuilder();
+
+        while (charPos < s.length()) {
+            c = s.charAt(charPos);
+
+            switch (c) {
+                case '\'':
+                    if (stringIsSingleQuoted) {									// Done. Swallow the trailing ' character
+                        result.add(IiXPathToken.newQuotedStringToken(charPos, sb.toString()));
+                        return charPos;
+                    }
+                    if (stringIsDoubleQuoted) {		// OK - single quote in double-quoted string.
+                        sb.append('\'');
+                    } else {
+                        throw new RuntimeException("Single quote character may not appear at position " + charPos);
+                    }
+                    break;
+                case '"':
+                    if (stringIsDoubleQuoted) {		// Done. Swallow the trailing " character
+                        result.add(IiXPathToken.newQuotedStringToken(charPos, sb.toString()));
+                        return charPos;
+                    }
+                    if (stringIsSingleQuoted) {		// OK - double quote in single-quoted string.
+                        sb.append('"');
+                    } else {
+                        throw new RuntimeException("Double quote character may not appear at position " + charPos);
+                    }
+                    break;
+                case ' ':
+                case '\t':
+                case '/':
+                case ':':
+                case '[':
+                case ']':
+                case '=':
+                case '.':
+                    if (stringIsSingleQuoted || stringIsDoubleQuoted) {
+                        sb.append(c);
+                    } else {
+                        /*
+                         * We are done here.
+                         */
+                        result.add(IiXPathToken.newUnquotedStringToken(charPos, sb.toString()));
+                        return charPos - 1;
+                    }
+                    break;
+                default:
+                    sb.append(c);
+                    break;
+            }
+
+            charPos++;
+        }
+
+        if (stringIsSingleQuoted || stringIsDoubleQuoted) {
+            throw new RuntimeException("Single/double-quoted string not correctly terminated.");
+        }
+
+        result.add(IiXPathToken.newUnquotedStringToken(charPos, sb.toString()));
+
+        return charPos;
+    }
+
+    private static class IiXPathToken {
+
+        private static IiXPathToken newSlash(final int pos) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.SLASH;
+            token.pos = pos;
+            token.value = "/";
+            return token;
+        }
+
+        private static IiXPathToken newColon(final int pos) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.COLON;
+            token.pos = pos;
+            token.value = ":";
+            return token;
+        }
+
+        private static IiXPathToken newSquareBracketOpen(final int pos) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.SQUARE_BRACKET_OPEN;
+            token.pos = pos;
+            token.value = "[";
+            return token;
+        }
+
+        private static IiXPathToken newSquareBracketClose(final int pos) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.SQUARE_BRACKET_CLOSE;
+            token.pos = pos;
+            token.value = "]";
+            return token;
+        }
+
+        private static IiXPathToken newEquals(final int pos) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.EQUALS;
+            token.pos = pos;
+            token.value = "=";
+            return token;
+        }
+
+        private static IiXPathToken newDot(final int pos) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.DOT;
+            token.pos = pos;
+            token.value = ".";
+            return token;
+        }
+
+        private static IiXPathToken newQuotedStringToken(final int pos, final String str) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.QUOTED_STRING;
+            token.pos = pos;
+            token.value = str;
+            return token;
+        }
+
+        private static IiXPathToken newUnquotedStringToken(final int pos, final String str) {
+            final IiXPathToken token = new IiXPathToken();
+            token.type = Type.UNQUOTED_STRING;
+            token.pos = pos;
+            token.value = str;
+            return token;
+        }
+
+        private Type type = null;
+        private int pos = 0;
+        private String value = null;
+
+        private IiXPathToken() {
+        }
+
+        private enum Type {
+            SLASH,
+            COLON,
+            SQUARE_BRACKET_OPEN,
+            SQUARE_BRACKET_CLOSE,
+            EQUALS,
+            DOT,
+            QUOTED_STRING,
+            UNQUOTED_STRING;
+        }
+    }
+
+    private final List<Step> steps;
+
+    public InstanceIdentifier(final List<Step> steps) {
+        this.steps = steps;
+    }
+
+    public List<Step> getSteps() {
+        return steps;
+    }
+
+    /**
+     * Depending on whether prefixes or module names were used as part of the II, the respective
+     * other may not have been resolved. Use this method to perform the resolution.
+     */
+    public void resolveModuleOrNamespace(final ModuleAndNamespaceResolver namespaceResolver) {
+        steps.forEach(s -> s.resolveModuleOrNamespace(namespaceResolver));
+    }
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof InstanceIdentifier)) {
+            return false;
+        }
+
+        final InstanceIdentifier other = (InstanceIdentifier) obj;
+        return this.steps.equals(other.steps);
+    }
+
+    @Override
+    public String toString() {
+        return "II " + steps.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/NamespaceModuleIdentifier.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/NamespaceModuleIdentifier.java
new file mode 100644
index 0000000..f735fbc
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/NamespaceModuleIdentifier.java
@@ -0,0 +1,115 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.util;
+
+import java.util.Objects;
+
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+
+/**
+ * A simple base class to encapsulate a namespace, module name and identifier. The class allows
+ * for either namespace or module-name to be supplied, as sometimes the respective other is not
+ * immediately available during processing. Method {@link resolveModuleOrNamespace} should be
+ * used to populate the respective other.
+ *
+ * @author Mark Hollmann
+ */
+public class NamespaceModuleIdentifier {
+
+    private String namespace;
+    private String moduleName;
+    private final String identifier;
+
+    /**
+     * Either namespace or module name should be supplied, and preferably both. There are valid usages
+     * where both can remain empty, so not enforcing this.
+     */
+    public NamespaceModuleIdentifier(final String namespace, final String moduleName, final String identifier) {
+        this.namespace = namespace;
+        this.moduleName = moduleName;
+        this.identifier = Objects.requireNonNull(identifier);
+    }
+
+    /**
+     * Returns the namespace, or null in case the namespace was not originally supplied and no resolution has been done yet.
+     */
+    public String getNamespace() {
+        return namespace;
+    }
+
+    /**
+     * Returns the module name, or null in case the module name was not originally supplied, and no resolution has been done
+     * yet.
+     */
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    /**
+     * Resolves the namespace or module name, as required.
+     */
+    public void resolveModuleOrNamespace(final ModuleAndNamespaceResolver resolver) {
+
+        if (moduleName == null && namespace != null) {
+            moduleName = resolver.getModuleForNamespace(namespace);
+        } else if (namespace == null && moduleName != null) {
+            namespace = resolver.getNamespaceForModule(moduleName);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return identifier.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return getNamespace() + "/" + getModuleName() + "/" + getIdentifier();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+
+        if (!(obj instanceof NamespaceModuleIdentifier)) {
+            return false;
+        }
+
+        final NamespaceModuleIdentifier other = (NamespaceModuleIdentifier) obj;
+
+        if (!this.identifier.equals(other.identifier)) {
+            return false;
+        }
+
+        if (this.moduleName != null && other.moduleName != null) {
+            return this.moduleName.equals(other.moduleName);
+        }
+
+        if (this.namespace != null && other.namespace != null) {
+            return this.namespace.equals(other.namespace);
+        }
+
+        return false;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/QNameHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/QNameHelper.java
new file mode 100644
index 0000000..bc1877d
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/QNameHelper.java
@@ -0,0 +1,63 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.util;
+
+import org.oran.smo.yangtools.parser.PrefixResolver;
+
+/**
+ * Utility class to handle QName.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class QNameHelper {
+
+    /**
+     * Returns whether the supplied qualified name has a prefix. A colon character ':' at the
+     * very beginning of the string (which would be an illegal QName) will cause false to be
+     * returned.
+     */
+    public static boolean hasPrefix(final String qName) {
+        return qName != null && qName.indexOf(':') > 0;
+    }
+
+    /**
+     * Given a QName, such as "foo:bar", extracts the prefix (here, "foo").
+     * <p/>
+     * If there is no prefix, PrefixResolver.NO_PREFIX will be returned. If this is not
+     * desirable, use hasPrefix() instead.
+     */
+    public static String extractPrefix(final String qName) {
+        /*
+         * Note that a colon at position 0 is likewise considered to denote "no prefix"
+         * (technically it is incorrect syntax).
+         */
+        final int indexOfColon = qName == null ? -1 : qName.indexOf(':');
+        return indexOfColon > 0 ? qName.substring(0, indexOfColon) : PrefixResolver.NO_PREFIX;
+    }
+
+    /**
+     * Given a QName, such as "foo:bar", extracts the name (here, "bar").
+     */
+    public static String extractName(final String qName) {
+        final int indexOfColon = qName == null ? -1 : qName.indexOf(':');
+        return indexOfColon > -1 ? qName.substring(indexOfColon + 1) : qName;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/StackTraceHelper.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/StackTraceHelper.java
new file mode 100644
index 0000000..d484da1
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/util/StackTraceHelper.java
@@ -0,0 +1,59 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Utility class for error handling - sometimes, if a model is really in bad shape,
+ * some NPEs may be thrown (or other exceptions) - this way the point in the code
+ * can be logged.
+ *
+ * @author Mark Hollmann
+ */
+public abstract class StackTraceHelper {
+
+    /**
+     * Returns the first few lines of the stacktrace attached to the exception in a string.
+     */
+    public static String getStackTraceInfo(final Exception ex) {
+
+        final StackTraceElement[] stackTraceElements = ex.getStackTrace();
+
+        if (stackTraceElements == null || stackTraceElements.length == 0) {
+            return "no stacktrace information available.";
+        }
+
+        final StringWriter stringWriter = new StringWriter();
+        final PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        final int framesToPrint = Math.min(stackTraceElements.length, 7);
+        for (int i = 0; i < framesToPrint; ++i) {
+            if (i > 0) {
+                printWriter.print(", ");
+            }
+            printWriter.print("[" + i + "] at " + stackTraceElements[i]);
+        }
+
+        return stringWriter.toString();
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Datastore.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Datastore.java
new file mode 100644
index 0000000..b792282
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Datastore.java
@@ -0,0 +1,131 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.oran.smo.yangtools.parser.data.util.IdentityRefValue;
+import org.oran.smo.yangtools.parser.model.util.YangFeature;
+
+/**
+ * Represents the "datastore" data node, part of a Yang Library.
+ * <p/>
+ * Does not have an explicit representation of the "schema" data node,
+ * which is simply an aggregation on "module-set" instances.
+ *
+ * @author Mark Hollmann
+ */
+public class Datastore {
+
+    /**
+     * The name of the module defined by RFC 8342 (https://datatracker.ietf.org/doc/html/rfc8342) - "Network Management
+     * Datastore Architecture"
+     */
+    public static final String IETF_DATASTORES_MODULE_NAME = "ietf-datastores";
+
+    /**
+     * The namespace of the module defined by RFC 8342
+     */
+    public static final String IETF_DATASTORES_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-datastores";
+
+    /**
+     * The identity of the "running" datastore, as defined by RFC 8342
+     */
+    public static final IdentityRefValue RUNNING_DATASTORE_IDENTITY = new IdentityRefValue(IETF_DATASTORES_NAMESPACE,
+            IETF_DATASTORES_MODULE_NAME, "running");
+
+    private final IdentityRefValue datastoreName;
+
+    private final String schemaName;
+
+    private final List<ModuleSet> moduleSets;
+
+    public Datastore(final IdentityRefValue datastoreName, final String schemaName, final List<ModuleSet> moduleSets) {
+        this.datastoreName = datastoreName;
+        this.schemaName = schemaName;
+        this.moduleSets = new ArrayList<>(moduleSets);
+    }
+
+    /**
+     * Returns the identity of the datastore.
+     */
+    public IdentityRefValue getDatastoreName() {
+        return datastoreName;
+    }
+
+    public String getSchemaName() {
+        return schemaName;
+    }
+
+    public List<ModuleSet> getModuleSets() {
+        return Collections.unmodifiableList(moduleSets);
+    }
+
+    /**
+     * Returns all IMPLEMENTING modules of this datastore, irrespective of the module-set in which they are.
+     */
+    public Set<Module> getImplementingModules() {
+        final Set<Module> modules = new HashSet<>();
+        moduleSets.forEach(ms -> modules.addAll(ms.getImplementingModules()));
+        return modules;
+    }
+
+    /**
+     * Returns all IMPORT-ONLY modules of this datastore, irrespective of the module-set in which they are.
+     */
+    public Set<Module> getImportOnlyModules() {
+        final Set<Module> modules = new HashSet<>();
+        moduleSets.forEach(ms -> modules.addAll(ms.getImportOnlyModules()));
+        return modules;
+    }
+
+    /**
+     * Returns all modules of this datastore, irrespective of the module-set in which they are.
+     */
+    public Set<Module> getAllModules() {
+        final Set<Module> allModules = new HashSet<>();
+        moduleSets.forEach(ms -> allModules.addAll(ms.getImplementingModules()));
+        moduleSets.forEach(ms -> allModules.addAll(ms.getImportOnlyModules()));
+        return allModules;
+    }
+
+    /**
+     * Returns the features supported by this datastore. This is a convenience method;
+     * the data is retrieved from the modules part of this datastore.
+     */
+    public Set<YangFeature> getSupportedFeatures() {
+
+        final Set<YangFeature> result = new HashSet<>();
+
+        getAllModules().forEach(module -> {
+            final String namespace = module.getNamespace();
+            module.getFeatures().forEach(featureName -> {
+                result.add(new YangFeature(namespace, module.getName(), featureName));
+            });
+        });
+
+        return result;
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/IetfYangLibraryParser.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/IetfYangLibraryParser.java
new file mode 100644
index 0000000..55095da
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/IetfYangLibraryParser.java
@@ -0,0 +1,521 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot.SourceDataType;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.data.util.IdentityRefValue;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.YangInputResolver;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+import org.oran.smo.yangtools.parser.yanglibrary.Module.IetfYangLibraryConformanceType;
+
+/**
+ * Parser for Yang Library instance data. Can handle both the "yang-library" and "modules-state" containers.
+ *
+ * @author Mark Hollmann
+ */
+public class IetfYangLibraryParser {
+
+    /**
+     * The module name for the yang-library module as defined in RFC 8525.
+     */
+    public static final String IETF_YANG_LIBRARY_MODULE_NAME = "ietf-yang-library";
+    /**
+     * The module namespace for the yang-library module as defined in RFC 8525.
+     */
+    public static final String IETF_YANG_LIBRARY_NAMESPACE = "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+
+    public static final String YANG_LIBRARY_MODULES_STATE = "modules-state";
+    public static final String YANG_LIBRARY_YANG_LIBRARY = "yang-library";
+
+    private final List<YangLibraryPopulator> populators;
+    private final FindingsManager findingsManager;
+    private final ParserExecutionContext context;
+
+    private static final ModuleAndNamespaceResolver RESOLVER = new ModuleAndNamespaceResolver();
+
+    static {
+        RESOLVER.recordModuleMapping(IETF_YANG_LIBRARY_MODULE_NAME, IETF_YANG_LIBRARY_NAMESPACE);
+        RESOLVER.recordNamespaceMapping(IETF_YANG_LIBRARY_NAMESPACE, IETF_YANG_LIBRARY_MODULE_NAME);
+
+        RESOLVER.recordModuleMapping(Datastore.IETF_DATASTORES_MODULE_NAME, Datastore.IETF_DATASTORES_NAMESPACE);
+        RESOLVER.recordNamespaceMapping(Datastore.IETF_DATASTORES_NAMESPACE, Datastore.IETF_DATASTORES_MODULE_NAME);
+    }
+
+    /**
+     * Creates a Yang Library parser using the default populator for RFC8525.
+     */
+    public IetfYangLibraryParser() {
+        this(Collections.singletonList(new RFC8525Populator()));
+    }
+
+    /**
+     * Creates a YL parser using the supplied populators. The client should make sure to supply a
+     * populator for extraction of core Yang Library data according to RFC8525.
+     */
+    public IetfYangLibraryParser(final List<YangLibraryPopulator> populators) {
+        this.populators = populators;
+
+        findingsManager = new FindingsManager(new ModifyableFindingSeverityCalculator());
+        context = new ParserExecutionContext(findingsManager);
+
+        context.setCheckModulesAgainstYangLibrary(false);
+    }
+
+    /**
+     * Returns the FindingsManager used during parsing. Issues encountered during parsing will be
+     * captured as Findings.
+     */
+    public FindingsManager getFindingsManager() {
+        return findingsManager;
+    }
+
+    /**
+     * Parses instance data into Yang Library instances. The supplied resolver must resolve to one or more
+     * data inputs (typically files containing XML or JSON data). All Yang Library instances encountered
+     * in the data will be extracted, not just the instance found at the top-level (ie., mount points are
+     * also handled).
+     * <p/>
+     * Yang library instance data using the (deprecated) "modules-state" will be converted to a corresponding
+     * representation of the "yang-library".
+     * <p/>
+     * Issues may be encountered during the parsing; after parsing, the findings manager should be inspected
+     * for any issues.
+     */
+    public List<YangLibrary> parseIntoYangLibraries(final YangInputResolver instanceDataInputResolver) {
+
+        findingsManager.clear();
+
+        final List<YangData> yangDatas = instanceDataInputResolver.getResolvedYangInput().stream().map(YangData::new)
+                .collect(Collectors.toList());
+
+        /*
+         * Parse in all of the data. The worst that can happen is that the XML or JSON is malformed, or that
+         * prefixes cannot be resolved.
+         */
+        for (final YangData yangData : yangDatas) {
+            yangData.parse(context);
+        }
+
+        if (!findingsManager.getAllFindings().isEmpty()) {
+            findingsManager.addFinding(new Finding(ParserFindingType.P000_UNSPECIFIED_ERROR,
+                    "There were findings during parsing of the YANG instance data that may have resulted in the YANG Library data not being populated correctly."));
+        }
+
+        /*
+         * We look at each input and try to find the relevant containers.
+         */
+        final List<YangLibrary> result = new ArrayList<>();
+
+        for (final YangData yangData : yangDatas) {
+            final YangDataDomDocumentRoot yangDataDomDocumentRoot = yangData.getYangDataDomDocumentRoot();
+            if (yangDataDomDocumentRoot != null) {
+                extractYangLibraryUnderDomNode(yangDataDomDocumentRoot, result);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Works like {@link parseIntoYangLibraries}, but uses the supplied data DOm as input of Yang Library data, and will
+     * only extract the top-level Yang Library instance (if any).
+     */
+    public static YangLibrary getTopLevelYangLibrary(final YangDataDomDocumentRoot dataDomDocumentRoot) {
+
+        final IetfYangLibraryParser yangLibraryParser = new IetfYangLibraryParser();
+        final List<YangLibrary> extractedYangLibraries = new ArrayList<>();
+        yangLibraryParser.extractYangLibraryUnderDomNode(dataDomDocumentRoot, extractedYangLibraries);
+
+        return YangLibrary.getTopLevelSchema(extractedYangLibraries);
+    }
+
+    /**
+     * Given a data DOM node (possibly being document root), tries to extract a YANG Library under the DOM node.
+     */
+    private void extractYangLibraryUnderDomNode(final YangDataDomNode domNode, List<YangLibrary> result) {
+
+        final ModulesState modulesStateInstance = createModulesStateBranch(domNode);
+        YangLibrary yangLibraryInstance = createYangLibraryBranch(domNode);
+
+        /*
+         * The modules-state is deprecated, so we translate to yang-library if needed. This
+         * allows a client to always operate on the yang-library without having to worry
+         * about the deprecated modules-state branch.
+         *
+         * Note we will never translate back from yang-library to modules-state, as this
+         * would require us to figure out which is the correct set of modules (looking
+         * at datastore and schema elements), which can be ambiguous - plus it is
+         * deprecated...
+         */
+        if (modulesStateInstance != null && yangLibraryInstance == null) {
+            yangLibraryInstance = translateModulesStateDataToYangLibraryData(modulesStateInstance);
+        }
+
+        if (yangLibraryInstance != null) {
+            result.add(yangLibraryInstance);
+        }
+
+        /*
+         * Recursively work down the DOM tree - the YANG library can conceivably be under a mount point
+         * further down the tree.
+         */
+        domNode.getChildren().forEach(child -> extractYangLibraryUnderDomNode(child, result));
+    }
+
+    private static YangLibrary translateModulesStateDataToYangLibraryData(final ModulesState modulesState) {
+
+        final YangLibrary yangLibraryInstance = new YangLibrary(modulesState.getMountPoint());
+        yangLibraryInstance.setContentId(modulesState.getModuleSetId());
+
+        final ModuleSet defaultModuleSet = new ModuleSet();
+        defaultModuleSet.setName("module-set-auto-generated-by-yang-library-parser");
+
+        for (final Module module : modulesState.getModules()) {
+            if (module.getConformanceType() == IetfYangLibraryConformanceType.IMPLEMENT) {
+                defaultModuleSet.addImplementingModule(module);
+            } else if (module.getConformanceType() == IetfYangLibraryConformanceType.IMPORT) {
+                defaultModuleSet.addImportOnlyModule(module);
+            }
+        }
+
+        yangLibraryInstance.addDatastore(new Datastore(Datastore.RUNNING_DATASTORE_IDENTITY,
+                "schema-auto-generated-by-yang-library-parser", Collections.singletonList(defaultModuleSet)));
+
+        return yangLibraryInstance;
+    }
+
+    // ============================= Modules state branch ========================================
+
+    private ModulesState createModulesStateBranch(final YangDataDomNode parentDomNode) {
+
+        final YangDataDomNode modulesStateDomNode = getDomChild(parentDomNode, YANG_LIBRARY_MODULES_STATE);
+
+        if (modulesStateDomNode != null) {
+            final ModulesState modulesState = new ModulesState(parentDomNode);
+            populateModulesState(modulesState, modulesStateDomNode);
+
+            /*
+             * The YANG model for RFC 7895 (modules-state) allows for semantic errors - for example, the
+             * same module, of different revisions, could be marked as IMPLEMENTING. This is likely to be
+             * causing problems for the client later on, so we do some validation here to try to catch
+             * these issues as early as possible.
+             */
+            validateModulesState(modulesState);
+
+            return modulesState;
+        }
+
+        return null;
+    }
+
+    private void populateModulesState(final ModulesState modulesState, final YangDataDomNode modulesStateDomNode) {
+
+        populators.forEach(pop -> pop.populateModulesState(context, modulesState, modulesStateDomNode));
+
+        for (final YangDataDomNode moduleChildDomNode : getDomChildren(modulesStateDomNode, "module")) {
+            final Module module = new Module();
+            modulesState.addModule(module);
+            populateModuleInModulesState(module, moduleChildDomNode);
+        }
+    }
+
+    private void populateModuleInModulesState(final Module module, final YangDataDomNode moduleDomNode) {
+
+        populators.forEach(pop -> pop.populateModuleInModulesState(context, module, moduleDomNode));
+
+        for (final YangDataDomNode submoduleDomNode : getDomChildren(moduleDomNode, "submodule")) {
+            final Submodule submodule = new Submodule();
+            module.addSubmodule(submodule);
+            populators.forEach(pop -> pop.populateSubmoduleInModulesState(context, submodule, submoduleDomNode));
+        }
+    }
+
+    private void validateModulesState(final ModulesState modulesState) {
+        validateModulesStateForConformanceType(modulesState);
+    }
+
+    private void validateModulesStateForConformanceType(final ModulesState modulesState) {
+        /*
+         * Couple basic rules:
+         *
+         * A correct enum value must be used for 'conformance-type'.
+         * The same module (by name) cannot have 'conformance-type implement'.
+         * There must be at least a single 'conformance-type implement'.
+         */
+        final Set<String> implementingModuleNames = new HashSet<>();
+        for (final Module module : modulesState.getModules()) {
+            if (module.getConformanceType() == IetfYangLibraryConformanceType.UNKNOWN) {
+                context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                        "Unknown conformance-type for module '" + module.getName() + "'."));
+            } else if (module.getConformanceType() == IetfYangLibraryConformanceType.IMPLEMENT) {
+                if (implementingModuleNames.contains(module.getName())) {
+                    context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                            "Module '" + module.getName() + "' listed more than once with conformance-type 'implement'."));
+                } else {
+                    implementingModuleNames.add(module.getName());
+                }
+            }
+        }
+
+        if (implementingModuleNames.isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                    "YANG library does not have at least a single module entry with conformance-type 'implement'."));
+        }
+    }
+
+    // ============================ YANG Library branch ======================================
+
+    private YangLibrary createYangLibraryBranch(final YangDataDomNode parentDomNode) {
+
+        try {
+            final YangDataDomNode yangLibraryDomNode = getDomChild(parentDomNode, YANG_LIBRARY_YANG_LIBRARY);
+            if (yangLibraryDomNode != null) {
+                final YangLibrary yangLibrary = new YangLibrary(parentDomNode);
+                populateYangLibrary(yangLibrary, yangLibraryDomNode);
+                return yangLibrary;
+            }
+        } catch (final Exception ex) {
+            context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                    "Incorrect YANG library."));
+        }
+
+        return null;
+    }
+
+    private void populateYangLibrary(final YangLibrary yangLibrary, final YangDataDomNode yangLibraryDomNode) {
+
+        populators.forEach(pop -> pop.populateYangLibrary(context, yangLibrary, yangLibraryDomNode));
+
+        final Map<String, ModuleSet> extractedModuleSets = new HashMap<>();
+
+        for (final YangDataDomNode moduleSetDomNode : getDomChildren(yangLibraryDomNode, "module-set")) {
+            final ModuleSet moduleSet = new ModuleSet();
+            populateModuleSet(moduleSet, moduleSetDomNode);
+            extractedModuleSets.put(moduleSet.getName(), moduleSet);
+        }
+
+        final Map<String, List<ModuleSet>> schemaToModuleSetMappings = getSchemaToModuleSetMappings(context,
+                extractedModuleSets, yangLibraryDomNode);
+
+        handleDatastoreElements(yangLibrary, schemaToModuleSetMappings, yangLibraryDomNode);
+    }
+
+    private void populateModuleSet(final ModuleSet moduleSet, final YangDataDomNode moduleSetDomNode) {
+
+        populators.forEach(pop -> pop.populateModuleSet(context, moduleSet, moduleSetDomNode));
+
+        for (final YangDataDomNode moduleDomNode : getDomChildren(moduleSetDomNode, "module")) {
+            final Module module = new Module();
+            moduleSet.addImplementingModule(module);
+            populateModuleInYangLibrary(module, moduleDomNode, Module.MODULE_IMPLEMENT);
+        }
+        for (final YangDataDomNode moduleDomNode : getDomChildren(moduleSetDomNode, "import-only-module")) {
+            final Module module = new Module();
+            moduleSet.addImportOnlyModule(module);
+            populateModuleInYangLibrary(module, moduleDomNode, Module.MODULE_IMPORT);
+        }
+    }
+
+    private void populateModuleInYangLibrary(final Module module, final YangDataDomNode moduleDomNode,
+            final String conformanceType) {
+
+        populators.forEach(pop -> pop.populateModuleInYangLibrary(context, module, moduleDomNode, conformanceType));
+
+        for (final YangDataDomNode submoduleDomNode : getDomChildren(moduleDomNode, "submodule")) {
+            final Submodule submodule = new Submodule();
+            module.addSubmodule(submodule);
+            populators.forEach(pop -> pop.populateSubmoduleInYangLibrary(context, submodule, submoduleDomNode));
+        }
+    }
+
+    /**
+     * Returns a mapping of schema name -to- list of module sets
+     */
+    private static Map<String, List<ModuleSet>> getSchemaToModuleSetMappings(final ParserExecutionContext context,
+            final Map<String, ModuleSet> extractedModuleSets, final YangDataDomNode yangLibraryDomNode) {
+
+        final Map<String, List<ModuleSet>> result = new HashMap<>();
+
+        for (final YangDataDomNode schemaDomNode : getDomChildren(yangLibraryDomNode, "schema")) {
+
+            final String schemaName = getValueOfChild(context, schemaDomNode, "name", "");
+            if (schemaName.isEmpty()) {
+                context.getFindingsManager().addFinding(new Finding(
+                        ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING, "Missing schema name."));
+            }
+
+            result.put(schemaName, new ArrayList<>());
+
+            final List<String> moduleSetNames = getValueOfChildren(context, schemaDomNode, "module-set");
+
+            for (final String moduleSetName : moduleSetNames) {
+                final ModuleSet moduleSet = extractedModuleSets.get(moduleSetName);
+                if (moduleSet != null) {
+                    result.get(schemaName).add(moduleSet);
+                } else {
+                    context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                            "schema '" + schemaName + "' refers to non-existing module-set '" + moduleSetName + "'."));
+                }
+            }
+        }
+
+        /*
+         * Special handling - sometimes whoever creates the Yang Library data forgets to use the "schema"
+         * data node. We are nice here and simply auto-generate one, assigning all the module-sets found.
+         */
+
+        if (result.isEmpty()) {
+            result.put("schema-auto-generated-by-yang-library-parser", new ArrayList<>(extractedModuleSets.values()));
+        }
+
+        return result;
+    }
+
+    private void handleDatastoreElements(final YangLibrary yangLibrary,
+            final Map<String, List<ModuleSet>> schemaToModuleSetMappings, final YangDataDomNode yangLibraryDomNode) {
+
+        for (final YangDataDomNode datastoreDomNode : getDomChildren(yangLibraryDomNode, "datastore")) {
+
+            IdentityRefValue datastoreIdentityRef = null;
+
+            final YangDataDomNode datastoreNameDomNode = getDomChild(datastoreDomNode, "name");
+            if (datastoreNameDomNode != null) {
+
+                final String datastoreIdentityRefAsString = Objects.toString(datastoreNameDomNode.getValue());
+
+                /*
+                 * The value of this leaf is an identity ref, e.g.:
+                 *
+                 * <datastore xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
+                 *     <name>ds:running</name>
+                 *     <schema>schema1</schema>
+                 * </datastore>
+                 *
+                 * ...or, in JSON...
+                 *
+                 * "ietf-yang-library:datastore" : [
+                 *   {
+                 *     "name" : "ietf-datastores:running",
+                 *     "schema" : "schema1"
+                 *   }
+                 * ]
+                 */
+
+                if (datastoreNameDomNode.getSourceDataType() == SourceDataType.XML) {
+                    datastoreIdentityRef = new IdentityRefValue(datastoreIdentityRefAsString, datastoreNameDomNode
+                            .getPrefixResolver(), datastoreNameDomNode.getNamespace());
+                } else {
+                    datastoreIdentityRef = new IdentityRefValue(datastoreIdentityRefAsString, datastoreNameDomNode
+                            .getNamespace());
+                }
+
+                /*
+                 * If the namespace is unknown (maybe the designer forgot to declare the namespace),
+                 * we will assume the namespace of the "ietf-datastores" module.
+                 */
+                if (datastoreIdentityRef.getIdentityNamespace() == null && datastoreIdentityRef
+                        .getIdentityModuleName() == null) {
+                    context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                            "Unresolvable/missing prefix/module for <datastore> name '" + datastoreIdentityRefAsString + "'."));
+                    datastoreIdentityRef = new IdentityRefValue(Datastore.IETF_DATASTORES_NAMESPACE,
+                            Datastore.IETF_DATASTORES_MODULE_NAME, datastoreIdentityRefAsString);
+                }
+
+            } else {
+                context.getFindingsManager().addFinding(new Finding(
+                        ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING, "Missing datastore name."));
+            }
+
+            final String schemaName = getValueOfChild(context, datastoreDomNode, "schema", "");
+            if (schemaName.isEmpty()) {
+                context.getFindingsManager().addFinding(new Finding(
+                        ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING,
+                        "Missing value for leaf 'schema' for datastore."));
+            }
+            if (!schemaToModuleSetMappings.containsKey(schemaName)) {
+                context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                        "datastore refers to non-existing schema '" + schemaName + "'."));
+            } else {
+                yangLibrary.addDatastore(new Datastore(datastoreIdentityRef, schemaName, schemaToModuleSetMappings.get(
+                        schemaName)));
+            }
+        }
+
+        /*
+         * Special handling: Designer did not specify a datastore in the YANG Library. If there is only a
+         * single schema we assume that this schema is the one to be used.
+         */
+        if (yangLibrary.getDatastores().isEmpty() && schemaToModuleSetMappings.size() == 1) {
+            final Entry<String, List<ModuleSet>> theOnlySchemaToModuleSetMappingEntry = schemaToModuleSetMappings.entrySet()
+                    .iterator().next();
+            yangLibrary.addDatastore(new Datastore(Datastore.RUNNING_DATASTORE_IDENTITY,
+                    theOnlySchemaToModuleSetMappingEntry.getKey(), theOnlySchemaToModuleSetMappingEntry.getValue()));
+        }
+    }
+
+    static YangDataDomNode getDomChild(final YangDataDomNode parentDomNode, final String soughtName) {
+        return parentDomNode.getChild(IETF_YANG_LIBRARY_NAMESPACE, IETF_YANG_LIBRARY_MODULE_NAME, soughtName);
+    }
+
+    static List<YangDataDomNode> getDomChildren(final YangDataDomNode parentDomNode, final String soughtName) {
+        return parentDomNode.getChildren(IETF_YANG_LIBRARY_NAMESPACE, IETF_YANG_LIBRARY_MODULE_NAME, soughtName);
+    }
+
+    static String getValueOfChild(final ParserExecutionContext context, final YangDataDomNode parentDomNode,
+            final String soughtName, final String defaultValue) {
+
+        final YangDataDomNode child = getDomChild(parentDomNode, soughtName);
+        final Object valueOfChild = child == null ? null : child.getValue();
+
+        if (valueOfChild != null && !(valueOfChild instanceof String)) {
+            context.getFindingsManager().addFinding(new Finding(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA,
+                    "Expected a string value for '" + soughtName + "'."));
+            return defaultValue;
+        }
+
+        return valueOfChild == null ? defaultValue : ((String) valueOfChild).trim();
+    }
+
+    static List<String> getValueOfChildren(final ParserExecutionContext context, final YangDataDomNode parentDomNode,
+            final String soughtName) {
+        return getDomChildren(parentDomNode, soughtName).stream().map(YangDataDomNode::getStringValue).collect(Collectors
+                .toList());
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Module.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Module.java
new file mode 100644
index 0000000..d392a26
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Module.java
@@ -0,0 +1,154 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+
+/**
+ * Represents the "module" data node as defined in RFC 8525.
+ *
+ * @author Mark Hollmann
+ */
+public class Module {
+
+    private String conformanceType = "";
+    private String name = "";
+    private String revision = "";
+    private String namespace = "";
+    private List<String> schemaLocations = Collections.<String> emptyList();
+    private List<Submodule> submodules = new ArrayList<>();
+    private List<String> features;
+    private List<String> deviatedByModuleNames;
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setRevision(final String revision) {
+        this.revision = revision;
+    }
+
+    /**
+     * Returns the revision of the module. If a revision has not been declared in the module (a very rare
+     * occurrence, but a valid scenario), returns null (not an empty string).
+     */
+    public String getRevision() {
+        return (revision == null || revision.isEmpty()) ? null : revision;
+    }
+
+    public ModuleIdentity getModuleIdentity() {
+        return new ModuleIdentity(getName(), getRevision());
+    }
+
+    public void setNamespace(final String namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setFeatures(final List<String> features) {
+        this.features = Collections.unmodifiableList(features);
+    }
+
+    /**
+     * Returns the list of features supported for this module.
+     */
+    public List<String> getFeatures() {
+        return features != null ? Collections.unmodifiableList(features) : Collections.<String> emptyList();
+    }
+
+    public void setSchemaLocations(final List<String> schemaLocations) {
+        this.schemaLocations = Collections.unmodifiableList(schemaLocations);
+    }
+
+    public List<String> getSchemaLocations() {
+        return Collections.unmodifiableList(schemaLocations);
+    }
+
+    public void addSubmodule(final Submodule submodule) {
+        submodules.add(submodule);
+    }
+
+    public List<Submodule> getSubmodules() {
+        return Collections.unmodifiableList(submodules);
+    }
+
+    public void setDeviatedByModuleNames(final List<String> deviatedByModuleNames) {
+        this.deviatedByModuleNames = new ArrayList<>(deviatedByModuleNames);
+    }
+
+    public List<String> getDeviatedByModuleNames() {
+        return deviatedByModuleNames != null ?
+                Collections.unmodifiableList(deviatedByModuleNames) :
+                Collections.<String> emptyList();
+    }
+
+    public void setConformanceType(final String conformanceType) {
+        this.conformanceType = conformanceType;
+    }
+
+    public static final String MODULE_IMPLEMENT = "implement";
+    public static final String MODULE_IMPORT = "import";
+
+    public IetfYangLibraryConformanceType getConformanceType() {
+        switch (conformanceType) {
+            case MODULE_IMPLEMENT:
+                return IetfYangLibraryConformanceType.IMPLEMENT;
+            case MODULE_IMPORT:
+                return IetfYangLibraryConformanceType.IMPORT;
+            default:
+        }
+
+        return IetfYangLibraryConformanceType.UNKNOWN;
+    }
+
+    public enum IetfYangLibraryConformanceType {
+        IMPLEMENT,
+        IMPORT,
+        UNKNOWN;
+    }
+
+    /*
+     * A utility mechanism that allows clients to attach application-specific data to this module.
+     */
+    private final Map<String, Object> appData = new HashMap<>();
+
+    public void setAppData(final String key, final Object data) {
+        appData.put(key, data);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getAppData(final String key) {
+        return (T) appData.get(key);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/ModuleSet.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/ModuleSet.java
new file mode 100644
index 0000000..80a0c26
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/ModuleSet.java
@@ -0,0 +1,61 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents the "module-set" data node as defined in RFC 8525.
+ *
+ * @author Mark Hollmann
+ */
+public class ModuleSet {
+
+    private String name = "";
+    private final List<Module> implementingModules = new ArrayList<>();
+    private final List<Module> importOnlyModules = new ArrayList<>();
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void addImplementingModule(final Module module) {
+        implementingModules.add(module);
+    }
+
+    public List<Module> getImplementingModules() {
+        return Collections.unmodifiableList(implementingModules);
+    }
+
+    public void addImportOnlyModule(final Module module) {
+        importOnlyModules.add(module);
+    }
+
+    public List<Module> getImportOnlyModules() {
+        return Collections.unmodifiableList(importOnlyModules);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/ModulesState.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/ModulesState.java
new file mode 100644
index 0000000..774f48f
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/ModulesState.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+
+/**
+ * Represents the (deprecated) "modules-state" data node as defined in RFC 8525
+ * (https://datatracker.ietf.org/doc/html/rfc8525)
+ * and as originally defined in RFC 7895.
+ *
+ * @author Mark Hollmann
+ */
+public class ModulesState {
+
+    private final YangDataDomNode mountPoint;
+
+    private String moduleSetId;
+    private List<Module> modules = new ArrayList<>();
+
+    public ModulesState(final YangDataDomNode mountPoint) {
+        this.mountPoint = mountPoint;
+    }
+
+    public YangDataDomNode getMountPoint() {
+        return mountPoint;
+    }
+
+    public void setModuleSetId(final String moduleSetId) {
+        this.moduleSetId = moduleSetId;
+    }
+
+    public String getModuleSetId() {
+        return moduleSetId;
+    }
+
+    public void addModule(final Module module) {
+        modules.add(module);
+    }
+
+    public List<Module> getModules() {
+        return Collections.unmodifiableList(modules);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/RFC8525Populator.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/RFC8525Populator.java
new file mode 100644
index 0000000..6509166
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/RFC8525Populator.java
@@ -0,0 +1,156 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.yanglibrary.Module.IetfYangLibraryConformanceType;
+
+/**
+ * A populater implementation that extracts data in accordance with RFC8525.
+ *
+ * @author Mark Hollmann
+ */
+public class RFC8525Populator implements YangLibraryPopulator {
+
+    @Override
+    public void populateModulesState(final ParserExecutionContext context, final ModulesState modulesState,
+            final YangDataDomNode modulesStateDomNode) {
+
+        modulesState.setModuleSetId(IetfYangLibraryParser.getValueOfChild(context, modulesStateDomNode, "module-set-id",
+                "---unspecified value---"));
+    }
+
+    @Override
+    public void populateModuleInModulesState(final ParserExecutionContext context, final Module module,
+            final YangDataDomNode moduleDomNode) {
+
+        module.setName(IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "name", ""));
+        module.setRevision(IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "revision", ""));
+        module.setNamespace(IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "namespace", ""));
+        module.setFeatures(IetfYangLibraryParser.getValueOfChildren(context, moduleDomNode, "feature"));
+        module.setConformanceType(IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "conformance-type", ""));
+
+        if (module.getName().isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(moduleDomNode,
+                    ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString(), "Missing module name."));
+        }
+        if (module.getNamespace().isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(moduleDomNode,
+                    ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString(), "Missing module namespace."));
+        }
+        if (module.getConformanceType() == IetfYangLibraryConformanceType.UNKNOWN) {
+            context.getFindingsManager().addFinding(new Finding(moduleDomNode,
+                    ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA.toString(),
+                    "missing / incorrect module conformance-type."));
+        }
+
+        final String schemaLocation = IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "schema", "");
+        if (schemaLocation != null && !schemaLocation.isEmpty()) {
+            module.setSchemaLocations(Collections.singletonList(schemaLocation));
+        }
+
+        final List<YangDataDomNode> deviationDomNodes = IetfYangLibraryParser.getDomChildren(moduleDomNode, "deviation");
+        module.setDeviatedByModuleNames(deviationDomNodes.stream().map(dli -> IetfYangLibraryParser.getValueOfChild(context,
+                dli, "name", "")).collect(Collectors.toList()));
+    }
+
+    @Override
+    public void populateSubmoduleInModulesState(final ParserExecutionContext context, final Submodule submodule,
+            final YangDataDomNode submoduleDomNode) {
+
+        submodule.setName(IetfYangLibraryParser.getValueOfChild(context, submoduleDomNode, "name", ""));
+        submodule.setRevision(IetfYangLibraryParser.getValueOfChild(context, submoduleDomNode, "revision", ""));
+
+        if (submodule.getName().isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(submoduleDomNode,
+                    ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString(), "Missing submodule name."));
+        }
+
+        final String subModuleSchemaLocation = IetfYangLibraryParser.getValueOfChild(context, submoduleDomNode, "schema",
+                "");
+        if (subModuleSchemaLocation != null && !subModuleSchemaLocation.isEmpty()) {
+            submodule.setSchemaLocations(Collections.singletonList(subModuleSchemaLocation));
+        }
+    }
+
+    @Override
+    public void populateYangLibrary(final ParserExecutionContext context, final YangLibrary yangLibrary,
+            final YangDataDomNode yangLibraryDomNode) {
+
+        yangLibrary.setContentId(IetfYangLibraryParser.getValueOfChild(context, yangLibraryDomNode, "content-id",
+                "---unspecified value---"));
+    }
+
+    @Override
+    public void populateModuleSet(final ParserExecutionContext context, final ModuleSet moduleSet,
+            final YangDataDomNode moduleSetDomNode) {
+
+        moduleSet.setName(IetfYangLibraryParser.getValueOfChild(context, moduleSetDomNode, "name", ""));
+        if (moduleSet.getName().isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(moduleSetDomNode,
+                    ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString(), "Missing module-set name."));
+        }
+    }
+
+    @Override
+    public void populateModuleInYangLibrary(final ParserExecutionContext context, final Module module,
+            final YangDataDomNode moduleDomNode, final String conformanceType) {
+
+        module.setName(IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "name", ""));
+        module.setRevision(IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "revision", ""));
+        module.setNamespace(IetfYangLibraryParser.getValueOfChild(context, moduleDomNode, "namespace", ""));
+        module.setSchemaLocations(IetfYangLibraryParser.getValueOfChildren(context, moduleDomNode, "location"));
+        module.setFeatures(IetfYangLibraryParser.getValueOfChildren(context, moduleDomNode, "feature"));
+        module.setConformanceType(conformanceType);
+
+        if (module.getName().isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(moduleDomNode,
+                    ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString(), "Missing module name."));
+        }
+        if (module.getNamespace().isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(moduleDomNode,
+                    ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString(), "Missing module namespace."));
+        }
+
+        module.setDeviatedByModuleNames(IetfYangLibraryParser.getValueOfChildren(context, moduleDomNode, "deviation"));
+    }
+
+    @Override
+    public void populateSubmoduleInYangLibrary(final ParserExecutionContext context, final Submodule submodule,
+            final YangDataDomNode submoduleDomNode) {
+
+        submodule.setName(IetfYangLibraryParser.getValueOfChild(context, submoduleDomNode, "name", ""));
+        submodule.setRevision(IetfYangLibraryParser.getValueOfChild(context, submoduleDomNode, "revision", ""));
+        submodule.setSchemaLocations(IetfYangLibraryParser.getValueOfChildren(context, submoduleDomNode, "location"));
+
+        if (submodule.getName().isEmpty()) {
+            context.getFindingsManager().addFinding(new Finding(submoduleDomNode,
+                    ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString(), "Missing submodule name."));
+        }
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Submodule.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Submodule.java
new file mode 100644
index 0000000..45e4dfa
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/Submodule.java
@@ -0,0 +1,86 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+
+/**
+ * Represents the "module" data node as defined in RFC 8525.
+ *
+ * @author Mark Hollmann
+ */
+public class Submodule {
+
+    private String name = "";
+    private String revision = "";
+    private List<String> schemaLocations = Collections.<String> emptyList();
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setRevision(final String revision) {
+        this.revision = revision;
+    }
+
+    /**
+     * Returns the revision of the submodule. If a revision has not been declared in the submodule (a
+     * very rare occurrence, but a valid scenario), returns null (not an empty string).
+     */
+    public String getRevision() {
+        return (revision == null || revision.isEmpty()) ? null : revision;
+    }
+
+    public ModuleIdentity getModuleIdentity() {
+        return new ModuleIdentity(getName(), getRevision());
+    }
+
+    public void setSchemaLocations(final List<String> schemaLocations) {
+        this.schemaLocations = Collections.unmodifiableList(schemaLocations);
+    }
+
+    public List<String> getSchemaLocations() {
+        return Collections.unmodifiableList(schemaLocations);
+    }
+
+    /*
+     * A utility mechanism that allows clients to attach application-specific data to this submodule.
+     */
+    private final Map<String, Object> appData = new HashMap<>();
+
+    public void setAppData(final String key, final Object data) {
+        appData.put(key, data);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getAppData(final String key) {
+        return (T) appData.get(key);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/YangLibrary.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/YangLibrary.java
new file mode 100644
index 0000000..38f88bc
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/YangLibrary.java
@@ -0,0 +1,118 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.data.util.IdentityRefValue;
+
+/**
+ * Represents an instance of a Yang Library as defined in RFC 8525 (https://datatracker.ietf.org/doc/html/rfc8525).
+ * <p/>
+ * Note that most servers are not using NMDA and will typically make use of the (deprecated) "modules-state"
+ * container. Also see {@link ModulesState} class.
+ *
+ * @author Mark Hollmann
+ */
+public class YangLibrary {
+
+    private String contentId = "";
+
+    private final List<Datastore> datastores = new ArrayList<>();
+
+    /**
+     * Denotes the point in the schema tree in which this YANG Library is mounted.
+     * This value may be null, denoting the top-level Yang Library.
+     */
+    private final YangDataDomNode mountPoint;
+
+    public YangLibrary(final YangDataDomNode mountPoint) {
+        this.mountPoint = mountPoint;
+    }
+
+    public String getContentId() {
+        return contentId;
+    }
+
+    public void setContentId(final String contentId) {
+        this.contentId = contentId;
+    }
+
+    public List<Datastore> getDatastores() {
+        return Collections.unmodifiableList(datastores);
+    }
+
+    public void addDatastore(final Datastore datastore) {
+        datastores.add(datastore);
+    }
+
+    /**
+     * Returns the point under which the library is mounted. May return null,
+     * indicating the top-level schema.
+     */
+    public YangDataDomNode getMountPoint() {
+        return mountPoint;
+    }
+
+    /**
+     * Returns whether this YANG Library describes the top-level schema;
+     * that is, the schema at the root of the schema tree.
+     */
+    public boolean containsTopLevelSchema() {
+        return mountPoint == null || mountPoint instanceof YangDataDomDocumentRoot;
+    }
+
+    /**
+     * Returns whether this YANG Library describes a mounted schema; that
+     * is, the schema has been mounted at some point in the schema tree
+     * (but not the root).
+     */
+    public boolean containsMountedSchema() {
+        return !containsTopLevelSchema();
+    }
+
+    /**
+     * Returns the "running" datastore. Returns null if no running datastore was
+     * found (this should not happen - servers must support the running datastore).
+     */
+    public Datastore getRunningDatastore() {
+        return getDatastore(Datastore.RUNNING_DATASTORE_IDENTITY);
+    }
+
+    /**
+     * Returns the specified datastore. Returns null if the datastore was not found.
+     */
+    public Datastore getDatastore(final IdentityRefValue identityRef) {
+        return datastores.stream().filter(ds -> identityRef.equals(ds.getDatastoreName())).findFirst().orElse(null);
+    }
+
+    /**
+     * Returns the top-level schema from among all the YANG Library instances supplied.
+     * Returns null if the top-level schema could not be found.
+     */
+    public static YangLibrary getTopLevelSchema(final List<YangLibrary> yangLibraries) {
+        return yangLibraries.stream().filter(YangLibrary::containsTopLevelSchema).findAny().orElse(null);
+    }
+}
diff --git a/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/YangLibraryPopulator.java b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/YangLibraryPopulator.java
new file mode 100644
index 0000000..6e4453e
--- /dev/null
+++ b/yang-parser/src/main/java/org/oran/smo/yangtools/parser/yanglibrary/YangLibraryPopulator.java
@@ -0,0 +1,89 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+
+/**
+ * Implementations of this interface will extract Yang Library-related data from data DOM nodes and
+ * populate various objects relating to yang library, eg. modules. Implementations are expected to
+ * not throw exceptions, but to add findings to the supplied context if errors are encountered.
+ * <p/>
+ * Clients will typically implement this interface if the Yang Library contains data in addition to
+ * what is defined in RFC 8525; for example, vendor-proprietary data relating to modules.
+ * <p/>
+ * A default implementation is provided in {@link RFC8525Populator} which handles all the data nodes
+ * as defined in RFC 8525.
+ *
+ * @author Mark Hollmann
+ */
+public interface YangLibraryPopulator {
+
+    /**
+     * Callback for population of the ModulesState object.
+     */
+    default void populateModulesState(final ParserExecutionContext context, final ModulesState modulesState,
+            final YangDataDomNode modulesStateDomNode) {
+    }
+
+    /**
+     * Callback for populating the Module object, from modules-state branch.
+     */
+    default void populateModuleInModulesState(final ParserExecutionContext context, final Module module,
+            final YangDataDomNode moduleDomNode) {
+    }
+
+    /**
+     * Callback for populating the Submodule object, from modules-state branch.
+     */
+    default void populateSubmoduleInModulesState(final ParserExecutionContext context, final Submodule submodule,
+            final YangDataDomNode submoduleDomNode) {
+    }
+
+    /**
+     * Callback for population of the YangLibrary object.
+     */
+    default void populateYangLibrary(final ParserExecutionContext context, final YangLibrary yangLibrary,
+            final YangDataDomNode yangLibraryDomNode) {
+    }
+
+    /**
+     * Callback for population of the ModuleSet object.
+     */
+    default void populateModuleSet(final ParserExecutionContext context, final ModuleSet moduleSet,
+            final YangDataDomNode moduleSetDomNode) {
+    }
+
+    /**
+     * Callback for populating the Module object, from yang-library branch.
+     */
+    default void populateModuleInYangLibrary(final ParserExecutionContext context, final Module module,
+            final YangDataDomNode moduleDomNode, final String conformanceType) {
+    }
+
+    /**
+     * Callback for populating the Submodule object, from yang-library branch.
+     */
+    default void populateSubmoduleInYangLibrary(final ParserExecutionContext context, final Submodule submodule,
+            final YangDataDomNode submoduleDomNode) {
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/JsonTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/JsonTest.java
new file mode 100644
index 0000000..01f34db
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/JsonTest.java
@@ -0,0 +1,423 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.dom.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNodeAnnotationValue;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class JsonTest extends YangTestCommon {
+
+    @Test
+    public void test_json_ok1() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_ok1.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+        assertNoFindings();
+
+        final YangDataDomDocumentRoot root = yangInstanceDataInput.getYangDataDomDocumentRoot();
+
+        final YangDataDomNode cont1 = getChildDataDomNode(root, "cont1");
+        assertTrue(cont1.getModuleName().equals("module1"));
+
+        final YangDataDomNode leaf11 = getChildDataDomNode(cont1, "leaf11");
+        assertTrue(leaf11.getModuleName().equals("module1"));
+        assertTrue(leaf11.getValue().equals(new String("hello")));
+
+        final YangDataDomNode leaf12 = getChildDataDomNode(cont1, "leaf12");
+        assertTrue(leaf12.getModuleName().equals("module1"));
+        assertTrue(leaf12.getValue().equals(new String("")));
+
+        final YangDataDomNode leaf13 = getChildDataDomNode(cont1, "leaf13");
+        assertTrue(leaf13.getValue() == null);
+
+        final YangDataDomNode leaf14 = getChildDataDomNode(cont1, "leaf14");
+        assertTrue(leaf14.getValue().equals(new Long(123)));
+
+        final YangDataDomNode leaf15 = getChildDataDomNode(cont1, "leaf15");
+        assertTrue(leaf15.getValue().equals(new Boolean(true)));
+
+        final YangDataDomNode leaf21index0 = getChildDataDomNode(cont1, "leaflist21", 0);
+        assertTrue(leaf21index0.getModuleName().equals("module1"));
+        assertTrue(leaf21index0.getValue().equals(new String("one")));
+
+        final YangDataDomNode leaf21index1 = getChildDataDomNode(cont1, "leaflist21", 1);
+        assertTrue(leaf21index1.getValue().equals(new String("two")));
+
+        final YangDataDomNode leaf22index0 = getChildDataDomNode(cont1, "leaflist22", 0);
+        assertTrue(leaf22index0.getValue().equals(new String("")));
+
+        final YangDataDomNode leaf22index1 = getChildDataDomNode(cont1, "leaflist22", 1);
+        assertTrue(leaf22index1.getValue() == null);
+
+        final YangDataDomNode leaf23index0 = getChildDataDomNode(cont1, "leaflist23", 0);
+        assertTrue(leaf23index0.getValue() == null);
+
+        final YangDataDomNode leaf23index1 = getChildDataDomNode(cont1, "leaflist23", 1);
+        assertTrue(leaf23index1.getValue().equals(new Boolean(true)));
+
+        final YangDataDomNode leaf24index0 = getChildDataDomNode(cont1, "leaflist24", 0);
+        assertTrue(leaf24index0.getValue().equals(new Long(10)));
+
+        final YangDataDomNode leaf24index1 = getChildDataDomNode(cont1, "leaflist24", 1);
+        assertTrue(leaf24index1.getValue().equals(new Long(-999)));
+
+        final YangDataDomNode leaf24index2 = getChildDataDomNode(cont1, "leaflist24", 2);
+        assertTrue(leaf24index2.getValue().equals(new Double(1234567890.123456)));
+
+        // =======================================
+
+        final YangDataDomNode cont2 = getChildDataDomNode(root, "cont2");
+        assertTrue(cont2.getModuleName().equals("module2"));
+
+        final YangDataDomNode leaf31 = getChildDataDomNode(cont2, "leaf31");
+        assertTrue(leaf31.getModuleName().equals("module2"));
+        assertTrue(leaf31.getValue().equals(new String("world")));
+
+        final YangDataDomNode leaf32 = getChildDataDomNode(cont2, "leaf32");
+        assertTrue(leaf32.getModuleName().equals("module99"));
+        assertTrue(leaf32.getValue().equals(new Boolean(false)));
+
+        final YangDataDomNode cont3 = getChildDataDomNode(cont2, "cont3");
+        assertTrue(cont3.getModuleName().equals("module2"));
+
+        final YangDataDomNode leaf33 = getChildDataDomNode(cont3, "leaf33");
+        assertTrue(leaf33.getValue() == null);
+
+        final YangDataDomNode leaflist34index0 = getChildDataDomNode(cont3, "leaflist34", 0);
+        assertTrue(leaflist34index0.getValue().equals(new String("one")));
+
+        final YangDataDomNode leaflist34index1 = getChildDataDomNode(cont3, "leaflist34", 1);
+        assertTrue(leaflist34index1.getValue().equals(new String("two")));
+
+        final YangDataDomNode leaflist35index0 = getChildDataDomNode(cont3, "leaflist35", 0);
+        assertTrue(leaflist35index0.getValue() == null);
+
+        final YangDataDomNode leaflist35index1 = getChildDataDomNode(cont3, "leaflist35", 1);
+        assertTrue(leaflist35index1.getValue().equals(new Boolean(true)));
+
+        // =======================================
+
+        final YangDataDomNode list5index0 = getChildDataDomNode(root, "list5", 0);
+        assertTrue(list5index0.getModuleName().equals("module5"));
+
+        final YangDataDomNode list5index0leaf51 = getChildDataDomNode(list5index0, "leaf51");
+        assertTrue(list5index0leaf51.getValue().equals(new Long(1234)));
+
+        final YangDataDomNode list5index0leaf52 = getChildDataDomNode(list5index0, "leaf52");
+        assertTrue(list5index0leaf52.getValue() == null);
+
+        final YangDataDomNode list5index0leaf53index0 = getChildDataDomNode(list5index0, "leaflist53", 0);
+        assertTrue(list5index0leaf53index0.getValue().equals(new Boolean(false)));
+
+        final YangDataDomNode list5index0leaf53index1 = getChildDataDomNode(list5index0, "leaflist53", 1);
+        assertTrue(list5index0leaf53index1.getValue().equals(new Boolean(true)));
+
+        final YangDataDomNode list5index1 = getChildDataDomNode(root, "list5", 1);
+        assertTrue(list5index1.getModuleName().equals("module5"));
+
+        final YangDataDomNode list5index1leaf51 = getChildDataDomNode(list5index1, "leaf51");
+        assertTrue(list5index1leaf51.getValue().equals(new Long(1235)));
+
+        final YangDataDomNode list5index1leaf52 = getChildDataDomNode(list5index1, "leaf52");
+        assertTrue(list5index1leaf52.getValue().equals(new String("hello")));
+
+        final YangDataDomNode list5index1leaf53index0 = getChildDataDomNode(list5index1, "leaflist53", 0);
+        assertTrue(list5index1leaf53index0.getValue().equals(new Boolean(false)));
+
+        final YangDataDomNode list5index1leaf53index1 = getChildDataDomNode(list5index1, "leaflist53", 1);
+        assertTrue(list5index1leaf53index1.getValue().equals(new Boolean(false)));
+    }
+
+    @Test
+    public void test_json_ok2() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_ok2.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+        assertNoFindings();
+
+        final YangDataDomDocumentRoot root = yangInstanceDataInput.getYangDataDomDocumentRoot();
+
+        final YangDataDomNode cont6 = getChildDataDomNode(root, "cont6");
+        assertTrue(cont6.getModuleName().equals("module6"));
+        assertTrue(cont6.getAnnotations().size() == 2);
+
+        final YangDataDomNodeAnnotationValue cont6anno1 = getDataDomNodeAnnotation(cont6, "anno1");
+        assertTrue(cont6anno1.getModuleName().equals("anno-module1"));
+        assertTrue(cont6anno1.getName().equals("anno1"));
+        assertTrue(cont6anno1.getValue().equals(new String("hello")));
+
+        final YangDataDomNodeAnnotationValue cont6anno2 = getDataDomNodeAnnotation(cont6, "anno2");
+        assertTrue(cont6anno2.getModuleName().equals("anno-module1"));
+        assertTrue(cont6anno2.getName().equals("anno2"));
+        assertTrue(cont6anno2.getValue().equals(new Long(12345)));
+
+        final YangDataDomNode leaf61 = getChildDataDomNode(cont6, "leaf61");
+        assertTrue(leaf61.getValue().equals(new String("hello")));
+        assertTrue(leaf61.getAnnotations().size() == 2);
+
+        final YangDataDomNodeAnnotationValue leaf61anno61 = getDataDomNodeAnnotation(leaf61, "anno61");
+        assertTrue(leaf61anno61.getModuleName().equals("anno-module6"));
+        assertTrue(leaf61anno61.getName().equals("anno61"));
+        assertTrue(leaf61anno61.getValue().equals(new Boolean(true)));
+
+        final YangDataDomNodeAnnotationValue leaf61anno62 = getDataDomNodeAnnotation(leaf61, "anno62");
+        assertTrue(leaf61anno62.getModuleName().equals("anno-module6"));
+        assertTrue(leaf61anno62.getName().equals("anno62"));
+        assertTrue(leaf61anno62.getValue() == null);
+
+        final YangDataDomNode leaf62 = getChildDataDomNode(cont6, "leaf62");
+        assertTrue(leaf62.getValue().equals(new String("")));
+        assertTrue(leaf62.getAnnotations().size() == 0);
+
+        final YangDataDomNode leaflist81Index0 = getChildDataDomNode(cont6, "leaflist81", 0);
+        assertTrue(leaflist81Index0.getValue().equals(new String("one")));
+        assertTrue(leaflist81Index0.getAnnotations().size() == 2);
+
+        final YangDataDomNodeAnnotationValue leaflist81Index0anno81 = getDataDomNodeAnnotation(leaflist81Index0, "anno81");
+        assertTrue(leaflist81Index0anno81.getModuleName().equals("anno-module8"));
+        assertTrue(leaflist81Index0anno81.getName().equals("anno81"));
+        assertTrue(leaflist81Index0anno81.getValue().equals(new Boolean(false)));
+
+        final YangDataDomNodeAnnotationValue leaflist81Index0anno82 = getDataDomNodeAnnotation(leaflist81Index0, "anno82");
+        assertTrue(leaflist81Index0anno82.getModuleName().equals("anno-module8"));
+        assertTrue(leaflist81Index0anno82.getName().equals("anno82"));
+        assertTrue(leaflist81Index0anno82.getValue().equals(new Long(-99987)));
+
+        final YangDataDomNode leaflist81Index1 = getChildDataDomNode(cont6, "leaflist81", 1);
+        assertTrue(leaflist81Index1.getValue().equals(new String("two")));
+        assertTrue(leaflist81Index1.getAnnotations().size() == 0);
+
+        final YangDataDomNode leaflist81Index2 = getChildDataDomNode(cont6, "leaflist81", 2);
+        assertTrue(leaflist81Index2.getValue().equals(new String("three")));
+        assertTrue(leaflist81Index2.getAnnotations().size() == 2);
+
+        final YangDataDomNodeAnnotationValue leaflist81Index2anno81 = getDataDomNodeAnnotation(leaflist81Index2, "anno81");
+        assertTrue(leaflist81Index2anno81.getModuleName().equals("anno-module8"));
+        assertTrue(leaflist81Index2anno81.getName().equals("anno81"));
+        assertTrue(leaflist81Index2anno81.getValue().equals(new Boolean(true)));
+
+        final YangDataDomNodeAnnotationValue leaflist81Index2anno82 = getDataDomNodeAnnotation(leaflist81Index2, "anno82");
+        assertTrue(leaflist81Index2anno82.getModuleName().equals("anno-module8"));
+        assertTrue(leaflist81Index2anno82.getName().equals("anno82"));
+        assertTrue(leaflist81Index2anno82.getValue().equals(new Double(12345678.12345678)));
+
+        final YangDataDomNode list7index0 = getChildDataDomNode(root, "list7", 0);
+        assertTrue(list7index0.getModuleName().equals("module7"));
+        assertTrue(list7index0.getAnnotations().size() == 2);
+
+        final YangDataDomNodeAnnotationValue list7index0anno71 = getDataDomNodeAnnotation(list7index0, "anno71");
+        assertTrue(list7index0anno71.getModuleName().equals("anno-module1"));
+        assertTrue(list7index0anno71.getName().equals("anno71"));
+        assertTrue(list7index0anno71.getValue().equals(new String("hello")));
+
+        final YangDataDomNodeAnnotationValue list7index0anno72 = getDataDomNodeAnnotation(list7index0, "anno72");
+        assertTrue(list7index0anno72.getModuleName().equals("anno-module2"));
+        assertTrue(list7index0anno72.getName().equals("anno72"));
+        assertTrue(list7index0anno72.getValue() == null);
+    }
+
+    @Test
+    public void test_json_error1_wrong_json_type_for_annotations_should_be_object() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error1.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString());
+    }
+
+    @Test
+    public void test_json_error2_wrong_json_types_in_array() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error2.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString());
+    }
+
+    @Test
+    public void test_json_error3_wrong_json_type_for_annotation_should_be_array() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error3.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString());
+    }
+
+    @Test
+    public void test_json_error4_wrong_json_type_for_annotation_should_be_array_of_objects() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error4.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P070_WRONG_JSON_VALUE_TYPE.toString());
+    }
+
+    @Test
+    public void test_json_error5_anno_array_too_large() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error5.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P069_UNEXPECTED_JSON_VALUE.toString());
+    }
+
+    @Test
+    public void test_json_error6_unknown_leaf() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error6.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P069_UNEXPECTED_JSON_VALUE.toString());
+    }
+
+    @Test
+    public void test_json_error7_unknown_leaf() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error7.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P069_UNEXPECTED_JSON_VALUE.toString());
+    }
+
+    @Test
+    public void test_json_error8_anno_member_has_no_module() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error8.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+    @Test
+    public void test_json_error9_missing_module_name() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_error9.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        yangInstanceDataInput.parse(context);
+
+        assertContextHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+    @Test
+    public void test_json_ok3() {
+
+        final File jsonFile = new File("src/test/resources/data-dom/json-test/json_ok3.json");
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        final ModuleAndNamespaceResolver namespaceResolver = new ModuleAndNamespaceResolver();
+        namespaceResolver.recordModuleMapping("module1", "ns1");
+        namespaceResolver.recordModuleMapping("module2", "ns2");
+        namespaceResolver.recordModuleMapping("module3", "ns3");
+        namespaceResolver.recordModuleMapping("module4", "ns4");
+        namespaceResolver.recordNamespaceMapping("ns1", "module1");
+        namespaceResolver.recordNamespaceMapping("ns2", "module2");
+        namespaceResolver.recordNamespaceMapping("ns3", "module3");
+        namespaceResolver.recordNamespaceMapping("ns4", "module4");
+
+        yangInstanceDataInput.parse(context);
+        yangInstanceDataInput.getYangDataDomDocumentRoot().resolveModuleOrNamespace(namespaceResolver);
+
+        assertNoFindings();
+
+        final YangDataDomDocumentRoot root = yangInstanceDataInput.getYangDataDomDocumentRoot();
+
+        final YangDataDomNode cont1 = getChildDataDomNode(root, "cont1");
+        assertTrue(cont1.getModuleName().equals("module1"));
+        assertTrue(cont1.getNamespace().equals("ns1"));
+        assertTrue(cont1.getAnnotations().size() == 2);
+
+        final YangDataDomNodeAnnotationValue cont1anno1 = getDataDomNodeAnnotation(cont1, "anno1");
+        assertTrue(cont1anno1.getModuleName().equals("module3"));
+        assertTrue(cont1anno1.getNamespace().equals("ns3"));
+        assertTrue(cont1anno1.getName().equals("anno1"));
+        assertTrue(cont1anno1.getValue().equals(new String("hello")));
+
+        final YangDataDomNodeAnnotationValue cont1anno2 = getDataDomNodeAnnotation(cont1, "anno2");
+        assertTrue(cont1anno2.getModuleName().equals("module4"));
+        assertTrue(cont1anno2.getNamespace().equals("ns4"));
+        assertTrue(cont1anno2.getName().equals("anno2"));
+        assertTrue(cont1anno2.getValue().equals(new Long(12345)));
+
+        final YangDataDomNode leaf11 = getChildDataDomNode(cont1, "leaf11");
+        assertTrue(leaf11.getModuleName().equals("module1"));
+        assertTrue(leaf11.getNamespace().equals("ns1"));
+        assertTrue(leaf11.getName().equals("leaf11"));
+        assertTrue(leaf11.getValue().equals(new String("hello")));
+
+        final YangDataDomNode leaf12 = getChildDataDomNode(cont1, "leaf12");
+        assertTrue(leaf12.getModuleName().equals("module2"));
+        assertTrue(leaf12.getNamespace().equals("ns2"));
+        assertTrue(leaf12.getName().equals("leaf12"));
+        assertTrue(leaf12.getValue().equals(new String("")));
+
+        final YangDataDomNode leaflist5Index0 = getChildDataDomNode(cont1, "leaflist5", 0);
+        assertTrue(leaflist5Index0.getModuleName().equals("module1"));
+        assertTrue(leaflist5Index0.getNamespace().equals("ns1"));
+        assertTrue(leaflist5Index0.getName().equals("leaflist5"));
+        assertTrue(leaflist5Index0.getValue().equals(new String("one")));
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/XmlPrefixesTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/XmlPrefixesTest.java
new file mode 100644
index 0000000..6da4f24
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/XmlPrefixesTest.java
@@ -0,0 +1,277 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.dom.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+import org.junit.Test;
+import org.w3c.dom.Document;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot.SourceDataType;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.data.parser.XmlParser;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+
+import junit.framework.Assert;
+
+public class XmlPrefixesTest {
+
+    @Test
+    public void test_MultipleNamespaces() {
+
+        final File instanceFile = new File("src/test/resources/data-dom/xml-test/multiple_namespaces.xml");
+        final YangData yangDataFile = new YangData(new FileBasedYangInput(instanceFile));
+
+        try (final InputStream inputStream = new FileInputStream(instanceFile)) {
+
+            final FindingsManager findingsManager = new FindingsManager(new ModifyableFindingSeverityCalculator());
+            final ParserExecutionContext context = new ParserExecutionContext(findingsManager);
+
+            final Document document = XmlParser.createDocument(inputStream);
+            document.getDocumentElement().normalize();
+
+            final YangDataDomDocumentRoot root = new YangDataDomDocumentRoot(yangDataFile, SourceDataType.XML);
+            root.buildFromXmlDocument(context, document);
+
+            final ModuleAndNamespaceResolver resolver = new ModuleAndNamespaceResolver();
+            resolver.recordNamespaceMapping("namespace0", "module0");
+            resolver.recordNamespaceMapping("namespace1", "module1");
+            resolver.recordNamespaceMapping("namespace2", "module2");
+            resolver.recordNamespaceMapping("namespace4", "module4");
+            resolver.recordNamespaceMapping("namespace9", "module9");
+            resolver.recordNamespaceMapping("www.foo.com", "foo");
+
+            root.resolveModuleOrNamespace(resolver);
+
+            assertTrue(root.getChildren().size() == 1);
+
+            final YangDataDomNode cont1 = root.getChildren().get(0);
+            assertTrue(cont1.getName().equals("cont1"));
+            assertTrue(cont1.getNamespace().equals("namespace0"));
+            assertTrue(cont1.getModuleName().equals("module0"));
+            assertTrue(cont1.getAnnotations().size() == 0);
+            assertTrue(cont1.getChildren().size() == 5);
+            assertTrue(cont1.toString().equals("cont1"));
+            assertTrue(cont1.getPath().equals("/cont1"));
+
+            final YangDataDomNode leaf1 = cont1.getChildren().get(0);
+            assertTrue(leaf1.getName().equals("leaf1"));
+            assertTrue(leaf1.getNamespace().equals("namespace0"));
+            assertTrue(leaf1.getModuleName().equals("module0"));
+            assertTrue(leaf1.getStringValue().equals("42"));
+            assertTrue(leaf1.getAnnotations().size() == 0);
+            assertTrue(leaf1.getChildren().size() == 0);
+
+            final YangDataDomNode leaf2 = cont1.getChildren().get(1);
+            assertTrue(leaf2.getName().equals("leaf2"));
+            assertTrue(leaf2.getNamespace().equals("namespace1"));
+            assertTrue(leaf2.getModuleName().equals("module1"));
+            assertTrue(leaf2.getStringValue().equals("43"));
+            assertTrue(leaf2.getAnnotations().size() == 0);
+            assertTrue(leaf2.getChildren().size() == 0);
+
+            final YangDataDomNode leaf3 = cont1.getChildren().get(2);
+            assertTrue(leaf3.getName().equals("leaf3"));
+            assertTrue(leaf3.getNamespace().equals("namespace2"));
+            assertTrue(leaf3.getModuleName().equals("module2"));
+            assertTrue(leaf3.getStringValue().equals("44"));
+            assertTrue(leaf3.getAnnotations().size() == 0);
+            assertTrue(leaf3.getChildren().size() == 0);
+
+            final YangDataDomNode cont2 = cont1.getChildren().get(3);
+            assertTrue(cont2.getName().equals("cont2"));
+            assertTrue(cont2.getNamespace().equals("namespace4"));
+            assertTrue(cont2.getModuleName().equals("module4"));
+            assertTrue(cont2.getAnnotations().size() == 0);
+            assertTrue(cont2.getChildren().size() == 6);
+
+            final YangDataDomNode leaf4 = cont2.getChildren().get(0);
+            assertTrue(leaf4.getName().equals("leaf4"));
+            assertTrue(leaf4.getNamespace().equals("namespace4"));
+            assertTrue(leaf4.getModuleName().equals("module4"));
+            assertTrue(leaf4.getStringValue().equals("40"));
+            assertTrue(leaf4.getAnnotations().size() == 0);
+            assertTrue(leaf4.getChildren().size() == 0);
+
+            final YangDataDomNode leaf5 = cont2.getChildren().get(1);
+            assertTrue(leaf5.getName().equals("leaf5"));
+            assertTrue(leaf5.getNamespace().equals("namespace1"));
+            assertTrue(leaf5.getStringValue().equals("50"));
+            assertTrue(leaf5.getAnnotations().size() == 0);
+            assertTrue(leaf5.getChildren().size() == 0);
+
+            final YangDataDomNode leaf6 = cont2.getChildren().get(2);
+            assertTrue(leaf6.getName().equals("leaf6"));
+            assertTrue(leaf6.getNamespace().equals("namespace9"));
+            assertTrue(leaf6.getStringValue().equals("60"));
+            assertTrue(leaf6.getAnnotations().size() == 0);
+            assertTrue(leaf6.getChildren().size() == 0);
+
+            final YangDataDomNode leaf7 = cont2.getChildren().get(3);
+            assertTrue(leaf7.getName().equals("leaf7"));
+            assertTrue(leaf7.getNamespace().equals("namespace4"));
+            assertTrue(leaf7.getStringValue() == null);
+            assertTrue(leaf7.getAnnotations().size() == 0);
+            assertTrue(leaf7.getChildren().size() == 0);
+
+            final YangDataDomNode leaf8 = cont2.getChildren().get(4);
+            assertTrue(leaf8.getName().equals("leaf8"));
+            assertTrue(leaf8.getNamespace().equals("namespace4"));
+            assertTrue(leaf8.getModuleName().equals("module4"));
+            assertTrue(leaf8.getStringValue().equals(""));
+            assertTrue(leaf8.getAnnotations().size() == 0);
+            assertTrue(leaf8.getChildren().size() == 0);
+
+            final YangDataDomNode leaf9 = cont2.getChildren().get(5);
+            assertTrue(leaf9.getName().equals("leaf9"));
+            assertTrue(leaf9.getNamespace().equals("namespace4"));
+            assertTrue(leaf9.getStringValue().equals("90"));
+            assertTrue(leaf9.getAnnotations().size() == 1);
+            assertTrue(leaf9.getChildren().size() == 0);
+
+            final YangDataDomNode cont3 = cont1.getChildren().get(4);
+            assertTrue(cont3.getName().equals("cont3"));
+            assertTrue(cont3.getNamespace().equals("namespace2"));
+            assertTrue(cont3.getAnnotations().size() == 0);
+            assertTrue(cont3.getChildren().size() == 7);
+
+            final YangDataDomNode leaf10 = cont3.getChildren().get(0);
+            assertTrue(leaf10.getName().equals("leaf10"));
+            assertTrue(leaf10.getNamespace().equals("namespace0"));
+            assertTrue(leaf10.getStringValue().equals("10"));
+            assertTrue(leaf10.getAnnotations().size() == 3);
+            assertTrue(leaf10.getAnnotations().get(0).getName().equals("myanno"));
+            assertTrue(leaf10.getAnnotations().get(0).getNamespace().equals("www.foo.com"));
+            assertTrue(leaf10.getAnnotations().get(0).getModuleName().equals("foo"));
+            assertTrue(leaf10.getAnnotations().get(0).getValue().equals("anno-value1"));
+            assertTrue(leaf10.getAnnotations().get(1).getName().equals("myanno2"));
+            assertTrue(leaf10.getAnnotations().get(1).getNamespace().equals("www.foo.com"));
+            assertTrue(leaf10.getAnnotations().get(1).getValue().equals("anno-value2"));
+            assertTrue(leaf10.getAnnotations().get(2).getName().equals("unknownanno"));
+            assertTrue(leaf10.getAnnotations().get(2).getNamespace().equals("www.foo.com"));
+            assertTrue(leaf10.getAnnotations().get(2).getValue().equals("unknown"));
+            assertTrue(leaf10.getChildren().size() == 0);
+
+            final YangDataDomNode leaf11 = cont3.getChildren().get(1);
+            assertTrue(leaf11.getName().equals("leaf11"));
+            assertTrue(leaf11.getNamespace() == null);
+            assertTrue(leaf11.getModuleName() == null);
+            assertTrue(leaf11.getStringValue().equals("??"));
+            assertTrue(leaf11.getAnnotations().size() == 0);
+            assertTrue(leaf11.getChildren().size() == 0);
+            assertTrue(leaf11.getFindings().size() == 1);
+            assertTrue(leaf11.getFindings().iterator().next().getFindingType().equals(
+                    ParserFindingType.P077_UNRESOLVABLE_PREFIX.toString()));
+
+            final YangDataDomNode leaf12 = cont3.getChildren().get(2);
+            assertTrue(leaf12.getName().equals("leaf12"));
+            assertTrue(leaf12.getNamespace().equals("namespace0"));
+            assertTrue(leaf12.getStringValue().equals("12"));
+            assertTrue(leaf12.getAnnotations().size() == 0);
+            assertTrue(leaf12.getChildren().size() == 0);
+            assertTrue(leaf12.getFindings().size() == 1);
+            assertTrue(leaf12.getFindings().iterator().next().getFindingType().equals(
+                    ParserFindingType.P077_UNRESOLVABLE_PREFIX.toString()));
+
+            final YangDataDomNode leaf13 = cont3.getChildren().get(3);
+            assertTrue(leaf13.getName().equals("leaf13"));
+            assertTrue(leaf13.getNamespace().equals("namespace1"));
+            assertTrue(leaf13.getStringValue().equals("13"));
+            assertTrue(leaf13.getAnnotations().size() == 0);
+            assertTrue(leaf13.getChildren().size() == 0);
+            assertTrue(leaf13.getFindings().size() == 0);
+
+            final YangDataDomNode leaf14 = cont3.getChildren().get(4);
+            assertTrue(leaf14.getName().equals("leaf14"));
+            assertTrue(leaf14.getNamespace().equals("namespace1"));
+            assertTrue(leaf14.getStringValue().equals("1 4"));
+            assertTrue(leaf14.getAnnotations().size() == 0);
+            assertTrue(leaf14.getChildren().size() == 0);
+            assertTrue(leaf14.getFindings().size() == 0);
+
+            final YangDataDomNode leaf15 = cont3.getChildren().get(5);
+            assertTrue(leaf15.getName().equals("leaf15"));
+            assertTrue(leaf15.getNamespace().equals("namespace1"));
+            assertTrue(leaf15.getStringValue().equals("First line Second line Third line"));
+
+            final YangDataDomNode leaf21 = cont3.getChildren().get(6);
+            assertTrue(leaf21.getName().equals("leaf21"));
+            assertTrue(leaf21.getNamespace().equals("namespace0"));
+            assertTrue(leaf21.getStringValue().equals("11\n 22\t\t"));
+
+        } catch (final Exception ex) {
+            ex.printStackTrace();
+            Assert.fail(ex.getMessage());
+        }
+    }
+
+    @Test
+    public void test_prefixes_on_instance_data_set() {
+
+        final File instanceFile = new File("src/test/resources/data-dom/xml-test/prefixes_on_instance_data_set.xml");
+        final YangData yangDataFile = new YangData(new FileBasedYangInput(instanceFile));
+
+        try (final InputStream inputStream = new FileInputStream(instanceFile)) {
+
+            final FindingsManager findingsManager = new FindingsManager(new ModifyableFindingSeverityCalculator());
+            final ParserExecutionContext context = new ParserExecutionContext(findingsManager);
+
+            final Document document = XmlParser.createDocument(inputStream);
+            document.getDocumentElement().normalize();
+
+            final YangDataDomDocumentRoot documentRoot = new YangDataDomDocumentRoot(yangDataFile, SourceDataType.XML);
+            documentRoot.buildFromXmlDocument(context, document);
+
+            assertTrue(documentRoot.getChildren().size() == 1);
+
+            final YangDataDomNode cont1 = documentRoot.getChildren().get(0);
+            assertTrue(cont1.getName().equals("cont1"));
+            assertTrue(cont1.getNamespace().equals("namespace0"));
+
+            final YangDataDomNode leaf1 = cont1.getChildren().get(0);
+            assertTrue(leaf1.getName().equals("leaf1"));
+            assertTrue(leaf1.getNamespace().equals("namespace0"));
+
+            final YangDataDomNode leaf2 = cont1.getChildren().get(1);
+            assertTrue(leaf2.getName().equals("leaf2"));
+            assertTrue(leaf2.getNamespace().equals("namespace1"));
+
+            final YangDataDomNode leaf3 = cont1.getChildren().get(2);
+            assertTrue(leaf3.getName().equals("leaf3"));
+            assertTrue(leaf3.getNamespace().equals("namespace2"));
+
+        } catch (final Exception ex) {
+            ex.printStackTrace();
+            Assert.fail(ex.getMessage());
+        }
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/XmlRootElementsTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/XmlRootElementsTest.java
new file mode 100644
index 0000000..72f4ddd
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/dom/test/XmlRootElementsTest.java
@@ -0,0 +1,129 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.dom.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot.SourceDataType;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class XmlRootElementsTest extends YangTestCommon {
+
+    private static final String DIR = "src/test/resources/data-dom/xml-test/";
+
+    @Test
+    public void testRootElement_Config() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-config.xml"));
+
+        assertNoFindings();
+        checkDataParsedCorrectly();
+    }
+
+    @Test
+    public void testRootElement_InstanceDataSet() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-instance-data-set.xml"));
+
+        assertNoFindings();
+        checkDataParsedCorrectly();
+    }
+
+    @Test
+    public void testRootElement_data() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-data.xml"));
+
+        assertNoFindings();
+        checkDataParsedCorrectly();
+    }
+
+    @Test
+    public void testRootElement_assume_module_root_element() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-assume-module-root-element.xml"));
+
+        assertHasFindingOfType(ParserFindingType.P071_INCORRECT_ROOT_ELEMENT_OF_DATA_FILE.toString());
+        checkDataParsedCorrectly();
+    }
+
+    @Test
+    public void testRootElement_InstanceDataSet_Wrong() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-instance-data-set-wrong.xml"));
+
+        assertHasFindingOfType(ParserFindingType.P079_EMPTY_DATA_FILE.toString());
+    }
+
+    @Test
+    public void testRootElement_RpcReply() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-rpc-reply.xml"));
+
+        assertHasNotFindingOfType(ParserFindingType.P071_INCORRECT_ROOT_ELEMENT_OF_DATA_FILE.toString());
+        checkDataParsedCorrectly();
+    }
+
+    @Test
+    public void testRootElement_RpcReply_Wrong() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-rpc-reply-wrong-no-data.xml"));
+
+        assertHasFindingOfType(ParserFindingType.P079_EMPTY_DATA_FILE.toString());
+    }
+
+    @Test
+    public void testRootElement_no_namespace() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        parseAbsoluteYangData(Arrays.asList(DIR + "root-data-no-namespace.xml"));
+
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+    private void checkDataParsedCorrectly() {
+
+        final YangDataDomDocumentRoot root = yangDeviceModel.getYangInstanceDataInputs().get(0)
+                .getYangDataDomDocumentRoot();
+
+        final YangDataDomNode cont1 = getChildDataDomNode(root, "cont1");
+        assertTrue(cont1.getNamespace().equals("test:module"));
+
+        final YangDataDomNode leaf1 = getChildDataDomNode(cont1, "leaf1");
+        assertTrue(leaf1.getNamespace().equals("test:module"));
+        assertTrue(leaf1.getValue().equals(new String("42")));
+        assertTrue(leaf1.getSourceDataType() == SourceDataType.XML);
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/parser/test/JsonParserTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/parser/test/JsonParserTest.java
new file mode 100644
index 0000000..3b20a44
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/parser/test/JsonParserTest.java
@@ -0,0 +1,537 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.parser.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonArray;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObject;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObjectMemberName;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonPrimitive;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonValue;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class JsonParserTest extends YangTestCommon {
+
+    private static final String DIR = "src/test/resources/data-parser/";
+
+    @Test
+    public void test_ok_json1() {
+
+        final Object jsonRoot = parseJsonFile("json-ok1.json");
+
+        assertNoFindings();
+
+        assertTrue(jsonRoot instanceof JsonObject);
+        final JsonObject jsonRootObject = (JsonObject) jsonRoot;
+
+        final JsonValue attr1 = getJsonObjectMemberValue(jsonRootObject, "attr1");
+        assertTrue(attr1 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr1).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) attr1).getValue()).equals("some string"));
+
+        final JsonValue attr2 = getJsonObjectMemberValue(jsonRootObject, "attr2");
+        assertTrue(attr2 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr2).getValue() instanceof Boolean);
+        assertTrue(((Boolean) ((JsonPrimitive) attr2).getValue()).equals(Boolean.TRUE));
+
+        final JsonValue attr3 = getJsonObjectMemberValue(jsonRootObject, "attr3");
+        assertTrue(attr3 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr3).getValue() instanceof Long);
+        assertTrue(((Long) ((JsonPrimitive) attr3).getValue()).intValue() == 12);
+
+        final JsonValue attr4 = getJsonObjectMemberValue(jsonRootObject, "attr4");
+        assertTrue(attr4 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr4).getValue() == null);
+
+        final JsonValue attr5 = getJsonObjectMemberValue(jsonRootObject, "attr5");
+        assertTrue(attr5 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr5).getValue() instanceof Boolean);
+        assertTrue(((Boolean) ((JsonPrimitive) attr5).getValue()).equals(Boolean.FALSE));
+
+        final JsonValue attr6 = getJsonObjectMemberValue(jsonRootObject, "attr6");
+        assertTrue(attr6 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr6).getValue() instanceof Double);
+        assertTrue(((Double) ((JsonPrimitive) attr6).getValue()).doubleValue() == 123456789.123456789d);
+
+        final JsonValue attr7 = getJsonObjectMemberValue(jsonRootObject, "attr7");
+        assertTrue(attr7 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr7).getValue() instanceof Long);
+        assertTrue(((Long) ((JsonPrimitive) attr7).getValue()).longValue() == 1234567890123L);
+
+        final JsonValue attr8 = getJsonObjectMemberValue(jsonRootObject, "attr8");
+        assertTrue(attr8 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr8).getValue() instanceof Long);
+        assertTrue(((Long) ((JsonPrimitive) attr8).getValue()).longValue() == Long.MAX_VALUE);
+
+        final JsonValue attr9 = getJsonObjectMemberValue(jsonRootObject, "attr9");
+        assertTrue(attr9 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr9).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) attr9).getValue()).equals("9223372036854775808"));
+
+        final JsonValue attr10 = getJsonObjectMemberValue(jsonRootObject, "attr10");
+        assertTrue(attr10 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr10).getValue() instanceof Long);
+        assertTrue(((Long) ((JsonPrimitive) attr10).getValue()).longValue() == Long.MIN_VALUE);
+
+        final JsonValue attr11 = getJsonObjectMemberValue(jsonRootObject, "attr11");
+        assertTrue(attr11 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr11).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) attr11).getValue()).equals("-9223372036854775809"));
+
+        // ======================
+
+        final JsonValue attr12 = getJsonObjectMemberValue(jsonRootObject, "attr12");
+        assertTrue(attr12 instanceof JsonObject);
+        assertTrue(((JsonObject) attr12).getValuesByMember().size() == 0);
+
+        final JsonValue attr13 = getJsonObjectMemberValue(jsonRootObject, "attr13");
+        assertTrue(attr13 instanceof JsonObject);
+        assertTrue(((JsonObject) attr13).getValuesByMember().size() == 2);
+
+        final JsonObject attr12Object = (JsonObject) attr13;
+
+        final JsonValue attr17 = getJsonObjectMemberValue(attr12Object, "attr17");
+        assertTrue(attr17 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr17).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) attr17).getValue()).equals("hello"));
+
+        final JsonValue attr18 = getJsonObjectMemberValue(attr12Object, "module:attr18");
+        assertTrue(attr18 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr18).getValue() instanceof Double);
+        assertTrue(((Double) ((JsonPrimitive) attr18).getValue()).doubleValue() == -1d);
+
+        // ======================
+
+        final JsonValue attr21 = getJsonObjectMemberValue(jsonRootObject, "attr21");
+        assertTrue(attr21 instanceof JsonArray);
+        assertTrue(((JsonArray) attr21).getValues().size() == 0);
+
+        final JsonValue attr22 = getJsonObjectMemberValue(jsonRootObject, "attr22");
+        assertTrue(attr22 instanceof JsonArray);
+        assertTrue(((JsonArray) attr22).getValues().size() == 3);
+
+        assertTrue(((JsonArray) attr22).getValues().get(0) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr22).getValues().get(0)).getValue() instanceof Double);
+        assertTrue(((Double) ((JsonPrimitive) ((JsonArray) attr22).getValues().get(0)).getValue()).doubleValue() == 1d);
+
+        assertTrue(((JsonArray) attr22).getValues().get(1) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr22).getValues().get(1)).getValue() instanceof Long);
+        assertTrue(((Long) ((JsonPrimitive) ((JsonArray) attr22).getValues().get(1)).getValue()).longValue() == 2L);
+
+        assertTrue(((JsonArray) attr22).getValues().get(2) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr22).getValues().get(2)).getValue() instanceof Double);
+        assertTrue(((Double) ((JsonPrimitive) ((JsonArray) attr22).getValues().get(2)).getValue()).doubleValue() == -99d);
+    }
+
+    @Test
+    public void test_ok_json2() {
+
+        final Object jsonRoot = parseJsonFile("json-ok2.json");
+
+        assertNoFindings();
+
+        assertTrue(jsonRoot instanceof JsonObject);
+        final JsonObject jsonRootObject = (JsonObject) jsonRoot;
+
+        final JsonValue attr1 = getJsonObjectMemberValue(jsonRootObject, "attr1");
+        assertTrue(attr1 instanceof JsonArray);
+        assertTrue(((JsonArray) attr1).getValues().size() == 0);
+
+        final JsonValue attr2 = getJsonObjectMemberValue(jsonRootObject, "attr2");
+        assertTrue(attr2 instanceof JsonArray);
+        assertTrue(((JsonArray) attr2).getValues().size() == 0);
+
+        final JsonValue attr3 = getJsonObjectMemberValue(jsonRootObject, "attr3");
+        assertTrue(attr3 instanceof JsonArray);
+        assertTrue(((JsonArray) attr3).getValues().size() == 0);
+
+        // ======================
+
+        final JsonValue attr4 = getJsonObjectMemberValue(jsonRootObject, "attr4");
+        assertTrue(attr4 instanceof JsonArray);
+        assertTrue(((JsonArray) attr4).getValues().size() == 5);
+
+        assertTrue(((JsonArray) attr4).getValues().get(0) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr4).getValues().get(0)).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) ((JsonArray) attr4).getValues().get(0)).getValue()).equals("hello"));
+
+        assertTrue(((JsonArray) attr4).getValues().get(1) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr4).getValues().get(1)).getValue() instanceof Boolean);
+        assertTrue(((Boolean) ((JsonPrimitive) ((JsonArray) attr4).getValues().get(1)).getValue()).booleanValue() == true);
+
+        assertTrue(((JsonArray) attr4).getValues().get(2) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr4).getValues().get(2)).getValue() instanceof Boolean);
+        assertTrue(((Boolean) ((JsonPrimitive) ((JsonArray) attr4).getValues().get(2)).getValue()).booleanValue() == false);
+
+        assertTrue(((JsonArray) attr4).getValues().get(3) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr4).getValues().get(3)).getValue() == null);
+
+        assertTrue(((JsonArray) attr4).getValues().get(4) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr4).getValues().get(4)).getValue() instanceof Double);
+        assertTrue(((Double) ((JsonPrimitive) ((JsonArray) attr4).getValues().get(4)).getValue())
+                .doubleValue() == 123456789.123456789d);
+
+        // ======================
+
+        final JsonValue attr5 = getJsonObjectMemberValue(jsonRootObject, "attr5");
+        assertTrue(attr5 instanceof JsonArray);
+        assertTrue(((JsonArray) attr5).getValues().size() == 4);
+
+        assertTrue(((JsonArray) attr5).getValues().get(0) instanceof JsonArray);
+        assertTrue(((JsonArray) ((JsonArray) attr5).getValues().get(0)).getValues().size() == 1);
+        assertTrue(((JsonArray) ((JsonArray) attr5).getValues().get(0)).getValues().get(0) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) ((JsonArray) attr5).getValues().get(0)).getValues().get(0))
+                .getValue() == null);
+
+        assertTrue(((JsonArray) attr5).getValues().get(1) instanceof JsonArray);
+        assertTrue(((JsonArray) ((JsonArray) attr5).getValues().get(1)).getValues().size() == 2);
+        assertTrue(((JsonArray) ((JsonArray) attr5).getValues().get(1)).getValues().get(0) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) ((JsonArray) attr5).getValues().get(1)).getValues().get(0))
+                .getValue() == null);
+        assertTrue(((JsonArray) ((JsonArray) attr5).getValues().get(1)).getValues().get(1) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) ((JsonArray) attr5).getValues().get(1)).getValues().get(1))
+                .getValue() instanceof Boolean);
+        assertTrue(((Boolean) ((JsonPrimitive) ((JsonArray) ((JsonArray) attr5).getValues().get(1)).getValues().get(1))
+                .getValue()).booleanValue() == true);
+
+        assertTrue(((JsonArray) attr5).getValues().get(2) instanceof JsonArray);
+        assertTrue(((JsonArray) ((JsonArray) attr5).getValues().get(2)).getValues().size() == 0);
+
+        assertTrue(((JsonArray) attr5).getValues().get(3) instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) ((JsonArray) attr5).getValues().get(3)).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) ((JsonArray) attr5).getValues().get(3)).getValue()).equals("hello"));
+
+        // ======================
+
+        final JsonValue attr6 = getJsonObjectMemberValue(jsonRootObject, "attr6");
+        assertTrue(attr6 instanceof JsonArray);
+        assertTrue(((JsonArray) attr6).getValues().size() == 2);
+
+        assertTrue(((JsonArray) attr6).getValues().get(0) instanceof JsonArray);
+        assertTrue(((JsonArray) ((JsonArray) attr6).getValues().get(0)).getValues().size() == 0);
+
+        assertTrue(((JsonArray) attr6).getValues().get(1) instanceof JsonObject);
+        assertTrue(((JsonObject) ((JsonArray) attr6).getValues().get(1)).getValuesByMember().size() == 0);
+
+        // ======================
+
+        final JsonValue attr7 = getJsonObjectMemberValue(jsonRootObject, "attr7");
+        assertTrue(attr7 instanceof JsonArray);
+        assertTrue(((JsonArray) attr7).getValues().size() == 2);
+
+        assertTrue(((JsonArray) attr7).getValues().get(0) instanceof JsonObject);
+        assertTrue(((JsonObject) ((JsonArray) attr7).getValues().get(0)).getValuesByMember().size() == 0);
+
+        assertTrue(((JsonArray) attr7).getValues().get(1) instanceof JsonObject);
+        assertTrue(((JsonObject) ((JsonArray) attr7).getValues().get(1)).getValuesByMember().size() == 0);
+
+        // ======================
+
+        final JsonValue attr8 = getJsonObjectMemberValue(jsonRootObject, "attr8");
+        assertTrue(attr8 instanceof JsonArray);
+        assertTrue(((JsonArray) attr8).getValues().size() == 2);
+
+        assertTrue(((JsonArray) attr8).getValues().get(0) instanceof JsonObject);
+        assertTrue(((JsonObject) ((JsonArray) attr8).getValues().get(0)).getValuesByMember().size() == 2);
+
+        final JsonValue attr21 = getJsonObjectMemberValue((JsonObject) ((JsonArray) attr8).getValues().get(0), "attr21");
+        assertTrue(attr21 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr21).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) attr21).getValue()).equals("hello"));
+
+        final JsonValue attr22 = getJsonObjectMemberValue((JsonObject) ((JsonArray) attr8).getValues().get(0), "attr22");
+        assertTrue(attr22 instanceof JsonArray);
+        assertTrue(((JsonArray) attr22).getValues().size() == 0);
+
+        assertTrue(((JsonArray) attr8).getValues().get(1) instanceof JsonObject);
+        assertTrue(((JsonObject) ((JsonArray) attr8).getValues().get(1)).getValuesByMember().size() == 0);
+
+        // ======================
+
+        final JsonValue attr9 = getJsonObjectMemberValue(jsonRootObject, "attr9");
+        assertTrue(attr9 instanceof JsonArray);
+        assertTrue(((JsonArray) attr9).getValues().size() == 2);
+        assertTrue(((JsonArray) attr9).getValues().get(0) instanceof JsonObject);
+        assertTrue(((JsonArray) attr9).getValues().get(1) instanceof JsonObject);
+        assertTrue(((JsonObject) ((JsonArray) attr9).getValues().get(0)).getValuesByMember().size() == 2);
+        assertTrue(((JsonObject) ((JsonArray) attr9).getValues().get(1)).getValuesByMember().size() == 0);
+
+        final JsonValue attr31 = getJsonObjectMemberValue((JsonObject) ((JsonArray) attr9).getValues().get(0), "attr31");
+        assertTrue(attr31 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr31).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) attr31).getValue()).equals("hello"));
+
+        final JsonValue attr32 = getJsonObjectMemberValue((JsonObject) ((JsonArray) attr9).getValues().get(0), "attr32");
+        assertTrue(attr32 instanceof JsonArray);
+        assertTrue(((JsonArray) attr32).getValues().size() == 2);
+        assertTrue(((JsonArray) attr32).getValues().get(0) instanceof JsonObject);
+        assertTrue(((JsonArray) attr32).getValues().get(1) instanceof JsonObject);
+
+        final JsonValue attr33 = getJsonObjectMemberValue((JsonObject) ((JsonArray) attr32).getValues().get(1), "attr33");
+        assertTrue(attr33 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr33).getValue() instanceof Boolean);
+        assertTrue(((Boolean) ((JsonPrimitive) attr33).getValue()).booleanValue() == true);
+
+        final JsonValue attr34 = getJsonObjectMemberValue((JsonObject) ((JsonArray) attr32).getValues().get(1), "attr34");
+        assertTrue(attr34 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr34).getValue() instanceof Long);
+        assertTrue(((Long) ((JsonPrimitive) attr34).getValue()).longValue() == -99999999999L);
+    }
+
+    @Test
+    public void test_ok_json3() {
+
+        final Object jsonRoot = parseJsonFile("json-ok3.json");
+
+        assertNoFindings();
+
+        assertTrue(jsonRoot instanceof JsonObject);
+        final JsonObject jsonRootObject = (JsonObject) jsonRoot;
+
+        verifyObjectMemberStringValue(jsonRootObject, "attr1", "");
+        verifyObjectMemberStringValue(jsonRootObject, "attr2", " ");
+        verifyObjectMemberStringValue(jsonRootObject, "attr3", "\t");
+        verifyObjectMemberStringValue(jsonRootObject, "attr4", "\n");
+        verifyObjectMemberStringValue(jsonRootObject, "attr5", "\"");
+        verifyObjectMemberStringValue(jsonRootObject, "attr6", "\\");
+        verifyObjectMemberStringValue(jsonRootObject, "attr7", "/");
+        verifyObjectMemberStringValue(jsonRootObject, "attr8", "\b");
+        verifyObjectMemberStringValue(jsonRootObject, "attr9", "\f");
+        verifyObjectMemberStringValue(jsonRootObject, "attr10", "\r");
+
+        verifyObjectMemberStringValue(jsonRootObject, "attr21", " ");
+    }
+
+    @Test
+    public void test_ok_json4() {
+
+        final Object jsonRoot = parseJsonFile("json-ok4.json");
+
+        assertNoFindings();
+
+        assertTrue(jsonRoot instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) jsonRoot).getValue() instanceof String);
+        assertTrue(((String) ((JsonPrimitive) jsonRoot).getValue()).equals("hello"));
+    }
+
+    @Test
+    public void test_ok_json5() {
+
+        final Object jsonRoot = parseJsonFile("json-ok5.json");
+
+        assertNoFindings();
+
+        assertTrue(jsonRoot instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) jsonRoot).getValue() == null);
+    }
+
+    @Test
+    public void test_error_but_continue1() {
+
+        final Object jsonRoot = parseJsonFile("json-error-but-continue1.json");
+
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertTrue(jsonRoot instanceof JsonObject);
+        final JsonObject jsonRootObject = (JsonObject) jsonRoot;
+
+        verifyObjectMemberStringValue(jsonRootObject, "attr1", "comma missing after this string");
+        verifyObjectMemberStringValue(jsonRootObject, "attr2", "comma after this string not needed");
+    }
+
+    @Test
+    public void test_error_but_continue2() {
+
+        final Object jsonRoot = parseJsonFile("json-error-but-continue2.json");
+
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertTrue(jsonRoot instanceof JsonArray);
+        final JsonArray jsonRootArray = (JsonArray) jsonRoot;
+
+        verifyArrayMemberStringValue(jsonRootArray, 0, "comma missing after this string");
+        verifyArrayMemberStringValue(jsonRootArray, 1, "comma after this string not needed");
+    }
+
+    @Test
+    public void test_error1() {
+        parseJsonFile("json-error1.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains(
+                "Expected a quoted member name"));
+    }
+
+    @Test
+    public void test_error2() {
+        parseJsonFile("json-error2.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains("Expected name separator"));
+    }
+
+    @Test
+    public void test_error3() {
+        parseJsonFile("json-error3.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains("Expected a value"));
+    }
+
+    @Test
+    public void test_error4() {
+        parseJsonFile("json-error4.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains("Expected a value"));
+    }
+
+    @Test
+    public void test_error5() {
+        parseJsonFile("json-error5.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains("does not translate"));
+    }
+
+    @Test
+    public void test_error6() {
+        parseJsonFile("json-error6.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains(
+                "Missing terminating double-quote character"));
+    }
+
+    @Test
+    public void test_error7() {
+        parseJsonFile("json-error7.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains("Missing escaped character"));
+    }
+
+    @Test
+    public void test_error8() {
+        parseJsonFile("json-error8.json");
+        assertHasFindingOfType(ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains(
+                "Unrecognized escaped character"));
+    }
+
+    @Test
+    public void test_error9() {
+        parseJsonFile("json-error9.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains(
+                "Unicode character not correctly escaped"));
+    }
+
+    @Test
+    public void test_error10() {
+        parseJsonFile("json-error10.json");
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(findingsManager.getAllFindings().iterator().next().getMessage().contains(
+                "Unicode character not correctly escaped"));
+    }
+
+    private void verifyObjectMemberStringValue(final JsonObject jsonObject, final String memberName,
+            final String expected) {
+        final JsonValue attr1 = getJsonObjectMemberValue(jsonObject, memberName);
+        assertTrue(attr1 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr1).getValue() instanceof String);
+        assertEquals(expected, (String) ((JsonPrimitive) attr1).getValue());
+    }
+
+    private void verifyArrayMemberStringValue(final JsonArray jsonArray, final int index, final String expected) {
+        final JsonValue attr1 = jsonArray.getValues().get(index);
+        assertTrue(attr1 instanceof JsonPrimitive);
+        assertTrue(((JsonPrimitive) attr1).getValue() instanceof String);
+        assertEquals(expected, (String) ((JsonPrimitive) attr1).getValue());
+    }
+
+    private Object parseJsonFile(final String fileName) {
+
+        final File jsonFile = new File(DIR + fileName);
+        final FileBasedYangInput fileBasedYangInput = new FileBasedYangInput(jsonFile);
+        final YangData yangInstanceDataInput = new YangData(fileBasedYangInput);
+
+        try {
+            return new JsonParser(context, yangInstanceDataInput, fileBasedYangInput.getInputStream()).parse();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_json_object_member_handling() {
+
+        final JsonObject jsonObject = new JsonObject();
+
+        jsonObject.putMember("member1", JsonPrimitive.valueOf(Boolean.TRUE));
+        jsonObject.putMember("member2", JsonPrimitive.valueOf(Boolean.FALSE));
+        jsonObject.putMember(new JsonObjectMemberName("member3"), JsonPrimitive.valueOf(null));
+
+        assertTrue(jsonObject.getValues().get("member1").equals(JsonPrimitive.TRUE));
+        assertTrue(jsonObject.getValues().get("member2").equals(JsonPrimitive.FALSE));
+        assertTrue(jsonObject.getValues().get("member3").equals(JsonPrimitive.NULL));
+
+        assertFalse(jsonObject.getValues().get("member1").equals(null));
+        assertFalse(jsonObject.getValues().get("member2").equals(null));
+        assertTrue(jsonObject.getValues().get("member3").equals(null));
+
+        assertTrue(jsonObject.getValuesByMember().get(new JsonObjectMemberName("member1")).equals(JsonPrimitive.TRUE));
+        assertTrue(jsonObject.getValuesByMember().get(new JsonObjectMemberName("member2")).equals(JsonPrimitive.FALSE));
+        assertTrue(jsonObject.getValuesByMember().get(new JsonObjectMemberName("member3")).equals(JsonPrimitive.NULL));
+
+        final JsonObjectMemberName jsonObjectMemberName99 = new JsonObjectMemberName("member99");
+
+        assertTrue(jsonObjectMemberName99.equals(jsonObjectMemberName99));
+        assertTrue(jsonObjectMemberName99.equals(new JsonObjectMemberName("member99")));
+        assertTrue(jsonObjectMemberName99.equals("member99"));
+
+        assertFalse(jsonObjectMemberName99.equals(null));
+        assertFalse(jsonObjectMemberName99.equals(new JsonObjectMemberName("memberXXXXXX")));
+        assertFalse(jsonObjectMemberName99.equals("memberXXXXX"));
+
+        final JsonPrimitive booleanTrue = JsonPrimitive.valueOf(Boolean.TRUE);
+
+        assertTrue(booleanTrue.equals(JsonPrimitive.valueOf(Boolean.TRUE)));
+        assertTrue(booleanTrue.equals(Boolean.TRUE));
+        assertTrue(booleanTrue.equals(true));
+        assertFalse(booleanTrue.equals(null));
+
+        final JsonPrimitive nullValue = JsonPrimitive.valueOf(null);
+
+        assertTrue(nullValue.equals(JsonPrimitive.valueOf(null)));
+        assertTrue(nullValue.equals(null));
+        assertFalse(nullValue.equals(Boolean.TRUE));
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/parser/test/JsonWriterTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/parser/test/JsonWriterTest.java
new file mode 100644
index 0000000..bd8c81d
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/parser/test/JsonWriterTest.java
@@ -0,0 +1,219 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.parser.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.parser.JsonParser;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonArray;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObject;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonPrimitive;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonValue;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+import org.oran.smo.yangtools.parser.data.parser.JsonWriter;
+
+public class JsonWriterTest extends YangTestCommon {
+
+    @Test
+    public void test_write_simple_json1() throws IOException {
+
+        final JsonPrimitive valueOf = JsonPrimitive.valueOf(null);
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(valueOf, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonPrimitive);
+        assertTrue(rootValue.equals(JsonPrimitive.NULL));
+    }
+
+    @Test
+    public void test_write_simple_json2() throws IOException {
+
+        final JsonPrimitive valueOf = JsonPrimitive.valueOf(true);
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(valueOf, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonPrimitive);
+        assertTrue(rootValue.equals(JsonPrimitive.TRUE));
+    }
+
+    @Test
+    public void test_write_simple_json3() throws IOException {
+
+        final JsonPrimitive valueOf = JsonPrimitive.valueOf(1);
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(valueOf, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonPrimitive);
+        assertTrue(rootValue.equals(JsonPrimitive.ONE));
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_write_simple_json4() throws IOException {
+
+        final JsonPrimitive valueOf = JsonPrimitive.valueOf("");
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(valueOf, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonPrimitive);
+        assertTrue(rootValue.equals(""));
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_write_simple_json5() throws IOException {
+
+        final JsonPrimitive valueOf = JsonPrimitive.valueOf("abcd\n\b\t\f\r\\\"/");
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(valueOf, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonPrimitive);
+        assertTrue(rootValue.equals("abcd\n\b\t\f\r\\\"/"));
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_write_simple_json6() throws IOException {
+
+        final JsonPrimitive valueOf = JsonPrimitive.valueOf("✉🌕");
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(valueOf, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonPrimitive);
+        assertTrue(rootValue.equals("✉🌕"));
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_write_simple_json7() throws IOException {
+
+        final JsonPrimitive valueOf = JsonPrimitive.valueOf("©®");
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(valueOf, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonPrimitive);
+        assertTrue(rootValue.equals("©®"));
+    }
+
+    @Test
+    public void test_write_array1() throws IOException {
+
+        final JsonArray array = new JsonArray();
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(array, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonArray);
+        assertTrue(((JsonArray) rootValue).getValues().isEmpty());
+    }
+
+    @Test
+    public void test_write_array2() throws IOException {
+
+        final JsonArray array = new JsonArray();
+        array.addValue(JsonPrimitive.valueOf(0));
+        array.addValue(JsonPrimitive.valueOf(false));
+        array.addValue(JsonPrimitive.valueOf(null));
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(array, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonArray);
+        assertTrue(((JsonArray) rootValue).getValues().size() == 3);
+        assertTrue(((JsonArray) rootValue).getValues().get(0).equals(JsonPrimitive.ZERO));
+        assertTrue(((JsonArray) rootValue).getValues().get(1).equals(JsonPrimitive.FALSE));
+        assertTrue(((JsonArray) rootValue).getValues().get(2).equals(JsonPrimitive.NULL));
+    }
+
+    @Test
+    public void test_write_object1() throws IOException {
+
+        final JsonObject object = new JsonObject();
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(object, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonObject);
+        assertTrue(((JsonObject) rootValue).getValues().isEmpty());
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_write_object2() throws IOException {
+
+        final JsonObject object = new JsonObject();
+
+        object.putMember("one", 1);
+        object.putMember("two", null);
+        object.putMember("three", true);
+        object.putMember("four", JsonPrimitive.valueOf("abc"));
+        object.putMember("five", "def");
+
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        JsonWriter.write(object, baos);
+
+        final JsonValue rootValue = new JsonParser(null, null, new ByteArrayInputStream(baos.toByteArray())).parse();
+
+        assertTrue(rootValue instanceof JsonObject);
+        final Map<String, JsonValue> values = ((JsonObject) rootValue).getValues();
+
+        assertTrue(values.get("one").equals(JsonPrimitive.ONE));
+        assertTrue(values.get("two").equals(JsonPrimitive.NULL));
+        assertTrue(values.get("three").equals(JsonPrimitive.TRUE));
+        assertTrue(values.get("four").equals("abc"));
+        assertTrue(values.get("five").equals("def"));
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/ComplexInstanceDataTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/ComplexInstanceDataTest.java
new file mode 100644
index 0000000..e22e2bf
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/ComplexInstanceDataTest.java
@@ -0,0 +1,695 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.instance.ContainerInstance;
+import org.oran.smo.yangtools.parser.data.instance.DataTreeBuilderPredicate;
+import org.oran.smo.yangtools.parser.data.instance.LeafInstance;
+import org.oran.smo.yangtools.parser.data.instance.LeafListInstance;
+import org.oran.smo.yangtools.parser.data.instance.ListInstance;
+import org.oran.smo.yangtools.parser.data.instance.RootInstance;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.YangInput;
+import org.oran.smo.yangtools.parser.input.YangInputResolver;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class ComplexInstanceDataTest extends YangTestCommon {
+
+    private static final String MODULE1 = "src/test/resources/data/instance-data/module1.yang";
+    private static final String MODULE2 = "src/test/resources/data/instance-data/module2.yang";
+
+    private static final String DATA1_XML = "src/test/resources/data/instance-data/data1.xml";
+    private static final String DATA2_XML = "src/test/resources/data/instance-data/data2.xml";
+    private static final String DATA1_JSON = "src/test/resources/data/instance-data/data1.json";
+    private static final String DATA2_JSON = "src/test/resources/data/instance-data/data2.json";
+
+    private static final String DATA3 = "src/test/resources/data/instance-data/data3.xml";
+    private static final String DATA4 = "src/test/resources/data/instance-data/data4.xml";
+
+    private static final String DATA5 = "src/test/resources/data/instance-data/data5.xml";
+    private static final String DATA6 = "src/test/resources/data/instance-data/data6.xml";
+
+    private static final String ERROR_DATA7 = "src/test/resources/data/instance-data/error-data7.xml";
+    private static final String ERROR_DATA8 = "src/test/resources/data/instance-data/error-data8.xml";
+    private static final String ERROR_DATA9 = "src/test/resources/data/instance-data/error-data9.xml";
+    private static final String ERROR_DATA10 = "src/test/resources/data/instance-data/error-data10.json";
+
+    private static final String NS1 = "test:module1";
+    private static final String NS2 = "test:module2";
+
+    @Test
+    public void test_module1_data1_data2_xml() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(DATA1_XML, DATA2_XML));
+
+        assertNoFindings();
+
+        final RootInstance combinedInstanceDataRoot = yangDeviceModel.getCombinedInstanceDataRoot();
+
+        // -------------- Simple stuff ----------------
+
+        final ContainerInstance cont1data = getContainerInstance(combinedInstanceDataRoot, NS1, "cont1");
+        assertTrue(cont1data != null);
+        cont1data.getPath();
+
+        assertTrue(cont1data.getDataDomNode().getNamespace().equals("test:module1"));
+        assertTrue(cont1data.getDataDomNode().getModuleName().equals("module1"));
+
+        final LeafInstance leaf11data = getLeafInstance(cont1data, NS1, "leaf11");
+        assertTrue(leaf11data != null);
+        assertTrue(leaf11data.getValue().equals("42"));
+
+        final LeafInstance leaf12data = getLeafInstance(cont1data, NS1, "leaf12");
+        assertTrue(leaf12data != null);
+        assertTrue(leaf12data.getValue().equals("58"));
+
+        final LeafInstance leaf13data = getLeafInstance(cont1data, NS1, "leaf13");
+        assertTrue(leaf13data != null);
+        assertTrue(leaf13data.getValue().equals("Hello!"));
+
+        final LeafInstance leaf14data = getLeafInstance(cont1data, NS1, "leaf14");
+        assertTrue(leaf14data != null);
+        assertTrue(leaf14data.getValue().equals(""));
+
+        // -------------- A few NPs and defaults ----------------
+
+        final ListInstance list2data4 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "4"));
+        assertTrue(list2data4 != null);
+
+        LeafInstance leaf21data = getLeafInstance(list2data4, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals("4"));
+
+        ContainerInstance cont22data = getContainerInstance(list2data4, NS1, "cont22");
+        assertTrue(cont22data != null);
+
+        LeafInstance leaf23data = getLeafInstance(cont22data, NS1, "leaf23");
+        assertTrue(leaf23data != null);
+        assertTrue(leaf23data.getValue().equals("One"));
+
+        LeafInstance leaf24data = getLeafInstance(cont22data, NS1, "leaf24");
+        assertTrue(leaf24data != null);
+        assertTrue(leaf24data.getValue().equals("Two"));
+
+        LeafInstance leaf25data = getLeafInstance(list2data4, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("Three"));
+
+        List<LeafListInstance> leaflist26data = getLeafListInstances(list2data4, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 1);
+        assertTrue(leaflist26data.get(0).getValue().equals("Six"));
+
+        // ... ... ... ...
+
+        final ListInstance list2data5 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "5"));
+        assertTrue(list2data5 != null);
+
+        leaf21data = getLeafInstance(list2data5, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals("5"));
+
+        cont22data = getContainerInstance(list2data5, NS1, "cont22");
+        assertTrue(cont22data != null);
+
+        leaf23data = getLeafInstance(cont22data, NS1, "leaf23");
+        assertTrue(leaf23data != null);
+        assertTrue(leaf23data.getValue().equals("One"));
+
+        leaf24data = getLeafInstance(cont22data, NS1, "leaf24");
+        assertTrue(leaf24data == null);
+
+        leaf25data = getLeafInstance(list2data5, NS1, "leaf25");
+        assertTrue(leaf25data == null);
+
+        leaflist26data = getLeafListInstances(list2data5, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 0);
+
+        // ... ... ... ...
+
+        final ListInstance list2data6 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "6"));
+        assertTrue(list2data6 != null);
+
+        leaf21data = getLeafInstance(list2data6, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals("6"));
+
+        cont22data = getContainerInstance(list2data6, NS1, "cont22");
+        assertTrue(cont22data == null);
+
+        leaf25data = getLeafInstance(list2data6, NS1, "leaf25");
+        assertTrue(leaf25data == null);
+
+        leaflist26data = getLeafListInstances(list2data6, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 0);
+
+        // --------------------- CDATA ---------------------------
+
+        final ContainerInstance cont8data = getContainerInstance(combinedInstanceDataRoot, NS1, "cont8");
+
+        final LeafInstance leaf81data = getLeafInstance(cont8data, NS1, "leaf81");
+        assertTrue(leaf81data != null);
+        assertTrue(leaf81data.getValue().equals("should ignore whitespaces"));
+
+        final LeafInstance leaf82data = getLeafInstance(cont8data, NS1, "leaf82");
+        assertTrue(leaf82data != null);
+        assertTrue(leaf82data.getValue().equals("should also ignore whitespaces"));
+
+        final LeafInstance leaf83data = getLeafInstance(cont8data, NS1, "leaf83");
+        assertTrue(leaf83data != null);
+        assertTrue(leaf83data.getValue().equals("  should be 2 whitespaces either side  "));
+
+        final LeafInstance leaf84data = getLeafInstance(cont8data, NS1, "leaf84");
+        assertTrue(leaf84data != null);
+        assertTrue(leaf84data.getValue().equals("Before  should be 2 whitespaces either side  After"));
+
+        final LeafInstance leaf85data = getLeafInstance(cont8data, NS1, "leaf85");
+        assertTrue(leaf85data != null);
+        assertTrue(leaf85data.getValue().equals(""));
+
+        final LeafInstance leaf86data = getLeafInstance(cont8data, NS1, "leaf86");
+        assertTrue(leaf86data != null);
+        assertTrue(leaf86data.getValue().equals("blurb more blurb"));
+    }
+
+    @Test
+    public void test_module1_data1_data2_json() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(DATA1_JSON, DATA2_JSON));
+
+        assertNoFindings();
+
+        final RootInstance combinedInstanceDataRoot = yangDeviceModel.getCombinedInstanceDataRoot();
+
+        // -------------- Simple stuff ----------------
+
+        final ContainerInstance cont1data = getContainerInstance(combinedInstanceDataRoot, NS1, "cont1");
+        assertTrue(cont1data != null);
+        cont1data.getPath();
+
+        assertTrue(cont1data.getDataDomNode().getNamespace().equals("test:module1"));
+        assertTrue(cont1data.getDataDomNode().getModuleName().equals("module1"));
+
+        final LeafInstance leaf11data = getLeafInstance(cont1data, NS1, "leaf11");
+        assertTrue(leaf11data != null);
+        assertTrue(leaf11data.getValue().equals(new Long(42)));
+
+        final LeafInstance leaf12data = getLeafInstance(cont1data, NS1, "leaf12");
+        assertTrue(leaf12data != null);
+        assertTrue(leaf12data.getDataDomNode().getNamespace().equals("test:module1"));
+        assertTrue(leaf12data.getDataDomNode().getModuleName().equals("module1"));
+        assertTrue(leaf12data.getValue().equals(new Long(58)));
+
+        final LeafInstance leaf13data = getLeafInstance(cont1data, NS1, "leaf13");
+        assertTrue(leaf13data != null);
+        assertTrue(leaf13data.getValue().equals("Hello!"));
+
+        final LeafInstance leaf14data = getLeafInstance(cont1data, NS1, "leaf14");
+        assertTrue(leaf14data != null);
+        assertTrue(leaf14data.getValue().equals(""));
+
+        // -------------- A few NPs and defaults ----------------
+
+        final ListInstance list2data4 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "4"));
+        assertTrue(list2data4 != null);
+
+        LeafInstance leaf21data = getLeafInstance(list2data4, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getDataDomNode().getNamespace().equals("test:module1"));
+        assertTrue(leaf21data.getDataDomNode().getModuleName().equals("module1"));
+        assertTrue(leaf21data.getValue().equals(new Long(4)));
+
+        ContainerInstance cont22data = getContainerInstance(list2data4, NS1, "cont22");
+        assertTrue(cont22data != null);
+
+        LeafInstance leaf23data = getLeafInstance(cont22data, NS1, "leaf23");
+        assertTrue(leaf23data != null);
+        assertTrue(leaf23data.getValue().equals("One"));
+
+        LeafInstance leaf24data = getLeafInstance(cont22data, NS1, "leaf24");
+        assertTrue(leaf24data != null);
+        assertTrue(leaf24data.getValue().equals("Two"));
+
+        LeafInstance leaf25data = getLeafInstance(list2data4, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("Three"));
+
+        List<LeafListInstance> leaflist26data = getLeafListInstances(list2data4, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 1);
+        assertTrue(leaflist26data.get(0).getValue().equals("Six"));
+
+        // ... ... ... ...
+
+        final ListInstance list2data5 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "5"));
+        assertTrue(list2data5 != null);
+
+        leaf21data = getLeafInstance(list2data5, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals(new Long(5)));
+
+        cont22data = getContainerInstance(list2data5, NS1, "cont22");
+        assertTrue(cont22data != null);
+
+        leaf23data = getLeafInstance(cont22data, NS1, "leaf23");
+        assertTrue(leaf23data != null);
+        assertTrue(leaf23data.getValue().equals("One"));
+
+        leaf24data = getLeafInstance(cont22data, NS1, "leaf24");
+        assertTrue(leaf24data == null);
+
+        leaf25data = getLeafInstance(list2data5, NS1, "leaf25");
+        assertTrue(leaf25data == null);
+
+        leaflist26data = getLeafListInstances(list2data5, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 0);
+
+        // ... ... ... ...
+
+        final ListInstance list2data6 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "6"));
+        assertTrue(list2data6 != null);
+
+        leaf21data = getLeafInstance(list2data6, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals(new Long(6)));
+
+        cont22data = getContainerInstance(list2data6, NS1, "cont22");
+        assertTrue(cont22data == null);
+
+        leaf25data = getLeafInstance(list2data6, NS1, "leaf25");
+        assertTrue(leaf25data == null);
+
+        leaflist26data = getLeafListInstances(list2data6, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 0);
+
+        // --------------------- Unions ---------------------------
+
+        final ContainerInstance cont5data = getContainerInstance(combinedInstanceDataRoot, NS1, "cont5");
+
+        final LeafInstance leaf51data = getLeafInstance(cont5data, NS1, "leaf51");
+        assertTrue(leaf51data != null);
+        assertTrue(leaf51data.getValue().equals(""));
+
+        // --------------------- CDATA ---------------------------
+
+        final ContainerInstance cont8data = getContainerInstance(combinedInstanceDataRoot, NS1, "cont8");
+
+        final LeafInstance leaf81data = getLeafInstance(cont8data, NS1, "leaf81");
+        assertTrue(leaf81data != null);
+        assertTrue(leaf81data.getValue().equals("should ignore whitespaces"));
+
+        final LeafInstance leaf82data = getLeafInstance(cont8data, NS1, "leaf82");
+        assertTrue(leaf82data != null);
+        assertTrue(leaf82data.getValue().equals("should also ignore whitespaces"));
+
+        final LeafInstance leaf83data = getLeafInstance(cont8data, NS1, "leaf83");
+        assertTrue(leaf83data != null);
+        assertTrue(leaf83data.getValue().equals("  should be 2 whitespaces either side  "));
+    }
+
+    @Test
+    public void test_module1_module2_data3_data4() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2));
+        parseAbsoluteYangData(Arrays.asList(DATA3, DATA4));
+
+        assertNoFindings();
+
+        final RootInstance combinedInstanceDataRoot = yangDeviceModel.getCombinedInstanceDataRoot();
+
+        // -------------- A few NPs and defaults ----------------
+
+        final ListInstance list2data35 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue(
+                "leaf21", "35"));
+        assertTrue(list2data35 != null);
+
+        LeafInstance leaf21data = getLeafInstance(list2data35, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals("35"));
+
+        ContainerInstance cont22data = getContainerInstance(list2data35, NS1, "cont22");
+        assertTrue(cont22data != null);
+
+        LeafInstance leaf23data = getLeafInstance(cont22data, NS1, "leaf23");
+        assertTrue(leaf23data != null);
+        assertTrue(leaf23data.getValue().equals("hello"));
+
+        LeafInstance leaf24data = getLeafInstance(cont22data, NS1, "leaf24");
+        assertTrue(leaf24data != null);
+        assertTrue(leaf24data.getValue().equals("world"));
+
+        LeafInstance leaf25data = getLeafInstance(list2data35, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("sure"));
+
+        List<LeafListInstance> leaflist26data = getLeafListInstances(list2data35, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 2);
+        assertTrue(leaflist26data.get(0).getValue().equals("four"));
+        assertTrue(leaflist26data.get(1).getValue().equals("five"));
+
+        // ... ... ... ...
+
+        final ListInstance list2data48 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue(
+                "leaf21", "48"));
+        assertTrue(list2data48 != null);
+
+        leaf21data = getLeafInstance(list2data48, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals("48"));
+
+        cont22data = getContainerInstance(list2data48, NS1, "cont22");
+        assertTrue(cont22data == null);
+
+        leaf25data = getLeafInstance(list2data48, NS1, "leaf25");
+        assertTrue(leaf25data == null);
+
+        leaflist26data = getLeafListInstances(list2data48, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 0);
+
+        // -------------- Some choice handling ----------------
+
+        final ContainerInstance cont3data = getContainerInstance(combinedInstanceDataRoot, NS1, "cont3");
+        assertTrue(cont3data != null);
+
+        final LeafInstance leaf33data = getLeafInstance(cont3data, NS1, "leaf33");
+        assertTrue(leaf33data == null);
+
+        final LeafInstance leaf34data = getLeafInstance(cont3data, NS1, "leaf34");
+        assertTrue(leaf34data == null);
+
+        final ContainerInstance cont35data = getContainerInstance(cont3data, NS1, "cont35");
+        assertTrue(cont35data == null);
+
+        final LeafInstance leaf38data = getLeafInstance(cont3data, NS1, "leaf38");
+        assertTrue(leaf38data == null);
+
+        final ContainerInstance cont39data = getContainerInstance(cont3data, NS1, "cont39");
+        assertTrue(cont39data != null);
+
+        // -------------- for augmentation ----------------
+
+        final ContainerInstance cont7data = getContainerInstance(combinedInstanceDataRoot, NS1, "cont7");
+        assertTrue(cont7data != null);
+
+        final LeafInstance leaf71data = getLeafInstance(cont7data, NS2, "leaf71");
+        assertTrue(leaf71data == null);
+
+        final LeafInstance leaf72data = getLeafInstance(cont7data, NS2, "leaf72");
+        assertTrue(leaf72data != null);
+        assertTrue(leaf72data.getValue().equals("-90"));
+
+        assertTrue(leaf72data.getDataDomNode().getNamespace().equals("test:module2"));
+        assertTrue(leaf72data.getDataDomNode().getModuleName().equals("module2"));
+    }
+
+    @Test
+    public void test_module1_data5_data6() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(DATA5, DATA6));
+
+        assertNoFindings();
+
+        final RootInstance combinedInstanceDataRoot = yangDeviceModel.getCombinedInstanceDataRoot();
+
+        // -------------- first list instance ----------------
+
+        final ListInstance list2data501 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue(
+                "leaf21", "501"));
+        assertTrue(list2data501 != null);
+
+        LeafInstance leaf21data = getLeafInstance(list2data501, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals("501"));
+
+        ContainerInstance cont22data = getContainerInstance(list2data501, NS1, "cont22");
+        assertTrue(cont22data != null);
+
+        LeafInstance leaf23data = getLeafInstance(cont22data, NS1, "leaf23");
+        assertTrue(leaf23data != null);
+        assertTrue(leaf23data.getValue().equals("hello"));
+
+        LeafInstance leaf24data = getLeafInstance(cont22data, NS1, "leaf24");
+        assertTrue(leaf24data != null);
+        assertTrue(leaf24data.getValue().equals("hi"));
+
+        LeafInstance leaf25data = getLeafInstance(list2data501, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("world"));
+
+        List<Object> leaflist26data = getLeafListValues(list2data501, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 0);
+
+        // -------------- second list instance ----------------
+
+        final ListInstance list2data502 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue(
+                "leaf21", "502"));
+        assertTrue(list2data501 != null);
+
+        leaf21data = getLeafInstance(list2data502, NS1, "leaf21");
+        assertTrue(leaf21data != null);
+        assertTrue(leaf21data.getValue().equals("502"));
+
+        cont22data = getContainerInstance(list2data502, NS1, "cont22");
+        assertTrue(cont22data == null);
+
+        leaf25data = getLeafInstance(list2data502, NS1, "leaf25");
+        assertTrue(leaf25data == null);
+
+        leaflist26data = getLeafListValues(list2data502, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 4);
+        assertTrue(leaflist26data.contains("red"));
+        assertTrue(leaflist26data.contains("yellow"));
+        assertTrue(leaflist26data.contains("green"));
+        assertTrue(leaflist26data.contains("blue"));
+    }
+
+    @Test
+    public void test_module1_data5_data6_datainput() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(DATA5, DATA6));
+
+        assertNoFindings();
+
+        final YangData yangDataInput1 = yangDeviceModel.getYangInstanceDataInputs().get(0);
+        assertTrue(yangDataInput1.getFindings().isEmpty());
+        yangDataInput1.toString();
+
+        final YangData yangDataInput2 = yangDeviceModel.getYangInstanceDataInputs().get(1);
+        assertTrue(yangDataInput2.getFindings().isEmpty());
+    }
+
+    @Test
+    public void test_module1_errordata7() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(ERROR_DATA7));
+
+        assertHasFindingOfType(ParserFindingType.P072_MISSING_KEY_VALUE.toString());
+        assertHasFindingOfType(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString());
+        assertHasFindingOfType(ParserFindingType.P076_DUPLICATE_INSTANCE_DATA.toString());
+    }
+
+    @Test
+    public void test_module1_errordata7_datainput() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(ERROR_DATA7));
+
+        final YangData yangDataInput = yangDeviceModel.getYangInstanceDataInputs().get(0);
+        final Set<String> findingTypes = yangDataInput.getFindings().stream().map(finding -> finding.getFindingType())
+                .collect(Collectors.toSet());
+
+        assertTrue(findingTypes.contains(ParserFindingType.P072_MISSING_KEY_VALUE.toString()));
+        assertTrue(findingTypes.contains(ParserFindingType.P075_CORRESPONDING_SCHEMA_NODE_NOT_FOUND.toString()));
+        assertTrue(findingTypes.contains(ParserFindingType.P076_DUPLICATE_INSTANCE_DATA.toString()));
+    }
+
+    @Test
+    public void test_module1_provoke_exception() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+
+        final YangInput yangInput = new YangInput() {
+            @Override
+            public String getName() {
+                return null;
+            }
+
+            @Override
+            public File getFile() {
+                return null;
+            }
+
+            @Override
+            public InputStream getInputStream() {
+                return null;
+            }
+
+            @Override
+            public String getMediaType() {
+                return null;
+            }
+        };
+
+        final YangInputResolver yangInputResolver = new YangInputResolver() {
+            @Override
+            public Set<YangInput> getResolvedYangInput() {
+                return Collections.singleton(yangInput);
+            }
+        };
+
+        yangDeviceModel.parseYangData(context, yangInputResolver, new DataTreeBuilderPredicate());
+
+        assertHasFindingOfType(ParserFindingType.P000_UNSPECIFIED_ERROR.toString());
+    }
+
+    @Test
+    public void test_module1_errordata8_errordata9() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(ERROR_DATA8, ERROR_DATA9));
+
+        assertHasFindingOfType(ParserFindingType.P073_LEAF_VALUE_ALREADY_SET.toString());
+        assertHasFindingOfType(ParserFindingType.P080_NULL_VALUE.toString());
+
+        final RootInstance combinedInstanceDataRoot = yangDeviceModel.getCombinedInstanceDataRoot();
+
+        final ListInstance list2data1 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "1"));
+        assertTrue(list2data1 != null);
+
+        LeafInstance leaf25data = getLeafInstance(list2data1, NS1, "leaf25");
+        assertTrue(leaf25data == null);
+
+        final ListInstance list2data2 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "2"));
+        assertTrue(list2data2 != null);
+
+        leaf25data = getLeafInstance(list2data2, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("abc 123"));
+
+        final ListInstance list2data3 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "3"));
+        assertTrue(list2data3 != null);
+
+        leaf25data = getLeafInstance(list2data3, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("abc 456"));
+
+        final ListInstance list2data4 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "4"));
+        assertTrue(list2data4 != null);
+
+        leaf25data = getLeafInstance(list2data4, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("abc 123"));
+
+        final ListInstance list2data5 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue("leaf21",
+                "5"));
+        assertTrue(list2data5 != null);
+
+        leaf25data = getLeafInstance(list2data5, NS1, "leaf25");
+        assertTrue(leaf25data != null);
+        assertTrue(leaf25data.getValue().equals("abc 123"));
+
+        // ===================================
+
+        final ListInstance list2data51 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue(
+                "leaf21", "51"));
+        assertTrue(list2data51 != null);
+
+        List<LeafListInstance> leaflist26data = getLeafListInstances(list2data51, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 2);
+        assertTrue(leaflist26data.get(0).getValue().equals("abc"));
+        assertTrue(leaflist26data.get(1).getValue().equals("def"));
+
+        final ListInstance list2data52 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue(
+                "leaf21", "52"));
+        assertTrue(list2data52 != null);
+
+        leaflist26data = getLeafListInstances(list2data52, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 2);
+        assertTrue(leaflist26data.get(0).getValue().equals("abc"));
+        assertTrue(leaflist26data.get(1).getValue().equals("def"));
+
+        final ListInstance list2data53 = getListInstanceData(combinedInstanceDataRoot, NS1, "list2", createKeyValue(
+                "leaf21", "53"));
+        assertTrue(list2data53 != null);
+
+        leaflist26data = getLeafListInstances(list2data53, NS1, "leaflist26");
+        assertTrue(leaflist26data != null);
+        assertTrue(leaflist26data.size() == 2);
+        assertTrue(leaflist26data.get(0).getValue().equals("abc"));
+        assertTrue(leaflist26data.get(1).getValue().equals("def"));
+    }
+
+    @Test
+    public void test_module1_errordata10_json() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1));
+        parseAbsoluteYangData(Arrays.asList(ERROR_DATA10));
+
+        assertHasFindingOfType(ParserFindingType.P080_NULL_VALUE.toString());
+    }
+
+    private static Map<String, String> createKeyValue(final String key, final String value) {
+        final Map<String, String> map = new HashMap<>();
+        map.put(key, value);
+        return map;
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/DataTreeBuilderPredicateTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/DataTreeBuilderPredicateTest.java
new file mode 100644
index 0000000..0bed93f
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/DataTreeBuilderPredicateTest.java
@@ -0,0 +1,132 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashSet;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.junit.Test;
+import org.w3c.dom.Document;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.data.YangData;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomDocumentRoot.SourceDataType;
+import org.oran.smo.yangtools.parser.data.instance.DataTreeBuilderPredicate;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class DataTreeBuilderPredicateTest extends YangTestCommon {
+
+    @Test
+    public void test_default_predicate() {
+
+        final File instanceFile = new File("src/test/resources/data/data-tree-builder-predicate-test/two-namespaces.xml");
+        final YangData yangDataFile = new YangData(new FileBasedYangInput(instanceFile));
+
+        try (final InputStream inputStream = new FileInputStream(instanceFile)) {
+
+            final FindingsManager findingsManager = new FindingsManager(new ModifyableFindingSeverityCalculator());
+            final ParserExecutionContext context = new ParserExecutionContext(findingsManager);
+
+            final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            final DocumentBuilder builder = factory.newDocumentBuilder();
+            final Document document = builder.parse(inputStream);
+
+            document.getDocumentElement().normalize();
+
+            final YangDataDomDocumentRoot documentRoot = new YangDataDomDocumentRoot(yangDataFile, SourceDataType.XML);
+            documentRoot.buildFromXmlDocument(context, document);
+
+            assertTrue(documentRoot.getChildren().size() == 2);
+
+            final YangDataDomNode cont1 = documentRoot.getChildren().get(0);
+            assertTrue(cont1.getName().equals("cont1"));
+            assertTrue(cont1.getNamespace().equals("namespace1"));
+
+            final YangDataDomNode cont2 = documentRoot.getChildren().get(1);
+            assertTrue(cont2.getName().equals("cont2"));
+            assertTrue(cont2.getNamespace().equals("namespace2"));
+
+            final DataTreeBuilderPredicate dataTreeBuilderPredicate = new DataTreeBuilderPredicate();
+
+            assertTrue(dataTreeBuilderPredicate.test(cont1) == true);
+            assertTrue(dataTreeBuilderPredicate.test(cont2) == true);
+
+        } catch (Exception e) {
+            fail();
+        }
+    }
+
+    @Test
+    public void test_predicate_one_namespace() {
+
+        final File instanceFile = new File("src/test/resources/data/data-tree-builder-predicate-test/two-namespaces.xml");
+        final YangData yangDataFile = new YangData(new FileBasedYangInput(instanceFile));
+
+        try (final InputStream inputStream = new FileInputStream(instanceFile)) {
+
+            final FindingsManager findingsManager = new FindingsManager(new ModifyableFindingSeverityCalculator());
+            final ParserExecutionContext context = new ParserExecutionContext(findingsManager);
+
+            final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            final DocumentBuilder builder = factory.newDocumentBuilder();
+            final Document document = builder.parse(inputStream);
+
+            document.getDocumentElement().normalize();
+
+            final YangDataDomDocumentRoot documentRoot = new YangDataDomDocumentRoot(yangDataFile, SourceDataType.XML);
+            documentRoot.buildFromXmlDocument(context, document);
+
+            assertTrue(documentRoot.getChildren().size() == 2);
+
+            final YangDataDomNode cont1 = documentRoot.getChildren().get(0);
+            assertTrue(cont1.getName().equals("cont1"));
+            assertTrue(cont1.getNamespace().equals("namespace1"));
+
+            final YangDataDomNode cont2 = documentRoot.getChildren().get(1);
+            assertTrue(cont2.getName().equals("cont2"));
+            assertTrue(cont2.getNamespace().equals("namespace2"));
+
+            final HashSet<String> hashSet = new HashSet<>(Collections.singletonList("namespace1"));
+            final DataTreeBuilderPredicate dataTreeBuilderPredicate = new DataTreeBuilderPredicate(hashSet);
+
+            assertTrue(dataTreeBuilderPredicate.test(cont1) == true);
+            assertTrue(dataTreeBuilderPredicate.test(cont2) == false);
+
+        } catch (Exception e) {
+            fail();
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/InstanceDataTreeBuilderTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/InstanceDataTreeBuilderTest.java
new file mode 100644
index 0000000..8875908
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/test/InstanceDataTreeBuilderTest.java
@@ -0,0 +1,91 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.instance.ContainerInstance;
+import org.oran.smo.yangtools.parser.data.instance.LeafInstance;
+import org.oran.smo.yangtools.parser.data.instance.LeafListInstance;
+import org.oran.smo.yangtools.parser.data.instance.ListInstance;
+import org.oran.smo.yangtools.parser.data.instance.RootInstance;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class InstanceDataTreeBuilderTest extends YangTestCommon {
+
+    @Test
+    public void test_single_data_file() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/data/instance-data-tree-builder-test/module1.yang"));
+        parseAbsoluteYangData(Arrays.asList(
+                "src/test/resources/data/instance-data-tree-builder-test/data-in-single-file.xml"));
+
+        assertNoFindings();
+
+        checkDataParsedCorrectly();
+    }
+
+    private void checkDataParsedCorrectly() {
+        final YModule module = getModule("module1");
+        assertTrue(module != null);
+
+        final RootInstance rootInstance = yangDeviceModel.getCombinedInstanceDataRoot();
+        assertTrue(rootInstance != null);
+
+        final ContainerInstance cont1Instance = getContainerInstance(rootInstance, "test:module", "cont1");
+        assertTrue(cont1Instance != null);
+
+        final Map<String, String> map1 = new HashMap<>();
+        map1.put("leaf111", "key-value-1");
+
+        final ListInstance list11InstanceKeyValue1 = getListInstanceData(cont1Instance, "test:module", "list11", map1);
+        assertTrue(list11InstanceKeyValue1 != null);
+
+        final LeafInstance leaf111Instance = getLeafInstance(list11InstanceKeyValue1, "test:module", "leaf111");
+        assertTrue(leaf111Instance != null);
+        assertTrue(leaf111Instance.getValue().equals("key-value-1"));
+
+        final LeafInstance leaf112Instance = getLeafInstance(list11InstanceKeyValue1, "test:module", "leaf112");
+        assertTrue(leaf112Instance != null);
+        assertTrue(leaf112Instance.getValue().equals("some string"));
+
+        final List<LeafListInstance> leaf113Instance = getLeafListInstances(list11InstanceKeyValue1, "test:module",
+                "leaflist113");
+        assertTrue(leaf113Instance != null);
+        assertTrue(leaf113Instance.size() == 3);
+        assertTrue(leaf113Instance.get(0).getValue().equals("20"));
+        assertTrue(leaf113Instance.get(1).getValue().equals("30"));
+        assertTrue(leaf113Instance.get(2).getValue().equals("40"));
+
+        LeafInstance leaf12Instance = getLeafInstance(cont1Instance, "test:module", "leaf12");
+        assertTrue(leaf12Instance != null);
+        assertTrue(leaf12Instance.getValue().equals("42"));
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/BinaryValueTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/BinaryValueTest.java
new file mode 100644
index 0000000..eb6f246
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/BinaryValueTest.java
@@ -0,0 +1,46 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.util.BinaryValue;
+
+public class BinaryValueTest {
+
+    @Test
+    public void test_binary_value_type() {
+
+        assertTrue(new BinaryValue(new byte[0]).getBinaryValue().length == 0);
+        assertTrue(new BinaryValue(new byte[10]).getBinaryValue().length == 10);
+
+        assertTrue(new String(new BinaryValue("aGVsbG8=").getBinaryValue()).equals("hello"));
+
+        try {
+            new BinaryValue("!£$%^&");
+            fail("Expected exception");
+        } catch (Exception expected) {
+        }
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/BitsValueTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/BitsValueTest.java
new file mode 100644
index 0000000..5f79ac1
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/BitsValueTest.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.util.BitsValue;
+
+public class BitsValueTest {
+
+    @Test
+    public void test_bits_value_type() {
+
+        assertTrue(new BitsValue().getSetBits().isEmpty());
+        assertTrue(new BitsValue("one two").getSetBits().size() == 2);
+        assertTrue(new BitsValue("one   two").getSetBits().size() == 2);
+        assertTrue(new BitsValue("    one two").getSetBits().size() == 2);
+        assertTrue(new BitsValue("one two		").getSetBits().size() == 2);
+
+        assertTrue(new BitsValue("one two").isBitSet("one") == true);
+        assertTrue(new BitsValue("one two").isBitSet("two") == true);
+        assertTrue(new BitsValue("one two").isBitSet("three") == false);
+        assertTrue(new BitsValue("one two").isBitSet(null) == false);
+
+        assertTrue(new BitsValue().setBit("one").isBitSet("one") == true);
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/IdentityRefValueTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/IdentityRefValueTest.java
new file mode 100644
index 0000000..0f93ca1
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/IdentityRefValueTest.java
@@ -0,0 +1,103 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.data.util.IdentityRefValue;
+
+public class IdentityRefValueTest {
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_identity_ref_value_type() {
+
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").getIdentityNamespace().equals("ns1"));
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").getIdentityModuleName().equals("module1"));
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").getIdentityName().equals("identity1"));
+
+        new IdentityRefValue("ns1", "module1", "identity1").toString();
+
+        /*
+         * For XML
+         */
+        final PrefixResolver prefixResolver = new PrefixResolver();
+        prefixResolver.addMapping("ns1", "urn:namespace1");
+        prefixResolver.addMapping("ns2", "urn:namespace2");
+
+        assertTrue(new IdentityRefValue("ns1:identity1", prefixResolver, "urn:namespace99").getIdentityNamespace().equals(
+                "urn:namespace1"));
+        assertTrue(new IdentityRefValue("ns1:identity1", prefixResolver, "urn:namespace99")
+                .getIdentityModuleName() == null);
+        assertTrue(new IdentityRefValue("ns1:identity1", prefixResolver, "urn:namespace99").getIdentityName().equals(
+                "identity1"));
+
+        assertTrue(new IdentityRefValue("identity1", prefixResolver, "urn:namespace99").getIdentityNamespace().equals(
+                "urn:namespace99"));
+        assertTrue(new IdentityRefValue("identity1", prefixResolver, "urn:namespace99").getIdentityModuleName() == null);
+        assertTrue(new IdentityRefValue("identity1", prefixResolver, "urn:namespace99").getIdentityName().equals(
+                "identity1"));
+
+        assertTrue(new IdentityRefValue("ns99:identity1", prefixResolver, "urn:namespace99")
+                .getIdentityNamespace() == null);
+        assertTrue(new IdentityRefValue("ns99:identity1", prefixResolver, "urn:namespace99")
+                .getIdentityModuleName() == null);
+        assertTrue(new IdentityRefValue("ns99:identity1", prefixResolver, "urn:namespace99").getIdentityName().equals(
+                "identity1"));
+
+        /*
+         * For JSON
+         */
+        assertTrue(new IdentityRefValue("module1:identity1", "module99").getIdentityNamespace() == null);
+        assertTrue(new IdentityRefValue("module1:identity1", "module99").getIdentityModuleName().equals("module1"));
+        assertTrue(new IdentityRefValue("module1:identity1", "module99").getIdentityName().equals("identity1"));
+
+        assertTrue(new IdentityRefValue("identity1", "module99").getIdentityNamespace() == null);
+        assertTrue(new IdentityRefValue("identity1", "module99").getIdentityModuleName().equals("module99"));
+        assertTrue(new IdentityRefValue("identity1", "module99").getIdentityName().equals("identity1"));
+
+        /*
+         * Equality
+         */
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(null) == false);
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(new Integer(1)) == false);
+
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(new IdentityRefValue("ns1", "module1",
+                "identityXXX")) == false);
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(new IdentityRefValue("ns1", "moduleXXX",
+                "identity1")) == false);
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(new IdentityRefValue("nsXXX", "module1",
+                "identity1")) == false);
+
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(new IdentityRefValue("ns1", "module1",
+                "identity1")) == true);
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(new IdentityRefValue("ns1", (String) null,
+                "identity1")) == true);
+        assertTrue(new IdentityRefValue("ns1", "module1", "identity1").equals(new IdentityRefValue(null, "module1",
+                "identity1")) == true);
+
+        assertTrue(new IdentityRefValue(null, "module1", "identity1").equals(new IdentityRefValue("ns1", (String) null,
+                "identity1")) == false);
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/ValueHelperTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/ValueHelperTest.java
new file mode 100644
index 0000000..a08a3bf
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/data/util/test/ValueHelperTest.java
@@ -0,0 +1,139 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.data.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.util.BinaryValue;
+import org.oran.smo.yangtools.parser.data.util.BitsValue;
+import org.oran.smo.yangtools.parser.data.util.ValueHelper;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper.YangDataType;
+
+public class ValueHelperTest {
+
+    @Before
+    public void setUp() {
+        new YangModel(new FileBasedYangInput(new File("src/test/resources/model-util/module1.yang")),
+                ConformanceType.IMPLEMENT);
+    }
+
+    @Test
+    public void test_integer_type() {
+        assertTrue(ValueHelper.fromLexicalRepresentation(null, YangDataType.UINT8) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("", YangDataType.UINT8) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("blurb", YangDataType.UINT8) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("10.0", YangDataType.UINT8) == null);
+
+        assertTrue(ValueHelper.fromLexicalRepresentation("+10", YangDataType.UINT8) instanceof BigInteger);
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.UINT8)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.UINT16)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.UINT32)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.UINT64)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.INT8)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.INT16)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.INT32)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+        assertTrue(((BigInteger) ValueHelper.fromLexicalRepresentation("+10", YangDataType.INT64)).compareTo(BigInteger
+                .valueOf(10L)) == 0);
+    }
+
+    @Test
+    public void test_decimal_type() {
+        assertTrue(ValueHelper.fromLexicalRepresentation(null, YangDataType.DECIMAL64) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("", YangDataType.DECIMAL64) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("blurb", YangDataType.DECIMAL64) == null);
+
+        assertTrue(ValueHelper.fromLexicalRepresentation("20.03", YangDataType.DECIMAL64) instanceof BigDecimal);
+        assertTrue(((BigDecimal) ValueHelper.fromLexicalRepresentation("20.03", YangDataType.DECIMAL64)).compareTo(
+                BigDecimal.valueOf(20.03d)) == 0);
+    }
+
+    @Test
+    public void test_string_type() {
+        assertTrue(ValueHelper.fromLexicalRepresentation(null, YangDataType.STRING) == null);
+
+        assertTrue(ValueHelper.fromLexicalRepresentation("", YangDataType.STRING) instanceof String);
+        assertTrue(((String) ValueHelper.fromLexicalRepresentation("ABC", YangDataType.STRING)).equals("ABC"));
+    }
+
+    @Test
+    public void test_boolean_type() {
+        assertTrue(ValueHelper.fromLexicalRepresentation(null, YangDataType.BOOLEAN) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("", YangDataType.BOOLEAN) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("blurb", YangDataType.BOOLEAN) == null);
+
+        assertTrue(ValueHelper.fromLexicalRepresentation("false", YangDataType.BOOLEAN) instanceof Boolean);
+        assertTrue(((Boolean) ValueHelper.fromLexicalRepresentation("false", YangDataType.BOOLEAN)).equals(Boolean.FALSE));
+        assertTrue(((Boolean) ValueHelper.fromLexicalRepresentation("true", YangDataType.BOOLEAN)).equals(Boolean.TRUE));
+    }
+
+    @Test
+    public void test_enumeration_type() {
+        assertTrue(ValueHelper.fromLexicalRepresentation(null, YangDataType.ENUMERATION) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("", YangDataType.ENUMERATION) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("ONE", YangDataType.ENUMERATION) instanceof String);
+        assertTrue(((String) ValueHelper.fromLexicalRepresentation("ONE", YangDataType.ENUMERATION)).equals("ONE"));
+    }
+
+    @Test
+    public void test_bits_type() {
+        assertTrue(ValueHelper.fromLexicalRepresentation(null, YangDataType.BITS) == null);
+
+        assertTrue(ValueHelper.fromLexicalRepresentation("", YangDataType.BITS) instanceof BitsValue);
+        assertTrue(((BitsValue) ValueHelper.fromLexicalRepresentation("ONE", YangDataType.BITS)).getSetBits().size() == 1);
+        assertTrue(((BitsValue) ValueHelper.fromLexicalRepresentation("  ONE   TWO 		", YangDataType.BITS))
+                .getSetBits().size() == 2);
+        assertTrue(((BitsValue) ValueHelper.fromLexicalRepresentation("ONE TWO", YangDataType.BITS)).getSetBits().contains(
+                "ONE"));
+        assertTrue(((BitsValue) ValueHelper.fromLexicalRepresentation("  ONE   TWO  ", YangDataType.BITS)).getSetBits()
+                .contains("TWO"));
+    }
+
+    @Test
+    public void test_binary_type() {
+        assertTrue(ValueHelper.fromLexicalRepresentation(null, YangDataType.BINARY) == null);
+        assertTrue(ValueHelper.fromLexicalRepresentation("", YangDataType.BINARY) instanceof BinaryValue);
+
+        assertTrue(((BinaryValue) ValueHelper.fromLexicalRepresentation("SGVsbG8gV29ybGQh", YangDataType.BINARY))
+                .getBinaryValue().length == 12);
+        assertTrue(Arrays.equals(((BinaryValue) ValueHelper.fromLexicalRepresentation("SGVsbG8gV29ybGQh",
+                YangDataType.BINARY)).getBinaryValue(), "Hello World!".getBytes()));
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/findings/test/FindingsManagerTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/findings/test/FindingsManagerTest.java
new file mode 100644
index 0000000..001087e
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/findings/test/FindingsManagerTest.java
@@ -0,0 +1,521 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.findings.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingSeverity;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.findings.ModuleAndFindingTypeAndSchemaNodePathFilterPredicate;
+import org.oran.smo.yangtools.parser.findings.ModuleAndSeverityFilterPredicate;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+
+public class FindingsManagerTest {
+
+    private YangDeviceModel yangDeviceModel;
+    private ModifyableFindingSeverityCalculator severityCalculator;
+    private FindingsManager findingsManager;
+    private ParserExecutionContext context;
+
+    @Before
+    public void setUp() {
+        yangDeviceModel = new YangDeviceModel("Yang Parser JAR Test Device Model");
+        severityCalculator = new ModifyableFindingSeverityCalculator();
+        findingsManager = new FindingsManager(severityCalculator);
+        context = new ParserExecutionContext(findingsManager);
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        yangFiles.add(new YangModel(new FileBasedYangInput(new File("src/test/resources/findings/module1.yang")),
+                ConformanceType.IMPLEMENT));
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+    }
+
+    @Test
+    public void test_severity_calculator() {
+
+        final ModifyableFindingSeverityCalculator severityCalculator = new ModifyableFindingSeverityCalculator();
+
+        severityCalculator.errorForFinding(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString());
+        severityCalculator.warningForFinding(ParserFindingType.P102_INVALID_STATUS.toString());
+        severityCalculator.infoForFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P104_USAGE_OF_DEPRECATED_ELEMENT.toString());
+
+        severityCalculator.setSeverityForFindingType(ParserFindingType.P111_CIRCULAR_TYPEDEF_REFERENCES.toString(),
+                FindingSeverity.WARNING);
+
+        assertTrue(severityCalculator.calculateSeverity("something else") == FindingSeverity.ERROR);
+
+        assertTrue(severityCalculator.calculateSeverity(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE
+                .toString()) == FindingSeverity.ERROR);
+        assertTrue(severityCalculator.calculateSeverity(ParserFindingType.P102_INVALID_STATUS
+                .toString()) == FindingSeverity.WARNING);
+        assertTrue(severityCalculator.calculateSeverity(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX
+                .toString()) == FindingSeverity.INFO);
+        assertTrue(severityCalculator.calculateSeverity(ParserFindingType.P104_USAGE_OF_DEPRECATED_ELEMENT
+                .toString()) == FindingSeverity.SUPPRESS);
+
+        assertTrue(severityCalculator.calculateSeverity(ParserFindingType.P111_CIRCULAR_TYPEDEF_REFERENCES
+                .toString()) == FindingSeverity.WARNING);
+    }
+
+    @Test
+    public void test_fine_grained_2options_all() {
+
+        addFineGrainedFilter("*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_2options_module1() {
+
+        addFineGrainedFilter("module1;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_2options_mod_star() {
+
+        addFineGrainedFilter("mod*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_2options_module1_and_others() {
+
+        addFineGrainedFilter("module1,module2;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_2options_moduleXXX_all() {
+
+        addFineGrainedFilter("moduleXXX;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_2options_warnings() {
+
+        severityCalculator.warningForFinding(ParserFindingType.P102_INVALID_STATUS.toString());
+
+        addFineGrainedFilter("*;WARNING");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_2options_info() {
+
+        severityCalculator.warningForFinding(ParserFindingType.P102_INVALID_STATUS.toString());
+
+        addFineGrainedFilter("*;INFO");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_2options_warnings_info() {
+
+        severityCalculator.warningForFinding(ParserFindingType.P102_INVALID_STATUS.toString());
+
+        addFineGrainedFilter("*;WARNING,INFO");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_2options_module1_warnings() {
+
+        severityCalculator.warningForFinding(ParserFindingType.P102_INVALID_STATUS.toString());
+
+        addFineGrainedFilter("module1;WARNING");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_2options_moduleXXX_warnings() {
+
+        severityCalculator.warningForFinding(ParserFindingType.P102_INVALID_STATUS.toString());
+
+        addFineGrainedFilter("moduleXXX;WARNING");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_3options_all() {
+
+        addFineGrainedFilter("*;*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_module1() {
+
+        addFineGrainedFilter("module1;*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_module1_moduleXXX() {
+
+        addFineGrainedFilter("module1,moduleXXX;*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_moduleXXX() {
+
+        addFineGrainedFilter("moduleXXX;*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_3options_mod_star() {
+
+        addFineGrainedFilter("mod*;*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_invalidstatus() {
+
+        addFineGrainedFilter("*;P102_INVALID_STATUS;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_p1_star() {
+
+        addFineGrainedFilter("*;P1*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_p0_star() {
+
+        addFineGrainedFilter("*;P0*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_3options_p000_star_invalidstatus() {
+
+        addFineGrainedFilter("*;P000*,P102_INVALID_STATUS;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_module1_p1_star() {
+
+        addFineGrainedFilter("module1;P1*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_moduleXXX_p1_star() {
+
+        addFineGrainedFilter("moduleXXX;P1*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_3options_moduelXXX_p1_star() {
+
+        addFineGrainedFilter("moduleXXX;P1*;*");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_3options_path_module_module1() {
+
+        addFineGrainedFilter("*;*;/module=module1");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_path_module_moduleXXX() {
+
+        addFineGrainedFilter("*;*;/module=moduleXXX");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_3options_path_module_module1_leaf_leaf1() {
+
+        addFineGrainedFilter("*;*;/module=module1/leaf=leaf1");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+    }
+
+    @Test
+    public void test_fine_grained_3options_path_module_module1_leaf_leaf2() {
+
+        addFineGrainedFilter("*;*;/module=module1/leaf=leaf2");
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        findingsManager.addFinding(new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_fine_grained_3options_path_module_module1_leaf_leaf1_not_on_leaf() {
+
+        addFineGrainedFilter("*;*;/module=module1/leaf=leaf1");
+
+        findingsManager.addFinding(new Finding(ParserFindingType.P102_INVALID_STATUS.toString(), "message"));
+        assertTrue(findingsManager.getAllFindings().size() == 1);
+    }
+
+    @Test
+    public void test_finding_general_finding() {
+
+        final Finding finding1 = new Finding(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString(), "Missing Value");
+        final Finding finding2 = new Finding(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString(), "Missing Value");
+
+        final Finding finding3 = new Finding(ParserFindingType.P102_INVALID_STATUS.toString(), "Missing Value");
+        final Finding finding4 = new Finding(ParserFindingType.P102_INVALID_STATUS.toString(), "Other Missing Value");
+
+        assertTrue(finding1.getDataDomNode() == null);
+        assertTrue(finding1.getFindingType().equals(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString()));
+        assertTrue(finding1.getLineNumber() == 0);
+        assertTrue(finding1.getMessage().equals("Missing Value"));
+        assertTrue(finding1.getStatement() == null);
+        assertTrue(finding1.getYangData() == null);
+        assertTrue(finding1.getYangModel() == null);
+
+        assertTrue(finding1.isYangModelRelated() == false);
+        assertTrue(finding1.isInstanceDataRelated() == false);
+        assertTrue(finding1.isGeneralFinding() == true);
+        assertTrue(finding1.toString().equals(" P101_EMPTY_DOCUMENTATION_VALUE: Missing Value"));
+
+        assertTrue(finding1.equals(null) == false);
+        assertTrue(finding1.equals(finding2) == true);
+        assertTrue(finding1.equals(finding3) == false);
+        assertTrue(finding3.equals(finding4) == false);
+    }
+
+    @Test
+    public void test_finding_module_finding() {
+
+        final YLeaf leaf1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule()
+                .getLeafs().get(0);
+
+        final Finding finding8 = new Finding(leaf1, ParserFindingType.P102_INVALID_STATUS.toString(), "message");
+
+        assertTrue(finding8.getDataDomNode() == null);
+        assertTrue(finding8.getFindingType().equals(ParserFindingType.P102_INVALID_STATUS.toString()));
+        assertTrue(finding8.getLineNumber() == 14);
+        assertTrue(finding8.getMessage().equals("message"));
+        assertTrue(finding8.getStatement() == leaf1);
+        assertTrue(finding8.getYangData() == null);
+        assertTrue(finding8.getYangModel() == yangDeviceModel.getModuleRegistry().getAllYangModels().get(0));
+
+        assertTrue(finding8.isYangModelRelated() == true);
+        assertTrue(finding8.isInstanceDataRelated() == false);
+        assertTrue(finding8.isGeneralFinding() == false);
+        assertTrue(finding8.toString().equals("module1.yang / line 14 P102_INVALID_STATUS: message"));
+    }
+
+    @Test
+    public void test_getFiltered_allow_all() {
+
+        final Finding finding1 = new Finding(ParserFindingType.P102_INVALID_STATUS.toString(), "message");
+        Set<Finding> findings = Collections.singleton(finding1);
+
+        final Set<Finding> filteredFindings = findingsManager.getFilteredFindings(findings);
+
+        assertTrue(filteredFindings.size() == 1);
+    }
+
+    @Test
+    public void test_getFiltered_suppless_all() {
+
+        final Finding finding1 = new Finding(ParserFindingType.P102_INVALID_STATUS.toString(), "message");
+        Set<Finding> findings = Collections.singleton(finding1);
+
+        findingsManager.setSuppressAll(true);
+        final Set<Finding> filteredFindings = findingsManager.getFilteredFindings(findings);
+
+        assertTrue(filteredFindings.size() == 0);
+    }
+
+    @Test
+    public void test_getFiltered_suppless_invalid_status() {
+
+        final Finding finding1 = new Finding(ParserFindingType.P102_INVALID_STATUS.toString(), "message");
+        Set<Finding> findings = Collections.singleton(finding1);
+
+        severityCalculator.suppressFinding(ParserFindingType.P102_INVALID_STATUS.toString());
+        final Set<Finding> filteredFindings = findingsManager.getFilteredFindings(findings);
+
+        assertTrue(filteredFindings.size() == 0);
+    }
+
+    private void addFineGrainedFilter(final String filterString) {
+        if (filterString.split(";").length == 2) {
+            findingsManager.addFilterPredicate(ModuleAndSeverityFilterPredicate.fromString(filterString, findingsManager
+                    .getFindingSeverityCalculator()));
+        } else {
+            findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                    filterString));
+        }
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/ByteArrayYangInputTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/ByteArrayYangInputTest.java
new file mode 100644
index 0000000..4516e3e
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/ByteArrayYangInputTest.java
@@ -0,0 +1,142 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.input.ByteArrayYangInput;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+
+public class ByteArrayYangInputTest {
+
+    private YangDeviceModel yangDeviceModel;
+    private ModifyableFindingSeverityCalculator severityCalculator;
+    private FindingsManager findingsManager;
+    private ParserExecutionContext context;
+
+    @Test
+    public void test_byte_array_input() {
+
+        final String moduleContent = getModuleContent();
+        final byte[] bytes = moduleContent.getBytes();
+        final ByteArrayYangInput byteArrayYangInput = new ByteArrayYangInput(bytes, "test");
+
+        // First run
+
+        yangDeviceModel = new YangDeviceModel("Yang Parser JAR Test Device Model");
+        severityCalculator = new ModifyableFindingSeverityCalculator();
+        findingsManager = new FindingsManager(severityCalculator);
+        context = new ParserExecutionContext(findingsManager);
+
+        List<YangModel> yangModelInputs = new ArrayList<>();
+        yangModelInputs.add(new YangModel(byteArrayYangInput, ConformanceType.IMPLEMENT));
+        yangDeviceModel.parseIntoYangModels(context, yangModelInputs);
+
+        YModule module = yangModelInputs.get(0).getYangModelRoot().getModule();
+        assertTrue(module.getModuleName().equals("byte-array-test-module"));
+
+        YContainer cont1 = module.getContainers().get(0);
+        assertTrue(cont1.getContainerName().equals("cont1"));
+
+        YLeaf leaf1 = cont1.getLeafs().get(0);
+        assertTrue(leaf1.getLeafName().equals("leaf1"));
+
+        // Set up the whole lot again for second run, except for the ByteArrayYangInput, to test repeated parsing.
+
+        yangDeviceModel = new YangDeviceModel("Yang Parser JAR Test Device Model");
+        severityCalculator = new ModifyableFindingSeverityCalculator();
+        findingsManager = new FindingsManager(severityCalculator);
+        context = new ParserExecutionContext(findingsManager);
+
+        yangModelInputs = new ArrayList<>();
+        yangModelInputs.add(new YangModel(byteArrayYangInput, ConformanceType.IMPLEMENT));
+        yangDeviceModel.parseIntoYangModels(context, yangModelInputs);
+
+        module = yangModelInputs.get(0).getYangModelRoot().getModule();
+        assertTrue(module.getModuleName().equals("byte-array-test-module"));
+
+        cont1 = module.getContainers().get(0);
+        assertTrue(cont1.getContainerName().equals("cont1"));
+
+        cont1.getLeafs().get(0);
+        assertTrue(leaf1.getLeafName().equals("leaf1"));
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_byte_array_input_equals() {
+
+        final byte[] bytes1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+        final byte[] bytes2 = new byte[] { 9, 8, 7, 6 };
+
+        final ByteArrayYangInput input1 = new ByteArrayYangInput(bytes1, "test");
+        final ByteArrayYangInput input2 = new ByteArrayYangInput(bytes1, "test");
+        final ByteArrayYangInput input3 = new ByteArrayYangInput(bytes1, "other");
+        final ByteArrayYangInput input4 = new ByteArrayYangInput(bytes2, "test");
+
+        assertTrue(input1.equals(input2) == true);
+        assertTrue(input1.equals(null) == false);
+        assertTrue(input1.equals("") == false);
+        assertTrue(input1.equals(input3) == false);
+        assertTrue(input1.equals(input4) == false);
+
+        assertTrue(input1.getName().equals("test"));
+        assertTrue(input1.getFile() == null);
+    }
+
+    private static String getModuleContent() {
+
+        final StringBuilder sb = new StringBuilder(1000);
+
+        sb.append("module byte-array-test-module {\n");
+        sb.append("\n");
+        sb.append("    namespace \"test:byte-array-test-module\";\n");
+        sb.append("    prefix \"this\";\n");
+        sb.append("\n");
+        sb.append("    revision \"2021-04-06\" {\n");
+        sb.append("        description \"initial revision\";\n");
+        sb.append("    }\n");
+        sb.append("\n");
+        sb.append("container cont1 {\n");
+        sb.append("\n");
+        sb.append("		leaf leaf1 {\n");
+        sb.append("			type int8;\n");
+        sb.append("		}\n");
+        sb.append("	}n");
+        sb.append("\n");
+        sb.append("}\n");
+
+        return sb.toString();
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/FileBasedYangInputResolverTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/FileBasedYangInputResolverTest.java
new file mode 100644
index 0000000..7e5a7c0
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/FileBasedYangInputResolverTest.java
@@ -0,0 +1,188 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Set;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.input.FileBasedYangInputResolver;
+import org.oran.smo.yangtools.parser.input.YangInput;
+
+public class FileBasedYangInputResolverTest {
+
+    private static final String ROOT = "src/test/resources/basics/file-based-resolver-test";
+
+    private static final String FILE1 = ROOT + "/folder1/file1.yang";
+    private static final String FILE2 = ROOT + "/folder1/file2.xml";
+    private static final String FILE3 = ROOT + "/folder1/file3.txt";
+
+    private static final String FILE4 = ROOT + "/folder2/file4.yang";
+    private static final String FILE5 = ROOT + "/folder2/file5";
+
+    private static final String DOES_NOT_EXISTS = ROOT + "/does-not-exist.yang";
+
+    @Test
+    public void test_ok_all() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(ROOT)));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 5);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE2);
+        assertContainsFile(resolvedYangInput, FILE3);
+        assertContainsFile(resolvedYangInput, FILE4);
+        assertContainsFile(resolvedYangInput, FILE5);
+    }
+
+    @Test
+    public void test_ok_folder1() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(
+                ROOT + "/folder1")));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 3);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE2);
+        assertContainsFile(resolvedYangInput, FILE3);
+    }
+
+    @Test
+    public void test_ok_root_supplied_twice() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(ROOT), new File(
+                ROOT)));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 5);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE2);
+        assertContainsFile(resolvedYangInput, FILE3);
+        assertContainsFile(resolvedYangInput, FILE4);
+        assertContainsFile(resolvedYangInput, FILE5);
+    }
+
+    @Test
+    public void test_ok_root_and_folder1_supplied() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(ROOT), new File(
+                ROOT + "/folder1")));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 5);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE2);
+        assertContainsFile(resolvedYangInput, FILE3);
+        assertContainsFile(resolvedYangInput, FILE4);
+        assertContainsFile(resolvedYangInput, FILE5);
+    }
+
+    @Test
+    public void test_ok_folder1_and_folder2_supplied() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(
+                ROOT + "/folder2"), new File(ROOT + "/folder1")));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 5);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE2);
+        assertContainsFile(resolvedYangInput, FILE3);
+        assertContainsFile(resolvedYangInput, FILE4);
+        assertContainsFile(resolvedYangInput, FILE5);
+    }
+
+    @Test
+    public void test_ok_yang_files() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(ROOT)), Arrays
+                .asList(FileBasedYangInputResolver.FILE_EXTENSION_YANG));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 2);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE4);
+    }
+
+    @Test
+    public void test_ok_yang_files_uppercase() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(ROOT)), Arrays
+                .asList(FileBasedYangInputResolver.FILE_EXTENSION_YANG));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 2);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE4);
+    }
+
+    @Test
+    public void test_ok_yang_and_xml_files() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(ROOT)), Arrays
+                .asList(FileBasedYangInputResolver.FILE_EXTENSION_YANG, FileBasedYangInputResolver.FILE_EXTENSION_XML));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 3);
+
+        assertContainsFile(resolvedYangInput, FILE1);
+        assertContainsFile(resolvedYangInput, FILE2);
+        assertContainsFile(resolvedYangInput, FILE4);
+    }
+
+    @Test
+    public void test_err_file_does_not_exist() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(Arrays.asList(new File(
+                DOES_NOT_EXISTS)));
+
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+        assertTrue(resolvedYangInput.size() == 0);
+    }
+
+    private void assertContainsFile(Set<YangInput> resolvedYangInput, final String path) {
+
+        final File sought = new File(path);
+
+        for (final YangInput input : resolvedYangInput) {
+            if (input.getFile().equals(sought)) {
+                return;
+            }
+        }
+
+        fail("Does not contain file " + path);
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/FileBasedYangInputTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/FileBasedYangInputTest.java
new file mode 100644
index 0000000..db6ec33
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/input/test/FileBasedYangInputTest.java
@@ -0,0 +1,77 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.input.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+
+public class FileBasedYangInputTest {
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_all_ok() {
+
+        final File file = new File("src/test/resources/basics/yang-input-test/module1-2020-01-01.yang");
+
+        final FileBasedYangInput input1 = new FileBasedYangInput(file);
+
+        assertTrue(input1.getFile() == file);
+        assertTrue(input1.getName().equals("module1-2020-01-01.yang"));
+        assertTrue(input1.getInputStream() != null);
+
+        final FileBasedYangInput input2 = new FileBasedYangInput(file);
+        assertTrue(input1.equals(input1));
+        assertTrue(input1.equals(input2));
+        assertFalse(input1.equals(null));
+        assertFalse(input1.equals(""));
+        assertFalse(input1.equals(new File("otherFile")));
+    }
+
+    @Test
+    public void test_failures() {
+
+        try {
+            new FileBasedYangInput(null);
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+
+        try {
+            new FileBasedYangInput(new File("unknown file"));
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+
+        try {
+            new FileBasedYangInput(new File("src/test"));
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/AnnotationRegistryTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/AnnotationRegistryTest.java
new file mode 100644
index 0000000..ecce50b
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/AnnotationRegistryTest.java
@@ -0,0 +1,65 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.schema.AnnotationRegistry;
+import org.oran.smo.yangtools.parser.model.util.YangAnnotation;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class AnnotationRegistryTest extends YangTestCommon {
+
+    @Test
+    public void test_all_modules() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/annotation-registry-test/module1.yang",
+                "src/test/resources/model-schema/annotation-registry-test/module2.yang", YANG_METADATA_PATH,
+                YANG_ORIGIN_PATH);
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final AnnotationRegistry annotationRegistry = yangDeviceModel.getTopLevelSchema().getAnnotationRegistry();
+
+        final List<YangAnnotation> annotations = annotationRegistry.getAnnotations();
+
+        assertTrue(annotations.contains(new YangAnnotation("test:module1", "module1", "created")));
+        assertTrue(annotations.contains(new YangAnnotation("test:module1", "module1", "last-modified")));
+
+        assertTrue(annotations.contains(new YangAnnotation("test:module2", "module2", "modified-user")));
+
+        assertTrue(annotations.contains(new YangAnnotation("urn:ietf:params:xml:ns:yang:ietf-origin", "ietf-origin",
+                "origin")));
+
+        assertTrue(annotations.size() == 4);
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/IdentityRegistryTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/IdentityRegistryTest.java
new file mode 100644
index 0000000..2364d1a
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/IdentityRegistryTest.java
@@ -0,0 +1,253 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.schema.IdentityRegistry;
+import org.oran.smo.yangtools.parser.model.util.YangIdentity;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class IdentityRegistryTest extends YangTestCommon {
+
+    @Test
+    public void test_all_modules() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/identity-registry-test/module1.yang",
+                "src/test/resources/model-schema/identity-registry-test/module2.yang",
+                "src/test/resources/model-schema/identity-registry-test/module3.yang",
+                "src/test/resources/model-schema/identity-registry-test/submodule4.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final IdentityRegistry identityRegistry = yangDeviceModel.getTopLevelSchema().getIdentityRegistry();
+
+        // ---- module 1 ---- bases ------
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity11"))
+                .size() == 0);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity12"))
+                .size() == 0);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity13"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity14"))
+                .size() == 3);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity14")).contains(
+                new YangIdentity("test:module1", "module1", "identity11")));
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity14")).contains(
+                new YangIdentity("test:module1", "module1", "identity12")));
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity14")).contains(
+                new YangIdentity("test:module1", "module1", "identity13")));
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity15"))
+                .size() == 1);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity15")).contains(
+                new YangIdentity("test:module1", "module1", "identity14")));
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity61"))
+                .size() == 2);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity61")).contains(
+                new YangIdentity("test:module1", "module1", "identity14")));
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity61")).contains(
+                new YangIdentity("test:module1", "module1", "identity42")));
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity99"))
+                .size() == 1);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity99")).contains(
+                new YangIdentity("test:module2", "module2", "identity99")));
+
+        // ---- module 2 ---- bases ------
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module2", "module2", "identity21"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module2", "module2", "identity22"))
+                .size() == 1);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module2", "module2", "identity22")).contains(
+                new YangIdentity("test:module2", "module2", "identity21")));
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module2", "module2", "identity23"))
+                .size() == 1);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module2", "module2", "identity23")).contains(
+                new YangIdentity("test:module1", "module1", "identity11")));
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module2", "module2", "identity99"))
+                .size() == 0);
+
+        // ---- module 3 ---- bases ------
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module3", "module3", "identity31"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module3", "module3", "identity32"))
+                .size() == 1);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module3", "module3", "identity32")).contains(
+                new YangIdentity("test:module3", "module3", "identity31")));
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module3", "module3", "identity33"))
+                .size() == 1);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module3", "module3", "identity33")).contains(
+                new YangIdentity("test:module2", "module2", "identity21")));
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module3", "module3", "identity99"))
+                .size() == 0);
+
+        // ---- submodule 4 ---- bases ------
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity41"))
+                .size() == 0);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity42"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity43"))
+                .size() == 2);
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity43")).contains(
+                new YangIdentity("test:module1", "module1", "identity41")));
+        assertTrue(identityRegistry.getBasesForIdentity(new YangIdentity("test:module1", "module1", "identity43")).contains(
+                new YangIdentity("test:module1", "module1", "identity42")));
+
+        // ---- module 1 ---- derivates ------
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity11"))
+                .size() == 2);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity11"))
+                .contains(new YangIdentity("test:module1", "module1", "identity14")));
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity11"))
+                .contains(new YangIdentity("test:module2", "module2", "identity23")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity12"))
+                .size() == 1);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity12"))
+                .contains(new YangIdentity("test:module1", "module1", "identity14")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity13"))
+                .size() == 1);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity13"))
+                .contains(new YangIdentity("test:module1", "module1", "identity14")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity14"))
+                .size() == 2);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity14"))
+                .contains(new YangIdentity("test:module1", "module1", "identity15")));
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity14"))
+                .contains(new YangIdentity("test:module1", "module1", "identity61")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity15"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity61"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity99"))
+                .size() == 0);
+
+        // ---- module 2 ---- derivates ------
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module2", "module2", "identity21"))
+                .size() == 2);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module2", "module2", "identity21"))
+                .contains(new YangIdentity("test:module2", "module2", "identity22")));
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module2", "module2", "identity21"))
+                .contains(new YangIdentity("test:module3", "module3", "identity33")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module2", "module2", "identity22"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module2", "module2", "identity23"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module2", "module2", "identity99"))
+                .size() == 1);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module2", "module2", "identity99"))
+                .contains(new YangIdentity("test:module1", "module1", "identity99")));
+
+        // ---- module 3 ---- derivates ------
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module3", "module3", "identity31"))
+                .size() == 1);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module3", "module3", "identity31"))
+                .contains(new YangIdentity("test:module3", "module3", "identity32")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module3", "module3", "identity32"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module3", "module3", "identity33"))
+                .size() == 0);
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module3", "module3", "identity99"))
+                .size() == 0);
+
+        // ---- submodule 4 ---- derivates ------
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity41"))
+                .size() == 1);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity41"))
+                .contains(new YangIdentity("test:module1", "module1", "identity43")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity42"))
+                .size() == 2);
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity42"))
+                .contains(new YangIdentity("test:module1", "module1", "identity43")));
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity42"))
+                .contains(new YangIdentity("test:module1", "module1", "identity61")));
+
+        assertTrue(identityRegistry.getDerivatesOfIdentity(new YangIdentity("test:module1", "module1", "identity43"))
+                .size() == 0);
+
+        // ---------------- check the derived trees ---------------
+
+        Set<YangIdentity> identityAndDerivedIdentities = identityRegistry.getIdentityAndDerivedIdentitiesRecursively(
+                new YangIdentity("test:module1", "module1", "identity11"));
+
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity11")));
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity14")));
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity15")));
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity61")));
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module2", "module2", "identity23")));
+        assertTrue(identityAndDerivedIdentities.size() == 5);
+
+        identityAndDerivedIdentities = identityRegistry.getIdentityAndDerivedIdentitiesRecursively(new YangIdentity(
+                "test:module1", "module1", "identity12"));
+
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity12")));
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity14")));
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity15")));
+        assertTrue(identityAndDerivedIdentities.contains(new YangIdentity("test:module1", "module1", "identity61")));
+        assertTrue(identityAndDerivedIdentities.size() == 4);
+
+        identityAndDerivedIdentities = identityRegistry.getIdentityAndDerivedIdentitiesRecursively(new YangIdentity(
+                "unknown-namespace", "unknown-module", "unknown-identity"));
+        assertTrue(identityAndDerivedIdentities.size() == 0);
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/ModuleRegistryTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/ModuleRegistryTest.java
new file mode 100644
index 0000000..521c3e8
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/ModuleRegistryTest.java
@@ -0,0 +1,232 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.schema.ModuleRegistry;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class ModuleRegistryTest extends YangTestCommon {
+
+    @Test
+    public void test_two_modules_implement_allOk() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang",
+                "src/test/resources/model-schema/module-registry-test/module2-2020-01-01.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        assertTrue(moduleRegistry.getAllYangModels().size() == 2);
+
+        assertTrue(moduleRegistry.find("module1", "2020-01-01") != null);
+        assertTrue(moduleRegistry.find("module2", "2020-01-01") != null);
+        assertTrue(moduleRegistry.find(new ModuleIdentity("module1")) != null);
+        assertTrue(moduleRegistry.find(new ModuleIdentity("module2")) != null);
+        assertTrue(moduleRegistry.find("module1", "1987-12-12") == null);
+        assertTrue(moduleRegistry.find("module2", "1987-12-12") == null);
+        assertTrue(moduleRegistry.find("XXX", "2020-01-01") == null);
+        assertTrue(moduleRegistry.find("XXX", null) == null);
+        assertTrue(moduleRegistry.find("XXX", "1987-12-12") == null);
+
+        assertTrue(moduleRegistry.find(new ModuleIdentity("module1", "2020-01-01")) != null);
+
+        assertTrue(moduleRegistry.byModuleName("module1").size() == 1);
+        assertTrue(moduleRegistry.byModuleName("module2").size() == 1);
+        assertTrue(moduleRegistry.byModuleName("XXX").isEmpty());
+    }
+
+    @Test
+    public void test_two_modules_implement_same_revision() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang",
+                "src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertHasFindingOfType(ParserFindingType.P003_DUPLICATE_INPUT.toString());
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        assertTrue(moduleRegistry.getAllYangModels().size() == 1);
+
+        assertTrue(moduleRegistry.find(new ModuleIdentity("module1")) != null);
+        assertTrue(moduleRegistry.find("XXX", "2020-01-01") == null);
+        assertTrue(moduleRegistry.find("XXX", null) == null);
+        assertTrue(moduleRegistry.find("XXX", "1987-12-12") == null);
+
+        assertTrue(moduleRegistry.byModuleName("module1").size() == 1);
+        assertTrue(moduleRegistry.byModuleName("module2").isEmpty());
+        assertTrue(moduleRegistry.byModuleName("XXX").isEmpty());
+    }
+
+    @Test
+    public void test_two_modules_implement_same_empty_revision() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-no-revision.yang",
+                "src/test/resources/model-schema/module-registry-test/module1-no-revision.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertHasFindingOfType(ParserFindingType.P003_DUPLICATE_INPUT.toString());
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        assertTrue(moduleRegistry.getAllYangModels().size() == 1);
+
+        assertTrue(moduleRegistry.find(new ModuleIdentity("module1")) != null);
+        assertTrue(moduleRegistry.find("XXX", "2020-01-01") == null);
+        assertTrue(moduleRegistry.find("XXX", null) == null);
+        assertTrue(moduleRegistry.find("XXX", "1987-12-12") == null);
+
+        assertTrue(moduleRegistry.byModuleName("module1").size() == 1);
+        assertTrue(moduleRegistry.byModuleName("module2").isEmpty());
+        assertTrue(moduleRegistry.byModuleName("XXX").isEmpty());
+    }
+
+    @Test
+    public void test_two_modules_implement_different_revisions() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang",
+                "src/test/resources/model-schema/module-registry-test/module1-no-revision.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertHasFindingOfType(ParserFindingType.P004_SAME_MODULE_DUPLICATE_IMPLEMENTS.toString());
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        assertTrue(moduleRegistry.getAllYangModels().size() == 2);
+
+        assertTrue(moduleRegistry.find("module1", "2020-01-01") != null);
+        assertTrue(moduleRegistry.find("module1", null) != null);
+        assertTrue(moduleRegistry.find("module1", "1987-12-12") == null);
+        assertTrue(moduleRegistry.find("XXX", "2020-01-01") == null);
+        assertTrue(moduleRegistry.find("XXX", null) == null);
+        assertTrue(moduleRegistry.find("XXX", "1987-12-12") == null);
+
+        assertTrue(moduleRegistry.byModuleName("module1").size() == 2);
+        assertTrue(moduleRegistry.byModuleName("XXX").isEmpty());
+    }
+
+    @Test
+    public void test_two_modules_different_revisions_onebeingempty_one_implement_one_import() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang");
+        final List<String> absoluteImportsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-no-revision.yang");
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        assertTrue(moduleRegistry.getAllYangModels().size() == 2);
+
+        assertTrue(moduleRegistry.find("module1", "2020-01-01") != null);
+        assertTrue(moduleRegistry.find("module1", null) != null);
+        assertTrue(moduleRegistry.find("module1", "1987-12-12") == null);
+        assertTrue(moduleRegistry.find("XXX", "2020-01-01") == null);
+        assertTrue(moduleRegistry.find("XXX", null) == null);
+        assertTrue(moduleRegistry.find("XXX", "1987-12-12") == null);
+
+        assertTrue(moduleRegistry.byModuleName("module1").size() == 2);
+        assertTrue(moduleRegistry.byModuleName("XXX").isEmpty());
+    }
+
+    @Test
+    public void test_two_modules_different_revision_one_implement_one_import() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang");
+        final List<String> absoluteImportsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module1-2020-02-02.yang");
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        assertTrue(moduleRegistry.getAllYangModels().size() == 2);
+
+        assertTrue(moduleRegistry.find("module1", "2020-01-01") != null);
+        assertTrue(moduleRegistry.find("module1", "2020-02-02") != null);
+        assertTrue(moduleRegistry.find("module1", null) == null);
+        assertTrue(moduleRegistry.find("module1", "1987-12-12") == null);
+        assertTrue(moduleRegistry.find("XXX", "2020-01-01") == null);
+        assertTrue(moduleRegistry.find("XXX", null) == null);
+        assertTrue(moduleRegistry.find("XXX", "1987-12-12") == null);
+
+        assertTrue(moduleRegistry.byModuleName("module1").size() == 2);
+        assertTrue(moduleRegistry.byModuleName("XXX").isEmpty());
+    }
+
+    @Test
+    public void test_submodules_implement_allOk() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/module-registry-test/module3-2020-01-01.yang",
+                "src/test/resources/model-schema/module-registry-test/module3-submodule1-1999-09-09.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        assertTrue(moduleRegistry.getAllYangModels().size() == 2);
+
+        assertTrue(moduleRegistry.find("module3", "2020-01-01") != null);
+        assertTrue(moduleRegistry.find("module3-submodule1", "1999-09-09") != null);
+        assertTrue(moduleRegistry.find(new ModuleIdentity("module3")) != null);
+        assertTrue(moduleRegistry.find(new ModuleIdentity("module3-submodule1")) != null);
+        assertTrue(moduleRegistry.find("module3", "1987-12-12") == null);
+        assertTrue(moduleRegistry.find("module3-submodule1", "1987-12-12") == null);
+        assertTrue(moduleRegistry.find("XXX", "2020-01-01") == null);
+        assertTrue(moduleRegistry.find("XXX", null) == null);
+        assertTrue(moduleRegistry.find("XXX", "1987-12-12") == null);
+
+        assertTrue(moduleRegistry.byModuleName("module3").size() == 1);
+        assertTrue(moduleRegistry.byModuleName("module3-submodule1").size() == 1);
+        assertTrue(moduleRegistry.byModuleName("XXX").isEmpty());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/PrefixAndNamespaceResolverTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/PrefixAndNamespaceResolverTest.java
new file mode 100644
index 0000000..74d4d71
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/PrefixAndNamespaceResolverTest.java
@@ -0,0 +1,109 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.ModulePrefixResolver;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class PrefixAndNamespaceResolverTest extends YangTestCommon {
+
+    @Test
+    public void test_all_modules() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/prefix-and-namespace-test/module1.yang",
+                "src/test/resources/model-schema/prefix-and-namespace-test/module2.yang",
+                "src/test/resources/model-schema/prefix-and-namespace-test/module3.yang",
+                "src/test/resources/model-schema/prefix-and-namespace-test/submodule4.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final ModuleAndNamespaceResolver namespaceResolver = yangDeviceModel.getTopLevelSchema()
+                .getModuleNamespaceResolver();
+        assertTrue(namespaceResolver.getNamespaceForModule("module1").equals("test:module1"));
+        assertTrue(namespaceResolver.getNamespaceForModule("module2").equals("test:module2"));
+        assertTrue(namespaceResolver.getNamespaceForModule("module3").equals("test:module3"));
+        assertTrue(namespaceResolver.getNamespaceForModule("submodule4").equals("test:module1"));
+        assertTrue(namespaceResolver.getNamespaceForModule("unknownmodule") == null);
+
+        assertTrue(namespaceResolver.getModuleForNamespace("test:module1").equals("module1"));
+        assertTrue(namespaceResolver.getModuleForNamespace("test:module2").equals("module2"));
+        assertTrue(namespaceResolver.getModuleForNamespace("test:module3").equals("module3"));
+        assertTrue(namespaceResolver.getModuleForNamespace("unknown namespace") == null);
+
+        final ModulePrefixResolver prefixResolverModule1 = getModule("module1").getPrefixResolver();
+
+        assertTrue(prefixResolverModule1.getDefaultModuleIdentity().getModuleName().equals("module1"));
+        assertTrue(prefixResolverModule1.getModuleForPrefix("this").getModuleName().equals("module1"));
+        assertTrue(prefixResolverModule1.getModuleForPrefix("mod2").getModuleName().equals("module2"));
+        assertTrue(prefixResolverModule1.getModuleForPrefix("mod3").getModuleName().equals("module3"));
+        assertTrue(prefixResolverModule1.getDefaultNamespaceUri().equals("test:module1"));
+        assertTrue(prefixResolverModule1.resolveNamespaceUri("this").equals("test:module1"));
+        assertTrue(prefixResolverModule1.resolveNamespaceUri("mod2").equals("test:module2"));
+        assertTrue(prefixResolverModule1.resolveNamespaceUri("mod3").equals("test:module3"));
+
+        final ModulePrefixResolver prefixResolverModule2 = getModule("module2").getPrefixResolver();
+
+        assertTrue(prefixResolverModule2.getDefaultModuleIdentity().getModuleName().equals("module2"));
+        assertTrue(prefixResolverModule2.getModuleForPrefix("this").getModuleName().equals("module2"));
+        assertTrue(prefixResolverModule2.getModuleForPrefix("mod1").getModuleName().equals("module1"));
+        assertTrue(prefixResolverModule2.getModuleForPrefix("mod3").getModuleName().equals("module3"));
+        assertTrue(prefixResolverModule2.getDefaultNamespaceUri().equals("test:module2"));
+        assertTrue(prefixResolverModule2.resolveNamespaceUri("this").equals("test:module2"));
+        assertTrue(prefixResolverModule2.resolveNamespaceUri("mod1").equals("test:module1"));
+        assertTrue(prefixResolverModule2.resolveNamespaceUri("mod3").equals("test:module3"));
+
+        final ModulePrefixResolver prefixResolverModule3 = getModule("module3").getPrefixResolver();
+
+        assertTrue(prefixResolverModule3.getDefaultModuleIdentity().getModuleName().equals("module3"));
+        assertTrue(prefixResolverModule3.getModuleForPrefix("this").getModuleName().equals("module3"));
+        assertTrue(prefixResolverModule3.getModuleForPrefix("mod1").getModuleName().equals("module1"));
+        assertTrue(prefixResolverModule3.getModuleForPrefix("mod2").getModuleName().equals("module2"));
+        assertTrue(prefixResolverModule3.getDefaultNamespaceUri().equals("test:module3"));
+        assertTrue(prefixResolverModule3.resolveNamespaceUri("this").equals("test:module3"));
+        assertTrue(prefixResolverModule3.resolveNamespaceUri("mod1").equals("test:module1"));
+        assertTrue(prefixResolverModule3.resolveNamespaceUri("mod2").equals("test:module2"));
+
+        final ModulePrefixResolver prefixResolverSubmodule4 = getSubModule("submodule4").getPrefixResolver();
+
+        assertTrue(prefixResolverSubmodule4.getDefaultModuleIdentity().getModuleName().equals("module1"));
+        assertTrue(prefixResolverSubmodule4.getModuleForPrefix("mod1").getModuleName().equals("module1"));
+        assertTrue(prefixResolverSubmodule4.getModuleForPrefix("mod2").getModuleName().equals("module2"));
+        assertTrue(prefixResolverSubmodule4.getModuleForPrefix("mod3").getModuleName().equals("module3"));
+        assertTrue(prefixResolverSubmodule4.getDefaultNamespaceUri().equals("test:module1"));
+        assertTrue(prefixResolverSubmodule4.resolveNamespaceUri("mod1").equals("test:module1"));
+        assertTrue(prefixResolverSubmodule4.resolveNamespaceUri("mod2").equals("test:module2"));
+        assertTrue(prefixResolverSubmodule4.resolveNamespaceUri("mod3").equals("test:module3"));
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/RemoveFindingsOnUnusedSchemaNodesTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/RemoveFindingsOnUnusedSchemaNodesTest.java
new file mode 100644
index 0000000..db8ff55
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/RemoveFindingsOnUnusedSchemaNodesTest.java
@@ -0,0 +1,139 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema.test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class RemoveFindingsOnUnusedSchemaNodesTest extends YangTestCommon {
+
+    @Test
+    public void test___simple___do_not_suppress_findings() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/remove-findings-on-unused-schema-nodes/simple/simple-module.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        context.setSuppressFindingsOnUnusedSchemaNodes(false);
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        /*
+         * We expect a number of findings
+         */
+        final YModule yModule = getModule("simple-module");
+
+        // ----- The typedef -----
+
+        final YangDomElement typedef01 = getDomChild(yModule.getDomElement(), CY.TYPEDEF, "typedef01");
+        assertDomElementHasFindingOfType(typedef01, ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+
+        final YangDomElement typeUnderTypedef01 = getDomChild(typedef01, CY.TYPE);
+        assertDomElementHasFindingOfType(typeUnderTypedef01, ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+
+        // ----- The grouping -----
+
+        final YangDomElement grouping01 = getDomChild(yModule.getDomElement(), CY.GROUPING, "grouping01");
+        assertDomElementHasFindingOfType(grouping01, ParserFindingType.P132_GROUPING_NOT_USED.toString());
+
+        final YangDomElement statementUnderGrouping01 = getDomChild(grouping01, "unknown-statement");
+        assertDomElementHasFindingOfType(statementUnderGrouping01, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+
+        // ----- The leaf02 -----
+
+        final YangDomElement cont1 = getDomChild(yModule.getDomElement(), CY.CONTAINER, "cont1");
+        final YangDomElement leaf02 = getDomChild(cont1, CY.LEAF, "leaf02");
+        final YangDomElement typeUnderLeaf02 = getDomChild(leaf02, CY.TYPE);
+        assertDomElementHasFindingOfType(typeUnderLeaf02, ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+
+        // ----- The leaf03 -----
+
+        final YangDomElement leaf03 = getDomChild(cont1, CY.LEAF, "leaf03");
+        final YangDomElement typeUnderLeaf03 = getDomChild(leaf03, CY.TYPE);
+        assertDomElementHasFindingOfType(typeUnderLeaf03, ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+
+        // ----- The deviation -----
+
+        final YangDomElement deviation = getDomChild(yModule.getDomElement(), CY.DEVIATION);
+        assertDomElementHasFindingOfType(deviation, ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE.toString());
+    }
+
+    @Test
+    public void test___simple___suppress_findings() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/remove-findings-on-unused-schema-nodes/simple/simple-module.yang");
+        final List<String> absoluteImportsFilePath = Collections.<String> emptyList();
+
+        context.setSuppressFindingsOnUnusedSchemaNodes(true);
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        /*
+         * We expect a number of findings
+         */
+        final YModule yModule = getModule("simple-module");
+
+        // ----- The typedef -----
+
+        final YangDomElement typedef01 = getDomChild(yModule.getDomElement(), CY.TYPEDEF, "typedef01");
+        assertDomElementHasFindingOfType(typedef01, ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+
+        final YangDomElement typeUnderTypedef01 = getDomChild(typedef01, CY.TYPE);
+        assertDomElementHasNoFindings(typeUnderTypedef01);
+
+        // ----- The grouping -----
+
+        final YangDomElement grouping01 = getDomChild(yModule.getDomElement(), CY.GROUPING, "grouping01");
+        assertDomElementHasFindingOfType(grouping01, ParserFindingType.P132_GROUPING_NOT_USED.toString());
+
+        final YangDomElement statementUnderGrouping01 = getDomChild(grouping01, "unknown-statement");
+        assertDomElementHasNoFindings(statementUnderGrouping01);
+
+        // ----- The leaf02 -----
+
+        final YangDomElement cont1 = getDomChild(yModule.getDomElement(), CY.CONTAINER, "cont1");
+        final YangDomElement leaf02 = getDomChild(cont1, CY.LEAF, "leaf02");
+        final YangDomElement typeUnderLeaf02 = getDomChild(leaf02, CY.TYPE);
+        assertDomElementHasNoFindings(typeUnderLeaf02);
+
+        // ----- The leaf03 -----
+
+        final YangDomElement leaf03 = getDomChild(cont1, CY.LEAF, "leaf03");
+        final YangDomElement typeUnderLeaf03 = getDomChild(leaf03, CY.TYPE);
+        assertDomElementHasFindingOfType(typeUnderLeaf03, ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+
+        // ----- The deviation -----
+
+        final YangDomElement deviation = getDomChild(yModule.getDomElement(), CY.DEVIATION);
+        assertDomElementHasFindingOfType(deviation, ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/RemoveProtocolAccessibleObjectsTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/RemoveProtocolAccessibleObjectsTest.java
new file mode 100644
index 0000000..3061fb1
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/RemoveProtocolAccessibleObjectsTest.java
@@ -0,0 +1,273 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class RemoveProtocolAccessibleObjectsTest extends YangTestCommon {
+
+    private static final String TEST_DIR = "src/test/resources/model-schema/remove-protocol-accessible-objects/";
+
+    private static final String BASE_NS = "test:base-module";
+    private static final String OTHER_NS = "test:other-module";
+    private static final String AUGMENTING_NS = "test:augmenting-module";
+
+    @Test
+    public void test___ignore_true___base_other_implement() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(TEST_DIR + "base-module.yang",
+                TEST_DIR + "other-module.yang");
+        final List<String> absoluteImportsFilePath = Collections.emptyList();
+
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final YModule baseModule = getModule("base-module");
+        assertNotNull(baseModule);
+
+        final YContainer cont1 = getContainer(baseModule, "cont1");
+        assertNotNull(cont1);
+        assertEquals(BASE_NS, cont1.getEffectiveNamespace());
+        final YContainer cont2 = getContainer(baseModule, "cont2");
+        assertNotNull(cont2);
+        assertEquals(BASE_NS, cont2.getEffectiveNamespace());
+
+        final YModule otherModule = getModule("other-module");
+        assertNotNull(otherModule);
+
+        final YContainer cont5 = getContainer(otherModule, "cont5");
+        assertNotNull(cont5);
+        assertEquals(OTHER_NS, cont5.getEffectiveNamespace());
+        final YContainer cont6 = getContainer(otherModule, "cont6");
+        assertNotNull(cont6);
+        assertEquals(OTHER_NS, cont6.getEffectiveNamespace());
+    }
+
+    @Test
+    public void test___ignore_true___base_implements_other_imports() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(TEST_DIR + "base-module.yang");
+        final List<String> absoluteImportsFilePath = Arrays.asList(TEST_DIR + "other-module.yang");
+
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final YModule baseModule = getModule("base-module");
+        assertNotNull(baseModule);
+
+        final YContainer cont1 = getContainer(baseModule, "cont1");
+        assertNotNull(cont1);
+        final YContainer cont2 = getContainer(baseModule, "cont2");
+        assertNotNull(cont2);
+
+        final YModule otherModule = getModule("other-module");
+        assertNotNull(otherModule);
+
+        final YContainer cont5 = getContainer(otherModule, "cont5");		// Shouldn't exist
+        assertNull(cont5);
+        final YContainer cont6 = getContainer(otherModule, "cont6");		// Shouldn't exist
+        assertNull(cont6);
+    }
+
+    @Test
+    public void test___ignore_false___base_implements___other_imports() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(TEST_DIR + "base-module.yang");
+        final List<String> absoluteImportsFilePath = Arrays.asList(TEST_DIR + "other-module.yang");
+
+        context.setIgnoreImportedProtocolAccessibleObjects(false);
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final YModule baseModule = getModule("base-module");
+        assertNotNull(baseModule);
+
+        final YContainer cont1 = getContainer(baseModule, "cont1");
+        assertNotNull(cont1);
+        final YContainer cont2 = getContainer(baseModule, "cont2");
+        assertNotNull(cont2);
+
+        final YModule otherModule = getModule("other-module");
+        assertNotNull(otherModule);
+
+        final YContainer cont5 = getContainer(otherModule, "cont5");		// Should exist as flag = false
+        assertNotNull(cont5);
+        final YContainer cont6 = getContainer(otherModule, "cont6");		// Should exist as flag = false
+        assertNotNull(cont6);
+    }
+
+    @Test
+    public void test___ignore_true___base_other_augments_implement() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(TEST_DIR + "base-module.yang",
+                TEST_DIR + "other-module.yang", TEST_DIR + "augmenting-module.yang");
+        final List<String> absoluteImportsFilePath = Collections.emptyList();
+
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final YModule baseModule = getModule("base-module");
+        assertNotNull(baseModule);
+
+        final YContainer cont1 = getContainer(baseModule, "cont1");
+        assertNotNull(cont1);
+        assertEquals(BASE_NS, cont1.getEffectiveNamespace());
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertNotNull(leaf11);
+        assertEquals(BASE_NS, leaf11.getEffectiveNamespace());
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertNotNull(leaf12);
+        assertEquals(AUGMENTING_NS, leaf12.getEffectiveNamespace());
+
+        final YContainer cont2 = getContainer(baseModule, "cont2");
+        assertNotNull(cont2);
+        assertEquals(BASE_NS, cont2.getEffectiveNamespace());
+
+        final YModule otherModule = getModule("other-module");
+        assertNotNull(otherModule);
+
+        final YContainer cont5 = getContainer(otherModule, "cont5");
+        assertNotNull(cont5);
+        assertEquals(OTHER_NS, cont5.getEffectiveNamespace());
+        final YLeaf leaf51 = getLeaf(cont5, "leaf51");
+        assertNotNull(leaf51);
+        assertEquals(OTHER_NS, leaf51.getEffectiveNamespace());
+        final YLeaf leaf52 = getLeaf(cont5, "leaf52");
+        assertNotNull(leaf52);
+        assertEquals(AUGMENTING_NS, leaf52.getEffectiveNamespace());
+
+        final YContainer cont6 = getContainer(otherModule, "cont6");
+        assertNotNull(cont6);
+        assertEquals(OTHER_NS, cont6.getEffectiveNamespace());
+    }
+
+    @Test
+    public void test___ignore_true___base_other_implement___augments_imports() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(TEST_DIR + "base-module.yang",
+                TEST_DIR + "other-module.yang");
+        final List<String> absoluteImportsFilePath = Arrays.asList(TEST_DIR + "augmenting-module.yang");
+
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final YModule baseModule = getModule("base-module");
+        assertNotNull(baseModule);
+
+        final YContainer cont1 = getContainer(baseModule, "cont1");
+        assertNotNull(cont1);
+        assertEquals(BASE_NS, cont1.getEffectiveNamespace());
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertNotNull(leaf11);
+        assertEquals(BASE_NS, leaf11.getEffectiveNamespace());
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertNull(leaf12);
+
+        final YContainer cont2 = getContainer(baseModule, "cont2");
+        assertNotNull(cont2);
+        assertEquals(BASE_NS, cont2.getEffectiveNamespace());
+
+        final YModule otherModule = getModule("other-module");
+        assertNotNull(otherModule);
+
+        final YContainer cont5 = getContainer(otherModule, "cont5");
+        assertNotNull(cont5);
+        assertEquals(OTHER_NS, cont5.getEffectiveNamespace());
+        final YLeaf leaf51 = getLeaf(cont5, "leaf51");
+        assertNotNull(leaf51);
+        assertEquals(OTHER_NS, leaf51.getEffectiveNamespace());
+        final YLeaf leaf52 = getLeaf(cont5, "leaf52");
+        assertNull(leaf52);
+
+        final YContainer cont6 = getContainer(otherModule, "cont6");
+        assertNotNull(cont6);
+        assertEquals(OTHER_NS, cont6.getEffectiveNamespace());
+    }
+
+    @Test
+    public void test___ignore_false___base_other_implement___augments_imports() {
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(TEST_DIR + "base-module.yang",
+                TEST_DIR + "other-module.yang");
+        final List<String> absoluteImportsFilePath = Arrays.asList(TEST_DIR + "augmenting-module.yang");
+
+        context.setIgnoreImportedProtocolAccessibleObjects(false);
+        parseAbsoluteYangModels(absoluteImplementsFilePath, absoluteImportsFilePath);
+
+        assertNoFindings();
+
+        final YModule baseModule = getModule("base-module");
+        assertNotNull(baseModule);
+
+        final YContainer cont1 = getContainer(baseModule, "cont1");
+        assertNotNull(cont1);
+        assertEquals(BASE_NS, cont1.getEffectiveNamespace());
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertNotNull(leaf11);
+        assertEquals(BASE_NS, leaf11.getEffectiveNamespace());
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertNotNull(leaf12);
+        assertEquals(AUGMENTING_NS, leaf12.getEffectiveNamespace());
+
+        final YContainer cont2 = getContainer(baseModule, "cont2");
+        assertNotNull(cont2);
+        assertEquals(BASE_NS, cont2.getEffectiveNamespace());
+
+        final YModule otherModule = getModule("other-module");
+        assertNotNull(otherModule);
+
+        final YContainer cont5 = getContainer(otherModule, "cont5");
+        assertNotNull(cont5);
+        assertEquals(OTHER_NS, cont5.getEffectiveNamespace());
+        final YLeaf leaf51 = getLeaf(cont5, "leaf51");
+        assertNotNull(leaf51);
+        assertEquals(OTHER_NS, leaf51.getEffectiveNamespace());
+        final YLeaf leaf52 = getLeaf(cont5, "leaf52");
+        assertNotNull(leaf52);
+        assertEquals(AUGMENTING_NS, leaf52.getEffectiveNamespace());
+
+        final YContainer cont6 = getContainer(otherModule, "cont6");
+        assertNotNull(cont6);
+        assertEquals(OTHER_NS, cont6.getEffectiveNamespace());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/StopAfterInitialParseTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/StopAfterInitialParseTest.java
new file mode 100644
index 0000000..50b761b
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/schema/test/StopAfterInitialParseTest.java
@@ -0,0 +1,107 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.schema.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class StopAfterInitialParseTest extends YangTestCommon {
+
+    @Test
+    public void test_no_processing_delay() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/stop-after-initial-parse-test/module1.yang",
+                "src/test/resources/model-schema/stop-after-initial-parse-test/module2.yang");
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, Collections.<String> emptyList());
+
+        assertNoFindings();
+
+        final YModule module1 = getModule("module1");
+        assertTrue(module1 != null);
+
+        final YContainer cont1 = getContainer(module1, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf2") != null);
+        assertTrue(getLeaf(cont1, "leaf99") != null);
+    }
+
+    @Test
+    public void test_processing_delay() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        // this here is different
+
+        context.setStopAfterInitialParse(true);
+
+        final List<String> absoluteImplementsFilePath = Arrays.asList(
+                "src/test/resources/model-schema/stop-after-initial-parse-test/module1.yang",
+                "src/test/resources/model-schema/stop-after-initial-parse-test/module2.yang");
+
+        parseAbsoluteYangModels(absoluteImplementsFilePath, Collections.<String> emptyList());
+
+        assertNoFindings();
+
+        final YModule module1 = getModule("module1");
+        assertTrue(module1 != null);
+
+        final YContainer cont1 = getContainer(module1, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf2") != null);
+
+        // this here is different
+
+        assertTrue(getLeaf(cont1, "leaf99") == null);
+
+        yangDeviceModel.getTopLevelSchema().processParsedYangModules(context);
+
+        assertTrue(getLeaf(cont1, "leaf99") != null);
+
+        // processing second time should not work:
+
+        try {
+            yangDeviceModel.getTopLevelSchema().processParsedYangModules(context);
+            fail("Expected an exception.");
+        } catch (IllegalStateException ex) {
+            // expected
+        } catch (Exception ex) {
+            fail("Expected an IllegalStateException.");
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/ietf/test/OtherExtensionsTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/ietf/test/OtherExtensionsTest.java
new file mode 100644
index 0000000..4c0e587
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/ietf/test/OtherExtensionsTest.java
@@ -0,0 +1,109 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.ietf.test;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.statements.ietf.CIETF;
+import org.oran.smo.yangtools.parser.model.statements.ietf.YIetfAnnotation;
+import org.oran.smo.yangtools.parser.model.statements.ietf.YIetfDefaultDenyAll;
+import org.oran.smo.yangtools.parser.model.statements.ietf.YIetfDefaultDenyWrite;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.C3GPP;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.Y3gppInVariant;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.Y3gppInitialValue;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.Y3gppNotNotifyable;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class OtherExtensionsTest extends YangTestCommon {
+
+    private static final String IETF_YANG_METADATA = "ietf-yang-metadata";
+    private static final String THREE_GPP_COMMON_YANG_EXTENSIONS = "_3gpp-common-yang-extensions";
+    private static final String IETF_NETCONF_ACM = "ietf-netconf-acm";
+
+    @Test
+    public void test_3gpp_extensions() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-statements-other/other-extension-test.yang", THREEGPP_YANG_EXT_PATH,
+                YANG_METADATA_PATH, NETCONF_ACM_PATH, "src/test/resources/_orig-modules/ietf-inet-types-2019-11-04.yang",
+                "src/test/resources/_orig-modules/ietf-yang-types-2019-11-04.yang"));
+
+        assertNoFindings();
+
+        final YModule module = getModule("other-extension-test");
+        assertTrue(module != null);
+
+        final YIetfAnnotation annotation = getExtensionChild(module, IETF_YANG_METADATA, "annotation");
+        assertTrue(annotation != null);
+        assertTrue(annotation.getAnnotationName().equals("last-modified"));
+        assertTrue(getChild(annotation, "type") != null);
+        assertTrue(annotation.getStatementModuleAndName().equals(CIETF.IETF_YANG_METADATA__ANNOTATION));
+
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        final YIetfDefaultDenyWrite defaultDenyWrite = getExtensionChild(cont1, IETF_NETCONF_ACM, "default-deny-write");
+        assertTrue(defaultDenyWrite != null);
+        assertTrue(defaultDenyWrite.getStatementModuleAndName().equals(CIETF.IETF_NETCONF_ACM__DEFAULT_DENY_WRITE));
+
+        final YLeaf leaf1 = getLeaf(cont1, "leaf1");
+
+        final Y3gppInVariant inVariant = getExtensionChild(leaf1, THREE_GPP_COMMON_YANG_EXTENSIONS, C3GPP.IN_VARIANT);
+        assertTrue(inVariant != null);
+        assertTrue(inVariant.getStatementModuleAndName().equals(C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__IN_VARIANT));
+
+        final Y3gppInitialValue threegppInitialValue = getExtensionChild(leaf1, THREE_GPP_COMMON_YANG_EXTENSIONS,
+                C3GPP.INITIAL_VALUE);
+        assertTrue(threegppInitialValue != null);
+        assertTrue(threegppInitialValue.getInitialValue().equals("Hello"));
+        assertTrue(threegppInitialValue.getStatementModuleAndName().equals(
+                C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__INITIAL_VALUE));
+
+        final Y3gppNotNotifyable threegppNotNotifyable = getExtensionChild(leaf1, THREE_GPP_COMMON_YANG_EXTENSIONS,
+                C3GPP.NOT_NOTIFYABLE);
+        assertTrue(threegppNotNotifyable != null);
+        assertNull(threegppNotNotifyable.getValue());
+        assertTrue(threegppNotNotifyable.getStatementModuleAndName().equals(
+                C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__NOT_NOTIFYABLE));
+
+        final YIetfDefaultDenyAll defaultDenyAll = getExtensionChild(leaf1, IETF_NETCONF_ACM, "default-deny-all");
+        assertTrue(defaultDenyAll != null);
+        assertTrue(defaultDenyAll.getStatementModuleAndName().equals(CIETF.IETF_NETCONF_ACM__DEFAULT_DENY_ALL));
+    }
+
+    @Test
+    public void test_CI_C3() {
+        assertTrue(CIETF.HANDLED_STATEMENTS.size() == 3);
+        assertTrue(CIETF.HANDLED_STATEMENTS.containsKey("ietf-yang-schema-mount"));
+        assertTrue(CIETF.HANDLED_STATEMENTS.containsKey("ietf-yang-metadata"));
+        assertTrue(CIETF.HANDLED_STATEMENTS.containsKey("ietf-netconf-acm"));
+
+        assertTrue(C3GPP.HANDLED_STATEMENTS.size() == 1);
+        assertTrue(C3GPP.HANDLED_STATEMENTS.containsKey("_3gpp-common-yang-extensions"));
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/oran/test/OranSmoTeivExtensionsTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/oran/test/OranSmoTeivExtensionsTest.java
new file mode 100644
index 0000000..4aeec95
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/oran/test/OranSmoTeivExtensionsTest.java
@@ -0,0 +1,175 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.oran.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement.StatementArgumentType;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement.MaxCardinality;
+import org.oran.smo.yangtools.parser.model.statements.oran.CORAN;
+import org.oran.smo.yangtools.parser.model.statements.oran.YOranSmoTeivASide;
+import org.oran.smo.yangtools.parser.model.statements.oran.YOranSmoTeivBSide;
+import org.oran.smo.yangtools.parser.model.statements.oran.YOranSmoTeivBiDirectionalTopologyRelationship;
+import org.oran.smo.yangtools.parser.model.statements.oran.YOranSmoTeivLabel;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeafList;
+import org.oran.smo.yangtools.parser.model.statements.yang.YList;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class OranSmoTeivExtensionsTest extends YangTestCommon {
+
+    protected static final String SMO_TIES_COMMON_YANG_EXT = "src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-extensions@2023-12-12.yang";
+    protected static final String SMO_TIES_COMMON_YANG_TYPES = "src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-types@2023-12-12.yang";
+
+    @Test
+    public void test_oran_extensions() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-statements-oran/oran-smo-teiv-extension-test.yang", SMO_TIES_COMMON_YANG_EXT,
+                SMO_TIES_COMMON_YANG_TYPES));
+
+        final YModule module = getModule("oran-smo-teiv-extension-test");
+        assertTrue(module != null);
+
+        final YOranSmoTeivLabel label0 = module.getRevisions().get(0).getChild(
+                CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__LABEL);
+        final YOranSmoTeivLabel label1 = module.getRevisions().get(1).getChild(
+                CORAN.ORAN_SMO_TEIV_COMMON_YANG_EXTENSIONS__LABEL);
+
+        assertNotNull(label0);
+        assertNotNull(label1);
+
+        assertEquals("2.3.4", label0.getLabel());
+        assertEquals(2, label0.getVersion());
+        assertEquals(3, label0.getRelease());
+        assertEquals(4, label0.getCorrection());
+
+        assertEquals("06.34.12345", label1.getLabel());
+        assertEquals(6, label1.getVersion());
+        assertEquals(34, label1.getRelease());
+        assertEquals(12345, label1.getCorrection());
+
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel1 = getChild(module,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-1");
+        assertNotNull(rel1);
+        assertNoFindingsOnStatement(rel1);
+
+        assertEquals("o-ran-smo-teiv-common-yang-extensions", rel1.getStatementModuleAndName().getModuleName());
+        assertEquals("biDirectionalTopologyRelationship", rel1.getStatementModuleAndName().getStatementName());
+        assertFalse(rel1.getStatementModuleAndName().isYangCoreStatement());
+        assertTrue(rel1.getStatementModuleAndName().isExtensionStatement());
+        assertEquals(StatementArgumentType.NAME, rel1.getArgumentType());
+        assertEquals(MaxCardinality.MULTIPLE, rel1.getMaxCardinalityUnderParent());
+        assertEquals("relationship-1", rel1.getRelationshipName());
+
+        final YLeaf leafAside = getLeaf(rel1, "leaf-a-side");
+        assertNotNull(leafAside);
+        assertNoFindingsOnStatement(leafAside);
+        final YOranSmoTeivASide aSide = getChild(leafAside, "or-teiv-ext:aSide");
+        assertNotNull(aSide);
+        assertNoFindingsOnStatement(aSide);
+
+        assertEquals("o-ran-smo-teiv-common-yang-extensions", aSide.getStatementModuleAndName().getModuleName());
+        assertEquals("aSide", aSide.getStatementModuleAndName().getStatementName());
+        assertFalse(aSide.getStatementModuleAndName().isYangCoreStatement());
+        assertTrue(aSide.getStatementModuleAndName().isExtensionStatement());
+        assertEquals(StatementArgumentType.NAME, aSide.getArgumentType());
+        assertEquals(MaxCardinality.ONE, aSide.getMaxCardinalityUnderParent());
+        assertEquals("role-a-side", aSide.getTeivTypeName());
+
+        final YLeafList leafBside = getLeafList(rel1, "leaf-b-side");
+        assertNotNull(leafBside);
+        assertNoFindingsOnStatement(leafBside);
+        final YOranSmoTeivBSide bSide = getChild(leafBside, "or-teiv-ext:bSide");
+        assertNotNull(bSide);
+        assertNoFindingsOnStatement(bSide);
+
+        assertEquals("o-ran-smo-teiv-common-yang-extensions", bSide.getStatementModuleAndName().getModuleName());
+        assertEquals("bSide", bSide.getStatementModuleAndName().getStatementName());
+        assertFalse(bSide.getStatementModuleAndName().isYangCoreStatement());
+        assertTrue(bSide.getStatementModuleAndName().isExtensionStatement());
+        assertEquals(StatementArgumentType.NAME, bSide.getArgumentType());
+        assertEquals(MaxCardinality.ONE, bSide.getMaxCardinalityUnderParent());
+        assertEquals("role-b-side", bSide.getTeivTypeName());
+
+        final YLeaf idLeaf = getLeaf(rel1, "id");
+        assertNotNull(idLeaf);
+        final YLeaf leafProp = getLeaf(rel1, "leaf-prop");
+        assertNotNull(leafProp);
+        final YLeafList leafListProp = getLeafList(rel1, "leaf-list-prop");
+        assertNotNull(leafListProp);
+        assertNotNull(getChild(rel1, "key"));
+
+        // - - - - error cases - - - - -
+
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel2 = getChild(module,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-2");
+        assertNotNull(rel2);
+        assertStatementHasFindingOfType(rel2, ParserFindingType.P025_INVALID_EXTENSION.toString());
+
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel3 = getChild(module,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-3");
+        assertNotNull(rel3);
+        assertStatementHasFindingOfType(rel3, ParserFindingType.P025_INVALID_EXTENSION.toString());
+
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel4 = getChild(module,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-4");
+        assertNotNull(rel4);
+        assertStatementHasFindingOfType(rel4, ParserFindingType.P025_INVALID_EXTENSION.toString());
+
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel5 = getChild(module,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-5");
+        assertNotNull(rel5);
+        assertStatementHasFindingOfType(rel5, ParserFindingType.P025_INVALID_EXTENSION.toString());
+
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel6 = getChild(module,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-6");
+        assertNotNull(rel6);
+        assertStatementHasFindingOfType(rel6, ParserFindingType.P025_INVALID_EXTENSION.toString());
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel7 = getChild(cont1,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-7");
+        assertNotNull(rel7);
+        assertStatementHasFindingOfType(rel7, ParserFindingType.P025_INVALID_EXTENSION.toString());
+
+        final YOranSmoTeivBiDirectionalTopologyRelationship rel8 = getChild(module,
+                "or-teiv-ext:biDirectionalTopologyRelationship", "relationship-8");
+        assertNotNull(rel8);
+        assertStatementHasFindingOfType(rel8, ParserFindingType.P025_INVALID_EXTENSION.toString());
+        final YContainer cont2 = getContainer(rel8, "cont2");
+        final YOranSmoTeivASide cont2aSide = getChild(cont2, "or-teiv-ext:aSide");
+        assertStatementHasFindingOfType(cont2aSide, ParserFindingType.P025_INVALID_EXTENSION.toString());
+        final YList list2 = getList(rel8, "list2");
+        final YOranSmoTeivBSide list2bSide = getChild(list2, "or-teiv-ext:bSide");
+        assertStatementHasFindingOfType(list2bSide, ParserFindingType.P025_INVALID_EXTENSION.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/AugmentTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/AugmentTest.java
new file mode 100644
index 0000000..ad7c581
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/AugmentTest.java
@@ -0,0 +1,248 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YChoice;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YInput;
+import org.oran.smo.yangtools.parser.model.statements.yang.YList;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRpc;
+import org.oran.smo.yangtools.parser.model.statements.yang.YStatus;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class AugmentTest extends YangTestCommon {
+
+    @Test
+    public void testAugmentIntoEmptyActionAndRpc() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P152_AUGMENT_TARGET_NODE_IN_SAME_MODULE.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("augment-test/augment-test-module.yang",
+                "augment-test/augment-test-module2.yang"));
+
+        final YModule augmentTestModule = getModule("augment-test-module");
+        assertTrue(augmentTestModule != null);
+
+        assertTrue(augmentTestModule.getRpcs().size() == 1);
+        assertTrue(augmentTestModule.getRpcs().get(0).getInput() != null);
+        assertTrue(augmentTestModule.getRpcs().get(0).getOutput() != null);
+
+        assertTrue(augmentTestModule.getRpcs().get(0).getInput().getLeafs().size() == 1);
+        assertTrue(augmentTestModule.getRpcs().get(0).getOutput().getLeafs().size() == 1);
+
+        final YContainer cont1 = getContainer(augmentTestModule, "cont1");
+
+        assertTrue(cont1.getActions().size() == 1);
+        assertTrue(cont1.getActions().get(0).getInput() != null);
+        assertTrue(cont1.getActions().get(0).getOutput() != null);
+
+        assertTrue(cont1.getActions().get(0).getInput().getLeafs().size() == 1);
+        assertTrue(cont1.getActions().get(0).getOutput().getLeafs().size() == 1);
+
+        // Tests added to handle augments into a choice
+
+        final YRpc rpc1 = getRpc(augmentTestModule, "rpc1");
+        final YInput rpc1input = rpc1.getInput();
+        final YContainer rpc1cont1 = getContainer(rpc1input, "cont1");
+        final YChoice choice1 = getChoice(rpc1cont1, "choice1");
+
+        assertTrue(getCase(choice1, "case1") != null);
+        assertTrue(getCase(choice1, "case2") != null);
+        assertTrue(getCase(choice1, "inserted-case-leaf") != null);
+        assertTrue(getCase(choice1, "inserted-case-leaf-from-second-module") != null);
+
+        // - - - - some other different target nodes - - - - - -
+
+        final YContainer cont2 = getContainer(augmentTestModule, "cont2");
+        assertTrue(getList(cont2, "list1") != null);
+        assertTrue(getLeaf(getList(cont2, "list1"), "leaf11") != null);
+        assertTrue(getLeaf(getList(cont2, "list1"), "leaf15") != null);
+
+        assertTrue(getLeaf(getNotification(cont2, "notification1"), "leaf18") != null);
+
+        // - - - - - status - - - - - -
+
+        final YContainer cont3 = getContainer(augmentTestModule, "cont3");
+        assertTrue(cont3.getEffectiveStatus().equals(YStatus.CURRENT));
+
+        assertTrue(getContainer(cont3, "cont11") != null);
+        assertTrue(getContainer(cont3, "cont11").getStatus().isDeprecated());
+        assertTrue(getContainer(cont3, "cont11").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getContainer(cont3, "cont12") != null);
+        assertTrue(getContainer(cont3, "cont12").getStatus().isDeprecated());
+        assertTrue(getContainer(cont3, "cont12").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getContainer(cont3, "cont13") != null);
+        assertTrue(getContainer(cont3, "cont13").getStatus().isObsolete());
+        assertTrue(getContainer(cont3, "cont13").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getContainer(cont3, "cont15") != null);
+        assertTrue(getContainer(cont3, "cont15").getStatus().isCurrent());
+        assertTrue(getContainer(cont3, "cont15").getEffectiveStatus().equals(YStatus.CURRENT));
+        assertTrue(getContainer(cont3, "cont16") != null);
+        assertTrue(getContainer(cont3, "cont16").getStatus().isDeprecated());
+        assertTrue(getContainer(cont3, "cont16").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getContainer(cont3, "cont17") != null);
+        assertTrue(getContainer(cont3, "cont17").getStatus().isObsolete());
+        assertTrue(getContainer(cont3, "cont17").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        // - - - - - strange path syntax - - - - - -
+
+        assertTrue(getContainer(cont1, "cont18") != null);
+        assertNoFindingsOnStatement(getAugment(augmentTestModule, "/this:cont1/"));
+
+        assertTrue(getContainer(cont1, "cont19") != null);
+        assertNoFindingsOnStatement(getAugment(augmentTestModule, "/:cont1"));
+
+        assertTrue(getContainer(cont1, "cont20") != null);
+        assertNoFindingsOnStatement(getAugment(augmentTestModule, "/cont1"));
+
+        assertTrue(getContainer(cont1, "cont21") == null);
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, "//this:cont1"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertTrue(getContainer(cont1, "cont22") == null);
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, "//this:cont1/"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertTrue(getContainer(cont1, "cont23") == null);
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, "/"), ParserFindingType.P054_UNRESOLVABLE_PATH
+                .toString());
+
+        assertTrue(getContainer(cont1, "cont24") == null);
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, null),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertTrue(getContainer(cont1, "cont25") == null);
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, null),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        // - - - - - - - - - issues with prefixes - - - - - -
+
+        assertHasFindingOfType(ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, "/nsm:some-cont"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, "/this:cont1/nsm:some-cont"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, "/this:cont1/unknown-prefix:some-cont"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertStatementHasFindingOfType(getAugment(augmentTestModule, "/this:cont1/:some-cont"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+    }
+
+    @Test
+    public void testAugment3() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("augment-test/augment-test-module3.yang"));
+
+        final YModule module = getModule("augment-test-module3");
+        assertTrue(module != null);
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getAction(cont1, "action1") != null);
+        assertTrue(getAction(cont1, "action1").getInput() != null);
+
+        assertTrue(getContainer(getAction(cont1, "action1").getInput(), "input-container") != null);
+        assertTrue(getContainer(getAction(cont1, "action1").getInput(), "input-container").getWhens().size() == 1);
+        assertTrue(getContainer(getAction(cont1, "action1").getInput(), "input-container").getWhens().get(0).getValue()
+                .equals("leaf-at-root = true"));
+
+        final YList list2 = getList(cont1, "list2");
+        assertTrue(list2 != null);
+
+        assertTrue(getLeaf(list2, "leaf6") != null);
+        assertTrue(getLeaf(list2, "leaf7") != null);
+        assertTrue(getAction(list2, "action3") != null);
+
+        final YChoice choice8 = getChoice(cont1, "choice8");
+        assertTrue(choice8 != null);
+
+        assertTrue(getCase(choice8, "shorthand-container") != null);
+        assertTrue(getCase(choice8, "shorthand-container").getIfFeatures().size() == 1);
+        assertTrue(getContainer(getCase(choice8, "shorthand-container"), "shorthand-container") != null);
+
+        assertTrue(getCase(choice8, "case3") != null);
+        assertTrue(getCase(choice8, "case3").getIfFeatures().size() == 2);
+        assertTrue(getContainer(getCase(choice8, "case3"), "case-container") != null);
+        assertTrue(getContainer(getCase(choice8, "case3"), "second-case-container") != null);
+
+        // ------------------------ failures ------------------------
+
+        assertStatementHasFindingOfType(getAugment(module, "/leaf-at-root"),
+                ParserFindingType.P151_TARGET_NODE_CANNOT_BE_AUGMENTED.toString());
+        assertStatementHasFindingOfType(getAugment(module, "/unknownprefix:somenode"),
+                ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString());
+        assertStatementHasFindingOfType(getAugment(module, "/this:unknown-node"), ParserFindingType.P054_UNRESOLVABLE_PATH
+                .toString());
+        assertStatementHasFindingOfType(getAugment(module, ""), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+        assertStatementHasFindingOfType(getAugment(module, "cont1"), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+        assertStatementHasFindingOfType(getAugment(module, null), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+
+        // -------------------------- not-allowed statements -------------------------
+
+        assertStatementHasFindingOfType(getAugment(module, "/this:cont1/choice8/case1").getActions().get(0),
+                ParserFindingType.P151_TARGET_NODE_CANNOT_BE_AUGMENTED.toString());
+        assertStatementHasFindingOfType(getAugment(module, "/this:cont1/choice8/case2").getNotifications().get(0),
+                ParserFindingType.P151_TARGET_NODE_CANNOT_BE_AUGMENTED.toString());
+    }
+
+    @Test
+    public void testAugmentIntoSubModule() {
+
+        //   	severityCalculator.suppressFinding(ParserFindingType.P152_AUGMENT_TARGET_NODE_IN_SAME_MODULE.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("augment-test/augment-intosub-module.yang",
+                "augment-test/augment-intosub-submodule.yang", "augment-test/augment-intosub-augmenting-module.yang"));
+
+        final YModule module = getModule("augment-intosub-module");
+        assertTrue(module != null);
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf11") != null);
+        assertTrue(getLeaf(cont1, "leaf11").getEffectiveNamespace().equals("test:augment-intosub-augmenting-module"));
+
+        final YContainer cont2 = getContainer(module, "cont2");
+        assertTrue(cont2 != null);
+
+        assertTrue(getLeaf(cont2, "leaf12") != null);
+        assertTrue(getLeaf(cont2, "leaf12").getEffectiveNamespace().equals("test:augment-intosub-augmenting-module"));
+
+        printFindings();
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/BelongsToTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/BelongsToTest.java
new file mode 100644
index 0000000..fa8662c
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/BelongsToTest.java
@@ -0,0 +1,75 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YSubmodule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class BelongsToTest extends YangTestCommon {
+
+    @Test
+    public void testBelongsToOwningModuleNotInInput() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("belongs-to-test/test-submodule.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P039_UNRESOLVABLE_BELONGS_TO.toString());
+
+        final YSubmodule submodule = getSubModule("test-submodule");
+        assertTrue(submodule != null);
+
+        assertStatementHasFindingOfType(submodule.getBelongsTo(), ParserFindingType.P039_UNRESOLVABLE_BELONGS_TO
+                .toString());
+    }
+
+    @Test
+    public void testBelongsToOwningModuleNotTheOwner() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("belongs-to-test/test-submodule.yang",
+                "belongs-to-test/test-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P048_ORPHAN_SUBMODULE.toString());
+
+        final YSubmodule submodule = getSubModule("test-submodule");
+        assertTrue(submodule != null);
+    }
+
+    @Test
+    public void testBelongsToOwningModuleNotAmodule() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("belongs-to-test/test-submodule.yang",
+                "belongs-to-test/test-submodule2.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P046_NOT_A_MODULE.toString());
+
+        final YSubmodule submodule = getSubModule("test-submodule2");
+        assertTrue(submodule != null);
+
+        assertStatementHasFindingOfType(submodule.getBelongsTo(), ParserFindingType.P046_NOT_A_MODULE.toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/BitsTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/BitsTest.java
new file mode 100644
index 0000000..dc87878
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/BitsTest.java
@@ -0,0 +1,227 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YTypedef;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+/**
+ * This test verifies bits/bit statements
+ */
+public class BitsTest extends YangTestCommon {
+
+    @Test
+    public void testBits() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P144_BIT_WITHOUT_POSITION.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("bits-test/bits-test-module.yang"));
+
+        final YModule module = getModule("bits-test-module");
+        assertTrue(module != null);
+
+        final YTypedef typedef1 = getTypedefForModule("bits-test-module", "typedef1");
+        assertTrue(typedef1 != null);
+        final Map<String, Long> positionOfBitsTypedef1 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedef1.getType(), null);
+        assertTrue(positionOfBitsTypedef1.containsKey("first"));
+        assertTrue(positionOfBitsTypedef1.containsKey("second"));
+        assertTrue(positionOfBitsTypedef1.containsKey("third"));
+        assertTrue(positionOfBitsTypedef1.get("first").longValue() == 0);
+        assertTrue(positionOfBitsTypedef1.get("second").longValue() == 1);
+        assertTrue(positionOfBitsTypedef1.get("third").longValue() == 2);
+        assertSubTreeNoFindings(typedef1);
+
+        final YTypedef typedef2 = getTypedefForModule("bits-test-module", "typedef2");
+        assertTrue(typedef2 != null);
+        final Map<String, Long> positionOfBitsTypedef2 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedef2.getType(), null);
+        assertTrue(positionOfBitsTypedef2.containsKey("first"));
+        assertTrue(positionOfBitsTypedef2.containsKey("second"));
+        assertTrue(positionOfBitsTypedef2.containsKey("third"));
+        assertTrue(positionOfBitsTypedef2.get("first").longValue() == 7);
+        assertTrue(positionOfBitsTypedef2.get("second").longValue() == 23);
+        assertTrue(positionOfBitsTypedef2.get("third").longValue() == 195);
+        assertSubTreeNoFindings(typedef2);
+
+        final YTypedef typedef3 = getTypedefForModule("bits-test-module", "typedef3");
+        assertTrue(typedef3 != null);
+        final Map<String, Long> positionOfBitsTypedef3 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedef3.getType(), null);
+        assertTrue(positionOfBitsTypedef3.containsKey("first"));
+        assertTrue(positionOfBitsTypedef3.containsKey("second"));
+        assertTrue(positionOfBitsTypedef3.containsKey("third"));
+        assertTrue(positionOfBitsTypedef3.get("first").longValue() == 98);
+        assertTrue(positionOfBitsTypedef3.get("second").longValue() == 99);
+        assertTrue(positionOfBitsTypedef3.get("third").longValue() == 100);
+        assertSubTreeNoFindings(typedef3);
+
+        final YTypedef typedef4 = getTypedefForModule("bits-test-module", "typedef4");
+        assertTrue(typedef4 != null);
+        final Map<String, Long> positionOfBitsTypedef4 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedef4.getType(), null);
+        assertTrue(positionOfBitsTypedef4.containsKey("first"));
+        assertTrue(positionOfBitsTypedef4.containsKey("second"));
+        assertTrue(positionOfBitsTypedef4.containsKey("third"));
+        assertTrue(positionOfBitsTypedef4.get("first").longValue() == 0);
+        assertTrue(positionOfBitsTypedef4.get("second").longValue() == 10);
+        assertTrue(positionOfBitsTypedef4.get("third").longValue() == 11);
+        assertSubTreeNoFindings(typedef4);
+
+        final YTypedef typedefDuplicatePosition1 = getTypedefForModule("bits-test-module", "typedef-duplicate-position1");
+        assertTrue(typedefDuplicatePosition1 != null);
+        final Map<String, Long> positionOfBitsTypedefDuplicatePosition1 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedefDuplicatePosition1.getType(), null);
+        assertTrue(positionOfBitsTypedefDuplicatePosition1.containsKey("first"));
+        assertTrue(positionOfBitsTypedefDuplicatePosition1.containsKey("second"));
+        assertTrue(positionOfBitsTypedefDuplicatePosition1.containsKey("third"));
+        assertTrue(positionOfBitsTypedefDuplicatePosition1.get("first").longValue() == 0);
+        assertTrue(positionOfBitsTypedefDuplicatePosition1.get("second").longValue() == 10);
+        assertTrue(positionOfBitsTypedefDuplicatePosition1.get("third").longValue() == 10);
+        assertStatementHasFindingOfType(getChild(typedefDuplicatePosition1.getType(), CY.BIT, "third"),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+
+        final YTypedef typedefDuplicatePosition2 = getTypedefForModule("bits-test-module", "typedef-duplicate-position2");
+        assertTrue(typedefDuplicatePosition2 != null);
+        final Map<String, Long> positionOfBitsTypedefDuplicatePosition2 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedefDuplicatePosition2.getType(), null);
+        assertTrue(positionOfBitsTypedefDuplicatePosition2.containsKey("first"));
+        assertTrue(positionOfBitsTypedefDuplicatePosition2.containsKey("second"));
+        assertTrue(positionOfBitsTypedefDuplicatePosition2.containsKey("third"));
+        assertTrue(positionOfBitsTypedefDuplicatePosition2.get("first").longValue() == 0);
+        assertTrue(positionOfBitsTypedefDuplicatePosition2.get("second").longValue() == 0);
+        assertTrue(positionOfBitsTypedefDuplicatePosition2.get("third").longValue() == 1);
+        assertStatementHasFindingOfType(getChild(typedefDuplicatePosition2.getType(), CY.BIT, "second"),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+
+        final YTypedef typedefTooLarge1 = getTypedefForModule("bits-test-module", "typedef-too-large1");
+        assertTrue(typedefTooLarge1 != null);
+        final Map<String, Long> positionOfBitsTypedefTooLarge1 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedefTooLarge1.getType(), null);
+        assertTrue(positionOfBitsTypedefTooLarge1.containsKey("first"));
+        assertTrue(positionOfBitsTypedefTooLarge1.containsKey("second"));
+        assertTrue(positionOfBitsTypedefTooLarge1.containsKey("third"));
+        assertTrue(positionOfBitsTypedefTooLarge1.get("first").longValue() == 0);
+        assertTrue(positionOfBitsTypedefTooLarge1.get("second").longValue() == 4294967295L);
+        assertTrue(positionOfBitsTypedefTooLarge1.get("third").longValue() == 4294967296L);
+        assertStatementHasFindingOfType(getChild(typedefTooLarge1.getType(), CY.BIT, "third"),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+
+        final YTypedef typedefTooLarge2 = getTypedefForModule("bits-test-module", "typedef-too-large2");
+        assertTrue(typedefTooLarge2 != null);
+        final Map<String, Long> positionOfBitsTypedefTooLarge2 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), typedefTooLarge2.getType(), null);
+        assertTrue(positionOfBitsTypedefTooLarge2.containsKey("first"));
+        assertTrue(positionOfBitsTypedefTooLarge2.containsKey("second"));
+        assertTrue(positionOfBitsTypedefTooLarge2.containsKey("third"));
+        assertTrue(positionOfBitsTypedefTooLarge2.get("first").longValue() == 0);
+        assertTrue(positionOfBitsTypedefTooLarge2.get("second").longValue() == -1);
+        assertTrue(positionOfBitsTypedefTooLarge2.get("third").longValue() == 0);
+        assertStatementHasFindingOfType(getChild(typedefTooLarge2.getType(), CY.BIT, "third"),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+
+        // ------------------------------- leafs tests using the typedefs above --------------------------
+
+        final YLeaf leaf1 = getLeaf(module, "leaf1");
+        assertTrue(leaf1 != null);
+        assertTrue(leaf1.getType() != null);
+        assertTrue(leaf1.getType().getDataType().equals("bits"));
+        final Map<String, Long> positionOfBitsLeaf1 = DataTypeHelper.calculatePositionOfBits(context.getFindingsManager(),
+                leaf1.getType(), positionOfBitsTypedef1);
+        assertTrue(positionOfBitsLeaf1.containsKey("first"));
+        assertTrue(positionOfBitsLeaf1.containsKey("second"));
+        assertTrue(positionOfBitsLeaf1.containsKey("third"));
+        assertTrue(positionOfBitsLeaf1.get("first").longValue() == 0);
+        assertTrue(positionOfBitsLeaf1.get("second").longValue() == 1);
+        assertTrue(positionOfBitsLeaf1.get("third").longValue() == 2);
+        assertSubTreeNoFindings(leaf1);
+
+        final YLeaf leaf2 = getLeaf(module, "leaf2");
+        assertTrue(leaf2 != null);
+        assertTrue(leaf2.getType() != null);
+        final Map<String, Long> positionOfBitsLeaf2 = DataTypeHelper.calculatePositionOfBits(context.getFindingsManager(),
+                leaf2.getType(), positionOfBitsTypedef2);
+        assertTrue(positionOfBitsLeaf2.containsKey("first") == false);
+        assertTrue(positionOfBitsLeaf2.containsKey("second"));
+        assertTrue(positionOfBitsLeaf2.containsKey("third") == false);
+        assertTrue(positionOfBitsLeaf2.get("second").longValue() == 23);
+        assertSubTreeNoFindings(leaf2);
+
+        final YLeaf leafWrongPosition1 = getLeaf(module, "leaf-wrong-position1");
+        assertTrue(leafWrongPosition1 != null);
+        assertTrue(leafWrongPosition1.getType() != null);
+        final Map<String, Long> positionOfBitsLeafWrongPosition1 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), leafWrongPosition1.getType(), positionOfBitsTypedef2);
+        assertTrue(positionOfBitsLeafWrongPosition1.containsKey("first"));
+        assertTrue(positionOfBitsLeafWrongPosition1.containsKey("second"));
+        assertTrue(positionOfBitsLeafWrongPosition1.containsKey("third") == false);
+        assertTrue(positionOfBitsLeafWrongPosition1.get("first").longValue() == 7);
+        assertTrue(positionOfBitsLeafWrongPosition1.get("second").longValue() == 24);
+        assertStatementHasFindingOfType(leafWrongPosition1.getType().getBits().get(1),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        final YLeaf leafWrongPosition2 = getLeaf(module, "leaf-wrong-position2");
+        assertTrue(leafWrongPosition2 != null);
+        assertTrue(leafWrongPosition2.getType() != null);
+        final Map<String, Long> positionOfBitsLeafWrongPosition2 = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), leafWrongPosition2.getType(), positionOfBitsTypedef2);
+        assertTrue(positionOfBitsLeafWrongPosition2.containsKey("first"));
+        assertTrue(positionOfBitsLeafWrongPosition2.containsKey("second"));
+        assertTrue(positionOfBitsLeafWrongPosition2.containsKey("third") == false);
+        assertTrue(positionOfBitsLeafWrongPosition2.get("first").longValue() == 7);
+        assertTrue(positionOfBitsLeafWrongPosition2.get("second").longValue() == 24);
+        assertStatementHasFindingOfType(leafWrongPosition2.getType().getBits().get(1),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        final YLeaf leafNewBit = getLeaf(module, "leaf-new-bit");
+        assertTrue(leafNewBit != null);
+        assertTrue(leafNewBit.getType() != null);
+        final Map<String, Long> positionOfBitsLeafNewBit = DataTypeHelper.calculatePositionOfBits(context
+                .getFindingsManager(), leafNewBit.getType(), positionOfBitsTypedef2);
+        assertTrue(positionOfBitsLeafNewBit.containsKey("first"));
+        assertTrue(positionOfBitsLeafNewBit.containsKey("second"));
+        assertTrue(positionOfBitsLeafNewBit.containsKey("third"));
+        assertTrue(positionOfBitsLeafNewBit.containsKey("fourth"));
+        assertTrue(positionOfBitsLeafNewBit.get("first").longValue() == 7);
+        assertTrue(positionOfBitsLeafNewBit.get("second").longValue() == 23);
+        assertTrue(positionOfBitsLeafNewBit.get("third").longValue() == 195);
+        assertTrue(positionOfBitsLeafNewBit.get("fourth").longValue() == 34);
+        assertStatementHasFindingOfType(leafNewBit.getType().getBits().get(3),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        final YLeaf leafNotBits = getLeaf(module, "leaf-not-bits");
+        assertStatementHasFindingOfType(leafNotBits, ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ConformanceTypeTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ConformanceTypeTest.java
new file mode 100644
index 0000000..80e8db0
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ConformanceTypeTest.java
@@ -0,0 +1,219 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class ConformanceTypeTest extends YangTestCommon {
+
+    @Test
+    public void test2ModulesImports() {
+
+        context.setFailFast(false);
+        context.setIgnoreImportedProtocolAccessibleObjects(false);
+
+        parseRelativeYangModels(Collections.<String> emptyList(), Arrays.asList("conformance-type-test/module1.yang",
+                "conformance-type-test/module2.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P005_NO_IMPLEMENTS.toString());
+
+        final YModule module1 = getModule("module1");
+        final YModule module2 = getModule("module2");
+
+        assertTrue(module1 != null);
+        assertTrue(module2 != null);
+
+        final YContainer container1 = getContainer(module1, "cont1");
+        final YContainer container2 = getContainer(module2, "cont2");
+
+        assertTrue(container1.getEffectiveConformanceType() == ConformanceType.IMPORT);
+        assertTrue(container2.getEffectiveConformanceType() == ConformanceType.IMPORT);
+
+        final YContainer contGroup2InModule1 = getContainer(module1, "contgroup2");
+        final YContainer contGroup2InModule2 = getContainer(module2, "contgroup2");
+
+        assertTrue(contGroup2InModule1.getEffectiveConformanceType() == ConformanceType.IMPORT);
+        assertTrue(contGroup2InModule2.getEffectiveConformanceType() == ConformanceType.IMPORT);
+    }
+
+    @Test
+    public void test2ModulesImplements() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("conformance-type-test/module1.yang",
+                "conformance-type-test/module2.yang"));
+
+        assertHasNotFindingOfType(ParserFindingType.P005_NO_IMPLEMENTS.toString());
+
+        final YModule module1 = getModule("module1");
+        final YModule module2 = getModule("module2");
+
+        assertTrue(module1 != null);
+        assertTrue(module2 != null);
+
+        final YContainer container1 = getContainer(module1, "cont1");
+        final YContainer container2 = getContainer(module2, "cont2");
+
+        assertTrue(container1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(container2.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+
+        final YContainer contGroup2InModule1 = getContainer(module1, "contgroup2");
+        final YContainer contGroup2InModule2 = getContainer(module2, "contgroup2");
+
+        assertTrue(contGroup2InModule1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(contGroup2InModule2.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+    }
+
+    @Test
+    public void test2ModulesOneImplementsOneImports() {
+
+        context.setIgnoreImportedProtocolAccessibleObjects(false);
+        parseRelativeYangModels(Arrays.asList("conformance-type-test/module1.yang"), Arrays.asList(
+                "conformance-type-test/module2.yang"));
+
+        final YModule module1 = getModule("module1");
+        final YModule module2 = getModule("module2");
+
+        assertTrue(module1 != null);
+        assertTrue(module2 != null);
+
+        final YContainer container1 = getContainer(module1, "cont1");
+        final YContainer container2 = getContainer(module2, "cont2");
+
+        assertTrue(container1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(container2.getEffectiveConformanceType() == ConformanceType.IMPORT);
+
+        final YContainer contGroup2InModule1 = getContainer(module1, "contgroup2");
+        final YContainer contGroup2InModule2 = getContainer(module2, "contgroup2");
+
+        assertTrue(contGroup2InModule1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(contGroup2InModule2.getEffectiveConformanceType() == ConformanceType.IMPORT);
+    }
+
+    /*
+     * Tests for "ignoreImportedProtocolAccessibleObjects"
+     */
+
+    @Test
+    public void test2ModulesImplementsIgnoreImportedProtocolAccessibleObjects() {
+
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+
+        parseRelativeImplementsYangModels(Arrays.asList("conformance-type-test/module1.yang",
+                "conformance-type-test/module2.yang"));
+
+        printFindings();
+        assertNoFindings();
+
+        final YModule module1 = getModule("module1");
+        final YModule module2 = getModule("module2");
+
+        assertTrue(module1 != null);
+        assertTrue(module2 != null);
+
+        final YContainer container1 = getContainer(module1, "cont1");
+        final YContainer container2 = getContainer(module2, "cont2");
+        assertTrue(container1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(container2.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+
+        final YContainer contGroup2InModule1 = getContainer(module1, "contgroup2");
+        final YContainer contGroup2InModule2 = getContainer(module2, "contgroup2");
+        assertTrue(contGroup2InModule1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(contGroup2InModule2.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+
+        assertTrue(getChild(module2, CY.RPC, "rpc1") != null);
+        assertTrue(getChild(module2, CY.LIST, "list1") != null);
+
+        assertTrue(getChild(module2, CY.FEATURE, "feature1") != null);
+        assertTrue(getChild(module2, "this:ext", "ext1") != null);
+    }
+
+    @Test
+    public void test2ModulesOneImplementsOneImportsIgnoreImportedProtocolAccessibleObjects() {
+
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+
+        parseRelativeYangModels(Arrays.asList("conformance-type-test/module1.yang"), Arrays.asList(
+                "conformance-type-test/module2.yang"));
+
+        final YModule module1 = getModule("module1");
+        final YModule module2 = getModule("module2");
+
+        assertTrue(module1 != null);
+        assertTrue(module2 != null);
+
+        final YContainer container1 = getContainer(module1, "cont1");
+        final YContainer container2 = getContainer(module2, "cont2");
+
+        assertTrue(container1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(container2 == null);
+
+        final YContainer contGroup2InModule1 = getContainer(module1, "contgroup2");
+        final YContainer contGroup2InModule2 = getContainer(module2, "contgroup2");
+
+        assertTrue(contGroup2InModule1.getEffectiveConformanceType() == ConformanceType.IMPLEMENT);
+        assertTrue(contGroup2InModule2 == null);
+
+        assertTrue(getChild(module2, CY.RPC, "rpc1") == null);
+        assertTrue(getChild(module2, CY.LIST, "list1") == null);
+
+        assertTrue(getChild(module2, CY.FEATURE, "feature1") != null);
+        assertTrue(getChild(module2, "this:ext", "ext1") != null);
+    }
+
+    // - - - - test crossing conformance type for module / submodule
+
+    @Test
+    public void test2ModuleAndSubmoduleSameConformance() {
+
+        parseRelativeYangModels(Arrays.asList("conformance-type-test/including-module.yang",
+                "conformance-type-test/submodule.yang"), Collections.emptyList());
+
+        final YModule module = getModule("including-module");
+        assertTrue(module != null);
+
+        assertNoFindings();
+    }
+
+    @Test
+    public void test2ModuleAndSubmoduleDifferentConformance() {
+
+        parseRelativeYangModels(Arrays.asList("conformance-type-test/including-module.yang"), Arrays.asList(
+                "conformance-type-test/submodule.yang"));
+
+        final YModule module = getModule("including-module");
+        assertTrue(module != null);
+
+        assertHasFindingOfType(ParserFindingType.P006_IMPLEMENT_IMPORT_MISMATCH.toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/DataTypeTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/DataTypeTest.java
new file mode 100644
index 0000000..be28623
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/DataTypeTest.java
@@ -0,0 +1,238 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper.YangDataType;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class DataTypeTest extends YangTestCommon {
+
+    @Test
+    public void testDataTypes() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P144_BIT_WITHOUT_POSITION.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("data-type-test/data-type-test.yang"));
+
+        final YModule module = getModule("data-type-test-module");
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        assertSubTreeNoFindings(cont1);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf1").getType().getDataType()) == YangDataType.INT8);
+
+        assertTrue(getLeaf(cont1, "leaf1").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf1").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                -128)) == 0);
+        assertTrue(getLeaf(cont1, "leaf1").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                127)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf2").getType().getDataType()) == YangDataType.INT16);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                10)) == 0);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                20)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf3").getType().getDataType()) == YangDataType.INT32);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                -30)) == 0);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                20)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf4").getType().getDataType()) == YangDataType.INT64);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                20)) == 0);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                Long.MAX_VALUE)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf5").getType().getDataType()) == YangDataType.UINT8);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                10)) == 0);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                10)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf6").getType().getDataType()) == YangDataType.UINT16);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                0)) == 0);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                20)) == 0);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(1).lower.compareTo(BigDecimal.valueOf(
+                40)) == 0);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(1).upper.compareTo(BigDecimal.valueOf(
+                40)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf7").getType().getDataType()) == YangDataType.UINT32);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                0)) == 0);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                20)) == 0);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(1).lower.compareTo(BigDecimal.valueOf(
+                40)) == 0);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(1).upper.compareTo(BigDecimal.valueOf(
+                60)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf8").getType().getDataType()) == YangDataType.UINT64);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                0)) == 0);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                20)) == 0);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(1).lower.compareTo(BigDecimal.valueOf(
+                30)) == 0);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(1).upper.compareTo(BigDecimal.valueOf(
+                30)) == 0);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(2).lower.compareTo(BigDecimal.valueOf(
+                40)) == 0);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(2).upper.compareTo(BigDecimal.valueOf(
+                60)) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf9").getType()
+                .getDataType()) == YangDataType.DECIMAL64);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getFractionDigits().getFractionDigits() == 1);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                0)) == 0);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                10)) == 0);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(1).lower.compareTo(BigDecimal.valueOf(
+                20.2d)) == 0);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(1).upper.compareTo(new BigDecimal(
+                "922337203685477580.7")) == 0);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf21").getType().getDataType()) == YangDataType.STRING);
+        assertTrue(getLeaf(cont1, "leaf21").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf21").getType().getLength().getBoundaries().get(0).upper == 20L);
+        assertTrue(getLeaf(cont1, "leaf21").getType().getPatterns().get(0).getPattern().equals("ab*c"));
+        assertTrue(getLeaf(cont1, "leaf21").getType().getPatterns().get(0).getModifier().getValue().equals("invert-match"));
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf22").getType()
+                .getDataType()) == YangDataType.BOOLEAN);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf23").getType()
+                .getDataType()) == YangDataType.ENUMERATION);
+        assertTrue(getLeaf(cont1, "leaf23").getType().getEnums().get(0).getEnumName().equals("one"));
+        assertTrue(getLeaf(cont1, "leaf23").getType().getEnums().get(0).getValue().getEnumValue() == 10);
+        assertTrue(getLeaf(cont1, "leaf23").getType().getEnums().get(0).getStatus().isDeprecated());
+        assertTrue(getLeaf(cont1, "leaf23").getType().getEnums().get(0).getIfFeatures().get(0).getValue().equals(
+                "feature1"));
+        assertTrue(getLeaf(cont1, "leaf23").getType().getEnums().get(1).getEnumName().equals("two"));
+        assertTrue(getLeaf(cont1, "leaf23").getType().getEnums().get(2).getEnumName().equals("three"));
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf24").getType().getDataType()) == YangDataType.BITS);
+        assertTrue(getLeaf(cont1, "leaf24").getType().getBits().get(0).getBitName().equals("one"));
+        assertTrue(getLeaf(cont1, "leaf24").getType().getBits().get(0).getPosition().getPosition() == 10);
+        assertTrue(getLeaf(cont1, "leaf24").getType().getBits().get(0).getStatus().isDeprecated());
+        assertTrue(getLeaf(cont1, "leaf24").getType().getBits().get(0).getIfFeatures().get(0).getValue().equals(
+                "feature1"));
+        assertTrue(getLeaf(cont1, "leaf24").getType().getBits().get(1).getBitName().equals("two"));
+        assertTrue(getLeaf(cont1, "leaf24").getType().getBits().get(2).getBitName().equals("three"));
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf25").getType().getDataType()) == YangDataType.BINARY);
+        assertTrue(getLeaf(cont1, "leaf25").getType().getLength().getBoundaries().get(0).lower == 90);
+        assertTrue(getLeaf(cont1, "leaf25").getType().getLength().getBoundaries().get(0).upper == 1010);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf26").getType()
+                .getDataType()) == YangDataType.LEAFREF);
+        assertTrue(getLeaf(cont1, "leaf26").getType().getPath().getValue().equals("/this:cont1/this:leaf1"));
+        assertTrue(getLeaf(cont1, "leaf26").getType().getRequireInstance().isRequireInstanceTrue());
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf27").getType()
+                .getDataType()) == YangDataType.IDENTITYREF);
+        assertTrue(getLeaf(cont1, "leaf27").getType().getBases().get(0).getValue().equals("identity1"));
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf28").getType().getDataType()) == YangDataType.EMPTY);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf29").getType().getDataType()) == YangDataType.UNION);
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf29").getType().getTypes().get(0)
+                .getDataType()) == YangDataType.INT32);
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf29").getType().getTypes().get(1)
+                .getDataType()) == YangDataType.STRING);
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont1, "leaf30").getType()
+                .getDataType()) == YangDataType.INSTANCE_IDENTIFIER);
+        assertTrue(getLeaf(cont1, "leaf30").getType().getRequireInstance().isRequireInstanceFalse());
+
+        // - - - - - container2 - - - - -
+
+        final YContainer cont2 = getContainer(module, "cont2");
+
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont2, "leaf51").getType()
+                .getDataType()) == YangDataType.DECIMAL64);
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf51").getType().getFractionDigits(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont2, "leaf52").getType()
+                .getDataType()) == YangDataType.DECIMAL64);
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf52").getType().getFractionDigits(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont2, "leaf53").getType()
+                .getDataType()) == YangDataType.DECIMAL64);
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf53").getType().getFractionDigits(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertTrue(DataTypeHelper.getYangDataType(getLeaf(cont2, "leaf54").getType()
+                .getDataType()) == YangDataType.DECIMAL64);
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf54").getType().getFractionDigits(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf58").getType().getBits().get(0).getPosition(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf58").getType().getBits().get(1).getPosition(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf58").getType().getBits().get(2).getPosition(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf58").getType().getBits().get(3).getPosition(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertNoFindingsOnStatement(getLeafList(cont2, "leaflist62").getMinElements());
+        assertStatementHasFindingOfType(getLeafList(cont2, "leaflist63").getMinElements(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeafList(cont2, "leaflist64").getMinElements(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeafList(cont2, "leaflist65").getMinElements(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertNoFindingsOnStatement(getLeafList(cont2, "leaflist71").getMaxElements());
+        assertNoFindingsOnStatement(getLeafList(cont2, "leaflist72").getMaxElements());
+        assertStatementHasFindingOfType(getLeafList(cont2, "leaflist73").getMaxElements(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeafList(cont2, "leaflist74").getMaxElements(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeafList(cont2, "leaflist75").getMaxElements(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertStatementHasFindingOfType(getLeafList(cont2, "leaflist76").getMaxElements(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertNoFindingsOnStatement(getLeaf(cont2, "leaf81").getType().getPatterns().get(0).getModifier());
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf82").getType().getPatterns().get(0).getModifier(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf83").getType().getPatterns().get(0).getModifier(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/DeviationTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/DeviationTest.java
new file mode 100644
index 0000000..a9672a8
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/DeviationTest.java
@@ -0,0 +1,483 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.C3GPP;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.Y3gppInitialValue;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDeviate.DeviateType;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDeviation;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+
+public class DeviationTest extends YangTestCommon {
+
+    @Test
+    public void testDeviateAdd() {
+
+        parseImplementsYangModels(Arrays.asList("deviation-test/deviation-host-test-module.yang",
+                "deviation-test/deviate-add-test-module.yang"), Arrays.asList(THREEGPP_YANG_EXT_PATH));
+
+        final YModule hostModule = getModule("deviation-host-test-module");
+        final YModule deviateAddModule = getModule("deviate-add-test-module");
+
+        // ------------------------- All of these are just fine -------------------------------
+
+        assertTrue(getContainer(hostModule, "cont1") != null);
+        assertSubTreeNoFindings(getContainer(hostModule, "cont1"));
+
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11") != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getType().getDataType().equals("string"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getDefault() != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getDefault().getValue().equals("Hello World!"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getMusts().size() == 1);
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getMusts().get(0).getXpathExpression().equals(
+                "strlen(.) > 5"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getUnits() != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getUnits().getValue().equals("seconds"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont1", "leaf11").getChild(
+                C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__INITIAL_VALUE) != null);
+        assertTrue(((Y3gppInitialValue) getLeafUnderContainer(hostModule, "cont1", "leaf11").getChild(
+                C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__INITIAL_VALUE)).getInitialValue().equals("Hello World"));
+
+        assertTrue(getList(hostModule, "list11") != null);
+        assertSubTreeNoFindings(getList(hostModule, "list11"));
+
+        assertTrue(getList(hostModule, "list11").getUniques().size() == 1);
+        assertTrue(getList(hostModule, "list11").getUniques().get(0).getValue().equals("leaf111 leaf112"));
+
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113") != null);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().size() == 3);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().get(0).getValue().equals("10"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().get(1).getValue().equals("13"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().get(2).getValue().equals("18"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getMusts().size() == 2);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getMusts().get(0).getXpathExpression().equals(
+                ". > 4"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getMusts().get(1).getXpathExpression().equals(
+                ". < 98"));
+
+        assertSubTreeNoFindings(getChild(deviateAddModule, "deviation", "/host:cont1/host:leaf11"));
+        assertSubTreeNoFindings(getChild(deviateAddModule, "deviation", "/host:list11"));
+        assertSubTreeNoFindings(getChild(deviateAddModule, "deviation", "/host:list11/host:leaflist113"));
+
+        // ------------------------- Trying to add things that already exist -------------------------------
+
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21") != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getType().getDataType().equals("int16"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getConfig().getValue().equals("false"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getMandatory().isMandatoryTrue());
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getUnits().getValue().equals("minutes"));
+
+        final YDeviation deviationCont2Leaf21 = (YDeviation) getChild(deviateAddModule, "deviation",
+                "/host:cont2/host:leaf21");
+        assertTrue(deviationCont2Leaf21 != null);
+        assertTrue(deviationCont2Leaf21.getDeviates().size() == 1);
+        assertTrue(deviationCont2Leaf21.getDeviates().get(0).getDeviateType() == DeviateType.ADD);
+
+        assertTrue(deviationCont2Leaf21.getDeviates().get(0).getType().getDataType().equals("string"));
+        assertStatementHasFindingOfType(deviationCont2Leaf21.getDeviates().get(0).getType(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+        assertStatementHasFindingOfType(deviationCont2Leaf21.getDeviates().get(0).getConfig(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+        assertStatementHasFindingOfType(deviationCont2Leaf21.getDeviates().get(0).getMandatory(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+        assertStatementHasFindingOfType(deviationCont2Leaf21.getDeviates().get(0).getUnits(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+
+        final YDeviation deviationList21 = (YDeviation) getChild(deviateAddModule, "deviation", "/host:list21");
+        assertTrue(deviationList21 != null);
+        assertTrue(deviationList21.getDeviates().size() == 1);
+        assertTrue(deviationList21.getDeviates().get(0).getDeviateType() == DeviateType.ADD);
+
+        assertTrue(deviationList21.getDeviates().get(0).getMinElements().getMinValue() == 67);
+        assertStatementHasFindingOfType(deviationList21.getDeviates().get(0).getMinElements(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+        assertTrue(deviationList21.getDeviates().get(0).getMaxElements().getMaxValue() == 82);
+        assertStatementHasFindingOfType(deviationList21.getDeviates().get(0).getMaxElements(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+
+        // ------------------------- Various other findings -------------------------------
+
+        final YDeviation deviationUnknownElement = (YDeviation) getChild(deviateAddModule, "deviation",
+                "/host:unknownelement");
+        assertTrue(deviationUnknownElement != null);
+        assertStatementHasFindingOfType(deviationUnknownElement, ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        final YDeviation deviationCont4 = (YDeviation) getChild(deviateAddModule, "deviation", "/host:cont4");
+        assertTrue(deviationCont4 != null);
+        assertStatementHasFindingOfType(deviationCont4.getDeviates().get(0),
+                ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+
+        final YDeviation deviationCont3 = (YDeviation) getChild(deviateAddModule, "deviation", "/host:cont3");
+        assertTrue(deviationCont3 != null);
+        assertStatementHasFindingOfType(deviationCont3.getDeviates().get(0).getMinElements(),
+                ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+        assertStatementHasFindingOfType(deviationCont3.getDeviates().get(0).getMaxElements(),
+                ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+
+        final YDeviation deviationList11Leaf112 = (YDeviation) getChild(deviateAddModule, "deviation",
+                "/host:list11/host:leaf112");
+        assertTrue(deviationList11Leaf112 != null);
+        assertStatementHasFindingOfType(deviationList11Leaf112.getDeviates().get(0).getDefaults().get(0),
+                ParserFindingType.P166_DEVIATE_RESULTS_IN_CHILD_CARDINALITY_VIOLATION.toString());
+    }
+
+    @Test
+    public void testDeviateReplace() {
+
+        parseImplementsYangModels(Arrays.asList("deviation-test/deviation-host-test-module.yang",
+                "deviation-test/deviate-replace-test-module.yang"), Arrays.asList(THREEGPP_YANG_EXT_PATH));
+
+        final YModule hostModule = getModule("deviation-host-test-module");
+        final YModule deviateReplaceModule = getModule("deviate-replace-test-module");
+
+        // ------------------------- All of these are just fine -------------------------------
+
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21") != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getType().getDataType().equals("int16"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getConfig().getValue().equals("true"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getMandatory().isMandatoryFalse());
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getUnits().getValue().equals("days"));
+        assertSubTreeNoFindings(getContainer(hostModule, "cont2"));
+
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113") != null);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getType().getDataType().equals("int16"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().size() == 2);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().get(0).getValue().equals(
+                "1234"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().get(1).getValue().equals(
+                "7890"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getMusts().size() == 1);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getMusts().get(0).getXpathExpression().equals(
+                ". > 4"));
+        assertTrue(((Y3gppInitialValue) getLeafListUnderList(hostModule, "list11", "leaflist113").getChild(
+                C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__INITIAL_VALUE)).getValue().equals("70"));
+        assertSubTreeNoFindings(getLeafListUnderList(hostModule, "list11", "leaflist113"));
+
+        assertTrue(getList(hostModule, "list21") != null);
+        assertTrue(getList(hostModule, "list21").getMinElements().getMinValue() == 2);
+        assertTrue(getList(hostModule, "list21").getMaxElements().getMaxValue() == 36);
+        assertSubTreeNoFindings(getList(hostModule, "list21"));
+
+        assertTrue(getLeafUnderContainer(hostModule, "cont5", "leaf51") != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont5", "leaf51").getType().getDataType().equals("string"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont5", "leaf51").getType().getLength() != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont5", "leaf51").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeafUnderContainer(hostModule, "cont5", "leaf51").getType().getLength().getBoundaries().get(
+                0).lower == 10);
+        assertTrue(getLeafUnderContainer(hostModule, "cont5", "leaf51").getType().getLength().getBoundaries().get(
+                0).upper == 40);
+        assertSubTreeNoFindings(getLeafUnderContainer(hostModule, "cont5", "leaf51"));
+
+        assertSubTreeNoFindings(getChild(deviateReplaceModule, "deviation", "/host:cont2/host:leaf21"));
+        assertSubTreeNoFindings(getChild(deviateReplaceModule, "deviation", "/host:list11/host:leaflist113"));
+        assertSubTreeNoFindings(getChild(deviateReplaceModule, "deviation", "/host:list21"));
+        assertSubTreeNoFindings(getChild(deviateReplaceModule, "deviation", "/host:cont5/host:leaf51"));
+
+        // ------------------------------- Trying to replace things that don't exist -----------------------
+
+        final YDeviation deviationCont1Leaf11 = (YDeviation) getChild(deviateReplaceModule, "deviation",
+                "/host:cont1/host:leaf11");
+        assertTrue(deviationCont1Leaf11 != null);
+        assertTrue(deviationCont1Leaf11.getDeviates().size() == 1);
+        assertTrue(deviationCont1Leaf11.getDeviates().get(0).getDeviateType() == DeviateType.REPLACE);
+        assertStatementHasFindingOfType(deviationCont1Leaf11.getDeviates().get(0).getUnits(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+
+        // ---------------- Various other findings ---------------------
+
+        final YDeviation deviationCont4 = (YDeviation) getChild(deviateReplaceModule, "deviation", "/host:cont4");
+        assertTrue(deviationCont4 != null);
+        assertStatementHasFindingOfType(deviationCont4.getDeviates().get(0),
+                ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+
+        final YDeviation deviationList11Leaf112 = (YDeviation) getChild(deviateReplaceModule, "deviation",
+                "/host:list11/host:leaf112");
+        assertTrue(deviationList11Leaf112 != null);
+        assertStatementHasFindingOfType(deviationList11Leaf112.getDeviates().get(0).getType(),
+                ParserFindingType.P057_DATA_TYPE_CHANGED.toString());
+
+        final YDeviation deviationList22 = (YDeviation) getChild(deviateReplaceModule, "deviation", "/host:list22");
+        assertTrue(deviationList22 != null);
+        assertStatementHasFindingOfType(deviationList22.getDeviates().get(0).getMinElements(),
+                ParserFindingType.P056_CONSTRAINT_NARROWED.toString());
+        assertStatementHasFindingOfType(deviationList22.getDeviates().get(0).getMaxElements(),
+                ParserFindingType.P056_CONSTRAINT_NARROWED.toString());
+
+        final YDeviation deviationList11Leaf114 = (YDeviation) getChild(deviateReplaceModule, "deviation",
+                "/host:list11/host:leaf114");
+        assertTrue(deviationList11Leaf114 != null);
+        assertStatementHasFindingOfType(deviationList11Leaf114.getDeviates().get(0).getDefaults().get(0),
+                ParserFindingType.P166_DEVIATE_RESULTS_IN_CHILD_CARDINALITY_VIOLATION.toString());
+    }
+
+    @Test
+    public void testDeviateDelete() {
+
+        parseImplementsYangModels(Arrays.asList("deviation-test/deviation-host-test-module.yang",
+                "deviation-test/deviate-delete-test-module.yang"), Arrays.asList(THREEGPP_YANG_EXT_PATH));
+
+        final YModule hostModule = getModule("deviation-host-test-module");
+        final YModule deviateDeleteModule = getModule("deviate-delete-test-module");
+
+        // ------------------------- All of these are just fine -------------------------------
+
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21") != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getType().getDataType().equals("int16"));
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getConfig() != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getMandatory() != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21").getUnits() == null);
+        assertSubTreeNoFindings(getLeafUnderContainer(hostModule, "cont2", "leaf21"));
+
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113") != null);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getType().getDataType().equals("int16"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().size() == 2);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().get(0).getValue().equals("10"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getDefaults().get(1).getValue().equals("13"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getMusts().size() == 1);
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getMusts().get(0).getXpathExpression().equals(
+                ". > 4"));
+        assertTrue(getLeafListUnderList(hostModule, "list11", "leaflist113").getChild(
+                C3GPP.THREEGPP_COMMON_YANG_EXTENSIONS__INITIAL_VALUE) == null);
+        assertSubTreeNoFindings(getLeafListUnderList(hostModule, "list11", "leaflist113"));
+
+        assertSubTreeNoFindings(getChild(deviateDeleteModule, "deviation", "/host:cont2/host:leaf21"));
+        assertSubTreeNoFindings(getChild(deviateDeleteModule, "deviation", "/host:list11/host:leaflist113"));
+
+        // ---------------- These deviations try to delete things that don't exist in the host model ---------------------
+
+        final YDeviation deviationCont1Leaf11 = (YDeviation) getChild(deviateDeleteModule, "deviation",
+                "/host:cont1/host:leaf11");
+        assertTrue(deviationCont1Leaf11 != null);
+        assertTrue(deviationCont1Leaf11.getDeviates().size() == 1);
+        assertTrue(deviationCont1Leaf11.getDeviates().get(0).getDeviateType() == DeviateType.DELETE);
+        assertStatementHasFindingOfType(deviationCont1Leaf11.getDeviates().get(0).getConfig(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+
+        final YDeviation deviationList11 = (YDeviation) getChild(deviateDeleteModule, "deviation", "/host:list11");
+        assertTrue(deviationList11 != null);
+        assertStatementHasFindingOfType(deviationList11.getDeviates().get(0).getMinElements(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+        assertStatementHasFindingOfType(deviationList11.getDeviates().get(0).getMaxElements(),
+                ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+
+        // ---------------- Various other findings ---------------------
+
+        final YDeviation deviationCont4 = (YDeviation) getChild(deviateDeleteModule, "deviation", "/host:cont4");
+        assertTrue(deviationCont4 != null);
+        assertStatementHasFindingOfType(deviationCont4.getDeviates().get(0),
+                ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+
+        final YDeviation deviationList11Leaf112 = (YDeviation) getChild(deviateDeleteModule, "deviation",
+                "/host:list11/host:leaf112");
+        assertTrue(deviationList11Leaf112 != null);
+        assertStatementHasFindingOfType(deviationList11Leaf112.getDeviates().get(0).getType(),
+                ParserFindingType.P166_DEVIATE_RESULTS_IN_CHILD_CARDINALITY_VIOLATION.toString());
+    }
+
+    @Test
+    public void testDeviateNotSupported() {
+
+        parseImplementsYangModels(Arrays.asList("deviation-test/deviation-host-test-module.yang",
+                "deviation-test/deviate-not-supported-test-module.yang"), Arrays.asList(THREEGPP_YANG_EXT_PATH));
+
+        final YModule hostModule = getModule("deviation-host-test-module");
+        final YModule deviateNotSupportedModule = getModule("deviate-not-supported-test-module");
+
+        // ------------------------- All of these are just fine -------------------------------
+
+        assertTrue(getContainer(hostModule, "cont2") != null);
+        assertTrue(getLeafUnderContainer(hostModule, "cont2", "leaf21") == null);
+        assertTrue(getList(hostModule, "list21") == null);
+        assertTrue(getList(hostModule, "cont1") == null);
+
+        assertSubTreeNoFindings(getChild(deviateNotSupportedModule, "deviation", "/host:cont2/host:leaf21"));
+        assertSubTreeNoFindings(getChild(deviateNotSupportedModule, "deviation", "/host:list21"));
+        assertSubTreeNoFindings(getChild(deviateNotSupportedModule, "deviation", "/host:cont1"));
+
+        // ---------------- These deviations try to not-support things that don't exist in the host model ---------------------
+
+        final YDeviation deviationUnknownElement = (YDeviation) getChild(deviateNotSupportedModule, "deviation",
+                "/host:unknownElement");
+        assertTrue(deviationUnknownElement != null);
+        assertTrue(deviationUnknownElement.getDeviates().size() == 1);
+        assertTrue(deviationUnknownElement.getDeviates().get(0).getDeviateType() == DeviateType.NOT_SUPPORTED);
+        assertStatementHasFindingOfType(deviationUnknownElement, ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        final YDeviation deviationCont3UnknownElement = (YDeviation) getChild(deviateNotSupportedModule, "deviation",
+                "/host:cont3/host:unknownElement");
+        assertTrue(deviationCont3UnknownElement != null);
+        assertStatementHasFindingOfType(deviationCont3UnknownElement, ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        // ---------------- Various other findings ---------------------
+
+        final YDeviation deviationCont4 = (YDeviation) getChild(deviateNotSupportedModule, "deviation", "/host:cont4");
+        assertTrue(deviationCont4 != null);
+        assertStatementHasFindingOfType(deviationCont4.getDeviates().get(0).getType(),
+                ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+    }
+
+    @Test
+    public void testDeviateOthers() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P152_AUGMENT_TARGET_NODE_IN_SAME_MODULE.toString());
+
+        parseImplementsYangModels(Arrays.asList("deviation-test/deviate-other-tests-module.yang"), Arrays.asList(
+                THREEGPP_YANG_EXT_PATH));
+
+        final YModule module = getModule("deviate-other-tests-module");
+        assertTrue(module != null);
+
+        // ---------------- Deviate something augmented ---------------------
+
+        assertTrue(getContainer(module, "cont01") != null);
+        assertSubTreeNoFindings(getContainer(module, "cont01"));
+
+        assertTrue(getLeafUnderContainer(module, "cont01", "leaf11") != null);
+        assertTrue(getLeafUnderContainer(module, "cont01", "leaf11").getType().getDataType().equals("string"));
+        assertTrue(getLeafUnderContainer(module, "cont01", "leaf11").getMandatory() != null);
+        assertTrue(getLeafUnderContainer(module, "cont01", "leaf11").getMandatory().isMandatoryTrue());
+        assertTrue(getLeafUnderContainer(module, "cont01", "leaf11").getConfig() != null);
+        assertTrue(getLeafUnderContainer(module, "cont01", "leaf11").getConfig().getValue().equals("false"));
+        assertTrue(getLeafListUnderContainer(module, "cont01", "leaflist12") != null);
+        assertTrue(getLeafListUnderContainer(module, "cont01", "leaflist12").getType().getDataType().equals("int16"));
+        assertTrue(getLeafListUnderContainer(module, "cont01", "leaflist12").getMinElements() != null);
+        assertTrue(getLeafListUnderContainer(module, "cont01", "leaflist12").getMinElements().getMinValue() == 20);
+        assertTrue(getLeafListUnderContainer(module, "cont01", "leaflist12").getMaxElements() != null);
+        assertTrue(getLeafListUnderContainer(module, "cont01", "leaflist12").getMaxElements().getMaxValue() == 25);
+
+        assertStatementHasSingleFindingOfType(getChild(module, "deviation", "/this:cont01/this:leaf11"),
+                ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE.toString());
+        assertStatementHasSingleFindingOfType(getChild(module, "deviation", "/this:cont01/this:leaflist12"),
+                ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE.toString());
+
+        // ---------------- Deviate-replace something that was deviate-added ---------------------
+
+        assertTrue(getContainer(module, "cont02") != null);
+        assertSubTreeNoFindings(getContainer(module, "cont02"));
+
+        assertTrue(getContainer(module, "cont02").getConfig() != null);
+        assertTrue(getContainer(module, "cont02").getConfig().getValue().equals("true"));
+
+        assertStatementHasFindingOfType(getChild(module, "deviation", "/this:cont02"),
+                ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE.toString());
+        assertStatementHasFindingOfType(((YDeviation) getChild(module, "deviation", "/this:cont02")).getDeviates().get(1)
+                .getConfig(), ParserFindingType.P164_DEVIATE_REPLACE_OF_DEVIATE_ADDED_STATEMENT.toString());
+
+        // ---------------- Deviate-add something that was deviate-added ---------------------
+
+        assertTrue(getContainer(module, "cont03") != null);
+        assertSubTreeNoFindings(getContainer(module, "cont03"));
+
+        assertTrue(getContainer(module, "cont03").getConfig() != null);
+        assertTrue(getContainer(module, "cont03").getConfig().getValue().equals("false"));
+
+        assertStatementHasFindingOfType(getChild(module, "deviation", "/this:cont03"),
+                ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE.toString());
+        assertStatementHasFindingOfType(((YDeviation) getChild(module, "deviation", "/this:cont03")).getDeviates().get(1)
+                .getConfig(), ParserFindingType.P161_INVALID_DEVIATE_OPERATION.toString());
+
+        // ---------------- Deviate-replace something that was deviate-replaced ---------------------
+
+        assertTrue(getContainer(module, "cont04") != null);
+        assertSubTreeNoFindings(getContainer(module, "cont04"));
+
+        assertTrue(getContainer(module, "cont04").getConfig() != null);
+        assertTrue(getContainer(module, "cont04").getConfig().getValue().equals("true"));
+
+        assertStatementHasFindingOfType(((YDeviation) getChild(module, "deviation", "/this:cont04")).getDeviates().get(1)
+                .getConfig(), ParserFindingType.P163_AMBIGUOUS_DEVIATE_REPLACE_OF_SAME_STATEMENT.toString());
+
+        // ---------------- Deviate-delete something that was deviate-replaced ---------------------
+
+        assertTrue(getContainer(module, "cont05") != null);
+        assertSubTreeNoFindings(getContainer(module, "cont05"));
+
+        assertTrue(getContainer(module, "cont05").getConfig() == null);
+
+        assertStatementHasFindingOfType(((YDeviation) getChild(module, "deviation", "/this:cont05")).getDeviates().get(1)
+                .getConfig(), ParserFindingType.P165_DEVIATE_DELETE_OF_DEVIATED_STATEMENT.toString());
+
+        // ---------------- Deviate-delete something that was deviate-added ---------------------
+
+        assertTrue(getContainer(module, "cont06") != null);
+        assertSubTreeNoFindings(getContainer(module, "cont06"));
+
+        assertTrue(getContainer(module, "cont06").getConfig() == null);
+
+        assertStatementHasFindingOfType(((YDeviation) getChild(module, "deviation", "/this:cont06")).getDeviates().get(1)
+                .getConfig(), ParserFindingType.P165_DEVIATE_DELETE_OF_DEVIATED_STATEMENT.toString());
+
+        // ---------------- Some error scenarios ---------------------
+
+        assertStatementHasFindingOfType(((YDeviation) getChild(module, "deviation", "/this:cont07")).getDeviates().get(0),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertStatementHasFindingOfType(((YDeviation) getChild(module, "deviation", "/this:cont08")).getDeviates().get(0),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertStatementHasFindingOfType(getChild(module, "deviation", "//this:cont08"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertStatementHasNotFindingOfType(getChild(module, "deviation", "/this:cont09/"),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertStatementHasFindingOfType(getChild(module, "deviation", "/"), ParserFindingType.P054_UNRESOLVABLE_PATH
+                .toString());
+
+        assertStatementHasFindingOfType(getChild(module, "deviation", ""), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+
+        assertStatementHasFindingOfType(getChild(module, "deviation", null),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertStatementHasNotFindingOfType(getChild(module, "deviation", "  /this:cont10  "),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+    }
+
+    @Test
+    public void testDeviateNotSupportedMultiLevel() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P162_DEVIATION_TARGET_NODE_IN_SAME_MODULE.toString());
+
+        parseImplementsYangModels(Arrays.asList("deviation-test/deviate-not-supported-multi-level-test-module.yang"), Arrays
+                .asList(THREEGPP_YANG_EXT_PATH));
+
+        final YModule module = getModule("deviate-not-supported-multi-level-test-module");
+        assertTrue(module != null);
+
+        assertNoFindings();
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        final YContainer cont2 = getContainer(cont1, "cont2");
+        assertTrue(cont2 == null);
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/GeneralSyntaxTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/GeneralSyntaxTest.java
new file mode 100644
index 0000000..b819370
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/GeneralSyntaxTest.java
@@ -0,0 +1,611 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement.StatementArgumentType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YCase;
+import org.oran.smo.yangtools.parser.model.statements.yang.YChoice;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLength;
+import org.oran.smo.yangtools.parser.model.statements.yang.YList;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLength.BoundaryPair;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YOrderedBy;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRange;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRpc;
+
+public class GeneralSyntaxTest extends YangTestCommon {
+
+    @Test
+    public void testGeneralSyntaxRpc() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("general-syntax-test/general-syntax-test-rpc.yang"));
+
+        assertNoFindings();
+
+        final YModule yModule = getModule("general-syntax-test-rpc");
+        assertTrue(yModule != null);
+
+        // -------------- RPCs -------------------
+
+        final YRpc rpc1 = getChild(yModule, CY.RPC, "rpc1");
+        assertTrue(rpc1 != null);
+
+        final YRpc rpc2 = getChild(yModule, CY.RPC, "rpc2");
+        assertTrue(rpc2 != null);
+        assertTrue(rpc2.getInput() != null);
+        assertTrue(rpc2.getOutput() != null);		// missing in YAM, auto-created by parser
+        assertTrue(rpc2.getInput().getContainers().get(0) != null);
+        assertTrue(rpc2.getInput().getContainers().get(0).getStatementIdentifier().equals("cont1"));
+
+        final YRpc rpc3 = getChild(yModule, CY.RPC, "rpc3");
+        assertTrue(rpc3 != null);
+        assertTrue(rpc3.getInput() != null);		// missing in YAM, auto-created by parser
+        assertTrue(rpc3.getOutput() != null);
+        assertTrue(rpc3.getOutput().getContainers().get(0) != null);
+        assertTrue(rpc3.getOutput().getContainers().get(0).getStatementIdentifier().equals("cont2"));
+
+        final YRpc rpc4 = getChild(yModule, CY.RPC, "rpc4");
+        assertTrue(rpc4 != null);
+        assertTrue(rpc4.getStatus() != null);
+        assertTrue(rpc4.getStatus().isDeprecated());
+        assertTrue(rpc4.getIfFeatures().get(0) != null);
+        assertTrue(rpc4.getIfFeatures().get(0).getValue().equals("feature1"));
+        assertTrue(rpc4.getTypedefs().get(0) != null);
+        assertTrue(rpc4.getTypedefs().get(0).getTypedefName().equals("typedef1"));
+        assertTrue(rpc4.getGroupings().get(0) != null);
+        assertTrue(rpc4.getGroupings().get(0).getGroupingName().equals("grouping1"));
+
+        assertTrue(rpc4.getOutput() != null);
+        assertTrue(rpc4.getOutput().getLeafs().get(0) != null);
+        assertTrue(rpc4.getOutput().getLeafs().get(0).getType().getDataType().equals("string"));
+        assertTrue(rpc4.getOutput().getAnyxmls().get(0) != null);
+        assertTrue(rpc4.getOutput().getAnyxmls().get(0).getStatementIdentifier().equals("anyxml1"));
+        assertTrue(rpc4.getOutput().getAnydata().get(0) != null);
+        assertTrue(rpc4.getOutput().getAnydata().get(0).getStatementIdentifier().equals("anydata1"));
+        assertTrue(rpc4.getOutput().getLists().get(0) != null);
+        assertTrue(rpc4.getOutput().getLists().get(0).getStatementIdentifier().equals("list1"));
+        assertTrue(rpc4.getOutput().getLeafLists().get(0) != null);
+        assertTrue(rpc4.getOutput().getLeafLists().get(0).getStatementIdentifier().equals("leaflist3"));
+        assertTrue(rpc4.getOutput().getChoices().get(0) != null);
+        assertTrue(rpc4.getOutput().getChoices().get(0).getStatementIdentifier().equals("choice1"));
+        assertTrue(rpc4.getOutput().getMusts().get(0) != null);
+        assertTrue(rpc4.getOutput().getMusts().get(0).getXpathExpression().equals("../contX"));
+        assertTrue(rpc4.getOutput().getTypedefs().get(0) != null);
+        assertTrue(rpc4.getOutput().getTypedefs().get(0).getTypedefName().equals("typedef2"));
+
+        assertTrue(rpc4.getInput() != null);
+        assertTrue(rpc4.getInput().getContainers().get(0) != null);
+        assertTrue(rpc4.getInput().getContainers().get(0).getContainerName().equals("cont4"));
+        assertTrue(rpc4.getInput().getLeafs().get(0) != null);
+        assertTrue(rpc4.getInput().getLeafs().get(0).getLeafName().equals("grouping-leaf"));
+        assertTrue(rpc4.getInput().getAnyxmls().get(0) != null);
+        assertTrue(rpc4.getInput().getAnyxmls().get(0).getStatementIdentifier().equals("anyxml1"));
+        assertTrue(rpc4.getInput().getAnydata().get(0) != null);
+        assertTrue(rpc4.getInput().getAnydata().get(0).getStatementIdentifier().equals("anydata1"));
+        assertTrue(rpc4.getInput().getLists().get(0) != null);
+        assertTrue(rpc4.getInput().getLists().get(0).getStatementIdentifier().equals("list1"));
+        assertTrue(rpc4.getInput().getLeafLists().get(0) != null);
+        assertTrue(rpc4.getInput().getLeafLists().get(0).getStatementIdentifier().equals("leaflist3"));
+        assertTrue(rpc4.getInput().getChoices().get(0) != null);
+        assertTrue(rpc4.getInput().getChoices().get(0).getStatementIdentifier().equals("choice1"));
+        assertTrue(rpc4.getInput().getMusts().get(0) != null);
+        assertTrue(rpc4.getInput().getMusts().get(0).getXpathExpression().equals("../contX"));
+        assertTrue(rpc4.getInput().getTypedefs().get(0) != null);
+        assertTrue(rpc4.getInput().getTypedefs().get(0).getTypedefName().equals("typedef2"));
+    }
+
+    @Test
+    public void testGeneralSyntaxConstraints() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("general-syntax-test/general-syntax-test-constraints.yang"));
+
+        final YModule module = getModule("general-syntax-test-constraints");
+        assertTrue(module != null);
+
+        // -------------- Length -------------------
+
+        {
+            final YContainer cont1 = getContainer(module, "cont1");
+
+            final YLeaf leaf1 = getLeaf(cont1, "leaf1");
+            final YLength length1 = leaf1.getType().getLength();
+
+            assertTrue(length1.getErrorAppTag() != null);
+            assertTrue(length1.getErrorAppTag().getValue().equals("some-app-tag"));
+            assertTrue(length1.getErrorMessage() != null);
+            assertTrue(length1.getErrorMessage().getValue().equals("wrong length"));
+            assertNoFindingsOnStatement(getLeaf(cont1, "leaf1").getType().getLength());
+
+            final List<BoundaryPair> boundaries1 = length1.getBoundaries();
+            assertTrue(boundaries1.size() == 1);
+            assertTrue(boundaries1.get(0).lower == 1L);
+            assertTrue(boundaries1.get(0).upper == 10L);
+
+            final List<BoundaryPair> boundaries2 = getLeaf(cont1, "leaf2").getType().getLength().getBoundaries();
+            assertTrue(boundaries2.size() == 1);
+            assertTrue(boundaries2.get(0).lower == 0L);
+            assertTrue(boundaries2.get(0).upper == Long.MAX_VALUE);
+            assertNoFindingsOnStatement(getLeaf(cont1, "leaf2").getType().getLength());
+
+            final List<BoundaryPair> boundaries3 = getLeaf(cont1, "leaf3").getType().getLength().getBoundaries();
+            assertTrue(boundaries3.size() == 3);
+            assertTrue(boundaries3.get(0).lower == 0L);
+            assertTrue(boundaries3.get(0).upper == 10L);
+            assertTrue(boundaries3.get(1).lower == 15L);
+            assertTrue(boundaries3.get(1).upper == 15L);
+            assertTrue(boundaries3.get(2).lower == 20L);
+            assertTrue(boundaries3.get(2).upper == Long.MAX_VALUE);
+            assertNoFindingsOnStatement(getLeaf(cont1, "leaf3").getType().getLength());
+
+            assertTrue(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(0));
+            assertTrue(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(10));
+            assertTrue(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(15));
+            assertTrue(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(20));
+            assertTrue(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(40404040404L));
+
+            assertFalse(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(-1));
+            assertFalse(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(11));
+            assertFalse(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(14));
+            assertFalse(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(16));
+            assertFalse(getLeaf(cont1, "leaf3").getType().getLength().isWithinLengthBoundaries(19));
+
+            final List<BoundaryPair> boundaries4 = getLeaf(cont1, "leaf4").getType().getLength().getBoundaries();
+            assertTrue(boundaries4.size() == 2);
+            assertTrue(boundaries4.get(0).lower == 0L);
+            assertTrue(boundaries4.get(0).upper == 0L);
+            assertTrue(boundaries4.get(1).lower == Long.MAX_VALUE);
+            assertTrue(boundaries4.get(1).upper == Long.MAX_VALUE);
+            assertNoFindingsOnStatement(getLeaf(cont1, "leaf4").getType().getLength());
+
+            final List<BoundaryPair> boundaries5 = getLeaf(cont1, "leaf5").getType().getLength().getBoundaries();
+            assertTrue(boundaries5.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf5").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<BoundaryPair> boundaries6 = getLeaf(cont1, "leaf6").getType().getLength().getBoundaries();
+            assertTrue(boundaries6.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf6").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<BoundaryPair> boundaries7 = getLeaf(cont1, "leaf7").getType().getLength().getBoundaries();
+            assertTrue(boundaries7.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf7").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<BoundaryPair> boundaries8 = getLeaf(cont1, "leaf8").getType().getLength().getBoundaries();
+            assertTrue(boundaries8.size() == 2);
+            assertTrue(boundaries8.get(0).lower == 10L);
+            assertTrue(boundaries8.get(0).upper == 20L);
+            assertTrue(boundaries8.get(1).lower == 21L);
+            assertTrue(boundaries8.get(1).upper == 30L);
+            assertNoFindingsOnStatement(getLeaf(cont1, "leaf8").getType().getLength());
+
+            final List<BoundaryPair> boundaries9 = getLeaf(cont1, "leaf9").getType().getLength().getBoundaries();
+            assertTrue(boundaries9.size() == 2);
+            assertTrue(boundaries9.get(0).lower == 10L);
+            assertTrue(boundaries9.get(0).upper == 20L);
+            assertTrue(boundaries9.get(1).lower == 20L);
+            assertTrue(boundaries9.get(1).upper == 30L);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf9").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<BoundaryPair> boundaries10 = getLeaf(cont1, "leaf10").getType().getLength().getBoundaries();
+            assertTrue(boundaries10.size() == 2);
+            assertTrue(boundaries10.get(0).lower == 19L);
+            assertTrue(boundaries10.get(0).upper == 30L);
+            assertTrue(boundaries10.get(1).lower == 10L);
+            assertTrue(boundaries10.get(1).upper == 20L);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf10").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<BoundaryPair> boundaries11 = getLeaf(cont1, "leaf11").getType().getLength().getBoundaries();
+            assertTrue(boundaries11.size() == 1);
+            assertTrue(boundaries11.get(0).lower == -1L);
+            assertTrue(boundaries11.get(0).upper == -3L);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf11").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<BoundaryPair> boundaries12 = getLeaf(cont1, "leaf12").getType().getLength().getBoundaries();
+            assertTrue(boundaries12.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf12").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<BoundaryPair> boundaries13 = getLeaf(cont1, "leaf13").getType().getLength().getBoundaries();
+            assertTrue(boundaries13.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont1, "leaf13").getType().getLength(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+        }
+
+        // -------------- Range for integer -------------------
+
+        {
+            final YContainer cont2 = getContainer(module, "cont2");
+            assertTrue(cont2 != null);
+
+            final YLeaf leaf1 = getLeaf(cont2, "leaf1");
+            assertTrue(leaf1 != null);
+            final YRange range1 = leaf1.getType().getRange();
+            assertTrue(range1 != null);
+
+            assertTrue(range1.getErrorAppTag() != null);
+            assertTrue(range1.getErrorAppTag().getValue().equals("some-app-tag"));
+            assertTrue(range1.getErrorMessage() != null);
+            assertTrue(range1.getErrorMessage().getValue().equals("wrong length"));
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf1").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries1 = range1.getBoundaries();
+            assertTrue(boundaries1.size() == 1);
+            assertTrue(boundaries1.get(0).lower.compareTo(BigDecimal.valueOf(1L)) == 0);
+            assertTrue(boundaries1.get(0).upper.compareTo(BigDecimal.valueOf(10L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf1").getType().getRange());
+
+            assertTrue(getLeaf(cont2, "leaf1").getType().getRange().isWithinRangeBoundaries(BigDecimal.valueOf(5L)));
+            assertFalse(getLeaf(cont2, "leaf1").getType().getRange().isWithinRangeBoundaries(BigDecimal.valueOf(-20L)));
+            assertFalse(getLeaf(cont2, "leaf1").getType().getRange().isWithinRangeBoundaries(BigDecimal.valueOf(90L)));
+
+            final List<YRange.BoundaryPair> boundaries2 = getLeaf(cont2, "leaf2").getType().getRange().getBoundaries();
+            assertTrue(boundaries2.get(0).lower.compareTo(BigDecimal.valueOf(0L)) == 0);
+            assertTrue(boundaries2.get(0).upper.compareTo(BigDecimal.valueOf(255L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf2").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries3 = getLeaf(cont2, "leaf3").getType().getRange().getBoundaries();
+            assertTrue(boundaries3.get(0).lower.compareTo(BigDecimal.valueOf(0L)) == 0);
+            assertTrue(boundaries3.get(0).upper.compareTo(BigDecimal.valueOf(65535L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf3").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries4 = getLeaf(cont2, "leaf4").getType().getRange().getBoundaries();
+            assertTrue(boundaries4.get(0).lower.compareTo(BigDecimal.valueOf(0L)) == 0);
+            assertTrue(boundaries4.get(0).upper.compareTo(BigDecimal.valueOf(4294967295L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf4").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries5 = getLeaf(cont2, "leaf5").getType().getRange().getBoundaries();
+            assertTrue(boundaries5.get(0).lower.compareTo(BigDecimal.valueOf(0L)) == 0);
+            assertTrue(boundaries5.get(0).upper.compareTo(new BigDecimal("18446744073709551615")) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf5").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries6 = getLeaf(cont2, "leaf6").getType().getRange().getBoundaries();
+            assertTrue(boundaries6.get(0).lower.compareTo(BigDecimal.valueOf(-128L)) == 0);
+            assertTrue(boundaries6.get(0).upper.compareTo(BigDecimal.valueOf(127L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf6").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries7 = getLeaf(cont2, "leaf7").getType().getRange().getBoundaries();
+            assertTrue(boundaries7.get(0).lower.compareTo(BigDecimal.valueOf(-32768L)) == 0);
+            assertTrue(boundaries7.get(0).upper.compareTo(BigDecimal.valueOf(32767L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf7").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries8 = getLeaf(cont2, "leaf8").getType().getRange().getBoundaries();
+            assertTrue(boundaries8.get(0).lower.compareTo(BigDecimal.valueOf(-2147483648L)) == 0);
+            assertTrue(boundaries8.get(0).upper.compareTo(BigDecimal.valueOf(2147483647L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf8").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries9 = getLeaf(cont2, "leaf9").getType().getRange().getBoundaries();
+            assertTrue(boundaries9.get(0).lower.compareTo(BigDecimal.valueOf(-9223372036854775808L)) == 0);
+            assertTrue(boundaries9.get(0).upper.compareTo(BigDecimal.valueOf(9223372036854775807L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf9").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries10 = getLeaf(cont2, "leaf10").getType().getRange().getBoundaries();
+            assertTrue(boundaries10.size() == 1);
+            assertTrue(boundaries10.get(0).lower.compareTo(BigDecimal.valueOf(10L)) == 0);
+            assertTrue(boundaries10.get(0).upper.compareTo(BigDecimal.valueOf(20L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf10").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries11 = getLeaf(cont2, "leaf11").getType().getRange().getBoundaries();
+            assertTrue(boundaries11.size() == 2);
+            assertTrue(boundaries11.get(0).lower.compareTo(BigDecimal.valueOf(10L)) == 0);
+            assertTrue(boundaries11.get(0).upper.compareTo(BigDecimal.valueOf(20L)) == 0);
+            assertTrue(boundaries11.get(1).lower.compareTo(BigDecimal.valueOf(30L)) == 0);
+            assertTrue(boundaries11.get(1).upper.compareTo(BigDecimal.valueOf(40L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf11").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries12 = getLeaf(cont2, "leaf12").getType().getRange().getBoundaries();
+            assertTrue(boundaries12.size() == 3);
+            assertTrue(boundaries12.get(0).lower.compareTo(BigDecimal.valueOf(10L)) == 0);
+            assertTrue(boundaries12.get(0).upper.compareTo(BigDecimal.valueOf(20L)) == 0);
+            assertTrue(boundaries12.get(1).lower.compareTo(BigDecimal.valueOf(25L)) == 0);
+            assertTrue(boundaries12.get(1).upper.compareTo(BigDecimal.valueOf(25L)) == 0);
+            assertTrue(boundaries12.get(2).lower.compareTo(BigDecimal.valueOf(30L)) == 0);
+            assertTrue(boundaries12.get(2).upper.compareTo(BigDecimal.valueOf(40L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf12").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries13 = getLeaf(cont2, "leaf13").getType().getRange().getBoundaries();
+            assertTrue(boundaries13.size() == 2);
+            assertTrue(boundaries13.get(0).lower.compareTo(BigDecimal.valueOf(0L)) == 0);
+            assertTrue(boundaries13.get(0).upper.compareTo(BigDecimal.valueOf(0L)) == 0);
+            assertTrue(boundaries13.get(1).lower.compareTo(BigDecimal.valueOf(255L)) == 0);
+            assertTrue(boundaries13.get(1).upper.compareTo(BigDecimal.valueOf(255L)) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont2, "leaf13").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries14 = getLeaf(cont2, "leaf14").getType().getRange().getBoundaries();
+            assertTrue(boundaries14.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf14").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries15 = getLeaf(cont2, "leaf15").getType().getRange().getBoundaries();
+            assertTrue(boundaries15.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf15").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries16 = getLeaf(cont2, "leaf16").getType().getRange().getBoundaries();
+            assertTrue(boundaries16.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf16").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries17 = getLeaf(cont2, "leaf17").getType().getRange().getBoundaries();
+            assertTrue(boundaries17.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf17").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries18 = getLeaf(cont2, "leaf18").getType().getRange().getBoundaries();
+            assertTrue(boundaries18.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf18").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries19 = getLeaf(cont2, "leaf19").getType().getRange().getBoundaries();
+            assertTrue(boundaries19.size() == 2);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf19").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries20 = getLeaf(cont2, "leaf20").getType().getRange().getBoundaries();
+            assertTrue(boundaries20.size() == 2);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf20").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries21 = getLeaf(cont2, "leaf21").getType().getRange().getBoundaries();
+            assertTrue(boundaries21.size() == 2);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf21").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries22 = getLeaf(cont2, "leaf22").getType().getRange().getBoundaries();
+            assertTrue(boundaries22.size() == 2);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf22").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries23 = getLeaf(cont2, "leaf23").getType().getRange().getBoundaries();
+            assertTrue(boundaries23.size() == 2);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf23").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries24 = getLeaf(cont2, "leaf24").getType().getRange().getBoundaries();
+            assertTrue(boundaries24.size() == 1);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf24").getType().getRange(),
+                    ParserFindingType.P053_INVALID_VALUE.toString());
+
+            final List<YRange.BoundaryPair> boundaries25 = getLeaf(cont2, "leaf25").getType().getRange().getBoundaries();
+            assertTrue(boundaries25.size() == 0);
+            assertStatementHasFindingOfType(getLeaf(cont2, "leaf25").getType().getRange(),
+                    ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+        }
+
+        // -------------- Range for decimal64 -------------------
+
+        {
+            final YContainer cont3 = getContainer(module, "cont3");
+            assertTrue(cont3 != null);
+
+            final YLeaf leaf1 = getLeaf(cont3, "leaf1");
+            assertTrue(leaf1 != null);
+            final YRange range1 = leaf1.getType().getRange();
+            assertTrue(range1 != null);
+
+            final List<YRange.BoundaryPair> boundaries1 = range1.getBoundaries();
+            assertTrue(boundaries1.size() == 1);
+            assertTrue(boundaries1.get(0).lower.compareTo(new BigDecimal("-922337203685477580.8")) == 0);
+            assertTrue(boundaries1.get(0).upper.compareTo(new BigDecimal("922337203685477580.7")) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont3, "leaf1").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries2 = getLeaf(cont3, "leaf2").getType().getRange().getBoundaries();
+            assertTrue(boundaries2.get(0).lower.compareTo(new BigDecimal("-9.223372036854775808")) == 0);
+            assertTrue(boundaries2.get(0).upper.compareTo(new BigDecimal("9.223372036854775807")) == 0);
+            assertNoFindingsOnStatement(getLeaf(cont3, "leaf2").getType().getRange());
+
+            final List<YRange.BoundaryPair> boundaries3 = getLeaf(cont3, "leaf3").getType().getRange().getBoundaries();
+            assertTrue(boundaries3.size() == 0);
+            assertNoFindingsOnStatement(getLeaf(cont3, "leaf3").getType().getRange());
+        }
+    }
+
+    @Test
+    public void testGeneralVarious() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("general-syntax-test/general-syntax-test-various.yang"));
+
+        final YModule module = getModule("general-syntax-test-various");
+        assertTrue(module != null);
+
+        // - - - - enums - - - - -
+
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        final YLeaf leaf1 = getLeaf(cont1, "leaf1");
+
+        assertNoFindingsOnStatement(leaf1.getType().getEnums().get(0));
+        assertNoFindingsOnStatement(leaf1.getType().getEnums().get(1));
+        assertNoFindingsOnStatement(leaf1.getType().getEnums().get(2));
+        assertStatementHasFindingOfType(leaf1.getType().getEnums().get(3), ParserFindingType.P141_WHITESPACE_IN_ENUM
+                .toString());
+        assertNoFindingsOnStatement(leaf1.getType().getEnums().get(4));
+        assertStatementHasFindingOfType(leaf1.getType().getEnums().get(5), ParserFindingType.P142_UNUSUAL_CHARACTERS_IN_ENUM
+                .toString());
+        assertStatementHasFindingOfType(leaf1.getType().getEnums().get(6).getValue(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertTrue(leaf1.getType().getEnums().get(6).getValue().getEnumValue() == 0);
+
+        assertTrue(leaf1.getType().getEnums().get(0).getValue().getValue().equals("0"));
+        assertTrue(leaf1.getType().getEnums().get(1).getStatus().isDeprecated());
+        assertTrue(leaf1.getType().getEnums().get(2).getStatementIdentifier().equals("two"));
+
+        // - - - - status - - - - -
+
+        final YContainer cont2 = getContainer(module, "cont2");
+
+        assertNoFindingsOnStatement(getLeaf(cont2, "leaf11").getStatus());
+        assertTrue(getLeaf(cont2, "leaf11").getStatus().isCurrent());
+        assertNoFindingsOnStatement(getLeaf(cont2, "leaf12").getStatus());
+        assertTrue(getLeaf(cont2, "leaf12").getStatus().isDeprecated());
+        assertNoFindingsOnStatement(getLeaf(cont2, "leaf13").getStatus());
+        assertTrue(getLeaf(cont2, "leaf13").getStatus().isObsolete());
+
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf14").getStatus(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertFalse(getLeaf(cont2, "leaf14").getStatus().isCurrent());
+        assertFalse(getLeaf(cont2, "leaf14").getStatus().isDeprecated());
+        assertFalse(getLeaf(cont2, "leaf14").getStatus().isObsolete());
+
+        assertStatementHasFindingOfType(getLeaf(cont2, "leaf15").getStatus(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertFalse(getLeaf(cont2, "leaf15").getStatus().isCurrent());
+        assertFalse(getLeaf(cont2, "leaf15").getStatus().isDeprecated());
+        assertFalse(getLeaf(cont2, "leaf15").getStatus().isObsolete());
+
+        // - - - - - container - - - - -
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertSubTreeNoFindings(cont3);
+
+        assertTrue(cont3.definesDataNode());
+        assertTrue(cont3.definesSchemaNode());
+
+        assertTrue(cont3.getGroupings().size() == 1);
+        assertTrue(cont3.getTypedefs().size() == 1);
+        assertTrue(cont3.getLeafs().size() == 2);
+        assertTrue(cont3.getChoices().size() == 1);
+        assertTrue(cont3.getLists().size() == 1);
+        assertTrue(cont3.getNotifications().size() == 1);
+        assertTrue(cont3.getLeafLists().size() == 1);
+        assertTrue(cont3.getAnydata().size() == 2);
+        assertTrue(cont3.getAnyxmls().size() == 3);
+
+        // - - - - - choice and case - - - - -
+
+        final YChoice choice1 = getChoice(module, "choice1");
+        assertSubTreeNoFindings(choice1);
+
+        assertTrue(choice1.getCases().size() == 8);
+        assertTrue(choice1.getChoices().size() == 0);
+        assertTrue(choice1.getConfig().getValue().equals("true"));
+        assertTrue(choice1.getDefault().getValue().equals("case2"));
+        assertTrue(choice1.getIfFeatures().size() == 0);
+        assertTrue(choice1.getMandatory() == null);
+        assertTrue(choice1.getStatus().isDeprecated());
+        assertTrue(choice1.getWhens().size() == 1);
+
+        // will always return empty lists as shorthand notation is resolved.
+        assertTrue(choice1.getAnydata().size() == 0);
+        assertTrue(choice1.getAnyxmls().size() == 0);
+        assertTrue(choice1.getContainers().size() == 0);
+        assertTrue(choice1.getLists().size() == 0);
+        assertTrue(choice1.getLeafs().size() == 0);
+        assertTrue(choice1.getLeafLists().size() == 0);
+
+        final YCase case2 = getCase(choice1, "case2");
+
+        assertTrue(case2.getAnydata().size() == 1);
+        assertTrue(case2.getAnyxmls().size() == 2);
+        assertTrue(case2.getChoices().size() == 0);
+        assertTrue(case2.getContainers().size() == 0);
+        assertTrue(case2.getLeafs().size() == 1);
+        assertTrue(case2.getLeafLists().size() == 1);
+        assertTrue(case2.getLists().size() == 0);
+        assertTrue(case2.getStatus().isObsolete());
+        assertTrue(case2.getUses().size() == 0);
+        assertTrue(case2.getWhens().size() == 1);
+
+        // - - - - - list - - - - -
+
+        final YList list4 = getList(module, "list4");
+        assertSubTreeNoFindings(list4);
+
+        assertTrue(list4.definesDataNode());
+        assertTrue(list4.definesSchemaNode());
+        assertTrue(list4.getConfig().getValue().equals("true"));
+        assertTrue(list4.getOrderedBy().isOrderedBySystem());
+        assertTrue(list4.getStatus().isCurrent());
+
+        assertTrue(list4.getUses().size() == 0);
+        assertTrue(list4.getContainers().size() == 0);
+        assertTrue(list4.getIfFeatures().size() == 0);
+        assertTrue(list4.getGroupings().size() == 1);
+        assertTrue(list4.getTypedefs().size() == 1);
+        assertTrue(list4.getActions().size() == 3);
+        assertTrue(list4.getLeafs().size() == 2);
+        assertTrue(list4.getChoices().size() == 1);
+        assertTrue(list4.getLists().size() == 1);
+        assertTrue(list4.getNotifications().size() == 1);
+        assertTrue(list4.getLeafLists().size() == 1);
+        assertTrue(list4.getAnydata().size() == 2);
+        assertTrue(list4.getAnyxmls().size() == 3);
+        assertTrue(list4.getMusts().size() == 0);
+        assertTrue(list4.getWhens().size() == 0);
+
+        // - - - - - leaf-list - - - - -
+
+        final YContainer cont5 = getContainer(module, "cont5");
+
+        final YOrderedBy yOrderedBy = getLeafList(cont5, "leaflist51").getOrderedBy();
+        assertEquals(StatementArgumentType.VALUE, yOrderedBy.getArgumentType());
+        assertEquals(CY.STMT_ORDERED_BY, yOrderedBy.getStatementModuleAndName());
+
+        assertTrue(getLeafList(cont5, "leaflist51").getOrderedBy().isOrderedByUser());
+        assertFalse(getLeafList(cont5, "leaflist51").getOrderedBy().isOrderedBySystem());
+        assertSubTreeNoFindings(getLeafList(cont5, "leaflist51"));
+
+        assertFalse(getLeafList(cont5, "leaflist52").getOrderedBy().isOrderedByUser());
+        assertTrue(getLeafList(cont5, "leaflist52").getOrderedBy().isOrderedBySystem());
+        assertSubTreeNoFindings(getLeafList(cont5, "leaflist52"));
+
+        assertFalse(getLeafList(cont5, "leaflist53").getOrderedBy().isOrderedByUser());
+        assertFalse(getLeafList(cont5, "leaflist53").getOrderedBy().isOrderedBySystem());
+        assertStatementHasFindingOfType(getLeafList(cont5, "leaflist53").getOrderedBy(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertFalse(getLeafList(cont5, "leaflist54").getOrderedBy().isOrderedByUser());
+        assertFalse(getLeafList(cont5, "leaflist54").getOrderedBy().isOrderedBySystem());
+        assertStatementHasFindingOfType(getLeafList(cont5, "leaflist54").getOrderedBy(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/GroupingTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/GroupingTest.java
new file mode 100644
index 0000000..cc6a517
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/GroupingTest.java
@@ -0,0 +1,330 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YChoice;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YWhen;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class GroupingTest extends YangTestCommon {
+
+    @Test
+    public void testGrouping() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("grouping-test/uses-module.yang",
+                "grouping-test/grouping-module.yang"));
+
+        assertNoFindings();
+
+        final YModule usesModule = getModule("uses-module");
+        assertTrue(usesModule != null);
+
+        final YContainer cont1 = getContainer(usesModule, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf11") != null);
+        assertTrue(getLeaf(cont1, "leaf11").getIfFeatures().size() == 0);
+        assertTrue(getContainer(cont1, "contgroup1") != null);
+        assertTrue(getContainer(cont1, "contgroup1").getIfFeatures().size() == 1);
+        assertTrue(getContainer(cont1, "contgroup1").getIfFeatures().get(0).getValue().equals("feature1 or feature2"));
+
+        assertTrue(getLeafUnderContainer(usesModule, "cont2", "leaf21") != null);
+        assertTrue(getLeafFromContainerContainer(usesModule, "cont2", "contgroup1", "leafgroup1") != null);
+
+        final YWhen when = getContainerUnderContainer(usesModule, "cont2", "contgroup1").getWhens().get(0);
+        assertTrue(when != null);
+        assertTrue(when.appliesToParentSchemaNode() == true);
+
+        final YContainer cont3 = getContainer(usesModule, "cont3");
+        assertTrue(cont3 != null);
+        assertTrue(cont3.getEffectiveNamespace().equals("urn:o-ran:yang:uses-module"));
+
+        assertTrue(getLeaf(cont3, "leaf31") != null);
+        assertTrue(getContainer(cont3, "contgroup1") != null);
+        assertTrue(getContainer(cont3, "contgroup1").getEffectiveNamespace().equals("urn:o-ran:yang:uses-module"));
+        assertTrue(getContainer(cont3, "contgroup1").getWhens().size() == 0);
+        assertTrue(getLeaf(getContainer(cont3, "contgroup1"), "leaf32") != null);
+        assertTrue(getLeaf(getContainer(cont3, "contgroup1"), "leaf32").getEffectiveNamespace().equals(
+                "urn:o-ran:yang:uses-module"));
+        assertTrue(getLeaf(getContainer(cont3, "contgroup1"), "leaf32").getWhens().size() == 1);
+        assertTrue(getLeaf(getContainer(cont3, "contgroup1"), "leaf32").getWhens().get(0).getValue().equals("abc > 10"));
+
+        // - - - augmenting a choice
+
+        final YContainer cont4 = getContainer(usesModule, "cont4");
+        assertTrue(cont4 != null);
+
+        assertTrue(getLeaf(cont4, "leaf21") != null);
+        assertTrue(getLeaf(cont4, "leaf22") != null);
+
+        final YChoice choice23 = getChoice(cont4, "choice23");
+        assertTrue(choice23 != null);
+
+        assertTrue(getCase(choice23, "leaf41") != null);
+        assertTrue(getCase(choice23, "leaf42") != null);
+        assertTrue(getCase(choice23, "case43") != null);
+        assertTrue(getCase(choice23, "cont44") != null);
+
+        // - - - - refine handling (without refine first, then with refine)
+
+        {
+            final YContainer cont5 = getContainer(usesModule, "cont5");
+            assertTrue(cont5 != null);
+
+            final YContainer cont31 = getContainer(cont5, "cont31");
+            assertTrue(cont31 != null);
+
+            assertTrue(getLeaf(cont31, "leaf35").getDefault().getValue().equals("hello"));
+            assertTrue(getLeaf(cont31, "leaf35").getMandatory() == null);
+
+            assertTrue(getLeaf(cont31, "leaf36").getConfig().getValue().equals("true"));
+            assertTrue(getLeaf(cont31, "leaf36").getMandatory().isMandatoryTrue());
+
+            assertTrue(getLeafList(cont31, "leaflist37").getDefaults().size() == 3);
+            assertTrue(getLeafList(cont31, "leaflist37").getDefaults().get(0).getDecimalDefaultValue().compareTo(BigDecimal
+                    .valueOf(10L)) == 0);
+            assertTrue(getLeafList(cont31, "leaflist37").getDefaults().get(1).getDecimalDefaultValue().compareTo(BigDecimal
+                    .valueOf(20L)) == 0);
+            assertTrue(getLeafList(cont31, "leaflist37").getDefaults().get(2).getDecimalDefaultValue().compareTo(BigDecimal
+                    .valueOf(30L)) == 0);
+            assertTrue(getLeafList(cont31, "leaflist37").getMinElements().getMinValue() == 2);
+            assertTrue(getLeafList(cont31, "leaflist37").getMaxElements().getMaxValue() == 5);
+
+            final YContainer cont32 = getContainer(cont5, "cont32");
+            assertTrue(cont32 != null);
+
+            assertTrue(cont32.getPresence() == null);
+            assertTrue(cont32.getIfFeatures().size() == 1);
+            assertTrue(cont32.getIfFeatures().get(0).getValue().equals("feature1"));
+            assertTrue(cont32.getMusts().size() == 1);
+            assertTrue(cont32.getMusts().get(0).getXpathExpression().equals("abc > 10"));
+        }
+
+        {
+            final YContainer cont6 = getContainer(usesModule, "cont6");
+            assertTrue(cont6 != null);
+
+            final YContainer cont31 = getContainer(cont6, "cont31");
+            assertTrue(cont31 != null);
+
+            assertTrue(getLeaf(cont31, "leaf35").getDefault().getValue().equals("world"));
+            assertTrue(getLeaf(cont31, "leaf35").getMandatory().isMandatoryTrue());
+
+            assertTrue(getLeaf(cont31, "leaf36").getConfig().getValue().equals("false"));
+            assertTrue(getLeaf(cont31, "leaf36").getMandatory().isMandatoryFalse());
+
+            assertTrue(getLeafList(cont31, "leaflist37").getDefaults().size() == 2);
+            assertTrue(getLeafList(cont31, "leaflist37").getDefaults().get(0).getDecimalDefaultValue().compareTo(BigDecimal
+                    .valueOf(80L)) == 0);
+            assertTrue(getLeafList(cont31, "leaflist37").getDefaults().get(1).getDecimalDefaultValue().compareTo(BigDecimal
+                    .valueOf(90L)) == 0);
+            assertTrue(getLeafList(cont31, "leaflist37").getMinElements().getMinValue() == 1);
+            assertTrue(getLeafList(cont31, "leaflist37").getMaxElements().getMaxValue() == 6);
+
+            final YContainer cont32 = getContainer(cont6, "cont32");
+            assertTrue(cont32 != null);
+
+            assertTrue(cont32.getPresence() != null);
+            assertTrue(cont32.getIfFeatures().size() == 2);
+            assertTrue(cont32.getIfFeatures().get(0).getValue().equals("feature1"));
+            assertTrue(cont32.getIfFeatures().get(1).getValue().equals("feature99"));
+            assertTrue(cont32.getMusts().size() == 2);
+            assertTrue(cont32.getMusts().get(0).getXpathExpression().equals("abc > 10"));
+            assertTrue(cont32.getMusts().get(1).getXpathExpression().equals("xyz > 99"));
+        }
+
+        // - - - - refine handling (extensions)
+
+        final YContainer cont7 = getContainer(usesModule, "cont7");
+        assertTrue(cont7 != null);
+
+        final YContainer cont41 = getContainer(cont7, "cont41");
+        assertTrue(cont41 != null);
+
+        assertTrue(getExtension(cont41, "grouping-module", "extension1", null) != null);
+        assertTrue(getExtension(cont41, "grouping-module", "extension2", "hello world") != null);
+        assertTrue(getExtension(cont41, "grouping-module", "extension2", "hello") == null);
+        assertTrue(getExtension(cont41, "grouping-module", "extension2", "world") == null);
+        assertTrue(getExtension(cont41, "grouping-module", "extension3", null) != null);
+
+        final YContainer cont42 = getContainer(cont7, "cont42");
+        assertTrue(cont42 != null);
+
+        assertTrue(getExtension(cont42, "grouping-module", "extension1", null) != null);
+        assertTrue(getExtension(cont42, "grouping-module", "extension2", "abc") != null);
+        assertTrue(getExtension(cont42, "grouping-module", "extension2", "def") != null);
+        assertTrue(getExtension(cont42, "grouping-module", "extension3", null) != null);
+    }
+
+    @Test
+    public void testGroupingFindings___do_not_suppress_unused() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        context.setSuppressFindingsOnUnusedSchemaNodes(false);
+        parseRelativeImplementsYangModels(Arrays.asList("grouping-test/faulty-grouping-module.yang"));
+
+        final YModule module = getModule("faulty-grouping-module");
+
+        assertStatementHasFindingOfType(getGrouping(module, "grouping1").getUses().get(0),
+                ParserFindingType.P121_CIRCULAR_USES_REFERENCES.toString());
+
+        // - - - - circular usage
+
+        assertTrue(getGrouping(module, "grouping2") != null);
+        assertStatementHasFindingOfType(getGrouping(module, "grouping2").getUses().get(0),
+                ParserFindingType.P121_CIRCULAR_USES_REFERENCES.toString());
+
+        assertTrue(getGrouping(module, "grouping3") != null);
+        assertStatementHasFindingOfType(getGrouping(module, "grouping3").getUses().get(0),
+                ParserFindingType.P121_CIRCULAR_USES_REFERENCES.toString());
+
+        // ------ augment path cannot be found or syntax error
+
+        assertTrue(getContainer(module, "cont5") != null);
+        assertHasFindingOfTypeAndContainsMessage(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
+                "'/absolute-path'");
+
+        assertTrue(getContainer(module, "cont6") != null);
+        assertHasFindingOfTypeAndContainsMessage(ParserFindingType.P054_UNRESOLVABLE_PATH.toString(),
+                "'container-that-does-not-exist-in-simple-grouping'");
+
+        // - - - - - - Invalid paths - - - - -
+
+        //        printFindings();
+
+        assertStatementHasFindingOfType(getChild(module, CY.USES, null), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+
+        assertStatementHasFindingOfType(getChild(module, CY.USES, ""), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+
+        assertStatementHasFindingOfType(getChild(module, CY.USES, " "), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+
+        assertStatementHasFindingOfType(getChild(module, CY.USES, "nsm:non-existing-grouping"),
+                ParserFindingType.P131_UNRESOLVABLE_GROUPING.toString());
+
+        final YContainer cont8 = getContainer(module, "cont8");
+
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(0).getChildren().get(0),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(0).getChildren().get(1),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(0).getChildren().get(2),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(0).getChildren().get(3),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(1).getChildren().get(0),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(1).getChildren().get(1),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(1).getChildren().get(2),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertDomElementHasFindingOfType(cont8.getDomElement().getChildren().get(1).getChildren().get(3),
+                ParserFindingType.P054_UNRESOLVABLE_PATH.toString());
+
+        // - - - - - - Nested unresolvable uses - - - - -
+
+        assertTrue(getContainer(module, "cont9") != null);
+        assertStatementHasFindingOfType(getContainer(module, "cont9").getUses().get(0),
+                ParserFindingType.P134_NESTED_USES_NOT_RESOLVABLE.toString());
+        assertFindingCountOnStatement(getContainer(module, "cont9").getUses().get(0), 2);
+    }
+
+    @Test
+    public void test_uses_refine() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("grouping-test/uses-refine-module.yang"));
+
+        final YModule module = getModule("uses-refine-module");
+        assertTrue(module != null);
+
+        // - - - - should be all ok - - - - - -
+
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        assertTrue(getLeaf(cont1, "leaf1").getDescription().getValue().equals("new description"));
+        assertTrue(getLeaf(cont1, "leaf1").getReference().getValue().equals("new reference"));
+        assertTrue(getLeaf(cont1, "leaf1").getConfig().isConfigTrue());
+        assertTrue(getLeaf(cont1, "leaf1").getDefault().getValue().equals("world"));
+        assertTrue(getLeaf(cont1, "leaf1").getMandatory().isMandatoryTrue());
+        assertTrue(getLeaf(cont1, "leaf1").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf1").getIfFeatures().get(0).getValue().equals("feature2"));
+
+        assertTrue(getLeaf(cont1, "leaf2").getDescription().getValue().equals("old description"));
+        assertTrue(getLeaf(cont1, "leaf2").getReference().getValue().equals("old reference"));
+        assertTrue(getLeaf(cont1, "leaf2").getConfig().isConfigFalse());
+        assertTrue(getLeaf(cont1, "leaf2").getDefault().getValue().equals("world"));
+        assertTrue(getLeaf(cont1, "leaf2").getMandatory().isMandatoryFalse());
+        assertTrue(getLeaf(cont1, "leaf2").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf2").getIfFeatures().get(0).getValue().equals("feature1"));
+
+        assertTrue(getLeaf(cont1, "leaf5").getMusts().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf5").getMusts().get(0).getXpathExpression().equals(". > ../leaf3"));
+        assertTrue(getLeaf(cont1, "leaf5").getMusts().get(1).getXpathExpression().equals(". > ../leaf4"));
+
+        assertTrue(getLeafList(cont1, "leaflist14").getDefaults().size() == 2);
+        assertTrue(getLeafList(cont1, "leaflist14").getDefaults().get(0).getDecimalDefaultValue().compareTo(BigDecimal
+                .valueOf(50L)) == 0);
+        assertTrue(getLeafList(cont1, "leaflist14").getDefaults().get(1).getDecimalDefaultValue().compareTo(BigDecimal
+                .valueOf(60L)) == 0);
+        assertTrue(getLeafList(cont1, "leaflist14").getMinElements().getMinValue() == 2);
+        assertTrue(getLeafList(cont1, "leaflist14").getMaxElements().getMaxValue() == 8);
+        assertTrue(getLeafList(cont1, "leaflist14").getIfFeatures().size() == 2);
+        assertTrue(getLeafList(cont1, "leaflist14").getIfFeatures().get(0).getValue().equals("feature1"));
+        assertTrue(getLeafList(cont1, "leaflist14").getIfFeatures().get(1).getValue().equals("feature2"));
+
+        assertTrue(getLeafList(cont1, "leaflist15").getDefaults().size() == 3);
+        assertTrue(getLeafList(cont1, "leaflist15").getDefaults().get(0).getDecimalDefaultValue().compareTo(BigDecimal
+                .valueOf(50L)) == 0);
+        assertTrue(getLeafList(cont1, "leaflist15").getDefaults().get(1).getDecimalDefaultValue().compareTo(BigDecimal
+                .valueOf(60L)) == 0);
+        assertTrue(getLeafList(cont1, "leaflist15").getDefaults().get(2).getDecimalDefaultValue().compareTo(BigDecimal
+                .valueOf(70L)) == 0);
+        assertTrue(getLeafList(cont1, "leaflist15").getMinElements().getMinValue() == 3);
+        assertTrue(getLeafList(cont1, "leaflist15").getMaxElements().getMaxValue() == 9);
+
+        assertTrue(getContainer(cont1, "cont74").getPresence().getValue().equals("meaningful!"));
+
+        // - - - - - - error scenarios - - - - - -
+
+        final YContainer cont2 = getContainer(module, "cont2");
+
+        assertStatementHasFindingOfType(cont2, ParserFindingType.P124_INVALID_REFINE_TARGET_NODE.toString());
+        assertStatementHasFindingOfType(cont2, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IdentityTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IdentityTest.java
new file mode 100644
index 0000000..b1c26df
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IdentityTest.java
@@ -0,0 +1,53 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class IdentityTest extends YangTestCommon {
+
+    @Test
+    public void testIdentity() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("identity-test/identity-test-module1.yang"));
+
+        final YModule module = getModule("identity-test-module1");
+
+        assertNoFindings();
+
+        assertTrue(module.getIdentities().get(0).getStatementIdentifier().equals("identity1"));
+        assertTrue(module.getIdentities().get(0).getIdentityName().equals("identity1"));
+        assertTrue(module.getIdentities().get(1).getBases().size() == 1);
+        assertTrue(module.getIdentities().get(2).getIfFeatures().get(0).getValue().equals("blue-moon"));
+
+        assertTrue(module.getIdentities().get(4).getStatus().isDeprecated());
+        assertTrue(module.getIdentities().get(4).getBases().size() == 2);
+        assertTrue(module.getIdentities().get(4).getBases().get(0).getValue().equals("identity1"));
+        assertTrue(module.getIdentities().get(4).getBases().get(1).getValue().equals("this:identity4"));
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IfFeatureTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IfFeatureTest.java
new file mode 100644
index 0000000..8b9bc8e
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IfFeatureTest.java
@@ -0,0 +1,144 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement.StatementArgumentType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIfFeature;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIfFeature.Token;
+import org.oran.smo.yangtools.parser.model.statements.yang.YIfFeature.Type;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+
+public class IfFeatureTest extends YangTestCommon {
+
+    @Test
+    public void testIfFeature() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("if-feature-test/if-feature-test-module.yang"));
+
+        final YModule module = getModule("if-feature-test-module");
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+        assertTrue(cont1.getIfFeatures().size() == 1);
+        assertTrue(cont1.getIfFeatures().get(0).getValue().equals("feature1"));
+        assertNoFindingsOnStatement(cont1);
+
+        final YIfFeature yIfFeature = cont1.getIfFeatures().get(0);
+        assertEquals(StatementArgumentType.NAME, yIfFeature.getArgumentType());
+        assertEquals(CY.STMT_IF_FEATURE, yIfFeature.getStatementModuleAndName());
+
+        assertFalse(yIfFeature.areTokensValid(context, null));
+        assertFalse(yIfFeature.areTokensValid(context, Collections.emptyList()));
+        assertFalse(yIfFeature.areTokensValid(context, Arrays.asList(new YIfFeature.Token(Type.RIGHT_PARENTHESIS, ")"))));
+        assertFalse(yIfFeature.areTokensValid(context, Arrays.asList(new YIfFeature.Token(Type.LEFT_PARENTHESIS, "("))));
+        assertFalse(yIfFeature.areTokensValid(context, Arrays.asList(new YIfFeature.Token(Type.NOT, "not"))));
+        assertFalse(yIfFeature.areTokensValid(context, Arrays.asList(new YIfFeature.Token(Type.LEFT_PARENTHESIS, "("),
+                new YIfFeature.Token(Type.RIGHT_PARENTHESIS, ")"))));
+        assertNoFindingsOnStatement(yIfFeature);
+
+        assertTrue(getLeaf(cont1, "leaf1") != null);
+        assertTrue(getLeaf(cont1, "leaf1").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf1").getIfFeatures().get(0).getValue().equals("feature2"));
+        assertNoFindingsOnStatement(getLeaf(cont1, "leaf1"));
+
+        assertTrue(getLeaf(cont1, "leaf2") != null);
+        assertTrue(getLeaf(cont1, "leaf2").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf2").getIfFeatures().get(0).getValue().equals("feature1 or feature2"));
+        assertNoFindingsOnStatement(getLeaf(cont1, "leaf2"));
+
+        assertTrue(getLeaf(cont1, "leaf3") != null);
+        assertTrue(getLeaf(cont1, "leaf3").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf3").getIfFeatures().get(0).getValue().equals(
+                "feature1 and(feature2 or				not feature3)"));
+        assertNoFindingsOnStatement(getLeaf(cont1, "leaf3"));
+
+        assertTrue(getLeaf(cont1, "leaf4") != null);
+        assertTrue(getLeaf(cont1, "leaf4").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf4").getIfFeatures().get(0).getValue().equals(
+                "(feature1 or feature2)and feature3 or feature1"));
+        assertNoFindingsOnStatement(getLeaf(cont1, "leaf4"));
+
+        final List<Token> leaf4tokens = getLeaf(cont1, "leaf4").getIfFeatures().get(0).getTokens();
+        assertTrue(leaf4tokens.size() == 9);
+        assertTrue(leaf4tokens.get(0).type == Type.LEFT_PARENTHESIS);
+        assertTrue(leaf4tokens.get(1).type == Type.FEATURE_NAME);
+        assertTrue(leaf4tokens.get(1).name.equals("feature1"));
+        assertTrue(leaf4tokens.get(2).type == Type.OR);
+        assertTrue(leaf4tokens.get(3).type == Type.FEATURE_NAME);
+        assertTrue(leaf4tokens.get(3).name.equals("feature2"));
+        assertTrue(leaf4tokens.get(4).type == Type.RIGHT_PARENTHESIS);
+        assertTrue(leaf4tokens.get(5).type == Type.AND);
+        assertTrue(leaf4tokens.get(6).type == Type.FEATURE_NAME);
+        assertTrue(leaf4tokens.get(6).name.equals("feature3"));
+        assertTrue(leaf4tokens.get(7).type == Type.OR);
+        assertTrue(leaf4tokens.get(8).type == Type.FEATURE_NAME);
+        assertTrue(leaf4tokens.get(8).name.equals("feature1"));
+
+        assertTrue(getLeaf(cont1, "leaf5") != null);
+        assertTrue(getLeaf(cont1, "leaf5").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf5").getIfFeatures().get(0).getValue().equals("(feature1"));
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf5").getIfFeatures().get(0),
+                ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+
+        assertTrue(getLeaf(cont1, "leaf6") != null);
+        assertTrue(getLeaf(cont1, "leaf6").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf6").getIfFeatures().get(0).getValue().equals("feature1 or"));
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf6").getIfFeatures().get(0),
+                ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+
+        assertTrue(getLeaf(cont1, "leaf7") != null);
+        assertTrue(getLeaf(cont1, "leaf7").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf7").getIfFeatures().get(0).getValue().equals(
+                "(feature1 or feature2)) or feature3 ("));
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf7").getIfFeatures().get(0),
+                ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+
+        assertTrue(getLeaf(cont1, "leaf8") != null);
+        assertTrue(getLeaf(cont1, "leaf8").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf8").getIfFeatures().get(0).getValue().equals("()"));
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf8").getIfFeatures().get(0),
+                ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+
+        assertTrue(getLeaf(cont1, "leaf9") != null);
+        assertTrue(getLeaf(cont1, "leaf9").getIfFeatures().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf9").getIfFeatures().get(0).getValue() == null);
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf9").getIfFeatures().get(0),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        // - - - - - -
+
+        assertEquals(0, YIfFeature.parseIfFeatureValueIntoTokens(null).size());
+
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ImportTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ImportTest.java
new file mode 100644
index 0000000..e9de118
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ImportTest.java
@@ -0,0 +1,165 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class ImportTest extends YangTestCommon {
+
+    private static final String TEST_DIR = "src/test/resources/model-statements-yang/import-test/";
+
+    @Test
+    public void testTwoImportsWithoutRevision() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "import-twice-no-revisions-test-module.yang",
+                YANG_METADATA_PATH));
+
+        assertHasFindingOfType(ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES.toString());
+
+        final YModule module = getModule("import-twice-no-revisions-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(1), ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES
+                .toString());
+    }
+
+    @Test
+    public void testFirstImportNoRevision() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "import-twice-first-no-revision-test-module.yang",
+                YANG_METADATA_PATH));
+
+        assertHasFindingOfType(ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES.toString());
+
+        final YModule module = getModule("import-twice-first-no-revision-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(1), ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES
+                .toString());
+    }
+
+    @Test
+    public void testSecondImportNoRevision() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "import-twice-second-no-revision-test-module.yang",
+                YANG_METADATA_PATH));
+
+        assertHasFindingOfType(ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES.toString());
+
+        final YModule module = getModule("import-twice-second-no-revision-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(1), ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES
+                .toString());
+    }
+
+    @Test
+    public void testBothHaveSameRevision() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "import-twice-same-revisions-test-module.yang",
+                YANG_METADATA_PATH));
+
+        assertHasFindingOfType(ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES.toString());
+
+        final YModule module = getModule("import-twice-same-revisions-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(1), ParserFindingType.P036_MODULE_IMPORTED_MULTIPLE_TIMES
+                .toString());
+    }
+
+    @Test
+    public void testImportsItself() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "import-itself-test-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+
+        final YModule module = getModule("import-itself-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(0), ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+    }
+
+    @Test
+    public void testUnresolvableNoRevisionImportNotInInput() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "unresolvable-import-no-revision-test-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+
+        final YModule module = getModule("unresolvable-import-no-revision-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(0), ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+    }
+
+    @Test
+    public void testAmbiguousNoRevisionImport() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "unresolvable-import-ambiguous-test-module.yang",
+                ORIG_MODULES_PATH + "ietf-yang-types-2010-09-24.yang",
+                ORIG_MODULES_PATH + "ietf-yang-types-2019-11-04.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P035_AMBIGUOUS_IMPORT.toString());
+
+        final YModule module = getModule("unresolvable-import-ambiguous-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(0), ParserFindingType.P035_AMBIGUOUS_IMPORT.toString());
+    }
+
+    @Test
+    public void testUnresolvableWithRevisionImportNotInInput() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "unresolvable-import-with-revision-test-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+
+        final YModule module = getModule("unresolvable-import-with-revision-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(0), ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+    }
+
+    @Test
+    public void testUnresolvableWithWrongRevisionImport() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(TEST_DIR + "unresolvable-import-wrong-revision-test-module.yang",
+                ORIG_MODULES_PATH + "ietf-yang-types-2010-09-24.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+
+        final YModule module = getModule("unresolvable-import-wrong-revision-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getImports().get(0), ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IncludeTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IncludeTest.java
new file mode 100644
index 0000000..deefa72
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/IncludeTest.java
@@ -0,0 +1,112 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class IncludeTest extends YangTestCommon {
+
+    @Test
+    public void testIncludeWithoutRevisionSubmoduleNotInInput() {
+
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "include-test/include-test-module-correct-submodule-no-revision.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P037_UNRESOLVABLE_INCLUDE.toString());
+
+        final YModule module = getModule("include-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getIncludes().get(0), ParserFindingType.P037_UNRESOLVABLE_INCLUDE
+                .toString());
+    }
+
+    @Test
+    public void testIncludeWithoutRevisionTwoSubmodulesInInput() {
+
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "include-test/include-test-module-correct-submodule-no-revision.yang",
+                "include-test/test-submodule-1999-01-01.yang", "include-test/test-submodule-2020-10-02.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P038_AMBIGUOUS_INCLUDE.toString());
+
+        final YModule module = getModule("include-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getIncludes().get(0), ParserFindingType.P038_AMBIGUOUS_INCLUDE.toString());
+    }
+
+    @Test
+    public void testIncludeIsModuleNotSubmodule() {
+
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "include-test/include-test-module-correct-submodule-no-revision.yang",
+                "include-test/other-test-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P045_NOT_A_SUBMODULE.toString());
+
+        final YModule module = getModule("include-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getIncludes().get(0), ParserFindingType.P045_NOT_A_SUBMODULE.toString());
+    }
+
+    @Test
+    public void testIncludeYangVersionMismatch() {
+
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "include-test/include-test-module-correct-submodule-no-revision.yang",
+                "include-test/test-submodule-1999-01-01.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P041_DIFFERENT_YANG_VERSIONS_BETWEEN_MODULE_AND_SUBMODULES.toString());
+
+        final YModule module = getModule("include-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getIncludes().get(0),
+                ParserFindingType.P041_DIFFERENT_YANG_VERSIONS_BETWEEN_MODULE_AND_SUBMODULES.toString());
+    }
+
+    @Test
+    public void testIncludeSubmoduleBelongsToDifferentModule() {
+
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "include-test/include-test-module-correct-submodule-no-revision.yang",
+                "include-test/test-submodule-belongs-to-other-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P047_SUBMODULE_OWNERSHIP_MISMATCH.toString());
+
+        final YModule module = getModule("include-test-module");
+        assertTrue(module != null);
+
+        assertStatementHasFindingOfType(module.getIncludes().get(0), ParserFindingType.P047_SUBMODULE_OWNERSHIP_MISMATCH
+                .toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/LengthTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/LengthTest.java
new file mode 100644
index 0000000..fdd8bbd
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/LengthTest.java
@@ -0,0 +1,307 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class LengthTest extends YangTestCommon {
+
+    @Test
+    public void testLengthSimple() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("length-test/length-test-module-simple.yang"));
+        assertTrue(findingsManager.getAllFindings().isEmpty());
+
+        final YModule module = getModule("length-test-module-simple");
+        assertTrue(module != null);
+
+        // -------------------------- Simple lengths that are fine --------------------
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf1").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf1").getType().getLength() == null);
+
+        assertTrue(getLeaf(cont1, "leaf2").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength().getBoundaries().get(0).upper == Long.MAX_VALUE);
+
+        assertTrue(getLeaf(cont1, "leaf3").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength().getBoundaries().get(0).upper == Long.MAX_VALUE);
+
+        assertTrue(getLeaf(cont1, "leaf4").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(0).upper == 0L);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(1).lower == Long.MAX_VALUE);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(1).upper == Long.MAX_VALUE);
+
+        assertTrue(getLeaf(cont1, "leaf5").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(0).upper == 0L);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(1).lower == Long.MAX_VALUE);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(1).upper == Long.MAX_VALUE);
+
+        assertTrue(getLeaf(cont1, "leaf6").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength().getBoundaries().get(0).upper == 100L);
+
+        assertTrue(getLeaf(cont1, "leaf7").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().get(0).upper == 20L);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().get(1).lower == 30L);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().get(1).upper == 60L);
+
+        assertTrue(getLeaf(cont1, "leaf8").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getLength().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getLength().getBoundaries().get(0).upper == 20L);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getLength().getBoundaries().get(1).lower == 30L);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getLength().getBoundaries().get(1).upper == Long.MAX_VALUE);
+
+        assertTrue(getLeaf(cont1, "leaf9").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength().getBoundaries().get(0).upper == 20L);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength().getBoundaries().get(1).lower == 30L);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength().getBoundaries().get(1).upper == 30L);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength().getBoundaries().get(2).lower == 80L);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getLength().getBoundaries().get(2).upper == 80L);
+
+        assertTrue(getLeaf(cont1, "leaf10").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength().getBoundaries().get(0).upper == 20L);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength().getBoundaries().get(1).lower == 30L);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength().getBoundaries().get(1).upper == 30L);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength().getBoundaries().get(2).lower == 80L);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getLength().getBoundaries().get(2).upper == 80L);
+
+        assertTrue(getLeaf(cont1, "leaf11").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength().getBoundaries().get(0).upper == 0L);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength().getBoundaries().get(1).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength().getBoundaries().get(1).upper == 10L);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength().getBoundaries().get(2).lower == 40L);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getLength().getBoundaries().get(2).upper == 40L);
+
+        assertTrue(getLeaf(cont1, "leaf12").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength().getBoundaries().get(0).upper == 0L);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength().getBoundaries().get(1).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength().getBoundaries().get(1).upper == 10L);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength().getBoundaries().get(2).lower == 70L);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getLength().getBoundaries().get(2).upper == 70L);
+
+        assertTrue(getLeaf(cont1, "leaf13").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().size() == 4);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(0).upper == 0L);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(1).lower == 2L);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(1).upper == 2L);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(2).lower == 3L);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(2).upper == 3L);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(3).lower == Long.MAX_VALUE);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getLength().getBoundaries().get(3).upper == Long.MAX_VALUE);
+    }
+
+    @Test
+    public void testLengthTypedefs() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("length-test/length-test-module-typedefs.yang"));
+
+        printFindings();
+
+        assertTrue(findingsManager.getAllFindings().isEmpty());
+
+        final YModule module = getModule("length-test-module-typedefs");
+        assertTrue(module != null);
+
+        // -------------------------- Lengths and typedefs that are fine --------------------
+
+        assertTrue(getTypedef(module, "typeStringNoLength") != null);
+        assertTrue(getTypedef(module, "typeStringNoLength").getType().getDataType().equals("string"));
+        assertTrue(getTypedef(module, "typeStringNoLength").getType().getLength() == null);
+
+        assertTrue(getTypedef(module, "typeStringWithLength") != null);
+        assertTrue(getTypedef(module, "typeStringWithLength").getType().getDataType().equals("string"));
+        assertTrue(getTypedef(module, "typeStringWithLength").getType().getLength() != null);
+        assertTrue(getTypedef(module, "typeStringWithLength").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getTypedef(module, "typeStringWithLength").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getTypedef(module, "typeStringWithLength").getType().getLength().getBoundaries().get(0).upper == 20L);
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf1").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf1").getType().getLength() == null);
+
+        assertTrue(getLeaf(cont1, "leaf2").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength().getBoundaries().get(0).lower == 0L);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getLength().getBoundaries().get(0).upper == Long.MAX_VALUE);
+
+        assertTrue(getLeaf(cont1, "leaf3").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getLength().getBoundaries().get(0).upper == 20L);
+
+        assertTrue(getLeaf(cont1, "leaf4").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(0).upper == 20L);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(1).lower == 30L);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getLength().getBoundaries().get(1).upper == 60L);
+
+        assertTrue(getLeaf(cont1, "leaf5").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(0).upper == 10L);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(1).lower == 12L);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(1).upper == 12L);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(2).lower == 17L);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getLength().getBoundaries().get(2).upper == 17L);
+
+        assertTrue(getLeaf(cont1, "leaf6").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength().getBoundaries().get(0).lower == 10L);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getLength().getBoundaries().get(0).upper == 20L);
+
+        assertTrue(getLeaf(cont1, "leaf7").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength() != null);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().get(0).lower == 17L);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getLength().getBoundaries().get(0).upper == 19L);
+    }
+
+    @Test
+    public void testLengthSimpleFaulty() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("length-test/length-test-module-simple-faulty.yang"));
+
+        final YModule module = getModule("length-test-module-simple-faulty");
+        assertTrue(module != null);
+
+        // -------------------------- Simple lengths that are faulty for a variety of reasons --------------------
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf1").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf2").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf3").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf4").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf5").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf6").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf7").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf8").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf9").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf10").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf11").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf12").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+    }
+
+    @Test
+    public void testLengthTypedefsFaulty() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("length-test/length-test-module-typedefs-faulty.yang"));
+
+        final YModule module = getModule("length-test-module-typedefs-faulty");
+        assertTrue(module != null);
+
+        // -------------------------- Lengths and typedefs that are incorrect --------------------
+
+        assertNoFindingsOnStatement(getTypedef(module, "typeStringNoLength"));
+        assertStatementHasFindingOfType(getTypedef(module, "typeStringWithLength").getType().getLength(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertNoFindingsOnStatement(getTypedef(module, "typeUsingTypeStringWithLength"));
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf1").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf2").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf3").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf4").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf5").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf6").getType().getLength(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ModuleTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ModuleTest.java
new file mode 100644
index 0000000..320a174
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/ModuleTest.java
@@ -0,0 +1,178 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement.StatementArgumentType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YAnydata;
+import org.oran.smo.yangtools.parser.model.statements.yang.YAnyxml;
+import org.oran.smo.yangtools.parser.model.statements.yang.YArgument;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContact;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDescription;
+import org.oran.smo.yangtools.parser.model.statements.yang.YExtension;
+import org.oran.smo.yangtools.parser.model.statements.yang.YGrouping;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YNamespace;
+import org.oran.smo.yangtools.parser.model.statements.yang.YOrganization;
+import org.oran.smo.yangtools.parser.model.statements.yang.YPrefix;
+import org.oran.smo.yangtools.parser.model.statements.yang.YYangVersion;
+import org.oran.smo.yangtools.parser.model.statements.yang.YYinElement;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class ModuleTest extends YangTestCommon {
+
+    @Test
+    public void testIdentity() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("module-test/module-test.yang"));
+
+        assertNoFindings();
+
+        final YModule yModule = getModule("module-test");
+        assertNotNull(yModule);
+
+        assertEquals(StatementArgumentType.NAME, yModule.getArgumentType());
+        assertEquals(CY.STMT_MODULE, yModule.getStatementModuleAndName());
+        assertEquals("module-test", yModule.getModuleName());
+        assertEquals("module-test", yModule.getStatementIdentifier());
+        assertFalse(yModule.definesDataNode());
+        assertFalse(yModule.definesSchemaNode());
+
+        final YYangVersion yYangVersion = yModule.getYangVersion();
+        assertNotNull(yYangVersion);
+
+        assertEquals(StatementArgumentType.VALUE, yYangVersion.getArgumentType());
+        assertEquals(CY.STMT_YANG_VERSION, yYangVersion.getStatementModuleAndName());
+        assertFalse(yYangVersion.is10Version());
+        assertTrue(yYangVersion.is11Version());
+        assertFalse(yYangVersion.definesDataNode());
+        assertFalse(yYangVersion.definesSchemaNode());
+
+        final YNamespace yNamespace = yModule.getNamespace();
+        assertNotNull(yNamespace);
+
+        assertEquals(StatementArgumentType.URI, yNamespace.getArgumentType());
+        assertEquals(CY.STMT_NAMESPACE, yNamespace.getStatementModuleAndName());
+        assertEquals("test:module-test", yNamespace.getNamespace());
+        assertFalse(yNamespace.definesDataNode());
+        assertFalse(yNamespace.definesSchemaNode());
+
+        final YPrefix yPrefix = yModule.getPrefix();
+        assertNotNull(yPrefix);
+
+        assertEquals(StatementArgumentType.VALUE, yPrefix.getArgumentType());
+        assertEquals(CY.STMT_PREFIX, yPrefix.getStatementModuleAndName());
+        assertEquals("this", yPrefix.getPrefix());
+        assertFalse(yPrefix.definesDataNode());
+        assertFalse(yPrefix.definesSchemaNode());
+
+        final YContact yContact = yModule.getContact();
+        assertNotNull(yContact);
+
+        assertEquals(StatementArgumentType.TEXT, yContact.getArgumentType());
+        assertEquals(CY.STMT_CONTACT, yContact.getStatementModuleAndName());
+        assertEquals("test-user", yContact.getValue());
+        assertFalse(yContact.definesDataNode());
+        assertFalse(yContact.definesSchemaNode());
+
+        final YOrganization yOrganization = yModule.getOrganization();
+        assertNotNull(yOrganization);
+
+        assertEquals(StatementArgumentType.TEXT, yOrganization.getArgumentType());
+        assertEquals(CY.STMT_ORGANIZATION, yOrganization.getStatementModuleAndName());
+        assertEquals("ORAN", yOrganization.getValue());
+        assertFalse(yOrganization.definesDataNode());
+        assertFalse(yOrganization.definesSchemaNode());
+
+        final YDescription yDescription = yModule.getDescription();
+        assertNotNull(yDescription);
+
+        assertEquals(StatementArgumentType.TEXT, yDescription.getArgumentType());
+        assertEquals(CY.STMT_DESCRIPTION, yDescription.getStatementModuleAndName());
+        assertTrue(yDescription.getValue().startsWith("some description"));
+        try {
+            yDescription.getDescription();
+            fail("Should have thrown.");
+        } catch (final Exception expected) {
+        }
+        assertFalse(yDescription.definesDataNode());
+        assertFalse(yDescription.definesSchemaNode());
+
+        final List<YExtension> yExtensions = yModule.getExtensions();
+        assertEquals(2, yExtensions.size());
+
+        assertEquals(StatementArgumentType.NAME, yExtensions.get(0).getArgumentType());
+        assertEquals(CY.STMT_EXTENSION, yExtensions.get(0).getStatementModuleAndName());
+        assertEquals("my-extension1", yExtensions.get(0).getExtensionName());
+        assertEquals("my-extension1", yExtensions.get(0).getStatementIdentifier());
+        assertTrue(yExtensions.get(0).getStatus().isDeprecated());
+        assertFalse(yExtensions.get(0).definesDataNode());
+        assertFalse(yExtensions.get(0).definesSchemaNode());
+        assertEquals("my-extension2", yExtensions.get(1).getExtensionName());
+
+        final YArgument yArgument = yExtensions.get(0).getArgument();
+        assertNotNull(yArgument);
+
+        assertEquals(StatementArgumentType.NAME, yArgument.getArgumentType());
+        assertEquals(CY.STMT_ARGUMENT, yArgument.getStatementModuleAndName());
+        assertEquals("some-arg", yArgument.getArgumentName());
+        assertFalse(yArgument.definesDataNode());
+        assertFalse(yArgument.definesSchemaNode());
+
+        final YYinElement yYinElement = yArgument.getYinElement();
+        assertNotNull(yYinElement);
+
+        assertEquals(StatementArgumentType.VALUE, yYinElement.getArgumentType());
+        assertEquals(CY.STMT_YIN_ELEMENT, yYinElement.getStatementModuleAndName());
+        assertFalse(yYinElement.definesDataNode());
+        assertFalse(yYinElement.definesSchemaNode());
+
+        final List<YAnydata> yAnydatas = yModule.getAnydata();
+        assertEquals(2, yAnydatas.size());
+        assertEquals("anydata1", yAnydatas.get(0).getName());
+        assertEquals("anydata2", yAnydatas.get(1).getName());
+
+        final List<YAnyxml> yAnyxmls = yModule.getAnyxmls();
+        assertEquals(2, yAnyxmls.size());
+        assertEquals("anyxml1", yAnyxmls.get(0).getName());
+        assertEquals("anyxml2", yAnyxmls.get(1).getName());
+
+        final List<YGrouping> yGrouping = yModule.getGroupings();
+        assertEquals(2, yGrouping.size());
+        assertEquals("grouping1", yGrouping.get(0).getGroupingName());
+        assertEquals("grouping2", yGrouping.get(1).getGroupingName());
+
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/PrefixesTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/PrefixesTest.java
new file mode 100644
index 0000000..bf60352
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/PrefixesTest.java
@@ -0,0 +1,47 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class PrefixesTest extends YangTestCommon {
+
+    @Test
+    public void testDuplicatePrefixes() {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-statements-yang/prefixes-test/duplicate-prefixes-test-module.yang",
+                YANG_ORIGIN_PATH, YANG_METADATA_PATH));
+
+        assertHasFindingOfType(ParserFindingType.P031_PREFIX_NOT_UNIQUE.toString());
+
+        final YModule module = getModule("duplicate-prefixes-test-module");
+        assertStatementHasFindingOfType(getChild(getChild(module, CY.IMPORT, "ietf-yang-metadata"), CY.PREFIX),
+                ParserFindingType.P031_PREFIX_NOT_UNIQUE.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/RangeTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/RangeTest.java
new file mode 100644
index 0000000..e9cf949
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/RangeTest.java
@@ -0,0 +1,362 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class RangeTest extends YangTestCommon {
+
+    @Test
+    public void testRangeSimple() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("range-test/range-test-module-simple.yang"));
+        assertTrue(findingsManager.getAllFindings().isEmpty());
+
+        final YModule module = getModule("range-test-module-simple");
+        assertTrue(module != null);
+
+        // -------------------------- Simple ranges that are fine --------------------
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf1").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf1").getType().getRange() == null);
+
+        assertTrue(getLeaf(cont1, "leaf2").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("127")));
+
+        assertTrue(getLeaf(cont1, "leaf2").getType().getErrorMessageText() == null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getErrorMessage() != null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getErrorMessage().getErrorMessageText() != null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getErrorMessageText() != null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getErrorMessage().getErrorMessageText().equals("wrong!"));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getErrorMessageText().equals("wrong!"));
+
+        assertTrue(getLeaf(cont1, "leaf3").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("127")));
+
+        assertTrue(getLeaf(cont1, "leaf4").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("127")));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("127")));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getDataType().equals("int8"));
+
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("127")));
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("127")));
+
+        assertTrue(getLeaf(cont1, "leaf6").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-100")));
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("100")));
+
+        assertTrue(getLeaf(cont1, "leaf7").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("-50")));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("-20")));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("30")));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("60")));
+
+        assertTrue(getLeaf(cont1, "leaf8").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("-20")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("30")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("127")));
+
+        assertTrue(getLeaf(cont1, "leaf9").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("-20")));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("30")));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("30")));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(2).lower.equals(new BigDecimal("80")));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(2).upper.equals(new BigDecimal("80")));
+
+        assertTrue(getLeaf(cont1, "leaf10").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "-20")));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("30")));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("30")));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(2).lower.equals(new BigDecimal("80")));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(2).upper.equals(new BigDecimal("80")));
+
+        assertTrue(getLeaf(cont1, "leaf11").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange().getBoundaries().get(2).lower.equals(new BigDecimal("40")));
+        assertTrue(getLeaf(cont1, "leaf11").getType().getRange().getBoundaries().get(2).upper.equals(new BigDecimal("40")));
+
+        assertTrue(getLeaf(cont1, "leaf12").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange().getBoundaries().get(2).lower.equals(new BigDecimal("70")));
+        assertTrue(getLeaf(cont1, "leaf12").getType().getRange().getBoundaries().get(2).upper.equals(new BigDecimal("70")));
+
+        assertTrue(getLeaf(cont1, "leaf13").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().size() == 4);
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("2")));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("2")));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(2).lower.equals(new BigDecimal("3")));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(2).upper.equals(new BigDecimal("3")));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(3).lower.equals(new BigDecimal(
+                "127")));
+        assertTrue(getLeaf(cont1, "leaf13").getType().getRange().getBoundaries().get(3).upper.equals(new BigDecimal(
+                "127")));
+
+    }
+
+    @Test
+    public void testRangeTypedefs() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("range-test/range-test-module-typedefs.yang"));
+
+        printFindings();
+
+        assertTrue(findingsManager.getAllFindings().isEmpty());
+
+        final YModule module = getModule("range-test-module-typedefs");
+        assertTrue(module != null);
+
+        // -------------------------- Simple ranges that are fine --------------------
+
+        assertTrue(getTypedef(module, "typeInt8noRange") != null);
+        assertTrue(getTypedef(module, "typeInt8noRange").getType().getDataType().equals("int8"));
+        assertTrue(getTypedef(module, "typeInt8noRange").getType().getRange() == null);
+
+        assertTrue(getTypedef(module, "typeInt8WithRange") != null);
+        assertTrue(getTypedef(module, "typeInt8WithRange").getType().getDataType().equals("int8"));
+        assertTrue(getTypedef(module, "typeInt8WithRange").getType().getRange() != null);
+        assertTrue(getTypedef(module, "typeInt8WithRange").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getTypedef(module, "typeInt8WithRange").getType().getRange().getBoundaries().get(0).lower.equals(
+                new BigDecimal("10")));
+        assertTrue(getTypedef(module, "typeInt8WithRange").getType().getRange().getBoundaries().get(0).upper.equals(
+                new BigDecimal("20")));
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf1").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf1").getType().getRange() == null);
+
+        assertTrue(getLeaf(cont1, "leaf2").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-128")));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("127")));
+
+        assertTrue(getLeaf(cont1, "leaf3").getType().getDataType().equals("int64"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal(
+                "-9223372036854775808")));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "9223372036854775807")));
+
+        assertTrue(getLeaf(cont1, "leaf4").getType().getDataType().equals("uint8"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("0")));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("255")));
+
+        assertTrue(getLeaf(cont1, "leaf5").getType().getDataType().equals("uint64"));
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("0")));
+        assertTrue(getLeaf(cont1, "leaf5").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal(
+                "18446744073709551615")));
+
+        assertTrue(getLeaf(cont1, "leaf6").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf6").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("20")));
+
+        assertTrue(getLeaf(cont1, "leaf7").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().size() == 2);
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("-50")));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("-20")));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("30")));
+        assertTrue(getLeaf(cont1, "leaf7").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("60")));
+
+        assertTrue(getLeaf(cont1, "leaf8").getType().getDataType().equals("uint64"));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("5")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("5")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(1).lower.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(1).upper.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(2).lower.equals(new BigDecimal("70")));
+        assertTrue(getLeaf(cont1, "leaf8").getType().getRange().getBoundaries().get(2).upper.equals(new BigDecimal("70")));
+
+        assertTrue(getLeaf(cont1, "leaf9").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("10")));
+        assertTrue(getLeaf(cont1, "leaf9").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("20")));
+
+        assertTrue(getLeaf(cont1, "leaf10").getType().getDataType().equals("int8"));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange() != null);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(0).lower.equals(new BigDecimal("17")));
+        assertTrue(getLeaf(cont1, "leaf10").getType().getRange().getBoundaries().get(0).upper.equals(new BigDecimal("19")));
+    }
+
+    @Test
+    public void testRangeSimpleFaulty() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("range-test/range-test-module-simple-faulty.yang"));
+
+        final YModule module = getModule("range-test-module-simple-faulty");
+        assertTrue(module != null);
+
+        // -------------------------- Simple ranges that are faulty for a variety of reasons --------------------
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf1").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf2").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf3").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf4").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf5").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf6").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf7").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf8").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf9").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf10").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf11").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf12").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+    }
+
+    @Test
+    public void testRangeTypedefsFaulty() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("range-test/range-test-module-typedefs-faulty.yang"));
+
+        final YModule module = getModule("range-test-module-typedefs-faulty");
+        assertTrue(module != null);
+
+        // -------------------------- Ranges and typedefs that are incorrect --------------------
+
+        assertNoFindingsOnStatement(getTypedef(module, "typeInt8noRange"));
+        assertNoFindingsOnStatement(getTypedef(module, "typeInt64noRange"));
+        assertNoFindingsOnStatement(getTypedef(module, "typeUint8noRange"));
+        assertNoFindingsOnStatement(getTypedef(module, "typeUint64noRange"));
+        assertStatementHasFindingOfType(getTypedef(module, "typeInt8WithRange").getType().getRange(),
+                ParserFindingType.P053_INVALID_VALUE.toString());
+        assertNoFindingsOnStatement(getTypedef(module, "typeUsingTypeInt8WithRange"));
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf1").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf2").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf3").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf4").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf5").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+        assertStatementHasFindingOfType(getLeaf(cont1, "leaf6").getType().getRange(), ParserFindingType.P053_INVALID_VALUE
+                .toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/RevisionTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/RevisionTest.java
new file mode 100644
index 0000000..bb4d42a
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/RevisionTest.java
@@ -0,0 +1,139 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ModuleAndFindingTypeAndSchemaNodePathFilterPredicate;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRevision;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class RevisionTest extends YangTestCommon {
+
+    @Test
+    public void testNoRevisionWithFailFastTrue() {
+
+        context.setFailFast(true);
+
+        parseRelativeImplementsYangModels(Arrays.asList("revision-test/revision-test-module-no-revision.yang"));
+
+        final YModule yModule = getModule("revision-test-module");
+        assertTrue(yModule != null);
+
+        assertTrue(yModule.getRevisions().size() == 0);
+        assertHasFindingOfType(ParserFindingType.P032_MISSING_REVISION.toString());
+        assertHasFindingOfType(ParserFindingType.P009_FAIL_FAST.toString());
+
+        /*
+         * Fail-fast is on so should suppress this one here.
+         */
+        assertHasNotFindingOfType(ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+    }
+
+    @Test
+    public void testNoRevisionWithFailFastFalse() {
+
+        context.setFailFast(false);
+
+        parseRelativeImplementsYangModels(Arrays.asList("revision-test/revision-test-module-no-revision.yang"));
+
+        final YModule yModule = getModule("revision-test-module");
+        assertTrue(yModule != null);
+
+        assertTrue(yModule.getRevisions().size() == 0);
+        assertHasFindingOfType(ParserFindingType.P032_MISSING_REVISION.toString());
+
+        assertHasNotFindingOfType(ParserFindingType.P009_FAIL_FAST.toString());
+    }
+
+    @Test
+    public void testNoRevisionWithFineGrainedFilterAndFailFastTrue() {
+
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "revision-test-module;*;*"));
+
+        parseRelativeImplementsYangModels(Arrays.asList("revision-test/revision-test-module-no-revision.yang"));
+
+        final YModule yModule = getModule("revision-test-module");
+        assertTrue(yModule != null);
+
+        assertTrue(yModule.getRevisions().size() == 0);
+
+        /*
+         * These should both be filtered. There should not be a fail-fast either
+         */
+        assertHasNotFindingOfType(ParserFindingType.P032_MISSING_REVISION.toString());
+        assertHasNotFindingOfType(ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+        assertHasNotFindingOfType(ParserFindingType.P009_FAIL_FAST.toString());
+    }
+
+    @Test
+    public void testDuplicateRevisionNonLatest() {
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "revision-test/revision-test-module-duplicate-revision-non-latest.yang"));
+
+        final YModule yModule = getModule("revision-test-module");
+        assertTrue(yModule != null);
+
+        assertHasFindingOfType(ParserFindingType.P049_DUPLICATE_REVISION.toString());
+    }
+
+    @Test
+    public void testDuplicateRevisionLatest() {
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "revision-test/revision-test-module-duplicate-revision-latest.yang"));
+
+        final YModule yModule = getModule("revision-test-module");
+        assertTrue(yModule != null);
+
+        assertHasFindingOfType(ParserFindingType.P050_DUPLICATE_LATEST_REVISION.toString());
+    }
+
+    @Test
+    public void testInvalidRevision() {
+        parseRelativeImplementsYangModels(Arrays.asList("revision-test/revision-test-module-invalid-revision.yang"));
+
+        final YModule yModule = getModule("revision-test-module");
+        assertTrue(yModule != null);
+
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        final List<YRevision> revisions = yModule.getRevisions();
+
+        assertTrue(revisions.size() == 8);
+
+        assertNoFindingsOnStatement(revisions.get(0));
+        assertStatementHasFindingOfType(revisions.get(1), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(revisions.get(2), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(revisions.get(3), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(revisions.get(4), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(revisions.get(5), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(revisions.get(6), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(revisions.get(7), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/StatusTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/StatusTest.java
new file mode 100644
index 0000000..a50e00c
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/StatusTest.java
@@ -0,0 +1,136 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YStatus;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class StatusTest extends YangTestCommon {
+
+    @Test
+    public void test_status_module1() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("status-test/status-test-module1.yang"));
+
+        final YModule module = getModule("status-test-module1");
+
+        assertNoFindings();
+
+        // -------------------- simple stuff --------------------
+
+        assertTrue(getLeaf(getContainer(module, "cont1"), "leaf11").getEffectiveStatus().equals(YStatus.CURRENT));
+        assertTrue(getLeaf(getContainer(module, "cont1"), "leaf12").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont1"), "leaf13").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont2"), "leaf21").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont2"), "leaf22").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont2"), "leaf23").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont3"), "leaf31").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont3"), "leaf32").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont3"), "leaf33").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        // -------------------- simple, using groupings --------------------
+
+        assertTrue(getLeaf(getContainer(module, "cont4"), "leaf97").getEffectiveStatus().equals(YStatus.CURRENT));
+        assertTrue(getLeaf(getContainer(module, "cont4"), "leaf98").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont4"), "leaf99").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont5"), "leaf97").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont5"), "leaf98").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont5"), "leaf99").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont6"), "leaf97").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont6"), "leaf98").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont6"), "leaf99").getEffectiveStatus().equals(YStatus.OBSOLETE));
+    }
+
+    @Test
+    public void test_status_module2() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("status-test/status-test-module2.yang"));
+
+        final YModule module = getModule("status-test-module2");
+
+        assertNoFindings();
+
+        // -------------------- status under uses --------------------
+
+        assertTrue(getLeaf(getContainer(module, "cont1"), "leaf97").getEffectiveStatus().equals(YStatus.CURRENT));
+        assertTrue(getLeaf(getContainer(module, "cont1"), "leaf98").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont1"), "leaf99").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont2"), "leaf97").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont2"), "leaf98").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont2"), "leaf99").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont3"), "leaf97").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont3"), "leaf98").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont3"), "leaf99").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        // -------------------- status under grouping --------------------
+
+        assertTrue(getLeaf(getContainer(module, "cont11"), "leaf91").getEffectiveStatus().equals(YStatus.CURRENT));
+        assertTrue(getLeaf(getContainer(module, "cont11"), "leaf92").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont11"), "leaf93").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont12"), "leaf91").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont12"), "leaf92").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont12"), "leaf93").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont13"), "leaf91").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont13"), "leaf92").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont13"), "leaf93").getEffectiveStatus().equals(YStatus.OBSOLETE));
+    }
+
+    @Test
+    public void test_status_module3() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("status-test/status-test-module3.yang"));
+
+        final YModule module = getModule("status-test-module3");
+
+        assertNoFindings();
+
+        // -------------------- status under both grouping and uses --------------------
+
+        assertTrue(getLeaf(getContainer(module, "cont31"), "leaf91").getEffectiveStatus().equals(YStatus.CURRENT));
+        assertTrue(getLeaf(getContainer(module, "cont31"), "leaf92").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont31"), "leaf93").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont32"), "leaf91").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont32"), "leaf92").getEffectiveStatus().equals(YStatus.DEPRECATED));
+        assertTrue(getLeaf(getContainer(module, "cont32"), "leaf93").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+        assertTrue(getLeaf(getContainer(module, "cont33"), "leaf91").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont33"), "leaf92").getEffectiveStatus().equals(YStatus.OBSOLETE));
+        assertTrue(getLeaf(getContainer(module, "cont33"), "leaf93").getEffectiveStatus().equals(YStatus.OBSOLETE));
+
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/StringTokenizationTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/StringTokenizationTest.java
new file mode 100644
index 0000000..b21f74a
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/StringTokenizationTest.java
@@ -0,0 +1,167 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class StringTokenizationTest extends YangTestCommon {
+
+    @Test
+    public void testYang1StringTokenization() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "string-tokenization-test/string-tokenization-yang1-test-module.yang"));
+
+        final YangModel yangModelFile = yangDeviceModel.getModuleRegistry().byModuleName(
+                "string-tokenization-yang1-test-module").get(0);
+
+        assertTrue(yangModelFile != null);
+        assertTrue(yangModelFile.getYangModelRoot().getYangVersion().equals("1"));
+
+        final YModule module = getModule("string-tokenization-yang1-test-module");
+
+        assertTrue(getContainer(module, "cont1") != null);
+        assertTrue(getContainer(module, "cont1").getDescription().getValue().equals("valid YANG 1 double-quoted string"));
+
+        assertTrue(getContainer(module, "cont2") != null);
+        assertTrue(getContainer(module, "cont2").getDescription().getValue().equals(
+                "valid YANG 1 double-quoted string with special characters \n \t \" \\ \\X \\_"));
+
+        assertTrue(getContainer(module, "cont3") != null);
+        assertTrue(getContainer(module, "cont3").getDescription().getValue().equals("valid YANG 1 double-quoted string"));
+
+        assertTrue(getContainer(module, "cont4") != null);
+        assertTrue(getContainer(module, "cont4").getDescription().getValue().equals("valid YANG 1 \ndouble-quoted string"));
+
+        assertTrue(getContainer(module, "cont5") != null);
+        assertTrue(getContainer(module, "cont5").getDescription().getValue().equals(""));
+
+        assertTrue(getContainer(module, "cont6") != null);
+        assertTrue(getContainer(module, "cont6").getDescription().getValue().equals(
+                "invalid YANG 1 double-quoted string because of trailing backslash"));
+
+        assertTrue(getContainer(module, "cont11") != null);
+        assertTrue(getContainer(module, "cont11").getDescription().getValue().equals("valid YANG 1 single-quoted string"));
+
+        assertTrue(getContainer(module, "cont12") != null);
+        assertTrue(getContainer(module, "cont12").getDescription().getValue().equals(
+                "valid YANG 1 single-quoted string \" \\n \\t \\\\ \\X"));
+
+        assertTrue(getContainer(module, "cont13") != null);
+        assertTrue(getContainer(module, "cont13").getDescription().getValue().equals("valid YANG 1\nsingle-quoted string"));
+
+        assertTrue(getContainer(module, "cont14") != null);
+        assertTrue(getContainer(module, "cont14").getDescription().getValue().equals(
+                "valid YANG 1\n                           single-quoted string"));
+
+        assertTrue(getContainer(module, "cont21") != null);
+        assertTrue(getContainer(module, "cont21").getDescription().getValue().equals("valid_YANG_1_unquoted_string"));
+
+        assertTrue(getContainer(module, "cont22") != null);
+        assertTrue(getContainer(module, "cont22").getDescription().getValue().equals(
+                "valid_YANG_1_unquoted_string_with_a_quote_at_the_end\""));
+
+        assertFindingCount(1);
+        assertHasFindingOfType(ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT.toString());
+        assertHasFinding(yangModelFile, 37, ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT.toString());
+    }
+
+    @Test
+    public void testYang1dot1StringTokenization() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList(
+                "string-tokenization-test/string-tokenization-yang1.1-test-module.yang"));
+
+        final YangModel yangModelFile = yangDeviceModel.getModuleRegistry().byModuleName(
+                "string-tokenization-yang1.1-test-module").get(0);
+
+        assertTrue(yangModelFile != null);
+        assertTrue(yangModelFile.getYangModelRoot().getYangVersion().equals("1.1"));
+
+        final YModule module = getModule("string-tokenization-yang1.1-test-module");
+
+        assertTrue(getContainer(module, "cont1") != null);
+        assertTrue(getContainer(module, "cont1").getDescription().getValue().equals("valid YANG 1.1 double-quoted string"));
+
+        assertTrue(getContainer(module, "cont2") != null);
+        assertTrue(getContainer(module, "cont2").getDescription().getValue().equals(
+                "invalid YANG 1.1 double-quoted string with special characters \n \t \" \\ \\X \\_"));
+
+        assertTrue(getContainer(module, "cont3") != null);
+        assertTrue(getContainer(module, "cont3").getDescription().getValue().equals("valid YANG 1.1 double-quoted string"));
+
+        assertTrue(getContainer(module, "cont4") != null);
+        assertTrue(getContainer(module, "cont4").getDescription().getValue().equals(
+                "valid YANG 1.1 \ndouble-quoted string"));
+
+        assertTrue(getContainer(module, "cont5") != null);
+        assertTrue(getContainer(module, "cont5").getDescription().getValue().equals(""));
+
+        assertTrue(getContainer(module, "cont6") != null);
+        assertTrue(getContainer(module, "cont6").getDescription().getValue().equals(
+                "invalid YANG 1.1 double-quoted string because of trailing backslash"));
+
+        assertTrue(getContainer(module, "cont11") != null);
+        assertTrue(getContainer(module, "cont11").getDescription().getValue().equals(
+                "valid YANG 1.1 single-quoted string"));
+
+        assertTrue(getContainer(module, "cont12") != null);
+        assertTrue(getContainer(module, "cont12").getDescription().getValue().equals(
+                "valid YANG 1.1 single-quoted string \" \\n \\t \\\\ \\X"));
+
+        assertTrue(getContainer(module, "cont13") != null);
+        assertTrue(getContainer(module, "cont13").getDescription().getValue().equals(
+                "valid YANG 1.1\nsingle-quoted string"));
+
+        assertTrue(getContainer(module, "cont14") != null);
+        assertTrue(getContainer(module, "cont14").getDescription().getValue().equals(
+                "valid YANG 1.1\n                           single-quoted string"));
+
+        assertTrue(getContainer(module, "cont21") != null);
+        assertTrue(getContainer(module, "cont21").getDescription().getValue().equals("valid_YANG_1_1_unquoted_string"));
+
+        assertTrue(getContainer(module, "cont22") != null);
+        assertTrue(getContainer(module, "cont22").getDescription().getValue().equals(
+                "invalid_YANG_1_1_unquoted_string_with_a_quote_at_the_end\""));
+
+        assertFindingCount(4);
+        assertHasFindingOfType(ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT.toString());
+        assertHasFindingOfType(ParserFindingType.P012_INVALID_CHARACTER_IN_UNQUOTED_TEXT.toString());
+
+        assertHasFinding(yangModelFile, 21, ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT.toString());
+        assertHasFinding(yangModelFile, 40, ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT.toString());
+        assertHasFinding(yangModelFile, 67, ParserFindingType.P012_INVALID_CHARACTER_IN_UNQUOTED_TEXT.toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/SubmoduleTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/SubmoduleTest.java
new file mode 100644
index 0000000..01ee3fd
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/SubmoduleTest.java
@@ -0,0 +1,139 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class SubmoduleTest extends YangTestCommon {
+
+    @Test
+    public void testSubmoduleByExplicitRevisionOk() {
+        parseRelativeImplementsYangModels(Arrays.asList("submodule-test/explicit-revision-ok/module.yang",
+                "submodule-test/explicit-revision-ok/submodule.yang"));
+        assertNoFindings();
+
+        final YModule yModule = getModule("submodule-test-module");
+        assertTrue(yModule != null);
+
+        final YContainer container1 = getContainer(yModule, "cont1");
+        assertTrue(container1 != null);
+
+        final YContainer container2 = getContainer(yModule, "cont2");
+        assertTrue(container2 != null);
+
+        final YLeaf leaf31 = getLeaf(yModule, "leaf31");
+        assertTrue(leaf31 != null);
+    }
+
+    @Test
+    public void testSubmoduleByExplicitRevisionWrongRevisionSupplied() {
+        parseRelativeImplementsYangModels(Arrays.asList("submodule-test/explicit-revision-not-found/module.yang",
+                "submodule-test/explicit-revision-not-found/submodule.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P037_UNRESOLVABLE_INCLUDE.toString());
+    }
+
+    @Test
+    public void testSubmoduleByExplicitRevisionNotSupplied() {
+        parseRelativeImplementsYangModels(Arrays.asList("submodule-test/explicit-revision-not-found/module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P037_UNRESOLVABLE_INCLUDE.toString());
+    }
+
+    @Test
+    public void test_multiple_submodules() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("submodule-test/multiple-submodules/module.yang",
+                "submodule-test/multiple-submodules/submodule1.yang", "submodule-test/multiple-submodules/submodule2.yang",
+                "submodule-test/multiple-submodules/submodule3.yang",
+                "submodule-test/multiple-submodules/importing-module.yang"));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module");
+        assertTrue(module != null);
+
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        assertTrue(cont1 != null);
+        assertTrue(getContainer(cont1, "cont51") == null);
+        assertTrue(getContainer(cont1, "cont52") != null);
+        assertTrue(getLeaf(cont1, "leaf11") != null);
+
+        final YContainer cont2 = getContainer(module, "cont2");
+        assertTrue(cont2 != null);
+        assertTrue(getLeaf(cont2, "leaf12") != null);
+        assertTrue(getLeaf(cont2, "leaf81") != null);
+        assertTrue(getLeaf(cont2, "leaf81").getEffectiveNamespace().equals("test:importing-module"));
+
+        final YContainer cont11 = getContainer(module, "cont11");
+        assertTrue(cont11 != null);
+        assertTrue(cont11.getEffectiveNamespace().equals("test:module"));
+        assertTrue(getLeaf(cont11, "leaf24") != null);
+
+        final YContainer cont12 = getContainer(module, "cont12");
+        assertTrue(cont12 != null);
+        assertTrue(getContainer(cont12, "cont14") == null);
+        assertTrue(getLeaf(cont12, "leaf25") != null);
+
+        final YContainer cont22 = getContainer(module, "cont22");
+        assertTrue(cont22 != null);
+        assertTrue(cont22.getEffectiveNamespace().equals("test:module"));
+        assertTrue(getContainer(cont22, "cont61") != null);
+
+        final YContainer cont23 = getContainer(module, "cont23");
+        assertTrue(cont23 != null);
+        assertTrue(getLeaf(cont23, "leaf31") != null);
+        assertTrue(getLeaf(cont23, "leaf82") != null);
+        assertTrue(getLeaf(cont23, "leaf82").getEffectiveNamespace().equals("test:importing-module"));
+
+        final YContainer cont33 = getContainer(module, "cont33");
+        assertTrue(cont33 != null);
+        assertTrue(cont33.getEffectiveNamespace().equals("test:module"));
+
+        final YContainer cont34 = getContainer(module, "cont34");
+        assertTrue(cont34 != null);
+        assertTrue(getContainer(cont34, "cont37") == null);
+
+        final YLeaf leaf1 = getLeaf(module, "leaf1");
+        assertTrue(leaf1 != null);
+        assertTrue(leaf1.getEffectiveNamespace().equals("test:module"));
+        assertTrue(leaf1.getType().getDataType().equals("boolean"));
+
+        final YLeaf leaf2 = getLeaf(module, "leaf2");
+        assertTrue(leaf2 != null);
+        assertTrue(leaf2.getEffectiveNamespace().equals("test:module"));
+        assertTrue(leaf2.getType().getDataType().equals("boolean"));
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/TypedefTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/TypedefTest.java
new file mode 100644
index 0000000..0386429
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/TypedefTest.java
@@ -0,0 +1,642 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.resolvers.TypeResolver;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YType;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+public class TypedefTest extends YangTestCommon {
+
+    private static final String TEST_MODULE_NS = "test:typedef-test-module";
+    private static final String TEST_MODULE_NAME = "typedef-test-module";
+
+    private static final String TEST_IMPORTING_MODULE_NS = "test:typedef-test-importing-module";
+    private static final String TEST_IMPORTING_MODULE_NAME = "typedef-test-importing-module";
+
+    @Test
+    public void testTypedef() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+
+        context.setSuppressFindingsOnUnusedSchemaNodes(false);
+        parseRelativeImplementsYangModels(Arrays.asList("typedef-test/typedef-test-module.yang",
+                "typedef-test/typedef-test-submodule.yang", "typedef-test/typedef-test-importing-module.yang"));
+
+        final YModule module = getModule("typedef-test-module");
+        final YModule importingModule = getModule("typedef-test-importing-module");
+
+        // - - - - lots of nesting - - - - - - -
+
+        assertNoFindingsOnStatement(getTypedef(module, "typedef1"));
+        assertDomElementHasFindingOfType(getTypedef(module, "typedef5").getDomElement().getChildren().get(0),
+                ParserFindingType.P112_EXCESSIVE_TYPEDEF_DEPTH.toString());
+
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        final YLeaf leaf01 = getLeaf(cont1, "leaf01");
+        assertOriginalTypedefStackSize(leaf01.getType(), 1);
+        assertOriginalTypedef(leaf01.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef1"));
+
+        final YLeaf leaf02 = getLeaf(cont1, "leaf02");
+        assertOriginalTypedefStackSize(leaf02.getType(), 2);
+        assertOriginalTypedef(leaf02.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef1"));
+        assertOriginalTypedef(leaf02.getType(), 1, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef2"));
+
+        final YLeaf leaf05 = getLeaf(cont1, "leaf05");
+        assertOriginalTypedefStackSize(leaf05.getType(), 5);
+        assertOriginalTypedef(leaf05.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef1"));
+        assertOriginalTypedef(leaf05.getType(), 1, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef2"));
+        assertOriginalTypedef(leaf05.getType(), 4, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef5"));
+
+        // - - - - circular - - - - - - -
+
+        assertStatementHasFindingOfType(getTypedef(module, "typedef7").getType(),
+                ParserFindingType.P111_CIRCULAR_TYPEDEF_REFERENCES.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef8").getType(),
+                ParserFindingType.P111_CIRCULAR_TYPEDEF_REFERENCES.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef9").getType(),
+                ParserFindingType.P111_CIRCULAR_TYPEDEF_REFERENCES.toString());
+
+        // - - - - bad typedef name - - - - - - -
+
+        assertStatementHasFindingOfType(getTypedef(module, "uint32"), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+        assertStatementHasFindingOfType(getTypedef(module, ""), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+        assertStatementHasFindingOfType(getTypedef(module, "my custom type"), ParserFindingType.P052_INVALID_YANG_IDENTIFIER
+                .toString());
+        assertStatementHasFindingOfType(getTypedef(module, null), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+
+        // - - - - not resolvable - - - - - - -
+
+        assertStatementHasFindingOfType(getTypedef(module, "typedef11").getType(),
+                ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef12").getType(),
+                ParserFindingType.P116_NESTED_DERIVED_TYPE_NOT_RESOLVABLE.toString());
+
+        // - - - - - resolvable, with and without prefix - - - - -
+
+        assertNoFindingsOnStatement(getTypedef(module, "typedef13"));
+        assertNoFindingsOnStatement(getTypedef(module, "typedef14"));
+        assertTrue(getTypedef(module, "typedef14").getType().getDataType().equals("uint32"));
+        assertNoFindingsOnStatement(getTypedef(module, "typedef15"));
+        assertTrue(getTypedef(module, "typedef15").getType().getDataType().equals("uint32"));
+
+        // - - - - - from submodule - - - - -
+
+        assertNoFindingsOnStatement(getTypedef(module, "typedef16"));
+        assertNoFindingsOnStatement(getTypedef(module, "typedef17"));
+        assertNoFindingsOnStatement(getTypedef(module, "typedef91"));
+        assertNoFindingsOnStatement(getTypedef(module, "typedef92"));
+        assertNoFindingsOnStatement(getTypedef(module, "typedef93"));
+        assertTrue(getTypedef(module, "typedef16").getType().getDataType().equals("boolean"));
+        assertTrue(getTypedef(module, "typedef17").getType().getDataType().equals("uint32"));
+
+        assertTrue(getLeaf(importingModule, "leaf1").getType().getDataType().equals("uint32"));
+        assertTrue(getLeaf(importingModule, "leaf2").getType().getDataType().equals("boolean"));
+        assertTrue(getLeaf(importingModule, "leaf3").getType().getDataType().equals("uint32"));
+
+        final YContainer cont2 = getContainer(module, "cont2");
+
+        final YLeaf leaf21 = getLeaf(cont2, "leaf21");
+        assertOriginalTypedefStackSize(leaf21.getType(), 3);
+        assertOriginalTypedef(leaf21.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef92"));
+        assertOriginalTypedef(leaf21.getType(), 1, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef91"));
+        assertOriginalTypedef(leaf21.getType(), 2, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef16"));
+
+        final YLeaf leaf22 = getLeaf(cont2, "leaf22");
+        assertOriginalTypedefStackSize(leaf22.getType(), 3);
+        assertOriginalTypedef(leaf22.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef13"));
+        assertOriginalTypedef(leaf22.getType(), 1, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef93"));
+        assertOriginalTypedef(leaf22.getType(), 2, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef17"));
+
+        // - - - - - bad types - - - - -
+
+        assertStatementHasFindingOfType(getTypedef(module, "typedef18").getType(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef19").getType(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef20").getType(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef21").getType(),
+                ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+
+        // - - - - - importing - - - - -
+
+        final YLeaf leaf1 = getLeaf(importingModule, "leaf1");
+        assertOriginalTypedefStackSize(leaf1.getType(), 1);
+        assertOriginalTypedef(leaf1.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef13"));
+
+        final YLeaf leaf2 = getLeaf(importingModule, "leaf2");
+        assertOriginalTypedefStackSize(leaf2.getType(), 1);
+        assertOriginalTypedef(leaf2.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef92"));
+
+        final YLeaf leaf4 = getLeaf(importingModule, "leaf4");
+        assertOriginalTypedefStackSize(leaf4.getType(), 3);
+        assertOriginalTypedef(leaf4.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef13"));
+        assertOriginalTypedef(leaf4.getType(), 1, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef93"));
+        assertOriginalTypedef(leaf4.getType(), 2, new NamespaceModuleIdentifier(TEST_IMPORTING_MODULE_NS,
+                TEST_IMPORTING_MODULE_NAME, "typedef51"));
+
+        final YContainer cont6 = getContainer(importingModule, "cont6");
+        final YLeaf leaf5 = getLeaf(cont6, "leaf5");
+        assertOriginalTypedefStackSize(leaf5.getType(), 2);
+        assertOriginalTypedef(leaf5.getType(), new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef13"));
+        assertOriginalTypedef(leaf5.getType(), 1, new NamespaceModuleIdentifier(TEST_MODULE_NS, TEST_MODULE_NAME,
+                "typedef93"));
+    }
+
+    @Test
+    public void test___typedef___not_used_or_used_once_only() {
+
+        context.setSuppressFindingsOnUnusedSchemaNodes(true);
+        parseRelativeImplementsYangModels(Arrays.asList("typedef-test/typedef-test-not-used-once-used.yang"));
+
+        final YModule module = getModule("typedef-test-not-used-once-used");
+
+        assertStatementHasFindingOfType(getTypedef(module, "typedef1"), ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef2"), ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY
+                .toString());
+        assertNoFindingsOnStatement(getTypedef(module, "typedef3"));
+    }
+
+    @Test
+    public void test_Typedef_no_submodule() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+
+        context.setSuppressFindingsOnUnusedSchemaNodes(false);
+        parseRelativeImplementsYangModels(Arrays.asList("typedef-test/typedef-test-module.yang",
+                "typedef-test/typedef-test-importing-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P037_UNRESOLVABLE_INCLUDE.toString());
+
+        final YModule module = getModule("typedef-test-module");
+
+        // - - - - - from submodule - - - - -
+
+        assertStatementHasFindingOfType(getTypedef(module, "typedef16").getType(),
+                ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+        assertStatementHasFindingOfType(getTypedef(module, "typedef17").getType(),
+                ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+    }
+
+    @Test
+    public void test_Typedef_restrictions() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P144_BIT_WITHOUT_POSITION.toString());
+
+        parseRelativeImplementsYangModels(Arrays.asList("typedef-test/typedef-test-restrictions-module.yang"));
+
+        final YModule module = getModule("typedef-test-restrictions-module");
+
+        // - - - - - - no changes - - - - - -
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertSubTreeNoFindings(cont1);
+
+        assertTrue(getLeaf(cont1, "leaf1").getDefault().getValue().equals("Hello"));
+        assertTrue(getLeaf(cont1, "leaf1").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont1, "leaf1").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf1").getType().getLength().getBoundaries().get(0).lower == 10);
+        assertTrue(getLeaf(cont1, "leaf1").getType().getLength().getBoundaries().get(0).upper == 20);
+        assertTrue(getLeaf(cont1, "leaf1").getType().getPatterns().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf1").getType().getPatterns().get(0).getPattern().equals("ab*c"));
+
+        assertTrue(getLeaf(cont1, "leaf2").getDefault().getDecimalDefaultValue().compareTo(BigDecimal.valueOf(35L)) == 0);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getDataType().equals("int32"));
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                30)) == 0);
+        assertTrue(getLeaf(cont1, "leaf2").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                40)) == 0);
+
+        assertTrue(getLeaf(cont1, "leaf3").getDefault().getValue().equals("one"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getDataType().equals("enumeration"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getEnums().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf3").getType().getEnums().get(0).getEnumName().equals("zero"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getEnums().get(0).getValue().getValue().equals("10"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getEnums().get(1).getEnumName().equals("one"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getEnums().get(1).getValue().getValue().equals("11"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getEnums().get(2).getEnumName().equals("two"));
+        assertTrue(getLeaf(cont1, "leaf3").getType().getEnums().get(2).getValue().getValue().equals("12"));
+
+        assertTrue(getLeaf(cont1, "leaf4").getDefault() == null);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getDataType().equals("bits"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getBits().size() == 3);
+        assertTrue(getLeaf(cont1, "leaf4").getType().getBits().get(0).getBitName().equals("four"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getBits().get(0).getPosition().getValue().equals("16"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getBits().get(1).getBitName().equals("five"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getBits().get(1).getPosition().getValue().equals("17"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getBits().get(2).getBitName().equals("six"));
+        assertTrue(getLeaf(cont1, "leaf4").getType().getBits().get(2).getPosition().getValue().equals("18"));
+
+        // - - - - - - some overrides - - - - - -
+
+        final YContainer cont2 = getContainer(module, "cont2");
+        assertSubTreeNoFindings(cont2);
+
+        assertTrue(getLeaf(cont2, "leaf7").getDefault().getValue().equals("World"));
+        assertTrue(getLeaf(cont2, "leaf7").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont2, "leaf7").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont2, "leaf7").getType().getLength().getBoundaries().get(0).lower == 12);
+        assertTrue(getLeaf(cont2, "leaf7").getType().getLength().getBoundaries().get(0).upper == 15);
+        assertTrue(getLeaf(cont2, "leaf7").getType().getPatterns().size() == 2);
+        assertTrue(getLeaf(cont2, "leaf7").getType().getPatterns().get(0).getPattern().equals("ab*c"));
+        assertTrue(getLeaf(cont2, "leaf7").getType().getPatterns().get(1).getPattern().equals("de*f"));
+
+        assertTrue(getLeaf(cont2, "leaf8").getDefault().getDecimalDefaultValue().compareTo(BigDecimal.valueOf(32L)) == 0);
+        assertTrue(getLeaf(cont2, "leaf8").getType().getDataType().equals("int32"));
+        assertTrue(getLeaf(cont2, "leaf8").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont2, "leaf8").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                30)) == 0);
+        assertTrue(getLeaf(cont2, "leaf8").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                35)) == 0);
+
+        assertTrue(getLeaf(cont2, "leaf9").getDefault().getValue().equals("zero"));
+        assertTrue(getLeaf(cont2, "leaf9").getType().getDataType().equals("enumeration"));
+        assertTrue(getLeaf(cont2, "leaf9").getType().getEnums().size() == 2);
+        assertTrue(getLeaf(cont2, "leaf9").getType().getEnums().get(0).getEnumName().equals("zero"));
+        assertTrue(getLeaf(cont2, "leaf9").getType().getEnums().get(0).getValue().getValue().equals("10"));
+        assertTrue(getLeaf(cont2, "leaf9").getType().getEnums().get(1).getEnumName().equals("one"));
+        assertTrue(getLeaf(cont2, "leaf9").getType().getEnums().get(1).getValue().getValue().equals("11"));
+
+        assertTrue(getLeaf(cont2, "leaf10").getDefault().getValue().equals("six"));
+        assertTrue(getLeaf(cont2, "leaf10").getType().getDataType().equals("bits"));
+        assertTrue(getLeaf(cont2, "leaf10").getType().getBits().size() == 2);
+        assertTrue(getLeaf(cont2, "leaf10").getType().getBits().get(0).getBitName().equals("five"));
+        assertTrue(getLeaf(cont2, "leaf10").getType().getBits().get(0).getPosition().getValue().equals("17"));
+        assertTrue(getLeaf(cont2, "leaf10").getType().getBits().get(1).getBitName().equals("six"));
+        assertTrue(getLeaf(cont2, "leaf10").getType().getBits().get(1).getPosition().getValue().equals("18"));
+
+        // - - - - - - some multi-level overrides - - - - - -
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertSubTreeNoFindings(cont3);
+
+        assertTrue(getLeaf(cont3, "leaf18").getDefault().getValue().equals("Moon"));
+        assertTrue(getLeaf(cont3, "leaf18").getType().getDataType().equals("string"));
+        assertTrue(getLeaf(cont3, "leaf18").getType().getLength().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont3, "leaf18").getType().getLength().getBoundaries().get(0).lower == 6);
+        assertTrue(getLeaf(cont3, "leaf18").getType().getLength().getBoundaries().get(0).upper == 7);
+        assertTrue(getLeaf(cont3, "leaf18").getType().getPatterns().size() == 3);
+        assertTrue(getLeaf(cont3, "leaf18").getType().getPatterns().get(0).getPattern().equals("ab*c"));
+        assertTrue(getLeaf(cont3, "leaf18").getType().getPatterns().get(1).getPattern().equals("gh*i"));
+        assertTrue(getLeaf(cont3, "leaf18").getType().getPatterns().get(2).getPattern().equals("mn*o"));
+
+        assertTrue(getLeaf(cont3, "leaf19").getDefault().getDecimalDefaultValue().compareTo(BigDecimal.valueOf(13L)) == 0);
+        assertTrue(getLeaf(cont3, "leaf19").getType().getDataType().equals("int32"));
+        assertTrue(getLeaf(cont3, "leaf19").getType().getRange().getBoundaries().size() == 1);
+        assertTrue(getLeaf(cont3, "leaf19").getType().getRange().getBoundaries().get(0).lower.compareTo(BigDecimal.valueOf(
+                16)) == 0);
+        assertTrue(getLeaf(cont3, "leaf19").getType().getRange().getBoundaries().get(0).upper.compareTo(BigDecimal.valueOf(
+                17)) == 0);
+
+        assertTrue(getLeaf(cont3, "leaf20").getDefault().getValue().equals("one"));
+        assertTrue(getLeaf(cont3, "leaf20").getType().getDataType().equals("enumeration"));
+        assertTrue(getLeaf(cont3, "leaf20").getType().getEnums().size() == 1);
+        assertTrue(getLeaf(cont3, "leaf20").getType().getEnums().get(0).getEnumName().equals("one"));
+        assertTrue(getLeaf(cont3, "leaf20").getType().getEnums().get(0).getValue().getValue().equals("11"));
+
+        // - - - - - - some illegal statements for restriction - - - - - -
+
+        final YContainer cont4 = getContainer(module, "cont4");
+
+        final YangDomElement leaf28domElement = getDomChild(cont4.getDomElement(), CY.LEAF, "leaf28");
+        assertDomElementHasFindingOfType(leaf28domElement, ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        final YangDomElement leaf29domElement = getDomChild(cont4.getDomElement(), CY.LEAF, "leaf29");
+        assertDomElementHasFindingOfType(leaf29domElement, ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        final YangDomElement leaf30domElement = getDomChild(cont4.getDomElement(), CY.LEAF, "leaf30");
+        final YangDomElement typeUnderLeaf30domElement = getDomChild(leaf30domElement, CY.TYPE);
+        assertDomElementHasFindingOfType(typeUnderLeaf30domElement.getChildren().get(0),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertDomElementHasFindingOfType(typeUnderLeaf30domElement.getChildren().get(1),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        final YangDomElement leaf31domElement = getDomChild(cont4.getDomElement(), CY.LEAF, "leaf31");
+        final YangDomElement typeUnderLeaf31domElement = getDomChild(leaf31domElement, CY.TYPE);
+        assertDomElementHasFindingOfType(typeUnderLeaf31domElement.getChildren().get(0),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertDomElementHasFindingOfType(typeUnderLeaf31domElement.getChildren().get(1),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        // - - - - - - some legal and illegal length restrictions - - - - - -
+
+        final YContainer cont5 = getContainer(module, "cont5");
+
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf51").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf52").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf53").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf54").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf55").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf56").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf57").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf58").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont5, "leaf59").getType().getLength(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf61"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf62"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf63"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf64"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf65"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf66"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf67"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf68"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf69"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf70"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf71"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf72"));
+        assertSubTreeNoFindings(getLeaf(cont5, "leaf73"));
+
+        // - - - - - - some legal and illegal range restrictions - - - - - -
+
+        final YContainer cont8 = getContainer(module, "cont8");
+
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf81").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf82").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf83").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf84").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf85").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf86").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf87").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf88").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+        assertStatementHasFindingOfType(getLeaf(cont8, "leaf89").getType().getRange(),
+                ParserFindingType.P117_ILLEGAL_DATA_TYPE_RESTRICTION.toString());
+
+        assertSubTreeNoFindings(getLeaf(cont8, "leaf91"));
+        assertSubTreeNoFindings(getLeaf(cont8, "leaf92"));
+        assertSubTreeNoFindings(getLeaf(cont8, "leaf93"));
+        assertSubTreeNoFindings(getLeaf(cont8, "leaf94"));
+    }
+
+    private static final String USED_TWICE_NS = "test:typedef-test-used-twice";
+    private static final String USED_TWICE_MODULE_NAME = "typedef-test-used-twice";
+
+    @Test
+    public void test_Typedef_used_twice() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("typedef-test/typedef-test-used-twice.yang"));
+
+        final YModule module = getModule("typedef-test-used-twice");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        final YLeaf leaf2 = getLeaf(cont1, "leaf2");
+        assertTrue(leaf2.getDefault() != null);
+        assertTrue(leaf2.getDefault().getValue().equals("10"));
+        assertOriginalTypedef(leaf2.getType(), new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef1"));
+
+        final YLeaf leaf3 = getLeaf(cont1, "leaf3");
+        assertTrue(leaf3.getDefault() != null);
+        assertTrue(leaf3.getDefault().getValue().equals("5"));
+        assertOriginalTypedef(leaf3.getType(), new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef1"));
+
+        final YLeaf leaf4 = getLeaf(cont1, "leaf4");
+        assertTrue(leaf4.getDefault() != null);
+        assertTrue(leaf4.getDefault().getValue().equals("5"));
+        assertOriginalTypedef(leaf4.getType(), new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef1"));
+
+        final YLeaf leaf5 = getLeaf(cont1, "leaf5");
+        assertTrue(leaf5.getDefault() != null);
+        assertTrue(leaf5.getDefault().getValue().equals("20"));
+        assertOriginalTypedef(leaf5.getType(), new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef1"));
+        assertOriginalTypedef(leaf5.getType(), 1, new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef2"));
+
+        final YLeaf leaf6 = getLeaf(cont1, "leaf6");
+        assertTrue(leaf6.getDefault() != null);
+        assertTrue(leaf6.getDefault().getValue().equals("20"));
+        assertOriginalTypedef(leaf6.getType(), new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef1"));
+        assertOriginalTypedef(leaf6.getType(), 1, new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef2"));
+
+        final YLeaf leaf7 = getLeaf(cont1, "leaf7");
+        assertTrue(leaf7.getDefault() != null);
+        assertTrue(leaf7.getDefault().getValue().equals("5"));
+        assertOriginalTypedef(leaf7.getType(), new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef1"));
+        assertOriginalTypedef(leaf7.getType(), 1, new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef3"));
+
+        final YLeaf leaf8 = getLeaf(cont1, "leaf8");
+        assertTrue(leaf8.getDefault() != null);
+        assertTrue(leaf8.getDefault().getValue().equals("5"));
+        assertOriginalTypedef(leaf8.getType(), new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef1"));
+        assertOriginalTypedef(leaf8.getType(), 1, new NamespaceModuleIdentifier(USED_TWICE_NS, USED_TWICE_MODULE_NAME,
+                "typedef3"));
+    }
+
+    @Test
+    public void test_Typedef_nested_union() {
+
+        parseRelativeImplementsYangModels(Arrays.asList("typedef-test/typedef-test-nested-union.yang"));
+
+        final YModule module = getModule("typedef-test-nested-union-module");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertTrue(leaf11.getType().getDataType().equals("union"));
+        assertTrue(leaf11.getType().getTypes().size() == 2);
+        assertTrue(leaf11.getType().getTypes().get(0).getDataType().equals("int16"));
+        assertTrue(leaf11.getType().getTypes().get(1).getDataType().equals("string"));
+
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertTrue(leaf12.getType().getDataType().equals("union"));
+        assertTrue(leaf12.getType().getTypes().size() == 4);
+        assertTrue(leaf12.getType().getTypes().get(0).getDataType().equals("int16"));
+        assertTrue(leaf12.getType().getTypes().get(1).getDataType().equals("string"));
+        assertTrue(leaf12.getType().getTypes().get(2).getDataType().equals("empty"));
+        assertTrue(leaf12.getType().getTypes().get(3).getDataType().equals("binary"));
+
+        final YLeaf leaf13 = getLeaf(cont1, "leaf13");
+        assertTrue(leaf13.getType().getDataType().equals("union"));
+        assertTrue(leaf13.getType().getTypes().size() == 4);
+        assertTrue(leaf13.getType().getTypes().get(0).getDataType().equals("empty"));
+        assertTrue(leaf13.getType().getTypes().get(1).getDataType().equals("binary"));
+        assertTrue(leaf13.getType().getTypes().get(2).getDataType().equals("int16"));
+        assertTrue(leaf13.getType().getTypes().get(3).getDataType().equals("string"));
+
+        final YLeaf leaf14 = getLeaf(cont1, "leaf14");
+        assertTrue(leaf14.getType().getDataType().equals("union"));
+        assertTrue(leaf14.getType().getTypes().size() == 4);
+        assertTrue(leaf14.getType().getTypes().get(0).getDataType().equals("int16"));
+        assertTrue(leaf14.getType().getTypes().get(1).getDataType().equals("empty"));
+        assertTrue(leaf14.getType().getTypes().get(2).getDataType().equals("binary"));
+        assertTrue(leaf14.getType().getTypes().get(3).getDataType().equals("string"));
+
+        final YLeaf leaf15 = getLeaf(cont1, "leaf15");
+        assertTrue(leaf15.getType().getDataType().equals("union"));
+        assertTrue(leaf15.getType().getTypes().size() == 6);
+        assertTrue(leaf15.getType().getTypes().get(0).getDataType().equals("int16"));
+        assertTrue(leaf15.getType().getTypes().get(1).getDataType().equals("empty"));
+        assertTrue(leaf15.getType().getTypes().get(2).getDataType().equals("int32"));
+        assertTrue(leaf15.getType().getTypes().get(3).getDataType().equals("boolean"));
+        assertTrue(leaf15.getType().getTypes().get(4).getDataType().equals("binary"));
+        assertTrue(leaf15.getType().getTypes().get(5).getDataType().equals("string"));
+
+        final YContainer cont2 = getContainer(module, "cont2");
+
+        final YLeaf leaf21 = getLeaf(cont2, "leaf21");
+        assertTrue(leaf21.getType().getDataType().equals("union"));
+        assertTrue(leaf21.getType().getTypes().size() == 2);
+        assertTrue(leaf21.getType().getTypes().get(0).getDataType().equals("binary"));
+        assertTrue(leaf21.getType().getTypes().get(1).getDataType().equals("empty"));
+
+        final YLeaf leaf22 = getLeaf(cont2, "leaf22");
+        assertTrue(leaf22.getType().getDataType().equals("union"));
+        assertTrue(leaf22.getType().getTypes().size() == 3);
+        assertTrue(leaf22.getType().getTypes().get(0).getDataType().equals("uint64"));
+        assertTrue(leaf22.getType().getTypes().get(1).getDataType().equals("binary"));
+        assertTrue(leaf22.getType().getTypes().get(2).getDataType().equals("empty"));
+
+        final YLeaf leaf23 = getLeaf(cont2, "leaf23");
+        assertTrue(leaf23.getType().getDataType().equals("union"));
+        assertTrue(leaf23.getType().getTypes().size() == 3);
+        assertTrue(leaf23.getType().getTypes().get(0).getDataType().equals("binary"));
+        assertTrue(leaf23.getType().getTypes().get(1).getDataType().equals("empty"));
+        assertTrue(leaf23.getType().getTypes().get(2).getDataType().equals("uint64"));
+
+        final YLeaf leaf24 = getLeaf(cont2, "leaf24");
+        assertTrue(leaf24.getType().getDataType().equals("union"));
+        assertTrue(leaf24.getType().getTypes().size() == 1);
+        assertTrue(leaf24.getType().getTypes().get(0).getDataType().equals("int32"));
+
+        final YLeaf leaf25 = getLeaf(cont2, "leaf25");
+        assertTrue(leaf25.getType().getDataType().equals("union"));
+        assertTrue(leaf25.getType().getTypes().size() == 2);
+        assertTrue(leaf25.getType().getTypes().get(0).getDataType().equals("uint64"));
+        assertTrue(leaf25.getType().getTypes().get(1).getDataType().equals("int32"));
+
+        final YLeaf leaf26 = getLeaf(cont2, "leaf26");
+        assertTrue(leaf26.getType().getDataType().equals("union"));
+        assertTrue(leaf26.getType().getTypes().size() == 3);
+        assertTrue(leaf26.getType().getTypes().get(0).getDataType().equals("boolean"));
+        assertTrue(leaf26.getType().getTypes().get(1).getDataType().equals("binary"));
+        assertTrue(leaf26.getType().getTypes().get(2).getDataType().equals("empty"));
+
+        final YLeaf leaf27 = getLeaf(cont2, "leaf27");
+        assertTrue(leaf27.getType().getDataType().equals("union"));
+        assertTrue(leaf27.getType().getTypes().size() == 4);
+        assertTrue(leaf27.getType().getTypes().get(0).getDataType().equals("boolean"));
+        assertTrue(leaf27.getType().getTypes().get(1).getDataType().equals("binary"));
+        assertTrue(leaf27.getType().getTypes().get(2).getDataType().equals("empty"));
+        assertTrue(leaf27.getType().getTypes().get(3).getDataType().equals("uint64"));
+
+        final YLeaf leaf28 = getLeaf(cont2, "leaf28");
+        assertTrue(leaf28.getType().getDataType().equals("union"));
+        assertTrue(leaf28.getType().getTypes().size() == 6);
+        assertTrue(leaf28.getType().getTypes().get(0).getDataType().equals("uint64"));
+        assertTrue(leaf28.getType().getTypes().get(1).getDataType().equals("boolean"));
+        assertTrue(leaf28.getType().getTypes().get(2).getDataType().equals("binary"));
+        assertTrue(leaf28.getType().getTypes().get(3).getDataType().equals("empty"));
+        assertTrue(leaf28.getType().getTypes().get(4).getDataType().equals("int32"));
+        assertTrue(leaf28.getType().getTypes().get(5).getDataType().equals("string"));
+    }
+
+    private static void assertOriginalTypedefStackSize(final YType yType, final int size) {
+        assertEquals(size, TypeResolver.getTypedefStack(yType).size());
+    }
+
+    private static void assertOriginalTypedef(final YType yType, final NamespaceModuleIdentifier soughtTypedefIdentity) {
+        assertOriginalTypedef(yType, 0, soughtTypedefIdentity);
+    }
+
+    private static void assertOriginalTypedef(final YType yType, final int index,
+            final NamespaceModuleIdentifier soughtTypedefIdentity) {
+
+        final List<NamespaceModuleIdentifier> stack = TypeResolver.getTypedefStack(yType);
+        if (index >= stack.size()) {
+            fail("Typedef stack index " + index + " does not exist.");
+        }
+
+        final NamespaceModuleIdentifier nsai = stack.get(index);
+        if (!nsai.toString().equals(soughtTypedefIdentity.toString())) {
+            fail("Expected '" + soughtTypedefIdentity + "' but got '" + nsai + "'.");
+        }
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/WhenTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/WhenTest.java
new file mode 100644
index 0000000..730ed15
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/statements/yang/test/WhenTest.java
@@ -0,0 +1,66 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.statements.yang.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YWhen;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class WhenTest extends YangTestCommon {
+
+    @Test
+    public void testWhen() {
+        parseRelativeImplementsYangModels(Arrays.asList("when-test/when-test.yang"));
+        final YModule yModule = getModule("when-test");
+
+        final YLeaf leafWithoutWhen = getLeafUnderContainer(yModule, "cont1", "leaf11");
+        assertTrue(leafWithoutWhen.getWhens().isEmpty());
+        assertNoFindingsOnStatement(leafWithoutWhen);
+
+        final YLeaf leafWithWhen = getLeafUnderContainer(yModule, "cont1", "leaf12");
+        final YWhen when1 = leafWithWhen.getWhens().get(0);
+        assertTrue(when1 != null);
+        assertEquals("../leaf11 = 'Hello'", when1.getValue());
+        assertEquals(Boolean.FALSE, when1.appliesToParentSchemaNode());
+        assertNoFindingsOnStatement(leafWithWhen);
+        assertNoFindingsOnStatement(when1);
+
+        final YLeaf augmentedLeafWithWhen = getLeafUnderContainer(yModule, "cont2", "leaf22");
+        final YWhen when2 = augmentedLeafWithWhen.getWhens().get(0);
+        assertTrue(when2 != null);
+        assertEquals("/this:cont1/this:leaf11 = 'World'", when2.getValue());
+        assertEquals(Boolean.TRUE, when2.appliesToParentSchemaNode());
+        assertNoFindingsOnStatement(augmentedLeafWithWhen);
+        assertNoFindingsOnStatement(when2);
+
+        final YWhen newWhen = new YWhen(when2.getParentStatement(), when2.getDomElement());
+        newWhen.cloneFrom(when2);
+        assertTrue(newWhen.getParentStatement() == augmentedLeafWithWhen);
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/test/ModuleIdentityTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/test/ModuleIdentityTest.java
new file mode 100644
index 0000000..387e9f5
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/test/ModuleIdentityTest.java
@@ -0,0 +1,57 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+
+public class ModuleIdentityTest {
+
+    @Test
+    public void test_all_ok() {
+
+        final ModuleIdentity module1 = new ModuleIdentity("module1");
+        assertTrue(module1.getModuleName().equals("module1"));
+        assertTrue(module1.getRevision().equals(ModuleIdentity.UNKWOWN_REVISION));
+        assertTrue(module1.isUnknownRevision() == true);
+
+        final ModuleIdentity module2 = new ModuleIdentity("module2", "2000-01-01");
+        assertTrue(module2.getModuleName().equals("module2"));
+        assertTrue(module2.getRevision().equals("2000-01-01"));
+        assertTrue(module2.isUnknownRevision() == false);
+
+        final ModuleIdentity module3 = new ModuleIdentity("module3", null);
+        assertTrue(module3.getModuleName().equals("module3"));
+        assertTrue(module3.getRevision() == null);
+        assertTrue(module3.isUnknownRevision() == false);
+
+        try {
+            new ModuleIdentity("module1", "");
+            fail("Should have thrown exception.");
+        } catch (final Exception ignore) {
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/DataTypeHelperTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/DataTypeHelperTest.java
new file mode 100644
index 0000000..91ad51c
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/DataTypeHelperTest.java
@@ -0,0 +1,413 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YType;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper;
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper.YangDataType;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class DataTypeHelperTest {
+
+    private YangDeviceModel yangDeviceModel;
+    private ModifyableFindingSeverityCalculator severityCalculator;
+    private FindingsManager findingsManager;
+    private ParserExecutionContext context;
+
+    @Before
+    public void setUp() {
+        yangDeviceModel = new YangDeviceModel("Yang Parser JAR Test Device Model");
+        severityCalculator = new ModifyableFindingSeverityCalculator();
+        findingsManager = new FindingsManager(severityCalculator);
+        context = new ParserExecutionContext(findingsManager);
+    }
+
+    @Test
+    public void test_is_yang_integer_type() {
+
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.UINT8) == true);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.UINT16) == true);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.UINT32) == true);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.UINT64) == true);
+
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.INT8) == true);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.INT16) == true);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.INT32) == true);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.INT64) == true);
+
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.DECIMAL64) == false);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.STRING) == false);
+        assertTrue(DataTypeHelper.isYangIntegerType(YangDataType.BOOLEAN) == false);
+    }
+
+    @Test
+    public void test_get_yang_data_type() {
+
+        assertTrue(DataTypeHelper.getYangDataType("uint8") == YangDataType.UINT8);
+        assertTrue(DataTypeHelper.getYangDataType("UINT8") == YangDataType.UINT8);
+        assertTrue(DataTypeHelper.getYangDataType("uInt8") == YangDataType.UINT8);
+
+        assertTrue(DataTypeHelper.getYangDataType("uint16") == YangDataType.UINT16);
+        assertTrue(DataTypeHelper.getYangDataType("uint32") == YangDataType.UINT32);
+        assertTrue(DataTypeHelper.getYangDataType("uint64") == YangDataType.UINT64);
+
+        assertTrue(DataTypeHelper.getYangDataType("int8") == YangDataType.INT8);
+        assertTrue(DataTypeHelper.getYangDataType("int16") == YangDataType.INT16);
+        assertTrue(DataTypeHelper.getYangDataType("int32") == YangDataType.INT32);
+        assertTrue(DataTypeHelper.getYangDataType("int64") == YangDataType.INT64);
+
+        assertTrue(DataTypeHelper.getYangDataType("decimal64") == YangDataType.DECIMAL64);
+        assertTrue(DataTypeHelper.getYangDataType("string") == YangDataType.STRING);
+        assertTrue(DataTypeHelper.getYangDataType("boolean") == YangDataType.BOOLEAN);
+        assertTrue(DataTypeHelper.getYangDataType("enumeration") == YangDataType.ENUMERATION);
+        assertTrue(DataTypeHelper.getYangDataType("bits") == YangDataType.BITS);
+        assertTrue(DataTypeHelper.getYangDataType("binary") == YangDataType.BINARY);
+        assertTrue(DataTypeHelper.getYangDataType("leafref") == YangDataType.LEAFREF);
+        assertTrue(DataTypeHelper.getYangDataType("identityref") == YangDataType.IDENTITYREF);
+        assertTrue(DataTypeHelper.getYangDataType("empty") == YangDataType.EMPTY);
+        assertTrue(DataTypeHelper.getYangDataType("union") == YangDataType.UNION);
+        assertTrue(DataTypeHelper.getYangDataType("instance-identifier") == YangDataType.INSTANCE_IDENTIFIER);
+
+        assertTrue(DataTypeHelper.getYangDataType("") == YangDataType.DERIVED____TYPE);
+        assertTrue(DataTypeHelper.getYangDataType("prefix:someType") == YangDataType.DERIVED____TYPE);
+
+        assertTrue(DataTypeHelper.isBuiltInType("decimal64") == true);
+        assertTrue(DataTypeHelper.isBuiltInType("prefix:someType") == false);
+    }
+
+    @Test
+    public void test_calculate_position_of_bits() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P144_BIT_WITHOUT_POSITION.toString());
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        yangFiles.add(new YangModel(new FileBasedYangInput(new File("src/test/resources/model-util/module1.yang")),
+                ConformanceType.IMPLEMENT));
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        final YModule module1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot()
+                .getModule();
+
+        final YLeaf leaf1 = module1.getLeafs().get(0);
+        final YLeaf leaf2 = module1.getLeafs().get(1);
+
+        Map<String, Long> positionOfBitsLeaf1 = DataTypeHelper.calculatePositionOfBits(null, leaf1.getType(), null);
+
+        assertTrue(positionOfBitsLeaf1.size() == 3);
+        assertTrue(positionOfBitsLeaf1.containsKey("one"));
+        assertTrue(positionOfBitsLeaf1.containsKey("two"));
+        assertTrue(positionOfBitsLeaf1.containsKey("three"));
+        assertTrue(positionOfBitsLeaf1.get("one") == 0);
+        assertTrue(positionOfBitsLeaf1.get("two") == 1);
+        assertTrue(positionOfBitsLeaf1.get("three") == 2);
+
+        Map<String, Long> positionOfBitsLeaf2 = DataTypeHelper.calculatePositionOfBits(null, leaf2.getType(), null);
+
+        assertTrue(positionOfBitsLeaf2.size() == 3);
+        assertTrue(positionOfBitsLeaf2.containsKey("one"));
+        assertTrue(positionOfBitsLeaf2.containsKey("two"));
+        assertTrue(positionOfBitsLeaf2.containsKey("three"));
+        assertTrue(positionOfBitsLeaf2.get("one") == 71);
+        assertTrue(positionOfBitsLeaf2.get("two") == 72);
+        assertTrue(positionOfBitsLeaf2.get("three") == 402);
+
+        final Map<String, Long> predefinedMapping = new HashMap<>();
+        predefinedMapping.put("zero", 999L);
+        predefinedMapping.put("one", 36L);
+
+        positionOfBitsLeaf1 = DataTypeHelper.calculatePositionOfBits(null, leaf1.getType(), predefinedMapping);
+
+        assertTrue(positionOfBitsLeaf1.get("one") == 36);
+        assertTrue(positionOfBitsLeaf1.get("two") == 37);
+        assertTrue(positionOfBitsLeaf1.get("three") == 38);
+
+        predefinedMapping.put("two", 99999999999999999L);
+        predefinedMapping.put("three", 36L);
+
+        positionOfBitsLeaf1 = DataTypeHelper.calculatePositionOfBits(null, leaf1.getType(), predefinedMapping);
+
+        assertTrue(positionOfBitsLeaf1.size() == 3);
+        assertTrue(positionOfBitsLeaf1.get("one") == 36);
+        assertTrue(positionOfBitsLeaf1.get("two") == 99999999999999999L);
+        assertTrue(positionOfBitsLeaf1.get("three") == 36);
+
+        assertTrue(findingsManager.getAllFindings().isEmpty());
+
+        positionOfBitsLeaf1 = DataTypeHelper.calculatePositionOfBits(findingsManager, leaf1.getType(), predefinedMapping);
+
+        assertTrue(positionOfBitsLeaf1.size() == 3);
+        assertTrue(positionOfBitsLeaf1.get("one") == 36);
+        assertTrue(positionOfBitsLeaf1.get("two") == 99999999999999999L);
+        assertTrue(positionOfBitsLeaf1.get("three") == 36);
+
+        assertTrue(findingsManager.hasFindingOfType(ParserFindingType.P053_INVALID_VALUE.toString()));
+    }
+
+    @Test
+    public void test_calculate_values_of_enums() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P144_BIT_WITHOUT_POSITION.toString());
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        yangFiles.add(new YangModel(new FileBasedYangInput(new File("src/test/resources/model-util/module1.yang")),
+                ConformanceType.IMPLEMENT));
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        final YModule module1 = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot()
+                .getModule();
+
+        final YLeaf leaf3 = module1.getLeafs().get(2);
+        final YLeaf leaf4 = module1.getLeafs().get(3);
+
+        Map<String, Long> valuesOfEnumsLeaf3 = DataTypeHelper.calculateValuesOfEnums(null, leaf3.getType(), null);
+
+        assertTrue(valuesOfEnumsLeaf3.size() == 3);
+        assertTrue(valuesOfEnumsLeaf3.containsKey("one"));
+        assertTrue(valuesOfEnumsLeaf3.containsKey("two"));
+        assertTrue(valuesOfEnumsLeaf3.containsKey("three"));
+        assertTrue(valuesOfEnumsLeaf3.get("one") == 0);
+        assertTrue(valuesOfEnumsLeaf3.get("two") == 1);
+        assertTrue(valuesOfEnumsLeaf3.get("three") == 2);
+
+        Map<String, Long> valuesOfEnumsLeaf4 = DataTypeHelper.calculateValuesOfEnums(null, leaf4.getType(), null);
+
+        assertTrue(valuesOfEnumsLeaf4.size() == 3);
+        assertTrue(valuesOfEnumsLeaf4.containsKey("one"));
+        assertTrue(valuesOfEnumsLeaf4.containsKey("two"));
+        assertTrue(valuesOfEnumsLeaf4.containsKey("three"));
+        assertTrue(valuesOfEnumsLeaf4.get("one") == 71);
+        assertTrue(valuesOfEnumsLeaf4.get("two") == 72);
+        assertTrue(valuesOfEnumsLeaf4.get("three") == 402);
+
+        final Map<String, Long> predefinedMapping = new HashMap<>();
+        predefinedMapping.put("zero", 999L);
+        predefinedMapping.put("one", 36L);
+
+        valuesOfEnumsLeaf3 = DataTypeHelper.calculateValuesOfEnums(null, leaf3.getType(), predefinedMapping);
+
+        assertTrue(valuesOfEnumsLeaf3.get("one") == 36);
+        assertTrue(valuesOfEnumsLeaf3.get("two") == 37);
+        assertTrue(valuesOfEnumsLeaf3.get("three") == 38);
+
+        predefinedMapping.put("two", 99999999999999999L);
+        predefinedMapping.put("three", 36L);
+
+        valuesOfEnumsLeaf3 = DataTypeHelper.calculateValuesOfEnums(null, leaf3.getType(), predefinedMapping);
+
+        assertTrue(valuesOfEnumsLeaf3.size() == 3);
+        assertTrue(valuesOfEnumsLeaf3.get("one") == 36);
+        assertTrue(valuesOfEnumsLeaf3.get("two") == 99999999999999999L);
+        assertTrue(valuesOfEnumsLeaf3.get("three") == 36);
+
+        assertTrue(findingsManager.getAllFindings().isEmpty());
+
+        valuesOfEnumsLeaf3 = DataTypeHelper.calculateValuesOfEnums(findingsManager, leaf3.getType(), predefinedMapping);
+
+        assertTrue(valuesOfEnumsLeaf3.size() == 3);
+        assertTrue(valuesOfEnumsLeaf3.get("one") == 36);
+        assertTrue(valuesOfEnumsLeaf3.get("two") == 99999999999999999L);
+        assertTrue(valuesOfEnumsLeaf3.get("three") == 36);
+
+        assertTrue(findingsManager.hasFindingOfType(ParserFindingType.P053_INVALID_VALUE.toString()));
+    }
+
+    @Test
+    public void test_stringefied_values() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P144_BIT_WITHOUT_POSITION.toString());
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        yangFiles.add(new YangModel(new FileBasedYangInput(new File(
+                "src/test/resources/model-util/stringefied-values-test.yang")), ConformanceType.IMPLEMENT));
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        assertTrue(findingsManager.getAllFindings().isEmpty());
+
+        final YModule module = yangDeviceModel.getModuleRegistry().getAllYangModels().get(0).getYangModelRoot().getModule();
+
+        // ------------------------- integers ------------------------------
+
+        final YType type11 = YangTestCommon.getLeaf(module, "leaf11").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid(null, type11) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("not a number", type11) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-123456", type11) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("123456", type11) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("0", type11) == true);
+
+        final YType type12 = YangTestCommon.getLeaf(module, "leaf12").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-123456", type12) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("123456", type12) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("9", type12) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("21", type12) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("10", type12) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("20", type12) == true);
+
+        final YType type13 = YangTestCommon.getLeaf(module, "leaf13").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-123456", type13) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("123456", type13) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-1", type13) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("21", type13) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("39", type13) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("61", type13) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("0", type13) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("20", type13) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("40", type13) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("60", type13) == true);
+
+        // ------------------------- decimal64 ------------------------------
+
+        final YType type21 = YangTestCommon.getLeaf(module, "leaf21").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid(null, type21) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("not a number", type21) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("1.11", type21) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-1.11", type21) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("1", type21) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("1.1", type21) == true);
+
+        final YType type22 = YangTestCommon.getLeaf(module, "leaf22").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid("5.000001", type22) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-0.001", type22) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("10.001", type22) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("0.000", type22) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("10.000", type22) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("20.199", type22) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("20.200", type22) == true);
+
+        final YType type23 = YangTestCommon.getLeaf(module, "leaf23").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid("123.45", type23) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-123.45", type23) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("1.2345", type23) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("-1.2345", type23) == true);
+
+        // ------------------------- boolean ------------------------------
+
+        final YType type31 = YangTestCommon.getLeaf(module, "leaf31").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid(null, type31) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("not a boolean", type31) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type31) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("TRUE", type31) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("true", type31) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("false", type31) == true);
+
+        // ------------------------- enumeration ------------------------------
+
+        final YType type41 = YangTestCommon.getLeaf(module, "leaf41").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid(null, type41) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type41) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("BLACK", type41) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("         RED        ", type41) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("red", type41) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("RED", type41) == true);
+
+        // ------------------------- bits ------------------------------
+
+        final YType type51 = YangTestCommon.getLeaf(module, "leaf51").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid(null, type51) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ZERO", type51) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("one", type51) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type51) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("         ONE        ", type51) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ONE", type51) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ONE TWO", type51) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("TWO ONE", type51) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("THREE ONE", type51) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("THREE one", type51) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ONE ONE", type51) == false);
+
+        // ------------------------- string ------------------------------
+
+        final YType type61 = YangTestCommon.getLeaf(module, "leaf61").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid(null, type61) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type61) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("hello", type61) == true);
+
+        final YType type62 = YangTestCommon.getLeaf(module, "leaf62").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type62) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCD", type62) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDEFGHIJK", type62) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDE", type62) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDEFGHIJ", type62) == true);
+
+        final YType type63 = YangTestCommon.getLeaf(module, "leaf63").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type63) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("A", type63) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDE", type63) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDEFG", type63) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDEFGHIJK", type63) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("AB", type63) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCD", type63) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDEFGH", type63) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ABCDEFGHIJ", type63) == true);
+
+        final YType type64 = YangTestCommon.getLeaf(module, "leaf64").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type64) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("a", type64) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("c", type64) == false);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("ac", type64) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("abc", type64) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("abbc", type64) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("abbc", type64) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("aBc", type64) == false);
+
+        // ------------------------- empty ------------------------------
+
+        final YType type71 = YangTestCommon.getLeaf(module, "leaf71").getType();
+        assertTrue(DataTypeHelper.isStringefiedValueValid(null, type71) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("", type71) == true);
+        assertTrue(DataTypeHelper.isStringefiedValueValid("hello", type71) == false);
+
+        // ------------------------- union ------------------------------
+
+        final YType type81 = YangTestCommon.getLeaf(module, "leaf81").getType();
+
+        try {
+            DataTypeHelper.isStringefiedValueValid("blurb", type81);
+            fail();
+        } catch (final Exception expected) {
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/GrammarHelperTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/GrammarHelperTest.java
new file mode 100644
index 0000000..0f53d82
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/GrammarHelperTest.java
@@ -0,0 +1,243 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.util.GrammarHelper;
+
+public class GrammarHelperTest {
+
+    @Test
+    public void test_contains_yang_whitespace() {
+
+        assertTrue(GrammarHelper.containsYangWhitespace(null) == false);
+        assertTrue(GrammarHelper.containsYangWhitespace("") == false);
+
+        assertTrue(GrammarHelper.containsYangWhitespace(" ") == true);
+        assertTrue(GrammarHelper.containsYangWhitespace("\t") == true);
+
+        assertTrue(GrammarHelper.containsYangWhitespace("Hello World!") == true);
+        assertTrue(GrammarHelper.containsYangWhitespace(" HelloWorld!") == true);
+        assertTrue(GrammarHelper.containsYangWhitespace("HelloWorld! ") == true);
+        assertTrue(GrammarHelper.containsYangWhitespace("HelloWorld!") == false);
+
+        assertTrue(GrammarHelper.containsYangWhitespace("Hello\tWorld!") == true);
+        assertTrue(GrammarHelper.containsYangWhitespace("\tHelloWorld!") == true);
+        assertTrue(GrammarHelper.containsYangWhitespace("HelloWorld!\t") == true);
+    }
+
+    @Test
+    public void test_is_yang_identifier() {
+
+        assertTrue(GrammarHelper.isYangIdentifier(null) == false);
+        assertTrue(GrammarHelper.isYangIdentifier("") == false);
+        assertTrue(GrammarHelper.isYangIdentifier(" ") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("\t") == false);
+
+        assertTrue(GrammarHelper.isYangIdentifier("_") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("A") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("Z") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("a") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("z") == true);
+
+        assertTrue(GrammarHelper.isYangIdentifier("-") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("0") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("9") == false);
+        assertTrue(GrammarHelper.isYangIdentifier(".") == false);
+        assertTrue(GrammarHelper.isYangIdentifier(";") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("$") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("*") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("\\") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("/") == false);
+        assertTrue(GrammarHelper.isYangIdentifier(":") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("à") == false);
+
+        assertTrue(GrammarHelper.isYangIdentifier("__") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("_._") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("_......._") == true);
+
+        assertTrue(GrammarHelper.isYangIdentifier("ABCDEFGHIJKLMNOPQRSTUVWXYZ") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("abcdefghijklmnopqrstuvwxyz") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("_0123456789") == true);
+
+        assertTrue(GrammarHelper.isYangIdentifier("_ABC") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("ABC_") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("_ABC.DEF") == true);
+        assertTrue(GrammarHelper.isYangIdentifier("ABC.def") == true);
+
+        assertTrue(GrammarHelper.isYangIdentifier(" ABC.def") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("ABC. def") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("ABC.def ") == false);
+        assertTrue(GrammarHelper.isYangIdentifier("ABC.à.def") == false);
+    }
+
+    @Test
+    public void test_is_yang_identifier_reference() {
+
+        assertTrue(GrammarHelper.isYangIdentifierReference(null) == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference(" ") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("\t") == false);
+
+        assertTrue(GrammarHelper.isYangIdentifierReference("_") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("A") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("Z") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("a") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("z") == true);
+
+        assertTrue(GrammarHelper.isYangIdentifierReference(":") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference(":_") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("_:") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("::") == false);
+
+        assertTrue(GrammarHelper.isYangIdentifierReference("A:A") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("_:A") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("A:_") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("A:a") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("z:A") == true);
+
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc:Abc") == true);
+        assertTrue(GrammarHelper.isYangIdentifierReference("A99:z00") == true);
+
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc::Abc") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc: :Abc") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference(":Abc:Abc") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc:Abc:") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc :Abc") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc: Abc") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc : Abc") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference(" Abc:Abc") == false);
+        assertTrue(GrammarHelper.isYangIdentifierReference("Abc:Abc ") == false);
+    }
+
+    @Test
+    public void test_is_parse_to_string_list() {
+
+        List<String> list = GrammarHelper.parseToStringList("");
+        assertTrue(list.size() == 0);
+        list = GrammarHelper.parseToStringList(" ");
+        assertTrue(list.size() == 0);
+        list = GrammarHelper.parseToStringList("     ");
+        assertTrue(list.size() == 0);
+        list = GrammarHelper.parseToStringList("\t");
+        assertTrue(list.size() == 0);
+        list = GrammarHelper.parseToStringList(" \t ");
+        assertTrue(list.size() == 0);
+        list = GrammarHelper.parseToStringList("\n");
+        assertTrue(list.size() == 0);
+        list = GrammarHelper.parseToStringList(" \n \t");
+        assertTrue(list.size() == 0);
+
+        list = GrammarHelper.parseToStringList("Abc");
+        assertTrue(list.size() == 1);
+        assertTrue(list.equals(Arrays.asList("Abc")));
+
+        list = GrammarHelper.parseToStringList(" Abc");
+        assertTrue(list.size() == 1);
+        assertTrue(list.equals(Arrays.asList("Abc")));
+
+        list = GrammarHelper.parseToStringList("Abc ");
+        assertTrue(list.size() == 1);
+        assertTrue(list.equals(Arrays.asList("Abc")));
+
+        list = GrammarHelper.parseToStringList("Abc\n");
+        assertTrue(list.size() == 1);
+        assertTrue(list.equals(Arrays.asList("Abc")));
+
+        list = GrammarHelper.parseToStringList("Abc Def");
+        assertTrue(list.size() == 2);
+        assertTrue(list.equals(Arrays.asList("Abc", "Def")));
+
+        list = GrammarHelper.parseToStringList("Abc\tDef");
+        assertTrue(list.size() == 2);
+        assertTrue(list.equals(Arrays.asList("Abc", "Def")));
+
+        list = GrammarHelper.parseToStringList("Abc\nDef");
+        assertTrue(list.size() == 2);
+        assertTrue(list.equals(Arrays.asList("Abc", "Def")));
+
+        list = GrammarHelper.parseToStringList("Abc   Def");
+        assertTrue(list.size() == 2);
+        assertTrue(list.equals(Arrays.asList("Abc", "Def")));
+
+        list = GrammarHelper.parseToStringList("  Abc Def");
+        assertTrue(list.size() == 2);
+        assertTrue(list.equals(Arrays.asList("Abc", "Def")));
+
+        list = GrammarHelper.parseToStringList("Abc Def\n");
+        assertTrue(list.size() == 2);
+        assertTrue(list.equals(Arrays.asList("Abc", "Def")));
+
+        list = GrammarHelper.parseToStringList("Abc :Def");
+        assertTrue(list.size() == 2);
+        assertTrue(list.equals(Arrays.asList("Abc", ":Def")));
+    }
+
+    @Test
+    public void test_is_unquotable_string() {
+
+        assertTrue(GrammarHelper.isUnquotableString("") == false);
+
+        assertTrue(GrammarHelper.isUnquotableString("ABC") == true);
+        assertTrue(GrammarHelper.isUnquotableString("a-yang-identifier") == true);
+
+        assertTrue(GrammarHelper.isUnquotableString("// inline comment") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC // inline comment") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC /* start block comment") == false);
+        assertTrue(GrammarHelper.isUnquotableString("/* start block comment") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC */ end block comment") == false);
+        assertTrue(GrammarHelper.isUnquotableString("*/ end block comment") == false);
+
+        assertTrue(GrammarHelper.isUnquotableString(" ") == false);
+        assertTrue(GrammarHelper.isUnquotableString("\t") == false);
+        assertTrue(GrammarHelper.isUnquotableString("\n") == false);
+        assertTrue(GrammarHelper.isUnquotableString("\r") == false);
+        assertTrue(GrammarHelper.isUnquotableString("'") == false);
+        assertTrue(GrammarHelper.isUnquotableString("\"") == false);
+        assertTrue(GrammarHelper.isUnquotableString(";") == false);
+        assertTrue(GrammarHelper.isUnquotableString("{") == false);
+        assertTrue(GrammarHelper.isUnquotableString("}") == false);
+        assertTrue(GrammarHelper.isUnquotableString("+") == false);
+
+        assertTrue(GrammarHelper.isUnquotableString("ABC DEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC\tDEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC\nDEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC\rDEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC'DEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC\"DEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC;DEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC{DEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC}DEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABC+DEF") == false);
+
+        assertTrue(GrammarHelper.isUnquotableString("ABCDEF ") == false);
+        assertTrue(GrammarHelper.isUnquotableString("\tABCDEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("}ABCDEF") == false);
+        assertTrue(GrammarHelper.isUnquotableString("ABCDEF+") == false);
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/NumberHelperTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/NumberHelperTest.java
new file mode 100644
index 0000000..7e30abc
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/NumberHelperTest.java
@@ -0,0 +1,144 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.util.DataTypeHelper.YangDataType;
+import org.oran.smo.yangtools.parser.model.util.NumberHelper;
+
+public class NumberHelperTest {
+
+    @Test
+    public void test_get_min_value_for_integer_type() {
+
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.UINT8).equals(BigDecimal.ZERO));
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.UINT16).equals(BigDecimal.ZERO));
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.UINT32).equals(BigDecimal.ZERO));
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.UINT64).equals(BigDecimal.ZERO));
+
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.INT8).equals(BigDecimal.valueOf(
+                Byte.MIN_VALUE)));
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.INT16).equals(BigDecimal.valueOf(
+                Short.MIN_VALUE)));
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.INT32).equals(BigDecimal.valueOf(
+                Integer.MIN_VALUE)));
+        assertTrue(NumberHelper.getMinValueForYangIntegerDataType(YangDataType.INT64).equals(BigDecimal.valueOf(
+                Long.MIN_VALUE)));
+
+        try {
+            NumberHelper.getMinValueForYangIntegerDataType(YangDataType.STRING);
+            fail("Should have thrown");
+        } catch (final Exception ignore) {
+        }
+    }
+
+    @Test
+    public void test_get_max_value_for_integer_type() {
+
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.UINT8).equals(BigDecimal.valueOf(
+                ((long) Byte.MAX_VALUE) * 2 + 1)));
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.UINT16).equals(BigDecimal.valueOf(
+                ((long) Short.MAX_VALUE) * 2 + 1)));
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.UINT32).equals(BigDecimal.valueOf(
+                ((long) Integer.MAX_VALUE) * 2 + 1)));
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.UINT64).equals(new BigDecimal(
+                "18446744073709551615")));
+
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.INT8).equals(BigDecimal.valueOf(
+                Byte.MAX_VALUE)));
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.INT16).equals(BigDecimal.valueOf(
+                Short.MAX_VALUE)));
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.INT32).equals(BigDecimal.valueOf(
+                Integer.MAX_VALUE)));
+        assertTrue(NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.INT64).equals(BigDecimal.valueOf(
+                Long.MAX_VALUE)));
+
+        try {
+            NumberHelper.getMaxValueForYangIntegerDataType(YangDataType.STRING);
+            fail("Should have thrown");
+        } catch (final Exception ignore) {
+        }
+    }
+
+    @Test
+    public void test_get_integer_default_value() {
+        assertTrue(NumberHelper.getIntegerDefaultValue("0").equals(BigInteger.valueOf(0)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("+0").equals(BigInteger.valueOf(0)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("-0").equals(BigInteger.valueOf(0)));
+
+        assertTrue(NumberHelper.getIntegerDefaultValue("00").equals(BigInteger.valueOf(0)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("+00").equals(BigInteger.valueOf(0)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("-00").equals(BigInteger.valueOf(0)));
+
+        assertTrue(NumberHelper.getIntegerDefaultValue("10").equals(BigInteger.valueOf(10)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("+10").equals(BigInteger.valueOf(10)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("-10").equals(BigInteger.valueOf(-10)));
+
+        assertTrue(NumberHelper.getIntegerDefaultValue("0x10").equals(BigInteger.valueOf(16)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("0x100").equals(BigInteger.valueOf(256)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("+0x10").equals(BigInteger.valueOf(16)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("+0x100").equals(BigInteger.valueOf(256)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("-0x10").equals(BigInteger.valueOf(-16)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("-0x100").equals(BigInteger.valueOf(-256)));
+
+        assertTrue(NumberHelper.getIntegerDefaultValue("010").equals(BigInteger.valueOf(8)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("0100").equals(BigInteger.valueOf(64)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("+010").equals(BigInteger.valueOf(8)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("+0100").equals(BigInteger.valueOf(64)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("-010").equals(BigInteger.valueOf(-8)));
+        assertTrue(NumberHelper.getIntegerDefaultValue("-0100").equals(BigInteger.valueOf(-64)));
+
+        assertTrue(NumberHelper.getIntegerDefaultValue("0x") == null);
+        assertTrue(NumberHelper.getIntegerDefaultValue("") == null);
+        assertTrue(NumberHelper.getIntegerDefaultValue(" ") == null);
+        assertTrue(NumberHelper.getIntegerDefaultValue("ABC") == null);
+    }
+
+    @Test
+    public void test_get_min_value_for_yang_decimal_data_type() {
+        assertTrue(NumberHelper.getMinValueForYangDecimalDataType(0) == null);
+        assertTrue(NumberHelper.getMinValueForYangDecimalDataType(1).equals(BigDecimal.valueOf(Long.MIN_VALUE).divide(
+                BigDecimal.valueOf(10))));
+        assertTrue(NumberHelper.getMinValueForYangDecimalDataType(2).equals(BigDecimal.valueOf(Long.MIN_VALUE).divide(
+                BigDecimal.valueOf(100))));
+        assertTrue(NumberHelper.getMinValueForYangDecimalDataType(3).equals(BigDecimal.valueOf(Long.MIN_VALUE).divide(
+                BigDecimal.valueOf(1000))));
+    }
+
+    @Test
+    public void test_get_max_value_for_yang_decimal_data_type() {
+        assertTrue(NumberHelper.getMaxValueForYangDecimalDataType(0) == null);
+        assertTrue(NumberHelper.getMaxValueForYangDecimalDataType(1).equals(BigDecimal.valueOf(Long.MAX_VALUE).divide(
+                BigDecimal.valueOf(10))));
+        assertTrue(NumberHelper.getMaxValueForYangDecimalDataType(2).equals(BigDecimal.valueOf(Long.MAX_VALUE).divide(
+                BigDecimal.valueOf(100))));
+        assertTrue(NumberHelper.getMaxValueForYangDecimalDataType(3).equals(BigDecimal.valueOf(Long.MAX_VALUE).divide(
+                BigDecimal.valueOf(1000))));
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/PatternHelperTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/PatternHelperTest.java
new file mode 100644
index 0000000..aa05099
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/PatternHelperTest.java
@@ -0,0 +1,61 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.util.PatternHelper;
+
+public class PatternHelperTest {
+
+    @Test
+    public void test___patterns() {
+
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("ab*c"), "ac"));
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("ab*c"), "abbc"));
+
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("$ab*c"), "$abbc"));
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("^ab*c"), "^abbc"));
+
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("ab*c$"), "abbc$"));
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("ab*c^"), "abbc^"));
+
+        assertFalse(Pattern.matches(PatternHelper.toJavaPatternString("ab*c$"), "abbc"));
+        assertFalse(Pattern.matches(PatternHelper.toJavaPatternString("ab*c^"), "abbc"));
+
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("[abc]+"), "acb"));
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("[^abc]+"), "def"));
+
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("xy^[abc]+"), "xy^a"));
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("xy^[^abc]+"), "xy^d"));
+
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("^[a\\^]+"), "^a^"));
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("^[\\^a]+"), "^a^"));
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("^[a^]+"), "^a^"));
+
+        assertTrue(Pattern.matches(PatternHelper.toJavaPatternString("^$^$"), "^$^$"));
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/StringHelperTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/StringHelperTest.java
new file mode 100644
index 0000000..4def755
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/StringHelperTest.java
@@ -0,0 +1,72 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.util.StringHelper;
+
+public class StringHelperTest {
+
+    //    @Test
+    //    public void test_to_double_quoted_string(){
+    //
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString("").equals("\"\""));
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString(" ").equals("\" \""));
+    //
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString("ABC").equals("\"ABC\""));
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString("ABC ").equals("\"ABC \""));
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString(" ABC ").equals("\" ABC \""));
+    //
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString("AB\"C").equals("\"AB\\\"C\""));	// AB"C   -->   AB\"C
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString("AB\nC").equals("\"AB\\nC\""));		// AB<CR>C   -->   AB\nC
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString("AB\tC").equals("\"AB\\tC\""));		// AB<TAB>C   -->   AB\tC
+    //    	assertTrue(StringHelper.convertToDoubleQuotedString("AB\\C").equals("\"AB\\\\C\""));		// AB\C   -->   AB\\C
+    //    }
+
+    @Test
+    public void test_to_module_revision() {
+
+        assertTrue(StringHelper.getModuleNameAndRevision("module1", null).equals("'module1'"));
+        assertTrue(StringHelper.getModuleNameAndRevision("module1", "").equals("'module1'"));
+        assertTrue(StringHelper.getModuleNameAndRevision("module1", "revision1").equals("'module1/revision1'"));
+    }
+
+    @Test
+    public void test_list_to_string() {
+
+        final List<String> list = Arrays.asList("ABC", "DEF");
+
+        assertTrue(StringHelper.toString(list, null, null, null, null, null).equals("ABCDEF"));
+        assertTrue(StringHelper.toString(list, "", "", "", "", "").equals("ABCDEF"));
+
+        assertTrue(StringHelper.toString(list, "[", "]", "", "", "").equals("[ABCDEF]"));
+        assertTrue(StringHelper.toString(list, "[", "]", ",", "", "").equals("[ABC,DEF]"));
+        assertTrue(StringHelper.toString(list, "[", "]", ",", "{", "}").equals("[{ABC},{DEF}]"));
+
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/YangAnnotationTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/YangAnnotationTest.java
new file mode 100644
index 0000000..91631c7
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/YangAnnotationTest.java
@@ -0,0 +1,75 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.util.YangAnnotation;
+
+public class YangAnnotationTest {
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_all_ok() {
+
+        final YangAnnotation YangAnnotation1 = new YangAnnotation("namespace1", "module1", "name1");
+        final YangAnnotation YangAnnotation2 = new YangAnnotation("namespace1", "module1", "name1");
+
+        assertTrue(YangAnnotation1.equals(YangAnnotation1));
+        assertTrue(YangAnnotation1.equals(YangAnnotation2));
+        assertTrue(YangAnnotation2.equals(YangAnnotation1));
+        assertFalse(YangAnnotation1.equals(null));
+        assertFalse(YangAnnotation1.equals("whatever"));
+        assertFalse(YangAnnotation1.equals(new YangAnnotation("namespace2", "module2", "name2")));
+
+        final YangAnnotation YangAnnotation3 = new YangAnnotation("namespace1", "module1", "name2");
+        assertTrue(YangAnnotation3.getAnnotationName().equals("name2"));
+        assertTrue(YangAnnotation3.getAnnotationModuleName().equals("module1"));
+        assertTrue(YangAnnotation3.getAnnotationNamespace().equals("namespace1"));
+    }
+
+    @Test
+    public void test_failures() {
+
+        try {
+            new YangAnnotation(null, null, null);
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+
+        try {
+            new YangAnnotation("ns", null, null);
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+
+        try {
+            new YangAnnotation(null, "name", null);
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/YangIdentityTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/YangIdentityTest.java
new file mode 100644
index 0000000..d2c9bfb
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/util/test/YangIdentityTest.java
@@ -0,0 +1,75 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.util.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.util.YangIdentity;
+
+public class YangIdentityTest {
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test_all_ok() {
+
+        final YangIdentity YangIdentity1 = new YangIdentity("namespace1", "module1", "name1");
+        final YangIdentity YangIdentity2 = new YangIdentity("namespace1", "module1", "name1");
+
+        assertTrue(YangIdentity1.equals(YangIdentity1));
+        assertTrue(YangIdentity1.equals(YangIdentity2));
+        assertTrue(YangIdentity2.equals(YangIdentity1));
+        assertFalse(YangIdentity1.equals(null));
+        assertFalse(YangIdentity1.equals("whatever"));
+        assertFalse(YangIdentity1.equals(new YangIdentity("namespace2", "module2", "name2")));
+
+        final YangIdentity YangIdentity3 = new YangIdentity("namespace1", "module1", "name2");
+        assertTrue(YangIdentity3.getIdentityName().equals("name2"));
+        assertTrue(YangIdentity3.getIdentityModuleName().equals("module1"));
+        assertTrue(YangIdentity3.getIdentityNamespace().equals("namespace1"));
+    }
+
+    @Test
+    public void test_failures() {
+
+        try {
+            new YangIdentity(null, null, null);
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+
+        try {
+            new YangIdentity("ns", null, null);
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+
+        try {
+            new YangIdentity(null, "name", null);
+            fail();
+        } catch (final Throwable th) {
+            /* ignore */}
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/yangdom/test/BasicParsingTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/yangdom/test/BasicParsingTest.java
new file mode 100644
index 0000000..dd5c981
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/model/yangdom/test/BasicParsingTest.java
@@ -0,0 +1,498 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.model.yangdom.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YInput;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRpc;
+import org.oran.smo.yangtools.parser.model.statements.yang.YSubmodule;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class BasicParsingTest extends YangTestCommon {
+
+    @Test
+    public void test_empty_file() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/empty-file.yang"));
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 0);
+    }
+
+    @Test
+    public void test_semicolon_only() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/semicolon-only.yang"));
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 0);
+    }
+
+    @Test
+    public void test_hello_world() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/hello-world.yang"));
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 0);
+    }
+
+    @Test
+    public void test_no_left_brace() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/no-left-brace.yang"));
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 0);
+    }
+
+    @Test
+    public void test_junk_at_end() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/junk-at-end.yang"));
+        assertHasFindingOfType(ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("junk-at-end-module").size() == 1);
+    }
+
+    @Test
+    public void test_block_comments() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/block-comments.yang"));
+        assertNoFindings();
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("block-comments-module").size() == 1);
+    }
+
+    @Test
+    public void test_line_comments() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/line-comments.yang"));
+        assertNoFindings();
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("line-comment-module").size() == 1);
+    }
+
+    @Test
+    public void test_simple_module() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/simple-module.yang"));
+
+        final YModule simpleModule = getModule("simple-module");
+        assertTrue(simpleModule != null);
+
+        final YangDomElement moduleDomElement = simpleModule.getDomElement();
+        assertTrue(moduleDomElement.toString().equals("module simple-module"));
+        assertTrue(moduleDomElement.hashCode() == "'module simple-module'".hashCode());
+        assertTrue(moduleDomElement.getTrimmedValueOrNull().equals("simple-module"));
+
+        final YRpc rpc1 = getRpc(simpleModule, "rpc1");
+        assertTrue(rpc1.getDomElement().getNameValue().equals("'rpc rpc1'"));
+        assertTrue(rpc1.getDomElement().getNameValue().equals("'rpc rpc1'"));
+
+        final YInput input1 = rpc1.getInput();
+        assertTrue(input1.getDomElement().getNameValue().equals("'input'"));
+        assertTrue(input1.getDomElement().getNameValue().equals("'input'"));
+        assertTrue(input1.getDomElement().getTrimmedValueOrNull() == null);
+        assertTrue(input1.getDomElement().getParentElement() == rpc1.getDomElement());
+
+        assertTrue(input1.getDomElement().getChildren().size() == 2);
+        input1.getDomElement().getChildren().get(1).remove();
+        assertTrue(input1.getDomElement().getChildren().size() == 1);
+        assertTrue(input1.getDomElement().getChildren().get(0).getValue().equals("leaf1"));
+
+        assertTrue(input1.getDomElement().getSimplifiedPath().equals("/module=simple-module/rpc=rpc1/input"));
+
+        final YLeaf leaf4 = getLeaf(simpleModule, "leaf4");
+        assertTrue(leaf4.getDomElement().getSimplifiedPath().equals("/module=simple-module/leaf=leaf4"));
+
+        assertTrue(leaf4.getWhens().get(0).getDomElement().getSimplifiedPath().equals(
+                "/module=simple-module/leaf=leaf4/when=(../leaf3)"));
+
+        assertTrue(getLeaf(simpleModule, "leaf5").getDescription().getValue().equals("Hello World"));
+        assertTrue(getLeaf(simpleModule, "leaf6").getDescription().getValue().equals("Hello World"));
+        assertTrue(getLeaf(simpleModule, "leaf7").getDescription().getValue().equals("Hello World!"));
+    }
+
+    @Test
+    public void test_multiple_semicolons() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/multiple-semicolons.yang"));
+        assertHasFindingOfType(ParserFindingType.P055_SUPERFLUOUS_STATEMENT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("multiple-semicolons").size() == 1);
+    }
+
+    @Test
+    public void test_multiple_plus() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/multiple-plus.yang"));
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 1);
+    }
+
+    @Test
+    public void test_quoted_plus_unquoted() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/quoted-plus-unquoted.yang"));
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 1);
+    }
+
+    @Test
+    public void test_unquoted_plus_unquoted() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/unquoted-plus-unquoted.yang"));
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 0);
+    }
+
+    @Test
+    public void test_document_end_missing() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/document-end-missing.yang"));
+        assertHasFindingOfType(ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 1);
+    }
+
+    @Test
+    public void test_double_left_brace() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/double-left-brace.yang"));
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+    @Test
+    public void test_three_statements() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/three-statements.yang"));
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+    @Test
+    public void test_mult_statements_at_root() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/multiple-statements-at-root.yang"));
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 0);
+    }
+
+    @Test
+    public void test_weird_root() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/weird-root.yang"));
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+
+        assertTrue(yangDeviceModel.getModuleRegistry().getAllYangModels().size() == 0);
+    }
+
+    @Test
+    public void test_missing_and_ducplicate_statements() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-and-duplicate-statements.yang"));
+
+        final YModule module = getModule("missing-and-duplicate-statements");
+        assertTrue(module != null);
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertDomElementHasFindingOfType(cont1.getDomElement(), ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+
+        final YLeaf leaf1 = getLeaf(cont1, "leaf1");
+        assertDomElementHasFindingOfType(leaf1.getDomElement(), ParserFindingType.P018_ILLEGAL_CHILD_STATEMENT.toString());
+        assertStatementHasFindingOfType(leaf1.getMandatory(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        final YLeaf leaf2 = getLeaf(cont1, "leaf2");
+        assertStatementHasFindingOfType(leaf2.getType().getBases().get(0), ParserFindingType.P052_INVALID_YANG_IDENTIFIER
+                .toString());
+
+        final YLeaf leaf3 = getLeaf(cont1, "leaf3");
+        assertStatementHasFindingOfType(leaf3.getMandatory(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        final YContainer contWithWeirdCharacters = getContainer(module, "cont2_with_weird_%%_characters");
+        assertStatementHasFindingOfType(contWithWeirdCharacters, ParserFindingType.P052_INVALID_YANG_IDENTIFIER.toString());
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertDomElementHasFindingOfType(cont3.getDomElement().getChildren().get(0),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertDomElementHasFindingOfType(cont3.getDomElement().getChildren().get(1),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+
+        assertStatementHasFindingOfType(module.getDeviations().get(0),
+                ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+    }
+
+    @Test
+    public void test_missing_import_name() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-import-name.yang"));
+
+        final YModule module = getModule("missing-import-name");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-import-name").size() == 1);
+
+        assertStatementHasFindingOfType(module.getImports().get(0), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+    }
+
+    @Test
+    public void test_missing_prefix_under_import() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-import.yang",
+                "src/test/resources/model-yangdom/basic-parsing-test/basic-empty-module.yang"));
+
+        final YModule module = getModule("missing-prefix-under-import");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-prefix-under-import").size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-empty-module").size() == 1);
+
+        assertStatementHasFindingOfType(module.getImports().get(0), ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT
+                .toString());
+    }
+
+    @Test
+    public void test_missing_prefix_name_under_import() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-import.yang",
+                "src/test/resources/model-yangdom/basic-parsing-test/basic-empty-module.yang"));
+
+        final YModule module = getModule("missing-prefix-name-under-import");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-prefix-name-under-import").size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-empty-module").size() == 1);
+
+        assertStatementHasFindingOfType(module.getImports().get(0).getPrefix(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+    @Test
+    public void test_missing_include_name() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-include-name.yang"));
+
+        final YModule module = getModule("missing-include-name");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-include-name").size() == 1);
+
+        assertStatementHasFindingOfType(module.getIncludes().get(0), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+    }
+
+    @Test
+    public void test_missing_belongsto() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/basic-module-including.yang",
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto.yang"));
+
+        final YModule module = getModule("basic-module-including");
+        assertTrue(module != null);
+        final YSubmodule submodule = getSubModule("basic-submodule");
+        assertTrue(submodule != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-module-including").size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-submodule").size() == 1);
+
+        assertStatementHasFindingOfType(submodule, ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+    }
+
+    @Test
+    public void test_missing_belongsto_name() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/basic-module-including.yang",
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto-name.yang"));
+
+        final YModule module = getModule("basic-module-including");
+        assertTrue(module != null);
+        final YSubmodule submodule = getSubModule("basic-submodule");
+        assertTrue(submodule != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-module-including").size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-submodule").size() == 1);
+
+        assertStatementHasFindingOfType(submodule.getBelongsTo(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+    }
+
+    @Test
+    public void test_missing_prefix_under_belongsto() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/basic-module-including.yang",
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-belongsto.yang"));
+
+        final YModule module = getModule("basic-module-including");
+        assertTrue(module != null);
+        final YSubmodule submodule = getSubModule("basic-submodule");
+        assertTrue(submodule != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-module-including").size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-submodule").size() == 1);
+
+        assertStatementHasFindingOfType(submodule.getBelongsTo(), ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT
+                .toString());
+    }
+
+    @Test
+    public void test_missing_prefix_name_under_belongsto() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/basic-module-including.yang",
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-belongsto.yang"));
+
+        final YModule module = getModule("basic-module-including");
+        assertTrue(module != null);
+        final YSubmodule submodule = getSubModule("basic-submodule");
+        assertTrue(submodule != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-module-including").size() == 1);
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("basic-submodule").size() == 1);
+
+        assertStatementHasFindingOfType(submodule.getBelongsTo().getPrefix(),
+                ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+    @Test
+    public void test_missing_prefix() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-prefix.yang"));
+
+        final YModule module = getModule("missing-prefix");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-prefix").size() == 1);
+
+        assertStatementHasFindingOfType(module, ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+    }
+
+    @Test
+    public void test_missing_prefix_name() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name.yang"));
+
+        final YModule module = getModule("missing-prefix-name");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-prefix-name").size() == 1);
+
+        assertStatementHasFindingOfType(module.getPrefix(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+        assertFindingCount(1);
+    }
+
+    @Test
+    public void test_missing_namespace() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-namespace.yang"));
+
+        final YModule module = getModule("missing-namespace");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-namespace").size() == 1);
+
+        assertStatementHasFindingOfType(module, ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+        assertFindingCount(1);
+    }
+
+    @Test
+    public void test_missing_namespace_name() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-namespace-name.yang"));
+
+        final YModule module = getModule("missing-namespace-name");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-namespace-name").size() == 1);
+
+        assertStatementHasFindingOfType(module.getNamespace(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+        assertFindingCount(1);
+    }
+
+    @Test
+    public void test_missing_yangversion_version() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/missing-yangversion-version.yang"));
+
+        final YModule module = getModule("missing-yangversion-version");
+        assertTrue(module != null);
+
+        assertTrue(yangDeviceModel.getModuleRegistry().byModuleName("missing-yangversion-version").size() == 1);
+
+        assertStatementHasFindingOfType(module.getYangVersion(), ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT
+                .toString());
+        assertFindingCount(1);
+    }
+
+    @Test
+    public void test_dangling_block_comment() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/dangling-block-comment.yang"));
+        assertHasFindingOfType(ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString());
+    }
+
+    @Test
+    public void test_dangling_double_quote() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/dangling-double-quote.yang"));
+        assertHasFindingOfType(ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString());
+    }
+
+    @Test
+    public void test_dangling_single_quote() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/dangling-single-quote.yang"));
+        assertHasFindingOfType(ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString());
+    }
+
+    @Test
+    public void test_dangling_plus_token() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/dangling-plus-token.yang"));
+        assertHasFindingOfType(ParserFindingType.P014_INVALID_SYNTAX_AT_DOCUMENT_END.toString());
+    }
+
+    @Test
+    public void test_incorrect_string_concatenation() {
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/model-yangdom/basic-parsing-test/incorrect-string-concatenation.yang"));
+        assertHasFindingOfType(ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/CheckYangLibraryAgainstSchemaTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/CheckYangLibraryAgainstSchemaTest.java
new file mode 100644
index 0000000..30ddc94
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/CheckYangLibraryAgainstSchemaTest.java
@@ -0,0 +1,315 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.instance.DataTreeBuilderPredicate;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInputResolver;
+import org.oran.smo.yangtools.parser.input.YangInput;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class CheckYangLibraryAgainstSchemaTest extends YangTestCommon {
+
+    private static final String ROOT = "src/test/resources/basics/check-yl-against-schema/";
+
+    private static final List<File> SIMPLE_MODULE = Collections.singletonList(new File(ROOT + "simple-module.yang"));
+
+    private static final List<File> YANG_LIBRARY_MODULE_AND_DEPENDENCIES = Arrays.asList(new File(
+            ROOT + "yang-library-module-and-dependencies"));
+
+    private static final List<File> YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE = Arrays.asList(new File(
+            ROOT + "yang-library-module-and-dependencies"), new File(ROOT + "simple-module.yang"));
+
+    @Test
+    public void test_make_sure_models_are_ok() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(
+                YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE);
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        for (final YangInput absoluteImplements : resolvedYangInput) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        assertNoFindings();
+    }
+
+    @Test
+    public void test___yang_lib___input_simple_and_dependencies___yl_only_lists_simple() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(
+                YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE);
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+
+        for (final YangInput absoluteImplements : resolvedYangInput) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-simple-module-only.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * The YL and dependencies are not listed in the data, so we expect findings for each of the dependent models (4x).
+         */
+        assertHasFindingOfType(ParserFindingType.P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY.toString());
+        assertFindingCount(4);
+    }
+
+    @Test
+    public void test___yang_lib___input_simple_and_dependencies___yl_lists_all() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(
+                YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE);
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+
+        for (final YangInput absoluteImplements : resolvedYangInput) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-all-listed.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * All should be good - all modules supplied, all inside the data file.
+         */
+        assertNoFindings();
+    }
+
+    @Test
+    public void test___yang_lib___input_simple___yl_lists_simple_and_dependencies() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(SIMPLE_MODULE);
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+
+        for (final YangInput absoluteImplements : resolvedYangInput) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-all-listed.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * The YL-related modules are listed in the data, but don't exist in the input. Mismatch.
+         */
+        assertHasFindingOfType(ParserFindingType.P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY.toString());
+        assertFindingCount(4);
+    }
+
+    @Test
+    public void test___yang_lib___input_simple___yl_lists_simple() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(SIMPLE_MODULE);
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+
+        for (final YangInput absoluteImplements : resolvedYangInput) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-simple-module-only.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * Only the module listed in the YL, and only the module is in the input.
+         */
+        assertNoFindings();
+    }
+
+    @Test
+    public void test___yang_lib___input_simple___yl_lists_simple___conformance_mismatch() {
+
+        final Set<YangInput> resolvedYangInput1 = new FileBasedYangInputResolver(YANG_LIBRARY_MODULE_AND_DEPENDENCIES)
+                .getResolvedYangInput();
+        final Set<YangInput> resolvedYangInput2 = new FileBasedYangInputResolver(SIMPLE_MODULE).getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+
+        for (final YangInput absoluteImplements : resolvedYangInput1) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+        for (final YangInput absoluteImplements : resolvedYangInput2) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPORT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-all-listed-conformance-mismatch.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * The conformance type for the "simple module" is wrong. Note that 2 findings will be issued for mismatches...
+         */
+        assertHasFindingOfType(ParserFindingType.P085_MISMATCH_BETWEEN_INPUT_MODULES_AND_YANG_LIBRARY.toString());
+        assertFindingCount(2);
+    }
+
+    @Test
+    public void test___yang_lib___input_simple___yl_lists_simple___namespace_mismatch() {
+
+        final Set<YangInput> resolvedYangInput1 = new FileBasedYangInputResolver(
+                YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE).getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        for (final YangInput absoluteImplements : resolvedYangInput1) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-all-listed-namespace-mismatch.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * The namespace for the "simple module" is wrong.
+         */
+        assertHasFindingOfType(ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA.toString());
+        assertFindingCount(1);
+    }
+
+    @Test
+    public void test___yang_lib___input_simple___yl_lists_simple___feature_mismatch() {
+
+        final Set<YangInput> resolvedYangInput1 = new FileBasedYangInputResolver(
+                YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE).getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        for (final YangInput absoluteImplements : resolvedYangInput1) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-all-listed-feature-mismatch.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * The feature for the "simple module" is wrong.
+         */
+        assertHasFindingOfType(ParserFindingType.P083_FEATURE_LISTED_IN_YANG_LIBRARY_NOT_FOUND.toString());
+        assertFindingCount(1);
+    }
+
+    @Test
+    public void test___yang_lib___input_simple___yl_lists_simple___features_ok() {
+
+        final Set<YangInput> resolvedYangInput1 = new FileBasedYangInputResolver(
+                YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE).getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        for (final YangInput absoluteImplements : resolvedYangInput1) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        // - - - - - - - - -
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-yang-library-all-listed-features-ok.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        assertNoFindings();
+    }
+
+    @Test
+    public void test_all_supplied___module_data_only() {
+
+        final FileBasedYangInputResolver resolver = new FileBasedYangInputResolver(
+                YANG_LIBRARY_MODULE_AND_DEPENDENCIES_AND_SIMPLE_MODULE);
+        final Set<YangInput> resolvedYangInput = resolver.getResolvedYangInput();
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+
+        for (final YangInput absoluteImplements : resolvedYangInput) {
+            yangFiles.add(new YangModel(absoluteImplements, ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        final FileBasedYangInputResolver dataResolver = new FileBasedYangInputResolver(Collections.singletonList(new File(
+                ROOT + "data-module-data-only.xml")));
+
+        yangDeviceModel.parseYangData(context, dataResolver, DataTreeBuilderPredicate.ALLOW_ALL);
+
+        /*
+         * No YL data supplied at all. The data should parse fine. Should be no findings.
+         */
+        assertNoFindings();
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/FailFastTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/FailFastTest.java
new file mode 100644
index 0000000..61ee201
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/FailFastTest.java
@@ -0,0 +1,64 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class FailFastTest extends YangTestCommon {
+
+    @Test
+    public void test_fail_fast_off() {
+
+        context.setFailFast(false);
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/fail-fast-test/bad-module.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString());
+        assertHasFindingOfType(ParserFindingType.P037_UNRESOLVABLE_INCLUDE.toString());
+        assertHasFindingOfType(ParserFindingType.P131_UNRESOLVABLE_GROUPING.toString());
+
+        assertTrue(context.getFindingsManager().hasFindingOfType(ParserFindingType.P131_UNRESOLVABLE_GROUPING.toString()));
+
+        assertHasNotFindingOfType(ParserFindingType.P009_FAIL_FAST.toString());
+    }
+
+    @Test
+    public void test_fail_fast_on() {
+
+        context.setFailFast(true);
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/fail-fast-test/bad-module.yang"));
+
+        assertHasNotFindingOfType(ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString());
+        assertHasFindingOfType(ParserFindingType.P037_UNRESOLVABLE_INCLUDE.toString());
+        assertHasNotFindingOfType(ParserFindingType.P131_UNRESOLVABLE_GROUPING.toString());
+
+        assertHasFindingOfType(ParserFindingType.P009_FAIL_FAST.toString());
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/ParseIetfModulesTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/ParseIetfModulesTest.java
new file mode 100644
index 0000000..ed980e9
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/ParseIetfModulesTest.java
@@ -0,0 +1,165 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.ThreeGppExtensionsClassSupplier;
+
+public class ParseIetfModulesTest {
+
+    private static final String ORIG_IANA_CRYPT_HASH = "src/test/resources/_orig-modules/iana-crypt-hash-2014-08-06.yang";
+
+    private static final String ORIG_IETF_YANG_TYPES = "src/test/resources/_orig-modules/ietf-yang-types-2019-11-04.yang";
+    private static final String ORIG_IETF_INET_TYPES = "src/test/resources/_orig-modules/ietf-inet-types-2019-11-04.yang";
+
+    private static final String ORIG_IETF_CRYPTO_TYPES = "src/test/resources/_orig-modules/ietf-crypto-types-2019-11-20.yang";
+    private static final String ORIG_IETF_DATASTORES = "src/test/resources/_orig-modules/ietf-datastores-2018-02-14.yang";
+    private static final String ORIG_IETF_INTERFACES = "src/test/resources/_orig-modules/ietf-interfaces-2018-02-20.yang";
+    private static final String ORIG_IETF_IP = "src/test/resources/_orig-modules/ietf-ip-2018-02-22.yang";
+    private static final String ORIG_IETF_KEYSTORE = "src/test/resources/_orig-modules/ietf-keystore-2019-11-20.yang";
+    private static final String ORIG_IETF_NETCONF = "src/test/resources/_orig-modules/ietf-netconf-2011-06-01.yang";
+    private static final String ORIG_IETF_NETCONF_ACM = "src/test/resources/_orig-modules/ietf-netconf-acm-2018-02-14.yang";
+    private static final String ORIG_IETF_NETCONF_CLIENT = "src/test/resources/_orig-modules/ietf-netconf-client-2019-11-20.yang";
+    private static final String ORIG_IETF_NETCONF_MONITORING = "src/test/resources/_orig-modules/ietf-netconf-monitoring-2010-10-04.yang";
+    private static final String ORIG_IETF_NETCONF_NOTIFICATIONS = "src/test/resources/_orig-modules/ietf-netconf-notifications-2012-02-06.yang";
+    private static final String ORIG_IETF_NETCONF_SERVER = "src/test/resources/_orig-modules/ietf-netconf-server-2018-09-20.yang";
+    private static final String ORIG_IETF_NETCONF_WITH_DEFAULTS = "src/test/resources/_orig-modules/ietf-netconf-with-defaults-2011-06-01.yang";
+    private static final String ORIG_IETF_NETWORK_INSTANCE = "src/test/resources/_orig-modules/ietf-network-instance-2019-01-21.yang";
+    private static final String ORIG_IETF_RESTCONF = "src/test/resources/_orig-modules/ietf-restconf-2017-01-26.yang";
+    private static final String ORIG_IETF_RESTCONF_MONITORING = "src/test/resources/_orig-modules/ietf-restconf-monitoring-2017-01-26.yang";
+    private static final String ORIG_IETF_SSH_CLIENT = "src/test/resources/_orig-modules/ietf-ssh-client-2019-11-20.yang";
+    private static final String ORIG_IETF_SSH_COMMON = "src/test/resources/_orig-modules/ietf-ssh-common-2019-11-20.yang";
+    private static final String ORIG_IETF_SSH_SERVER = "src/test/resources/_orig-modules/ietf-ssh-server-2019-11-20-yang";
+    private static final String ORIG_IETF_SUBSCRIBED_NOTIFICATIONS = "src/test/resources/_orig-modules/ietf-subscribed-notifications-2019-05-06.yang";
+    private static final String ORIG_IETF_SYSTEM = "src/test/resources/_orig-modules/ietf-system-2014-08-06.yang";
+    private static final String ORIG_IETF_TCP_CLIENT = "src/test/resources/_orig-modules/ietf-tcp-client-2019-10-18.yang";
+    private static final String ORIG_IETF_TCP_COMMON = "src/test/resources/_orig-modules/ietf-tcp-common-2019-10-18.yang";
+    private static final String ORIG_IETF_TCP_SERVER = "src/test/resources/_orig-modules/ietf-tcp-server-2019-10-18.yang";
+    private static final String ORIG_IETF_TLS_CLIENT = "src/test/resources/_orig-modules/ietf-tls-client-2019-11-20.yang";
+    private static final String ORIG_IETF_TLS_COMMON = "src/test/resources/_orig-modules/ietf-tls-common-2019-11-20.yang";
+    private static final String ORIG_IETF_TLS_SERVER = "src/test/resources/_orig-modules/ietf-tls-server-2019-11-20.yang";
+
+    private static final String ORIG_IETF_TRUST_ANCHORS = "src/test/resources/_orig-modules/ietf-trust-anchors-2019-04-29.yang";
+    private static final String ORIG_IETF_TRUSTSTORE = "src/test/resources/_orig-modules/ietf-truststore-2019-11-20.yang";
+    private static final String ORIG_IETF_X509_CERT_TO_NAME = "src/test/resources/_orig-modules/ietf-x509-cert-to-name-2014-12-10.yang";
+
+    private static final String ORIG_IETF_YANG_LIBRARY = "src/test/resources/_orig-modules/ietf-yang-library-2019-01-04.yang";
+    private static final String ORIG_IETF_YANG_METADATA = "src/test/resources/_orig-modules/ietf-yang-metadata-2016-08-05.yang";
+    private static final String ORIG_IETF_YANG_PATCH = "src/test/resources/_orig-modules/ietf-yang-patch-2017-02-22.yang";
+    private static final String ORIG_IETF_YANG_PUSH = "src/test/resources/_orig-modules/ietf-yang-push-2019-05-21.yang";
+    private static final String ORIG_IETF_YANG_SCHEMA_MOUNT = "src/test/resources/_orig-modules/ietf-yang-schema-mount-2019-01-14.yang";
+
+    @Test
+    public void test_all_ietf() {
+
+        YangDeviceModel yangDeviceModel;
+        ModifyableFindingSeverityCalculator severityCalculator;
+        FindingsManager findingsManager;
+        ParserExecutionContext context;
+
+        yangDeviceModel = new YangDeviceModel("Yang Parser JAR Test Device Model");
+        severityCalculator = new ModifyableFindingSeverityCalculator();
+        findingsManager = new FindingsManager(severityCalculator);
+
+        final ThreeGppExtensionsClassSupplier otherStatementFactory = new ThreeGppExtensionsClassSupplier();
+
+        context = new ParserExecutionContext(findingsManager, Arrays.asList(otherStatementFactory));
+        context.setFailFast(false);
+        context.setIgnoreImportedProtocolAccessibleObjects(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P144_BIT_WITHOUT_POSITION.toString());
+
+        final List<String> ietfModules = Arrays.asList(ORIG_IETF_YANG_TYPES, ORIG_IETF_INET_TYPES,
+
+                ORIG_IETF_DATASTORES, ORIG_IETF_INTERFACES, ORIG_IETF_IP, ORIG_IETF_NETCONF, ORIG_IETF_NETCONF_ACM,
+                ORIG_IETF_NETCONF_MONITORING, ORIG_IETF_NETCONF_NOTIFICATIONS, ORIG_IETF_NETCONF_WITH_DEFAULTS,
+                ORIG_IETF_NETWORK_INSTANCE, ORIG_IETF_RESTCONF, ORIG_IETF_RESTCONF_MONITORING,
+                ORIG_IETF_SUBSCRIBED_NOTIFICATIONS, ORIG_IETF_SYSTEM, ORIG_IETF_TCP_CLIENT, ORIG_IETF_TCP_COMMON,
+                ORIG_IETF_TCP_SERVER, ORIG_IETF_X509_CERT_TO_NAME, ORIG_IETF_YANG_LIBRARY, ORIG_IETF_YANG_METADATA,
+                ORIG_IETF_YANG_PATCH, ORIG_IETF_YANG_PUSH, ORIG_IETF_YANG_SCHEMA_MOUNT,
+
+                ORIG_IANA_CRYPT_HASH
+
+        /*
+         * All of the below are not stable, i.e. not released as RFCs yet.
+         *
+         * They use import-by-revision. We will not process these for now.
+         */
+
+        //				ORIG_IETF_CRYPTO_TYPES,
+        //				ORIG_IETF_KEYSTORE,
+        //				ORIG_IETF_NETCONF_CLIENT,
+        //				ORIG_IETF_NETCONF_SERVER,
+        //				ORIG_IETF_SSH_CLIENT,
+        //				ORIG_IETF_SSH_COMMON,
+        //				ORIG_IETF_SSH_SERVER,
+        //				ORIG_IETF_TLS_CLIENT,
+        //				ORIG_IETF_TLS_COMMON,
+        //				ORIG_IETF_TLS_SERVER,
+        //				ORIG_IETF_TRUST_ANCHORS,
+        //				ORIG_IETF_TRUSTSTORE,
+        );
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+        for (final String absoluteImplementsFilePath : ietfModules) {
+            yangFiles.add(new YangModel(new FileBasedYangInput(new File(absoluteImplementsFilePath)),
+                    ConformanceType.IMPLEMENT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        assertTrue(findingsManager.getAllFindings().size() == 0);
+
+        printFindings(findingsManager.getAllFindings());
+    }
+
+    private void printFindings(final Set<Finding> findings) {
+
+        final List<String> collect = findings.stream().map(Finding::toString).collect(Collectors.toList());
+        Collections.sort(collect);
+        collect.forEach(System.err::println);
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/UnsatisfiedIfFeatureRemoveTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/UnsatisfiedIfFeatureRemoveTest.java
new file mode 100644
index 0000000..8d27314
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/UnsatisfiedIfFeatureRemoveTest.java
@@ -0,0 +1,902 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YCase;
+import org.oran.smo.yangtools.parser.model.statements.yang.YChoice;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.util.YangFeature;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class UnsatisfiedIfFeatureRemoveTest extends YangTestCommon {
+
+    private static final String MODULE1 = "src/test/resources/basics/unsatisfied-if-feature-remove-test/module1.yang";
+    private static final String MODULE2 = "src/test/resources/basics/unsatisfied-if-feature-remove-test/module2.yang";
+    private static final String SUBMODULE3 = "src/test/resources/basics/unsatisfied-if-feature-remove-test/submodule3.yang";
+
+    @Test
+    public void test_module1_no_removal_no_supported_features() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertTrue(leaf11 != null);
+
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertTrue(leaf12 != null);
+
+        final YLeaf leaf13 = getLeaf(cont1, "leaf13");
+        assertTrue(leaf13 != null);
+
+        final YLeaf leaf14 = getLeaf(cont1, "leaf14");
+        assertTrue(leaf14 != null);
+    }
+
+    @Test
+    public void test_module1_no_removal_with_supported_features() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature11"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature12"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature13"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature14"));
+
+        context.setSupportedFeatures(supportedFeatures);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertTrue(leaf11 != null);
+
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertTrue(leaf12 != null);
+
+        final YLeaf leaf13 = getLeaf(cont1, "leaf13");
+        assertTrue(leaf13 != null);
+
+        final YLeaf leaf14 = getLeaf(cont1, "leaf14");
+        assertTrue(leaf14 != null);
+    }
+
+    @Test
+    public void test_module1_with_removal_no_supported_features() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        assertTrue(getLeaf(cont1, "leaf11") == null);
+        assertTrue(getLeaf(cont1, "leaf12") == null);
+        assertTrue(getLeaf(cont1, "leaf13") == null);
+        assertTrue(getLeaf(cont1, "leaf14") == null);
+
+        final YContainer cont2 = getContainer(module, "cont2");
+        assertTrue(cont2 != null);
+        final YChoice choice21 = getChoice(cont2, "choice21");
+        assertTrue(choice21 != null);
+
+        assertTrue(getCase(choice21, "case211") == null);
+        assertTrue(getCase(choice21, "case212") == null);
+        assertTrue(getCase(choice21, "case213") == null);
+        assertTrue(getCase(choice21, "case214") == null);
+        assertTrue(getCase(choice21, "leaf215") == null);
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertTrue(cont3 != null);
+
+        assertTrue(getLeaf(cont3, "leaf51") == null);
+        assertTrue(getLeaf(cont3, "leaf52") == null);
+        assertTrue(getLeaf(cont3, "leaf53") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_supported_features() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature11"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature12"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature13"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature14"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertTrue(leaf11 != null);
+
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertTrue(leaf12 != null);
+
+        final YLeaf leaf13 = getLeaf(cont1, "leaf13");
+        assertTrue(leaf13 != null);
+
+        final YLeaf leaf14 = getLeaf(cont1, "leaf14");
+        assertTrue(leaf14 != null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature11_only() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature11"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertTrue(leaf11 != null);
+
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertTrue(leaf12 == null);
+
+        final YLeaf leaf13 = getLeaf(cont1, "leaf13");
+        assertTrue(leaf13 != null);
+
+        final YLeaf leaf14 = getLeaf(cont1, "leaf14");
+        assertTrue(leaf14 == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature11_and_feature12() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature11"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature12"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertTrue(leaf11 != null);
+
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertTrue(leaf12 != null);
+
+        final YLeaf leaf13 = getLeaf(cont1, "leaf13");
+        assertTrue(leaf13 != null);
+
+        final YLeaf leaf14 = getLeaf(cont1, "leaf14");
+        assertTrue(leaf14 == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature12_and_feature13() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature12"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature13"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont1 = getContainer(module, "cont1");
+        assertTrue(cont1 != null);
+
+        final YLeaf leaf11 = getLeaf(cont1, "leaf11");
+        assertTrue(leaf11 == null);
+
+        final YLeaf leaf12 = getLeaf(cont1, "leaf12");
+        assertTrue(leaf12 != null);
+
+        final YLeaf leaf13 = getLeaf(cont1, "leaf13");
+        assertTrue(leaf13 != null);
+
+        final YLeaf leaf14 = getLeaf(cont1, "leaf14");
+        assertTrue(leaf14 == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature13_and_feature14() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature13"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature14"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        final YModule module = getModule("module1");
+
+        /*
+         * Should have resulted in a finding - feature 14 depends on 11 and 12, and these are not set.
+         */
+
+        assertStatementHasFindingOfType(getFeature(module, "feature14"), ParserFindingType.P086_FEATURE_CANNOT_BE_SUPPORTED
+                .toString());
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature16() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature16"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont2 = getContainer(module, "cont2");
+        assertTrue(cont2 != null);
+
+        final YChoice choice21 = getChoice(cont2, "choice21");
+        assertTrue(choice21 != null);
+
+        assertTrue(choice21.getCases().size() == 1);
+
+        final YCase case211 = getCase(choice21, "case211");
+        assertTrue(case211 != null);
+        assertTrue(getLeaf(case211, "leaf211") != null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature18_and_feature19() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature18"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature19"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont2 = getContainer(module, "cont2");
+        assertTrue(cont2 != null);
+
+        final YChoice choice21 = getChoice(cont2, "choice21");
+        assertTrue(choice21 != null);
+
+        assertTrue(choice21.getCases().size() == 3);
+
+        final YCase case213 = getCase(choice21, "case213");
+        assertTrue(case213 != null);
+        assertTrue(getLeaf(case213, "leaf213") != null);
+
+        final YCase case214 = getCase(choice21, "case214");
+        assertTrue(case214 != null);
+        assertTrue(getLeaf(case214, "leaf214") != null);
+
+        final YCase case215 = getCase(choice21, "leaf215");
+        assertTrue(case215 != null);
+        assertTrue(getLeaf(case215, "leaf215") != null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature21() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature21"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertTrue(cont3 != null);
+
+        assertTrue(getLeaf(cont3, "leaf51") == null);
+        assertTrue(getLeaf(cont3, "leaf52") == null);
+        assertTrue(getLeaf(cont3, "leaf53") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature23() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature23"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertTrue(cont3 != null);
+
+        assertTrue(getLeaf(cont3, "leaf51") != null);
+        assertTrue(getLeaf(cont3, "leaf52") == null);
+        assertTrue(getLeaf(cont3, "leaf53") != null);
+
+        assertTrue(getLeaf(cont3, "leaf53").getType().getEnums().size() == 2);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature21_and_feature23() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature21"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature23"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertTrue(cont3 != null);
+
+        assertTrue(getLeaf(cont3, "leaf51") != null);
+        assertTrue(getLeaf(cont3, "leaf52") != null);
+        assertTrue(getLeaf(cont3, "leaf53") != null);
+
+        assertTrue(getLeaf(cont3, "leaf53").getType().getEnums().size() == 2);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature22_and_feature23() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature22"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature23"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P143_ENUM_WITHOUT_VALUE.toString());
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont3 = getContainer(module, "cont3");
+        assertTrue(cont3 != null);
+
+        assertTrue(getLeaf(cont3, "leaf51") != null);
+        assertTrue(getLeaf(cont3, "leaf52") == null);
+        assertTrue(getLeaf(cont3, "leaf53") != null);
+
+        assertTrue(getLeaf(cont3, "leaf53").getType().getEnums().size() == 3);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature31() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature31"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont4 = getContainer(module, "cont4");
+        assertTrue(cont4 != null);
+
+        assertTrue(getLeaf(cont4, "leaf91") != null);
+        assertTrue(getLeaf(cont4, "leaf92") == null);
+        assertTrue(getLeaf(cont4, "leaf93") == null);
+        assertTrue(getLeaf(cont4, "leaf94") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature31_and_module2_feature11() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature31"));
+        supportedFeatures.add(new YangFeature("urn:test:module2", "module2", "feature11"));	// !!!!! module2 !!!!!
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont4 = getContainer(module, "cont4");
+        assertTrue(cont4 != null);
+
+        assertTrue(getLeaf(cont4, "leaf91") != null);
+        assertTrue(getLeaf(cont4, "leaf92") != null);
+        assertTrue(getLeaf(cont4, "leaf93") != null);
+        assertTrue(getLeaf(cont4, "leaf94") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature31_and_feature11_of_both_modules() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature31"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature11"));
+        supportedFeatures.add(new YangFeature("urn:test:module2", "module2", "feature11"));	// !!!!! module2 !!!!!
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont4 = getContainer(module, "cont4");
+        assertTrue(cont4 != null);
+
+        assertTrue(getLeaf(cont4, "leaf91") != null);
+        assertTrue(getLeaf(cont4, "leaf92") != null);
+        assertTrue(getLeaf(cont4, "leaf93") != null);
+        assertTrue(getLeaf(cont4, "leaf94") != null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature51() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature51"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont5 = getContainer(module, "cont5");
+        assertTrue(cont5 != null);
+
+        assertTrue(getLeaf(cont5, "leaf51") != null);
+        assertTrue(getLeaf(cont5, "leaf52") == null);
+        assertTrue(getLeaf(cont5, "leaf53") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature52_and_feature58() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature52"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature58"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont5 = getContainer(module, "cont5");
+        assertTrue(cont5 != null);
+
+        assertTrue(getLeaf(cont5, "leaf51") == null);
+        assertTrue(getLeaf(cont5, "leaf52") != null);
+        assertTrue(getLeaf(cont5, "leaf53") != null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature52() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature52"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        final YModule module = getModule("module1");
+
+        assertStatementHasFindingOfType(getFeature(module, "feature52"), ParserFindingType.P086_FEATURE_CANNOT_BE_SUPPORTED
+                .toString());
+    }
+
+    @Test
+    public void test_module1_no_remove_thus_leaf61_does_exists() {
+
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(false);		// !!!!!! FALSE !!!!!!
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont6 = getContainer(module, "cont6");
+        assertTrue(cont6 != null);
+        assertTrue(getLeaf(cont6, "leaf61") != null);
+    }
+
+    @Test
+    public void test_module1_remove_thus_leaf61_not_exists() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont6 = getContainer(module, "cont6");
+        assertTrue(cont6 != null);
+        assertTrue(getLeaf(cont6, "leaf61") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature71() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature71"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont7 = getContainer(module, "cont7");
+        assertTrue(cont7 != null);
+
+        assertTrue(getLeaf(cont7, "leaf71") != null);
+        assertTrue(getLeaf(cont7, "leaf72") == null);
+        assertTrue(getLeaf(cont7, "leaf73") == null);
+        assertTrue(getLeaf(cont7, "leaf74") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature71_and_feature72() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature71"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature72"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont7 = getContainer(module, "cont7");
+        assertTrue(cont7 != null);
+
+        assertTrue(getLeaf(cont7, "leaf71") == null);
+        assertTrue(getLeaf(cont7, "leaf72") == null);
+        assertTrue(getLeaf(cont7, "leaf73") == null);
+        assertTrue(getLeaf(cont7, "leaf74") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature71_and_feature72_and_feature73() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature71"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature72"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature73"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont7 = getContainer(module, "cont7");
+        assertTrue(cont7 != null);
+
+        assertTrue(getLeaf(cont7, "leaf71") == null);
+        assertTrue(getLeaf(cont7, "leaf72") != null);
+        assertTrue(getLeaf(cont7, "leaf73") == null);
+        assertTrue(getLeaf(cont7, "leaf74") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature71_and_feature72_and_feature73_and_feature74() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature71"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature72"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature73"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature74"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont7 = getContainer(module, "cont7");
+        assertTrue(cont7 != null);
+
+        assertTrue(getLeaf(cont7, "leaf71") == null);
+        assertTrue(getLeaf(cont7, "leaf72") != null);
+        assertTrue(getLeaf(cont7, "leaf73") != null);
+        assertTrue(getLeaf(cont7, "leaf74") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature71_and_feature73_and_feature75() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature71"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature73"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature75"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont7 = getContainer(module, "cont7");
+        assertTrue(cont7 != null);
+
+        assertTrue(getLeaf(cont7, "leaf71") != null);
+        assertTrue(getLeaf(cont7, "leaf72") == null);
+        assertTrue(getLeaf(cont7, "leaf73") != null);
+        assertTrue(getLeaf(cont7, "leaf74") == null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature74() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature74"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont7 = getContainer(module, "cont7");
+        assertTrue(cont7 != null);
+
+        assertTrue(getLeaf(cont7, "leaf71") == null);
+        assertTrue(getLeaf(cont7, "leaf72") == null);
+        assertTrue(getLeaf(cont7, "leaf73") == null);
+        assertTrue(getLeaf(cont7, "leaf74") != null);
+    }
+
+    @Test
+    public void test_module1_with_removal_with_feature74_and_feature76() {
+
+        final Set<YangFeature> supportedFeatures = new HashSet<>();
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature74"));
+        supportedFeatures.add(new YangFeature("urn:test:module1", "module1", "feature76"));
+
+        context.setSupportedFeatures(supportedFeatures);
+        context.setRemoveSchemaNodesNotSatisfyingIfFeature(true);
+
+        severityCalculator.suppressFinding(ParserFindingType.P103_ILLEGAL_IF_FEATURE_SYNTAX.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P132_GROUPING_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+        parseAbsoluteImplementsYangModels(Arrays.asList(MODULE1, MODULE2, SUBMODULE3));
+
+        assertNoFindings();
+
+        final YModule module = getModule("module1");
+
+        final YContainer cont7 = getContainer(module, "cont7");
+        assertTrue(cont7 != null);
+
+        assertTrue(getLeaf(cont7, "leaf71") == null);
+        assertTrue(getLeaf(cont7, "leaf72") == null);
+        assertTrue(getLeaf(cont7, "leaf73") == null);
+        assertTrue(getLeaf(cont7, "leaf74") == null);
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/YangDeviceModelTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/YangDeviceModelTest.java
new file mode 100644
index 0000000..c7b5619
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/YangDeviceModelTest.java
@@ -0,0 +1,163 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.test;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ModuleAndFindingTypeAndSchemaNodePathFilterPredicate;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class YangDeviceModelTest extends YangTestCommon {
+
+    @Test
+    public void test_correct_modules_supplied() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yang-device-model-test/module1.yang",
+                "src/test/resources/basics/yang-device-model-test/module2.yang"));
+
+        assertNoFindings();
+    }
+
+    @Test
+    public void test_only_one_correct_module_supplied() {
+
+        suppressAllExcept(Arrays.asList(ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString(),
+                ParserFindingType.P131_UNRESOLVABLE_GROUPING.toString(), ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE
+                        .toString(), ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString()));
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yang-device-model-test/module1.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString());
+        assertHasFindingOfType(ParserFindingType.P131_UNRESOLVABLE_GROUPING.toString());
+        assertHasFindingOfType(ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+        assertHasFindingOfType(ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+    }
+
+    @Test
+    public void test_empty_module_not_filtered() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P005_NO_IMPLEMENTS.toString());
+
+        /*
+         * The module is empty, but no exception will be thrown.
+         */
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/basics/yang-device-model-test/empty-file.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+    }
+
+    @Test
+    public void test_empty_module_filtered() {
+
+        /*
+         * Will not be swallowed - a P013 cannot be suppressed.
+         */
+        severityCalculator.suppressFinding(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "empty-file*;*;*"));
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/basics/yang-device-model-test/empty-file.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P013_INVALID_SYNTAX_AT_DOCUMENT_ROOT.toString());
+    }
+
+    @Test
+    public void test_missing_prefix_not_filtered() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P005_NO_IMPLEMENTS.toString());
+
+        /*
+         * This is missing the prefix statement, which is absolutely vital. This will provoke a NPE during
+         * parsing. The NPE should be swallowed, at the same time there should be a finding on the missing prefix.
+         */
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/basics/yang-device-model-test/module-missing-prefix.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P019_MISSING_REQUIRED_CHILD_STATEMENT.toString());
+    }
+
+    @Test
+    public void test_missing_prefix_filtered() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P005_NO_IMPLEMENTS.toString());
+
+        /*
+         * As before, now filtered.
+         */
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "module-missing-prefix*;*;*"));
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/basics/yang-device-model-test/module-missing-prefix.yang"));
+
+        assertNoFindings();
+    }
+
+    @Test
+    public void test_correct_modules_plus_missing_prefix_filtered() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        /*
+         * The two modules are fine, the one with the missing prefix will be filtered.
+         */
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "module-missing-prefix*;*;*"));
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yang-device-model-test/module1.yang",
+                "src/test/resources/basics/yang-device-model-test/module2.yang",
+                "src/test/resources/basics/yang-device-model-test/module-missing-prefix.yang"));
+
+        assertNoFindings();
+    }
+
+    @Test
+    public void test_one_correct_module_plus_missing_prefix_filtered() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P133_GROUPING_USED_ONCE_ONLY.toString());
+
+        /*
+         * The fine-grained-filter takes care of the issues inside the module-missing-prefix,
+         * the rest is still correctly processed.
+         */
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "module-missing-prefix*;*;*"));
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yang-device-model-test/module1.yang",
+                "src/test/resources/basics/yang-device-model-test/module-missing-prefix.yang"));
+
+        assertHasFindingOfType(ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString());
+        assertHasFindingOfType(ParserFindingType.P131_UNRESOLVABLE_GROUPING.toString());
+        assertHasFindingOfType(ParserFindingType.P113_UNRESOLVABLE_DERIVED_TYPE.toString());
+        assertHasFindingOfType(ParserFindingType.P034_UNRESOLVABLE_IMPORT.toString());
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/YangDomWriteOutTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/YangDomWriteOutTest.java
new file mode 100644
index 0000000..4bbc30c
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/test/YangDomWriteOutTest.java
@@ -0,0 +1,335 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YAction;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.yangdom.OriginalFileNameOutputFileNameResolver;
+import org.oran.smo.yangtools.parser.model.yangdom.OutputFileNameResolver;
+import org.oran.smo.yangtools.parser.model.yangdom.OutputStreamResolver;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+
+public class YangDomWriteOutTest extends YangTestCommon {
+
+    private static final String OUT_DIR = "target/test-output/out-files";
+
+    @Test
+    public void testSimpleWriteOut() throws IOException {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yangdom-write-out-test/module1.yang"));
+
+        final YModule module = getModule("module1");
+        assertTrue(module != null);
+
+        // write out with default resolver
+
+        createCleanTargetDir();
+        yangDeviceModel.getTopLevelSchema().writeOut(new File(OUT_DIR));
+
+        assertTrue(new File(OUT_DIR, "module1-2020-09-30.yang").exists());
+
+        // write out with file-name resolver
+
+        createCleanTargetDir();
+        yangDeviceModel.getTopLevelSchema().writeOut(new File(OUT_DIR), new OriginalFileNameOutputFileNameResolver());
+
+        assertTrue(new File(OUT_DIR, "module1.yang").exists());
+
+        // write out with custom resolver
+
+        yangDeviceModel.getTopLevelSchema().writeOut(new File(OUT_DIR), new OutputFileNameResolver() {
+            @Override
+            public String getOutputFileNameForYangInput(YangModel yangModelInput) {
+                return "out-module.yang";
+            }
+        });
+
+        assertTrue(new File(OUT_DIR, "out-module.yang").exists());
+
+        // read back in the module and make sure content is correct.
+
+        setUp();
+        parseAbsoluteImplementsYangModels(Arrays.asList(new File(OUT_DIR, "out-module.yang").getAbsolutePath()));
+
+        final YModule module1 = getModule("module1");
+        assertTrue(module1 != null);
+
+        assertTrue(module1.getNamespace().getNamespace().equals("test:module1"));
+        assertTrue(module1.getRevisions().get(0).getValue().equals("2020-09-30"));
+
+        final YContainer cont1 = getContainer(module1, "cont1");
+        assertTrue(cont1 != null);
+
+        final YAction action11 = getChild(cont1, CY.ACTION, "action11");
+        assertTrue(action11 != null);
+
+        final YContainer cont112 = action11.getInput().getContainers().get(0);
+        assertTrue(cont112 != null);
+    }
+
+    @Test
+    public void testSimpleStreamOut() throws IOException {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yangdom-write-out-test/module1.yang"));
+
+        final YModule module = getModule("module1");
+        assertTrue(module != null);
+
+        // write out to stream
+
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        final OutputStreamResolver resolver = new OutputStreamResolver() {
+            @Override
+            public OutputStream getOutputStreamForYangInput(YangModel yangModelInput) {
+                return os;
+            }
+        };
+
+        yangDeviceModel.getTopLevelSchema().writeOut(resolver);
+
+        final byte[] streamResult = os.toByteArray();
+        assertTrue(streamResult.length > 0);
+
+        // write out the module to file
+
+        createCleanTargetDir();
+        yangDeviceModel.getTopLevelSchema().writeOut(new File(OUT_DIR), new OriginalFileNameOutputFileNameResolver());
+
+        assertTrue(new File(OUT_DIR, "module1.yang").exists());
+
+        // contents of file and byte[] must match exactly
+
+        final FileInputStream fis = new FileInputStream(new File(OUT_DIR, "module1.yang"));
+        final ByteArrayOutputStream fileBuffer = new ByteArrayOutputStream();
+
+        int nRead;
+        byte[] data = new byte[100000];
+
+        while ((nRead = fis.read(data, 0, data.length)) != -1) {
+            fileBuffer.write(data, 0, nRead);
+        }
+        fis.close();
+        final byte[] fileContents = fileBuffer.toByteArray();
+
+        assertTrue(streamResult.length == fileContents.length);
+    }
+
+    @Test
+    public void testWriteOutToFileChangedOnly() throws IOException {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yangdom-write-out-test/module1.yang"));
+
+        final YModule module = getModule("module1");
+        assertTrue(module != null);
+
+        final YContainer cont1 = module.getContainers().get(0);
+        cont1.getYangModelRoot().getDomDocumentRoot().setDomHasBeenModified();
+
+        createCleanTargetDir();
+        final List<YangModel> writeOutChanged = yangDeviceModel.getTopLevelSchema().writeOutChanged(new File(OUT_DIR),
+                new OriginalFileNameOutputFileNameResolver());
+
+        assertTrue(new File(OUT_DIR, "module1.yang").exists());
+        assertTrue(writeOutChanged.size() == 1);
+    }
+
+    @Test
+    public void testWriteOutToStreamChangedOnly() throws IOException {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yangdom-write-out-test/module1.yang"));
+
+        final YModule module = getModule("module1");
+        assertTrue(module != null);
+
+        final YContainer cont1 = module.getContainers().get(0);
+        cont1.getYangModelRoot().getDomDocumentRoot().setDomHasBeenModified();
+
+        // write out to stream
+
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        final OutputStreamResolver resolver = new OutputStreamResolver() {
+            @Override
+            public OutputStream getOutputStreamForYangInput(YangModel yangModelInput) {
+                return os;
+            }
+        };
+
+        final List<YangModel> writeOutChanged = yangDeviceModel.getTopLevelSchema().writeOutChanged(resolver);
+        assertTrue(writeOutChanged.size() == 1);
+
+        final byte[] streamResult = os.toByteArray();
+        assertTrue(streamResult.length > 0);
+    }
+
+    @Test
+    public void testWriteOutChangedOnlyButModuleNotChanged() throws IOException {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yangdom-write-out-test/module1.yang"));
+
+        final YModule module = getModule("module1");
+        assertTrue(module != null);
+
+        // Don't mark as modified, should not be written out.
+
+        //    	final YContainer cont1 = module.getContainers().get(0);
+        //    	cont1.getYangModelRoot().getDomDocumentRoot().setDomHasBeenModified();
+
+        createCleanTargetDir();
+        final List<YangModel> writeOutChanged = yangDeviceModel.getTopLevelSchema().writeOutChanged(new File(OUT_DIR),
+                new OriginalFileNameOutputFileNameResolver());
+
+        assertFalse(new File(OUT_DIR, "module1.yang").exists());
+        assertTrue(writeOutChanged.size() == 0);
+    }
+
+    @Test
+    public void testWeirdStringsAndCharactersWriteOut() throws IOException {
+
+        parseAbsoluteImplementsYangModels(Arrays.asList("src/test/resources/basics/yangdom-write-out-test/module1.yang"));
+        assertHasFindingOfType(ParserFindingType.P011_INVALID_CHARACTER_ESCAPING_IN_QUOTED_TEXT.toString());
+        assertHasFindingOfType(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString());
+
+        final YModule module = getModule("module1");
+        assertTrue(module != null);
+
+        checkDescriptions(module);
+
+        // write out with file-name resolver
+
+        createCleanTargetDir();
+        yangDeviceModel.getTopLevelSchema().writeOut(new File(OUT_DIR), new OriginalFileNameOutputFileNameResolver());
+
+        assertTrue(new File(OUT_DIR, "module1.yang").exists());
+
+        // read back in the module and make sure content is correct.
+
+        setUp();
+        parseAbsoluteImplementsYangModels(Arrays.asList(new File(OUT_DIR, "module1.yang").getAbsolutePath()));
+
+        /*
+         * The writing-out of the strings should have cleaned up any illegal escaping, so we shouldn't see this again.
+         */
+        assertHasFindingOfType(ParserFindingType.P101_EMPTY_DOCUMENTATION_VALUE.toString());
+
+        final YModule module1 = getModule("module1");
+        assertTrue(module1 != null);
+
+        checkDescriptions(module1);
+    }
+
+    private void checkDescriptions(final YModule module) {
+        final YContainer cont2 = getContainer(module, "cont2");
+        assertTrue(cont2 != null);
+
+        final YLeaf leaf21 = getLeaf(cont2, "leaf21");
+        assertTrue(leaf21.getDescription().getValue().equals("simple string with space character"));
+
+        final YLeaf leaf22 = getLeaf(cont2, "leaf22");
+        assertTrue(leaf22.getDescription().getValue().equals("simple string\twith tab character"));
+
+        final YLeaf leaf23 = getLeaf(cont2, "leaf23");
+        assertTrue(leaf23.getDescription().getValue().equals("simple string with \" escaped quote character"));
+
+        final YLeaf leaf24 = getLeaf(cont2, "leaf24");
+        assertTrue(leaf24.getDescription().getValue().equals("simple string with \\' escaped single-quote character"));
+
+        final YLeaf leaf25 = getLeaf(cont2, "leaf25");
+        assertTrue(leaf25.getDescription().getValue().equals("exact characters\ttab and quote \""));
+
+        final YLeaf leaf26 = getLeaf(cont2, "leaf26");
+        assertTrue(leaf26.getDescription().getValue().equals(
+                "exact characters stretching over\n   multiple lines - note three spaces at start of line"));
+
+        final YLeaf leaf27 = getLeaf(cont2, "leaf27");
+        assertTrue(leaf27.getDescription().getValue().equals("+"));
+
+        final YLeaf leaf28 = getLeaf(cont2, "leaf28");
+        assertTrue(leaf28.getDescription().getValue().equals(";"));
+
+        final YLeaf leaf29 = getLeaf(cont2, "leaf29");
+        assertTrue(leaf29.getDescription().getValue().equals(";;"));
+
+        final YLeaf leaf30 = getLeaf(cont2, "leaf30");
+        assertTrue(leaf30.getDescription().getValue().equals("Hello+World!"));
+
+        final YLeaf leaf31 = getLeaf(cont2, "leaf31");
+        assertTrue(leaf31.getDescription().getValue().equals("on next line"));
+
+        final YLeaf leaf32 = getLeaf(cont2, "leaf32");
+        assertTrue(leaf32.getDescription().getValue().equals("some on this line some on the next line"));
+
+        final YLeaf leaf33 = getLeaf(cont2, "leaf33");
+        assertTrue(leaf33.getDescription().getValue().equals("First paragraph. \nSecond paragraph."));
+
+        final YLeaf leaf34 = getLeaf(cont2, "leaf34");
+        assertTrue(leaf34.getDescription().getValue().equals("this_is_//_not_a_comment"));
+
+        final YLeaf leaf35 = getLeaf(cont2, "leaf35");
+        assertTrue(leaf35.getDescription().getValue().equals("this_is_/*_not_a_comment"));
+
+        final YLeaf leaf36 = getLeaf(cont2, "leaf36");
+        assertTrue(leaf36.getDescription().getValue().equals("this_is_*/_not_a_comment"));
+
+        final YLeaf leaf37 = getLeaf(cont2, "leaf37");
+        assertTrue(leaf37.getDescription().getValue().equals(""));
+
+        final YLeaf leaf38 = getLeaf(cont2, "leaf38");
+        assertTrue(leaf38.getDescription().getValue().equals("{"));
+
+        final YLeaf leaf39 = getLeaf(cont2, "leaf39");
+        assertTrue(leaf39.getDescription().getValue().equals("}"));
+
+        final YLeaf leaf40 = getLeaf(cont2, "leaf40");
+        assertTrue(leaf40.getDescription().getValue().equals("\""));
+    }
+
+    private void createCleanTargetDir() {
+
+        final File dir = new File(OUT_DIR);
+
+        if (!dir.exists()) {
+            dir.mkdirs();
+        }
+
+        final File[] listFiles = dir.listFiles();
+        for (final File file : listFiles) {
+            file.delete();
+        }
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/testutils/YangTestCommon.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/testutils/YangTestCommon.java
new file mode 100644
index 0000000..fdedeb8
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/testutils/YangTestCommon.java
@@ -0,0 +1,870 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.testutils;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+
+import org.oran.smo.yangtools.parser.ParserExecutionContext;
+import org.oran.smo.yangtools.parser.YangDeviceModel;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNode;
+import org.oran.smo.yangtools.parser.data.dom.YangDataDomNodeAnnotationValue;
+import org.oran.smo.yangtools.parser.data.instance.AbstractStructureInstance;
+import org.oran.smo.yangtools.parser.data.instance.AnyDataInstance;
+import org.oran.smo.yangtools.parser.data.instance.AnyXmlInstance;
+import org.oran.smo.yangtools.parser.data.instance.ContainerInstance;
+import org.oran.smo.yangtools.parser.data.instance.DataTreeBuilderPredicate;
+import org.oran.smo.yangtools.parser.data.instance.LeafInstance;
+import org.oran.smo.yangtools.parser.data.instance.LeafListInstance;
+import org.oran.smo.yangtools.parser.data.instance.ListInstance;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObject;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonObjectMemberName;
+import org.oran.smo.yangtools.parser.data.parser.JsonParser.JsonValue;
+import org.oran.smo.yangtools.parser.findings.Finding;
+import org.oran.smo.yangtools.parser.findings.FindingFilterPredicate;
+import org.oran.smo.yangtools.parser.findings.FindingsManager;
+import org.oran.smo.yangtools.parser.findings.ModifyableFindingSeverityCalculator;
+import org.oran.smo.yangtools.parser.findings.ModuleAndFindingTypeAndSchemaNodePathFilterPredicate;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInput;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInputResolver;
+import org.oran.smo.yangtools.parser.model.ConformanceType;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.YangModel;
+import org.oran.smo.yangtools.parser.model.schema.ModuleRegistry;
+import org.oran.smo.yangtools.parser.model.statements.AbstractStatement;
+import org.oran.smo.yangtools.parser.model.statements.ExtensionStatement;
+import org.oran.smo.yangtools.parser.model.statements.StatementModuleAndName;
+import org.oran.smo.yangtools.parser.model.statements.YangModelRoot;
+import org.oran.smo.yangtools.parser.model.statements.ietf.IetfExtensionsClassSupplier;
+import org.oran.smo.yangtools.parser.model.statements.oran.OranExtensionsClassSupplier;
+import org.oran.smo.yangtools.parser.model.statements.threegpp.ThreeGppExtensionsClassSupplier;
+import org.oran.smo.yangtools.parser.model.statements.yang.CY;
+import org.oran.smo.yangtools.parser.model.statements.yang.YAction;
+import org.oran.smo.yangtools.parser.model.statements.yang.YAugment;
+import org.oran.smo.yangtools.parser.model.statements.yang.YCase;
+import org.oran.smo.yangtools.parser.model.statements.yang.YChoice;
+import org.oran.smo.yangtools.parser.model.statements.yang.YContainer;
+import org.oran.smo.yangtools.parser.model.statements.yang.YDeviation;
+import org.oran.smo.yangtools.parser.model.statements.yang.YFeature;
+import org.oran.smo.yangtools.parser.model.statements.yang.YGrouping;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeaf;
+import org.oran.smo.yangtools.parser.model.statements.yang.YLeafList;
+import org.oran.smo.yangtools.parser.model.statements.yang.YList;
+import org.oran.smo.yangtools.parser.model.statements.yang.YModule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YNotification;
+import org.oran.smo.yangtools.parser.model.statements.yang.YRpc;
+import org.oran.smo.yangtools.parser.model.statements.yang.YSubmodule;
+import org.oran.smo.yangtools.parser.model.statements.yang.YType;
+import org.oran.smo.yangtools.parser.model.statements.yang.YTypedef;
+import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
+
+public class YangTestCommon {
+
+    public static final String YANG_FILE_EXTENSION = ".yang";
+
+    protected static final String TARGET_DIR = "target/test-output";
+
+    private static final String YANG_TEST_FILES = "src/test/resources/model-statements-yang/";
+
+    protected static final String ORIG_MODULES_PATH = "src/test/resources/_orig-modules/";
+
+    protected static final String THREEGPP_YANG_EXT_PATH = ORIG_MODULES_PATH + "_3gpp-common-yang-extensions-2022-10-20.yang";
+    protected static final String YANG_METADATA_PATH = ORIG_MODULES_PATH + "ietf-yang-metadata-2016-08-05.yang";
+    protected static final String YANG_ORIGIN_PATH = ORIG_MODULES_PATH + "ietf-origin-2018-02-14.yang";
+    protected static final String NETCONF_ACM_PATH = ORIG_MODULES_PATH + "ietf-netconf-acm-2018-02-14.yang";
+
+    protected YangDeviceModel yangDeviceModel;
+    protected ModifyableFindingSeverityCalculator severityCalculator;
+    protected FindingsManager findingsManager;
+    protected ParserExecutionContext context;
+
+    @Before
+    public void setUp() {
+        yangDeviceModel = new YangDeviceModel("Yang Parser JAR Test Device Model");
+
+        severityCalculator = new ModifyableFindingSeverityCalculator();
+
+        findingsManager = new FindingsManager(severityCalculator);
+        findingsManager.addFilterPredicate(ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.fromString(
+                "ietf*,iana*;*;*"));
+
+        createContext();
+
+        context.setFailFast(false);
+        context.setSuppressFindingsOnUnusedSchemaNodes(true);
+    }
+
+    protected void createContext() {
+
+        final ThreeGppExtensionsClassSupplier threeGppStatementFactory = new ThreeGppExtensionsClassSupplier();
+        final IetfExtensionsClassSupplier ietfStatementFactory = new IetfExtensionsClassSupplier();
+        final OranExtensionsClassSupplier oranStatementFactory = new OranExtensionsClassSupplier();
+
+        context = new ParserExecutionContext(findingsManager, Arrays.asList(threeGppStatementFactory, oranStatementFactory,
+                ietfStatementFactory));
+    }
+
+    protected void suppressAllExcept(final String findingType) {
+        suppressAllExcept(Collections.singletonList(findingType));
+    }
+
+    protected void suppressAllExcept(final List<String> findingTypes) {
+
+        final FindingFilterPredicate predicate = new FindingFilterPredicate() {
+            @Override
+            public boolean test(Finding t) {
+                return !findingTypes.contains(t.getFindingType());
+            }
+        };
+
+        findingsManager.addFilterPredicate(predicate);
+    }
+
+    protected void parseAbsoluteImplementsYangModels(final List<String> absoluteImplementsFilePaths) {
+        parseImplementsYangModels(Collections.<String> emptyList(), absoluteImplementsFilePaths);
+    }
+
+    protected void parseRelativeImplementsYangModels(final List<String> relativeImplementsFilePaths) {
+        parseImplementsYangModels(relativeImplementsFilePaths, Collections.<String> emptyList());
+    }
+
+    protected void parseImplementsYangModels(final List<String> relativeImplementsFilePaths,
+            final List<String> absoluteImplementsFilePaths) {
+        parseYangModels(relativeImplementsFilePaths, absoluteImplementsFilePaths, Collections.<String> emptyList(),
+                Collections.<String> emptyList());
+    }
+
+    protected void parseRelativeYangModels(final List<String> relativeImplementsFilePaths,
+            final List<String> relativeImportFilePaths) {
+        parseYangModels(relativeImplementsFilePaths, Collections.<String> emptyList(), relativeImportFilePaths, Collections
+                .<String> emptyList());
+    }
+
+    protected void parseAbsoluteYangModels(final List<String> absoluteImplementsFilePaths,
+            final List<String> absoluteImportFilePaths) {
+        parseYangModels(Collections.<String> emptyList(), absoluteImplementsFilePaths, Collections.<String> emptyList(),
+                absoluteImportFilePaths);
+    }
+
+    protected void parseYangModels(final List<String> relativeImplementsFilePaths,
+            final List<String> absoluteImplementsFilePaths, final List<String> relativeImportsFilePaths,
+            final List<String> absoluteImportsFilePaths) {
+
+        final List<YangModel> yangFiles = new ArrayList<>();
+
+        for (final String relativeImplementsFilePath : relativeImplementsFilePaths) {
+            yangFiles.add(new YangModel(new FileBasedYangInput(new File(YANG_TEST_FILES + relativeImplementsFilePath)),
+                    ConformanceType.IMPLEMENT));
+        }
+        for (final String absoluteImplementsFilePath : absoluteImplementsFilePaths) {
+            yangFiles.add(new YangModel(new FileBasedYangInput(new File(absoluteImplementsFilePath)),
+                    ConformanceType.IMPLEMENT));
+        }
+
+        for (final String relativeImportsFilePath : relativeImportsFilePaths) {
+            yangFiles.add(new YangModel(new FileBasedYangInput(new File(YANG_TEST_FILES + relativeImportsFilePath)),
+                    ConformanceType.IMPORT));
+        }
+        for (final String absoluteImportsFilePath : absoluteImportsFilePaths) {
+            yangFiles.add(new YangModel(new FileBasedYangInput(new File(absoluteImportsFilePath)), ConformanceType.IMPORT));
+        }
+
+        yangDeviceModel.parseIntoYangModels(context, yangFiles);
+
+        /*
+         * There should NEVER be a P000 finding, this would indicate a null objects wasn't handled somewhere.
+         */
+        assertHasNotFindingOfType(ParserFindingType.P000_UNSPECIFIED_ERROR.toString());
+    }
+
+    protected void parseRelativeYangData(final List<String> relativeFilePaths) {
+        final List<File> collect = relativeFilePaths.stream().map(relpath -> new File(YANG_TEST_FILES + relpath)).collect(
+                Collectors.toList());
+        yangDeviceModel.parseYangData(context, new FileBasedYangInputResolver(collect), new DataTreeBuilderPredicate());
+    }
+
+    protected void parseAbsoluteYangData(final List<String> absoluteFilePaths) {
+        final List<File> collect = absoluteFilePaths.stream().map(abspath -> new File(abspath)).collect(Collectors
+                .toList());
+        yangDeviceModel.parseYangData(context, new FileBasedYangInputResolver(collect), new DataTreeBuilderPredicate());
+    }
+
+    /**
+     * Get module from yangDeviceModel
+     */
+    public YModule getModule(final String moduleName) {
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+
+        for (final YangModel yangModelFile : moduleRegistry.getAllYangModels()) {
+            final YangModelRoot yangModelRoot = yangModelFile.getYangModelRoot();
+            final YModule yModule = yangModelRoot.getModule();
+            if ((yModule != null) && (yModule.getModuleName().equals(moduleName))) {
+                return yModule;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get sub-module from yangDeviceModel
+     */
+    public YSubmodule getSubModule(final String subModuleName) {
+
+        final ModuleRegistry moduleRegistry = yangDeviceModel.getModuleRegistry();
+        for (final YangModel yangModelFile : moduleRegistry.getAllYangModels()) {
+            final YangModelRoot yangModelRoot = yangModelFile.getYangModelRoot();
+            final YSubmodule ySubModule = yangModelRoot.getSubmodule();
+            if (ySubModule != null && ySubModule.getSubmoduleName().equals(subModuleName)) {
+                return ySubModule;
+            }
+        }
+        return null;
+    }
+
+    public static YRpc getRpc(final AbstractStatement parent, final String rpcName) {
+        return getChild(parent, CY.RPC, rpcName);
+    }
+
+    public static YContainer getContainer(final AbstractStatement parent, final String containerName) {
+        return getChild(parent, CY.CONTAINER, containerName);
+    }
+
+    public static YList getList(final AbstractStatement parent, final String listName) {
+        return getChild(parent, CY.LIST, listName);
+    }
+
+    public static YNotification getNotification(final AbstractStatement parent, final String notificationName) {
+        return getChild(parent, CY.NOTIFICATION, notificationName);
+    }
+
+    public static YChoice getChoice(final AbstractStatement parent, final String choiceName) {
+        return getChild(parent, CY.CHOICE, choiceName);
+    }
+
+    public static YCase getCase(final YChoice parent, final String caseName) {
+        return getChild(parent, CY.CASE, caseName);
+    }
+
+    public static YGrouping getGrouping(final YModule module, final String groupingName) {
+        return getChild(module, CY.GROUPING, groupingName);
+    }
+
+    public static YLeaf getLeaf(final AbstractStatement parent, final String leafName) {
+        return getChild(parent, CY.LEAF, leafName);
+    }
+
+    public static YAction getAction(final AbstractStatement parent, final String actionName) {
+        return getChild(parent, CY.ACTION, actionName);
+    }
+
+    public static YLeafList getLeafList(final AbstractStatement parent, final String leafListName) {
+        return getChild(parent, CY.LEAF_LIST, leafListName);
+    }
+
+    public YTypedef getTypedefForModule(final String moduleName, final String typedefName) {
+        final YModule module = getModule(moduleName);
+        return (YTypedef) (module == null ? null : getChild(module, CY.TYPEDEF, typedefName));
+    }
+
+    public static YTypedef getTypedef(final AbstractStatement parent, final String typedefName) {
+        return getChild(parent, CY.TYPEDEF, typedefName);
+    }
+
+    public static YAugment getAugment(final AbstractStatement parent, final String path) {
+        return getChild(parent, CY.AUGMENT, path);
+    }
+
+    public static YFeature getFeature(final AbstractStatement parent, final String featureName) {
+        return getChild(parent, CY.FEATURE, featureName);
+    }
+
+    public static YDeviation getDeviation(final AbstractStatement parent, final String path) {
+        return (YDeviation) parent.getChildStatements().stream().filter(stmt -> stmt.is(CY.STMT_DEVIATION)).filter(
+                stmt -> stmt.getDomElement().getValue().equals(path)).findAny().orElse(null);
+    }
+
+    public ExtensionStatement getExtension(final AbstractStatement parent, final String owningModuleName,
+            final String extensionName, final String argument) {
+        for (final ExtensionStatement extensionStatement : parent.getExtensionChildStatements()) {
+            final String prefix = extensionStatement.getExtensionModulePrefix();
+            final ModuleIdentity owningModule = extensionStatement.getPrefixResolver().getModuleForPrefix(prefix);
+            if (owningModuleName.equals(owningModule.getModuleName()) && extensionStatement.getExtensionStatementName()
+                    .equals(extensionName)) {
+                if (argument == null || (argument.equals(extensionStatement.getValue()))) {
+                    return extensionStatement;
+                }
+            }
+        }
+        return null;
+    }
+
+    public YContainer getContainerUnderContainer(final AbstractStatement parent, final String containerName1,
+            final String containerName2) {
+        final YContainer cont1 = getContainer(parent, containerName1);
+        return cont1 == null ? null : getContainer(cont1, containerName2);
+    }
+
+    public YLeafList getLeafListUnderContainer(final AbstractStatement parent, final String containerName,
+            final String leafListName) {
+        final YContainer cont1 = getContainer(parent, containerName);
+        return cont1 == null ? null : getLeafList(cont1, leafListName);
+    }
+
+    public YLeafList getLeafListUnderList(final AbstractStatement parent, final String listName,
+            final String leafListName) {
+        final YList list1 = getList(parent, listName);
+        return list1 == null ? null : getLeafList(list1, leafListName);
+    }
+
+    public YLeaf getLeafUnderContainer(final AbstractStatement parent, final String containerName, final String leafName) {
+        final YContainer cont1 = getContainer(parent, containerName);
+        return cont1 == null ? null : getLeaf(cont1, leafName);
+    }
+
+    public YLeaf getLeafUnderList(final AbstractStatement parent, final String listName, final String leafName) {
+        final YList list = getList(parent, listName);
+        return list == null ? null : getLeaf(list, leafName);
+    }
+
+    public YList getListUnderContainer(final AbstractStatement parent, final String containerName, final String listName) {
+        final YContainer cont1 = getContainer(parent, containerName);
+        return cont1 == null ? null : getList(cont1, listName);
+    }
+
+    /**
+     * Get leaflist from container (container-list-leaflist)
+     */
+    public YLeafList getLeafListFromContainerList(final YModule yModule, final String containerName,
+            final String leafListName) {
+
+        for (final YContainer container : yModule.getContainers()) {
+            if (container.getContainerName().equals(containerName)) {
+                for (final YList list : container.getLists()) {
+                    for (final YLeafList leafList : list.getLeafLists()) {
+                        if (leafList.getLeafListName().equals(leafListName)) {
+                            return leafList;
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     *
+     * Get leaf from container within another container (container-container-leaf)
+     */
+    public YLeaf getLeafFromContainerContainer(final YModule yModule, final String containerName1,
+            final String containerName2, final String leafName) {
+        for (final YContainer container : yModule.getContainers()) {
+            if (container.getContainerName().equals(containerName1)) {
+                for (final YContainer innerContainer : container.getContainers()) {
+                    if (innerContainer.getContainerName().equals(containerName2)) {
+                        return getLeaf(innerContainer, leafName);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get leaf from List within a container (container-list-leaf)
+     */
+    public YLeaf getLeafFromContainerList(final YModule yModule, final String containerName, final String listName,
+            final String leafName) {
+        final YList yList = getListUnderContainer(yModule, containerName, listName);
+        for (final YLeaf leaf : yList.getLeafs()) {
+            if (leaf.getLeafName().equals(leafName)) {
+                return leaf;
+            }
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends AbstractStatement> T getChild(final AbstractStatement parent, final String childType) {
+
+        if (parent == null) {
+            return null;
+        }
+
+        for (final AbstractStatement child : parent.getChildStatements()) {
+            if (child.getDomElement().getName().equals(childType)) {
+                return (T) child;
+            }
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T extends AbstractStatement> T getChild(final AbstractStatement parent, final String childType,
+            final String childName) {
+
+        if (parent == null) {
+            return null;
+        }
+
+        for (final AbstractStatement child : parent.getChildStatements()) {
+            if (child.getDomElement().getName().equals(childType)) {
+                if (childName == null && child.getDomElement().getValue() == null) {
+                    return (T) child;
+                } else if (childName != null && childName.equals(child.getDomElement().getValue())) {
+                    return (T) child;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends AbstractStatement> T getExtensionChild(final AbstractStatement parent, final String module,
+            final String extName) {
+
+        if (parent == null) {
+            return null;
+        }
+
+        for (final ExtensionStatement child : parent.getExtensionChildStatements()) {
+            final StatementModuleAndName childSman = child.getStatementModuleAndName();
+            if (childSman.getModuleName().equals(module) && childSman.getStatementName().equals(extName)) {
+                return (T) child;
+            }
+        }
+
+        return null;
+    }
+
+    public YangDomElement getDomChild(final YangDomElement domParent, final String domChildName,
+            final String domChildValue) {
+
+        if (domParent == null) {
+            return null;
+        }
+
+        for (final YangDomElement domChild : domParent.getChildren()) {
+            if (domChild.getName().equals(domChildName) && domChild.getValue().equals(domChildValue)) {
+                return domChild;
+            }
+        }
+
+        return null;
+    }
+
+    public YangDomElement getDomChild(final YangDomElement domParent, final String domChildName) {
+
+        if (domParent == null) {
+            return null;
+        }
+
+        for (final YangDomElement domChild : domParent.getChildren()) {
+            if (domChild.getName().equals(domChildName)) {
+                return domChild;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Get identityref type from leaf (leaf-type)
+     */
+    public YType getIdentityType(final YLeaf leaf) {
+        for (final YType type : leaf.getType().getTypes()) {
+            if (type.getDataType().equals("identityref")) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get a leaf from container by passing type.
+     */
+    public YLeaf getLeafOfTypeFromContainer(final YContainer container, final String type) {
+        for (final YLeaf yleaf : container.getLeafs()) {
+            if ((yleaf.getType().getDataType()).equals(type)) {
+                return yleaf;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get container from container (container-container)
+     */
+
+    /**
+     * Get case from choice within a container (container-choice-case)
+     */
+    public YCase getCaseFromChoiceContainer(final YModule yModule, final String containerName, final String choiceName,
+            final String caseName) {
+        final YChoice choice = getChoiceFromContainer(yModule, containerName, choiceName);
+        for (final YCase ycase : choice.getCases()) {
+            if (ycase.getCaseName().equals(caseName)) {
+                return ycase;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get choice from a container
+     */
+    public YChoice getChoiceFromContainer(final YModule yModule, final String containerName, final String choiceName) {
+        final YContainer container = getContainer(yModule, containerName);
+        for (final YChoice choice : container.getChoices()) {
+            if (choice.getChoiceName().equals(choiceName)) {
+                return choice;
+            }
+        }
+        return null;
+    }
+
+    protected LeafInstance getLeafInstance(final AbstractStructureInstance parent, final String namespace,
+            final String name) {
+        return parent.getLeafInstance(namespace, name);
+    }
+
+    protected ContainerInstance getContainerInstance(final AbstractStructureInstance parent, final String namespace,
+            final String name) {
+        return parent.getContainerInstance(namespace, name);
+    }
+
+    protected List<LeafListInstance> getLeafListInstances(final AbstractStructureInstance parent, final String namespace,
+            final String name) {
+        if (!parent.hasLeafListInstance(namespace, name)) {
+            return Collections.<LeafListInstance> emptyList();
+        }
+        return parent.getLeafListInstances(namespace, name);
+    }
+
+    protected List<Object> getLeafListValues(final AbstractStructureInstance parent, final String namespace,
+            final String name) {
+        return parent.getLeafListValues(namespace, name);
+    }
+
+    protected AnyDataInstance getAnyDataInstance(final AbstractStructureInstance parent, final String namespace,
+            final String name) {
+        return parent.getAnyDataInstance(namespace, name);
+    }
+
+    protected AnyXmlInstance getAnyXmlInstance(final AbstractStructureInstance parent, final String namespace,
+            final String name) {
+        return parent.getAnyXmlInstance(namespace, name);
+    }
+
+    protected ListInstance getListInstanceData(AbstractStructureInstance parent, String ns, String name,
+            Map<String, String> keyValues) {
+
+        if (!parent.hasListInstance(ns, name)) {
+            return null;
+        }
+
+        return (ListInstance) parent.getListInstances(ns, name).stream().filter(inst -> keyValues.equals(
+                ((ListInstance) inst).getKeyValues())).findAny().orElse(null);
+    }
+
+    protected static YangDataDomNode getChildDataDomNode(final YangDataDomNode parent, final String name) {
+        return parent.getChildren().stream().filter(child -> name.equals(child.getName())).findAny().orElse(null);
+    }
+
+    protected static YangDataDomNode getChildDataDomNode(final YangDataDomNode parent, final String name,
+            final String value) {
+        return parent.getChildren().stream().filter(child -> name.equals(child.getName()) && value.equals(child.getValue()))
+                .findAny().orElse(null);
+    }
+
+    protected static YangDataDomNode getChildDataDomNode(final YangDataDomNode parent, final String name, final int index) {
+        final List<YangDataDomNode> collect = parent.getChildren().stream().filter(child -> name.equals(child.getName()))
+                .collect(Collectors.toList());
+        return index < collect.size() ? collect.get(index) : null;
+    }
+
+    protected static YangDataDomNodeAnnotationValue getDataDomNodeAnnotation(final YangDataDomNode domNode,
+            final String name) {
+        return domNode.getAnnotations().stream().filter(anno -> name.equals(anno.getName())).findAny().orElse(null);
+    }
+
+    /**
+     * Check no findings found other than input argument
+     */
+    public boolean hasFindingsOfTypeOtherThan(final String findingType) {
+        for (final Finding finding : context.getFindingsManager().getAllFindings()) {
+            if (!finding.getFindingType().equals(findingType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void assertSubTreeNoFindings(final AbstractStatement statement) {
+        assertNoFindingsOnStatement(statement);
+        for (final AbstractStatement child : statement.getChildStatements()) {
+            assertSubTreeNoFindings(child);
+        }
+    }
+
+    public void assertNoFindings() {
+        assertNoFindings(findingsManager.getAllFindings());
+    }
+
+    public void assertNoFindingsOnStatement(final AbstractStatement statement) {
+        assertNoFindings(statement.getFindings());
+    }
+
+    public void assertNoFindings(final Set<Finding> findings) {
+        if (findings.isEmpty()) {
+            return;
+        }
+
+        System.err.println("Findings count is " + findings.size() + ", not empty as expected.");
+        printFindings(findings);
+        fail();
+    }
+
+    public void assertOneFindingOnly() {
+        assertFindingCount(1);
+    }
+
+    public void assertOneFindingOnlyOnStatement(final AbstractStatement statement) {
+        assertFindingCountOnStatement(statement, 1);
+    }
+
+    public void assertOneFindingOnly(final Set<Finding> findings) {
+        assertFindingCount(findings, 1);
+    }
+
+    public void assertFindingCount(final int count) {
+        assertFindingCount(findingsManager.getAllFindings(), count);
+    }
+
+    public void assertFindingCountOnStatement(final AbstractStatement statement, final int count) {
+        assertFindingCount(statement.getFindings(), count);
+    }
+
+    public void assertFindingCount(final Set<Finding> findings, final int count) {
+        if (findings.size() == count) {
+            return;
+        }
+
+        System.err.println("Findings count is " + findings.size() + ", not as expected " + count);
+        printFindings(findings);
+        fail();
+    }
+
+    public void assertOneFindingOnly(final String findingType) {
+        assertSingleFindingOfType(findingsManager.getAllFindings(), findingType);
+    }
+
+    public void assertStatementHasSingleFindingOfType(final AbstractStatement statement, final String findingType) {
+        assertSingleFindingOfType(statement.getFindings(), findingType);
+    }
+
+    public void assertSingleFindingOfType(final Set<Finding> findings, final String findingType) {
+        assertFindingCount(findings, 1);
+        assertHasFindingOfType(findings, findingType);
+    }
+
+    public void assertHasFinding(final YangModel yangModelFile, final int lineNumber, final String findingType) {
+        for (final Finding finding : context.getFindingsManager().getAllFindings()) {
+            if (finding.getLineNumber() == lineNumber && finding.getFindingType().equals(findingType) && finding
+                    .getYangModel() == yangModelFile) {
+                return;
+            }
+        }
+        fail();
+    }
+
+    public void assertHasFindingOfType(final String findingType) {
+        assertHasFindingOfType(context.getFindingsManager().getAllFindings(), findingType);
+    }
+
+    public void assertHasNotFindingOfType(final String findingType) {
+        assertHasNotFindingOfType(context.getFindingsManager().getAllFindings(), findingType);
+    }
+
+    public void assertStatementHasFindingOfType(final AbstractStatement statement, final String findingType) {
+        assertHasFindingOfType(statement.getFindings(), findingType);
+    }
+
+    public void assertStatementHasNotFindingOfType(final AbstractStatement statement, final String findingType) {
+        assertHasNotFindingOfType(statement.getFindings(), findingType);
+    }
+
+    public void assertDomElementHasFindingOfType(final YangDomElement domElement, final String findingType) {
+        final Set<Finding> filtered = context.getFindingsManager().getAllFindings().stream().filter(finding -> domElement
+                .getYangModel() == finding.getYangModel() && domElement.getLineNumber() == finding.getLineNumber()).collect(
+                        Collectors.toSet());
+
+        assertHasFindingOfType(filtered, findingType);
+    }
+
+    public void assertDomElementHasNotFindingOfType(final YangDomElement domElement, final String findingType) {
+        final Set<Finding> filtered = context.getFindingsManager().getAllFindings().stream().filter(finding -> domElement
+                .getYangModel() == finding.getYangModel() && domElement.getLineNumber() == finding.getLineNumber()).collect(
+                        Collectors.toSet());
+
+        assertHasNotFindingOfType(filtered, findingType);
+    }
+
+    public void assertDomElementHasNoFindings(final YangDomElement domElement) {
+        Set<Finding> filtered = context.getFindingsManager().getAllFindings().stream().filter(finding -> domElement
+                .getYangModel() == finding.getYangModel() && domElement.getLineNumber() == finding.getLineNumber()).collect(
+                        Collectors.toSet());
+
+        assertNoFindings(filtered);
+    }
+
+    public void assertHasFindingOfTypeAndContainsMessage(final String findingType, final String message) {
+
+        final Optional<Finding> findAny = context.getFindingsManager().getAllFindings().stream().filter(finding -> finding
+                .getFindingType().equals(findingType)).filter(finding -> finding.getMessage().contains(message)).findAny();
+
+        if (!findAny.isPresent()) {
+            System.err.println("Does not have finding of type " + findingType + " containing message " + message);
+            printFindings(context.getFindingsManager().getAllFindings());
+            fail();
+        }
+    }
+
+    public void assertHasFindingOfType(final Set<Finding> findings, final String findingType) {
+        if (hasFindingOfType(findings, findingType)) {
+            return;
+        }
+
+        System.err.println("Does not have finding of type " + findingType);
+        printFindings(findings);
+        fail();
+    }
+
+    public void assertHasNotFindingOfType(final Set<Finding> findings, final String findingType) {
+
+        if (!hasFindingOfType(findings, findingType)) {
+            return;
+        }
+
+        System.err.println("Has finding of type " + findingType);
+        printFindings(findings);
+        fail();
+    }
+
+    public void assertContextHasFindingOfType(final String findingType) {
+        assertTrue(contextHasFindingsOfTypes(Collections.singletonList(findingType)));
+    }
+
+    public void assertContextHasFindingsOfTypes(final List<String> findingTypes) {
+        assertTrue(contextHasFindingsOfTypes(findingTypes));
+    }
+
+    public void assertStatementHasFindingsOfTypes(final AbstractStatement statement, final List<String> findingTypes) {
+        assertTrue(statementHasFindingsOfTypes(statement, findingTypes));
+    }
+
+    public void assertHasFindingsOfTypes(final Set<Finding> findings, final List<String> findingTypes) {
+        assertTrue(hasFindingsOfTypes(findings, findingTypes));
+    }
+
+    public boolean contextHasFindingOfType(final String findingType) {
+        return hasFindingOfType(context.getFindingsManager().getAllFindings(), findingType);
+    }
+
+    public boolean statementHasFindingOfType(final AbstractStatement statement, final String findingType) {
+        return hasFindingOfType(statement.getFindings(), findingType);
+
+    }
+
+    public boolean hasFindingOfType(final Set<Finding> findings, final String findingType) {
+        for (final Finding finding : findings) {
+            if (finding.getFindingType().equals(findingType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean contextHasFindingsOfTypes(final List<String> findingTypes) {
+        return hasFindingsOfTypes(context.getFindingsManager().getAllFindings(), findingTypes);
+    }
+
+    public boolean statementHasFindingsOfTypes(final AbstractStatement statement, final List<String> findingTypes) {
+        return hasFindingsOfTypes(statement.getFindings(), findingTypes);
+
+    }
+
+    public boolean hasFindingsOfTypes(final Set<Finding> findings, final List<String> findingTypes) {
+
+        for (final String findingType : findingTypes) {
+            if (!hasFindingOfType(findings, findingType)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void printFindings() {
+        printFindings(findingsManager.getAllFindings());
+    }
+
+    public void printFindingsForStatement(final AbstractStatement statement) {
+        printFindings(statement.getFindings());
+    }
+
+    public void printFindings(final Set<Finding> findings) {
+
+        final List<String> collect = findings.stream().map(Finding::toString).collect(Collectors.toList());
+        Collections.sort(collect);
+        collect.forEach(System.err::println);
+    }
+
+    // ================================== JSON stuff =======================================
+
+    protected static JsonValue getJsonObjectMemberValue(final JsonObject jsonObject, final String memberName) {
+
+        final Set<Entry<JsonObjectMemberName, JsonValue>> entrySet = jsonObject.getValuesByMember().entrySet();
+        for (final Entry<JsonObjectMemberName, JsonValue> entry : entrySet) {
+
+            if (memberName.equals(entry.getKey().getMemberName())) {
+                return entry.getValue();
+            }
+        }
+
+        return null;
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/InstanceIdentifierTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/InstanceIdentifierTest.java
new file mode 100644
index 0000000..f7fea0c
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/InstanceIdentifierTest.java
@@ -0,0 +1,712 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.util.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+import org.oran.smo.yangtools.parser.util.InstanceIdentifier;
+import org.oran.smo.yangtools.parser.util.InstanceIdentifier.Step;
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+public class InstanceIdentifierTest {
+
+    @Test
+    public void test___xml___ok() {
+
+        final PrefixResolver prefixResolver = new PrefixResolver();
+        prefixResolver.addMapping("ns1", "namespace1");
+        prefixResolver.addMapping("ns2", "namespace2");
+        prefixResolver.addMapping("ns3", "namespace3");
+
+        final InstanceIdentifier ii0 = InstanceIdentifier.parseXmlEncodedString("", prefixResolver);
+        assertTrue(ii0.getSteps().isEmpty());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii1 = InstanceIdentifier.parseXmlEncodedString(" \t", prefixResolver);
+        assertTrue(ii1.getSteps().isEmpty());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii2 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1", prefixResolver);
+        assertEquals(1, ii2.getSteps().size());
+
+        assertEquals("node1", ii2.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii2.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii2.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii2.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii2.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertNull(ii2.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii3 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1/ns2 : node2", prefixResolver);
+        assertEquals(2, ii3.getSteps().size());
+
+        assertEquals("node1", ii3.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii3.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii3.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii3.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii3.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertNull(ii3.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        assertEquals("node2", ii3.getSteps().get(1).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace2", ii3.getSteps().get(1).getDataNodeNsai().getNamespace());
+        assertNull(ii3.getSteps().get(1).getDataNodeNsai().getModuleName());
+        assertNull(ii3.getSteps().get(1).getPredicateKeyValues());
+        assertNull(ii3.getSteps().get(1).getPredicateLeafListMemberValue());
+        assertNull(ii3.getSteps().get(1).getPredicateListEntryOrLeafListMemberIndex());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii4 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1/node2", prefixResolver);		// technically that's illegal syntax, but we will encounter it in the wild.
+        assertEquals(2, ii4.getSteps().size());
+
+        assertEquals("node1", ii4.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii4.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii4.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii4.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii4.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertNull(ii4.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        assertEquals("node2", ii4.getSteps().get(1).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii4.getSteps().get(1).getDataNodeNsai().getNamespace());
+        assertNull(ii4.getSteps().get(1).getDataNodeNsai().getModuleName());
+        assertNull(ii4.getSteps().get(1).getPredicateKeyValues());
+        assertNull(ii4.getSteps().get(1).getPredicateLeafListMemberValue());
+        assertNull(ii4.getSteps().get(1).getPredicateListEntryOrLeafListMemberIndex());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii5 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1[ns2:leaf = 'A.BC']",
+                prefixResolver);
+        assertEquals(1, ii5.getSteps().size());
+
+        assertEquals("node1", ii5.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii5.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii5.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii5.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertNull(ii5.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        final Map<NamespaceModuleIdentifier, String> ii5KeyValues0 = ii5.getSteps().get(0).getPredicateKeyValues();
+        assertNotNull(ii5KeyValues0);
+        assertEquals(1, ii5KeyValues0.size());
+
+        assertTrue(ii5KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertEquals("A.BC", ii5KeyValues0.get(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii6 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1[leaf=\"'AB.C'\"]",
+                prefixResolver);		// technically that's illegal syntax, but we will encounter it in the wild.
+        assertEquals(1, ii6.getSteps().size());
+
+        assertEquals("node1", ii6.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii6.getSteps().get(0).getDataNodeNsai().getNamespace());
+
+        final Map<NamespaceModuleIdentifier, String> ii6KeyValues0 = ii6.getSteps().get(0).getPredicateKeyValues();
+        assertNotNull(ii6KeyValues0);
+        assertEquals(1, ii6KeyValues0.size());
+
+        assertTrue(ii6KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace1", null, "leaf")));
+        assertEquals("'AB.C'", ii6KeyValues0.get(new NamespaceModuleIdentifier("namespace1", null, "leaf")));
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii7 = InstanceIdentifier.parseXmlEncodedString(
+                "/ns1:node1[ns2:leaf=\"ABC\"][ns3:other-leaf=''] ", prefixResolver);
+        assertEquals(1, ii7.getSteps().size());
+
+        assertEquals("node1", ii7.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii7.getSteps().get(0).getDataNodeNsai().getNamespace());
+
+        final Map<NamespaceModuleIdentifier, String> ii7KeyValues0 = ii7.getSteps().get(0).getPredicateKeyValues();
+        assertNotNull(ii7KeyValues0);
+        assertEquals(2, ii7KeyValues0.size());
+
+        assertTrue(ii7KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertEquals("ABC", ii7KeyValues0.get(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertTrue(ii7KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace3", null, "other-leaf")));
+        assertEquals("", ii7KeyValues0.get(new NamespaceModuleIdentifier("namespace3", null, "other-leaf")));
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii8 = InstanceIdentifier.parseXmlEncodedString(
+                "/ns1:node1[ns2:leaf='ABC'] [other-leaf=XYZ]", prefixResolver);		// technically that's illegal syntax, but we will encounter it in the wild.
+        assertEquals(1, ii8.getSteps().size());
+
+        assertEquals("node1", ii8.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii8.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii8.getSteps().get(0).getDataNodeNsai().getModuleName());
+
+        final Map<NamespaceModuleIdentifier, String> ii8KeyValues0 = ii8.getSteps().get(0).getPredicateKeyValues();
+        assertNotNull(ii8KeyValues0);
+        assertEquals(2, ii8KeyValues0.size());
+
+        assertTrue(ii8KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertEquals("ABC", ii8KeyValues0.get(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertTrue(ii8KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace1", null, "other-leaf")));
+        assertEquals("XYZ", ii8KeyValues0.get(new NamespaceModuleIdentifier("namespace1", null, "other-leaf")));
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii9 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1[4]", prefixResolver);
+        assertEquals(1, ii9.getSteps().size());
+
+        assertEquals("node1", ii9.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii9.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii9.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii9.getSteps().get(0).getPredicateLeafListMemberValue());
+
+        assertNotNull(ii9.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+        assertEquals(new Integer(4), ii9.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii10 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1[.='A B C']", prefixResolver);
+        assertEquals(1, ii10.getSteps().size());
+
+        assertEquals("node1", ii10.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii10.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii10.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii10.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        assertNotNull(ii10.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertEquals("A B C", ii10.getSteps().get(0).getPredicateLeafListMemberValue());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii11 = InstanceIdentifier.parseXmlEncodedString(
+                "/ns1:node1/ns2:node2[5]/ns3:node3[.='ABC']/ns1:node1[ns2:leaf2='XYZ']/ns3:node3[ns1:leaf1='EFG'][ns2:leaf2='RST']",
+                prefixResolver);
+        assertEquals(5, ii11.getSteps().size());
+
+        assertEquals("node1", ii11.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii11.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii11.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii11.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+        assertNull(ii11.getSteps().get(0).getPredicateLeafListMemberValue());
+
+        assertEquals("node2", ii11.getSteps().get(1).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace2", ii11.getSteps().get(1).getDataNodeNsai().getNamespace());
+        assertNull(ii11.getSteps().get(1).getPredicateKeyValues());
+        assertNull(ii11.getSteps().get(1).getPredicateLeafListMemberValue());
+        assertEquals(new Integer(5), ii11.getSteps().get(1).getPredicateListEntryOrLeafListMemberIndex());
+
+        assertEquals("node3", ii11.getSteps().get(2).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace3", ii11.getSteps().get(2).getDataNodeNsai().getNamespace());
+        assertNull(ii11.getSteps().get(2).getPredicateKeyValues());
+        assertNull(ii11.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertEquals("ABC", ii11.getSteps().get(2).getPredicateLeafListMemberValue());
+
+        assertEquals("node1", ii11.getSteps().get(3).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii11.getSteps().get(3).getDataNodeNsai().getNamespace());
+        assertNull(ii11.getSteps().get(3).getPredicateListEntryOrLeafListMemberIndex());
+        assertNull(ii11.getSteps().get(3).getPredicateLeafListMemberValue());
+        assertEquals("XYZ", ii11.getSteps().get(3).getPredicateKeyValues().get(new NamespaceModuleIdentifier("namespace2",
+                null, "leaf2")));
+
+        assertEquals("node3", ii11.getSteps().get(4).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace3", ii11.getSteps().get(4).getDataNodeNsai().getNamespace());
+        assertNull(ii11.getSteps().get(4).getPredicateListEntryOrLeafListMemberIndex());
+        assertNull(ii11.getSteps().get(4).getPredicateLeafListMemberValue());
+        assertEquals("EFG", ii11.getSteps().get(4).getPredicateKeyValues().get(new NamespaceModuleIdentifier("namespace1",
+                null, "leaf1")));
+        assertEquals("RST", ii11.getSteps().get(4).getPredicateKeyValues().get(new NamespaceModuleIdentifier("namespace2",
+                null, "leaf2")));
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii12 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1[ns2:leaf='\\\"[]=./']",
+                prefixResolver);
+        assertEquals(1, ii12.getSteps().size());
+
+        final Map<NamespaceModuleIdentifier, String> ii12KeyValues0 = ii12.getSteps().get(0).getPredicateKeyValues();
+        assertTrue(ii12KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertEquals("\\\"[]=./", ii12KeyValues0.get(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+    }
+
+    @Test
+    public void test___xml___resolver___ok() {
+
+        final PrefixResolver prefixResolver = new PrefixResolver();
+        prefixResolver.addMapping("ns1", "namespace1");
+        prefixResolver.addMapping("ns2", "namespace2");
+
+        final ModuleAndNamespaceResolver namespaceResolver = new ModuleAndNamespaceResolver();
+        namespaceResolver.recordNamespaceMapping("namespace1", "module1");
+        namespaceResolver.recordNamespaceMapping("namespace2", "module2");
+        namespaceResolver.recordModuleMapping("module1", "namespace1");
+        namespaceResolver.recordModuleMapping("module2", "namespace2");
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii1 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1", prefixResolver);
+        ii1.resolveModuleOrNamespace(namespaceResolver);
+
+        assertEquals(1, ii1.getSteps().size());
+
+        assertEquals("node1", ii1.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii1.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertEquals("module1", ii1.getSteps().get(0).getDataNodeNsai().getModuleName());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii2 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1[ns2:leaf='ABC']",
+                prefixResolver);
+        ii2.resolveModuleOrNamespace(namespaceResolver);
+
+        assertEquals(1, ii2.getSteps().size());
+
+        assertEquals("node1", ii2.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii2.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertEquals("module1", ii2.getSteps().get(0).getDataNodeNsai().getModuleName());
+
+        final Map<NamespaceModuleIdentifier, String> ii2KeyValues0 = ii2.getSteps().get(0).getPredicateKeyValues();
+        assertTrue(ii2KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertEquals("ABC", ii2KeyValues0.get(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertTrue(ii2KeyValues0.containsKey(new NamespaceModuleIdentifier(null, "module2", "leaf")));
+        assertEquals("ABC", ii2KeyValues0.get(new NamespaceModuleIdentifier(null, "module2", "leaf")));
+    }
+
+    @Test
+    public void test___json___ok() {
+
+        final InstanceIdentifier ii1 = InstanceIdentifier.parseJsonEncodedString("");
+        assertTrue(ii1.getSteps().isEmpty());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii2 = InstanceIdentifier.parseJsonEncodedString("/module1:node1");
+        assertEquals(1, ii2.getSteps().size());
+
+        assertEquals("node1", ii2.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("module1", ii2.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii2.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii2.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii2.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertNull(ii2.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii3 = InstanceIdentifier.parseJsonEncodedString("/module1:node1/module2:node2");
+        assertEquals(2, ii3.getSteps().size());
+
+        assertEquals("node1", ii3.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("module1", ii3.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii3.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii3.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii3.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertNull(ii3.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        assertEquals("node2", ii3.getSteps().get(1).getDataNodeNsai().getIdentifier());
+        assertEquals("module2", ii3.getSteps().get(1).getDataNodeNsai().getModuleName());
+        assertNull(ii3.getSteps().get(1).getDataNodeNsai().getNamespace());
+        assertNull(ii3.getSteps().get(1).getPredicateKeyValues());
+        assertNull(ii3.getSteps().get(1).getPredicateLeafListMemberValue());
+        assertNull(ii3.getSteps().get(1).getPredicateListEntryOrLeafListMemberIndex());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii4 = InstanceIdentifier.parseJsonEncodedString("/module1:node1/node2");
+        assertEquals(2, ii4.getSteps().size());
+
+        assertEquals("node1", ii4.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("module1", ii4.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii4.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertNull(ii4.getSteps().get(0).getPredicateKeyValues());
+        assertNull(ii4.getSteps().get(0).getPredicateLeafListMemberValue());
+        assertNull(ii4.getSteps().get(0).getPredicateListEntryOrLeafListMemberIndex());
+
+        assertEquals("node2", ii4.getSteps().get(1).getDataNodeNsai().getIdentifier());
+        assertEquals("module1", ii4.getSteps().get(1).getDataNodeNsai().getModuleName());
+        assertNull(ii4.getSteps().get(1).getDataNodeNsai().getNamespace());
+        assertNull(ii4.getSteps().get(1).getPredicateKeyValues());
+        assertNull(ii4.getSteps().get(1).getPredicateLeafListMemberValue());
+        assertNull(ii4.getSteps().get(1).getPredicateListEntryOrLeafListMemberIndex());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii8 = InstanceIdentifier.parseJsonEncodedString(
+                "/module1:node1[module2:leaf='ABC'][other-leaf=XYZ]");
+        assertEquals(1, ii8.getSteps().size());
+
+        assertEquals("node1", ii8.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("module1", ii8.getSteps().get(0).getDataNodeNsai().getModuleName());
+        assertNull(ii8.getSteps().get(0).getDataNodeNsai().getNamespace());
+
+        final Map<NamespaceModuleIdentifier, String> ii8KeyValues0 = ii8.getSteps().get(0).getPredicateKeyValues();
+        assertNotNull(ii8KeyValues0);
+        assertEquals(2, ii8KeyValues0.size());
+
+        assertTrue(ii8KeyValues0.containsKey(new NamespaceModuleIdentifier(null, "module2", "leaf")));
+        assertEquals("ABC", ii8KeyValues0.get(new NamespaceModuleIdentifier(null, "module2", "leaf")));
+        assertTrue(ii8KeyValues0.containsKey(new NamespaceModuleIdentifier(null, "module1", "other-leaf")));
+        assertEquals("XYZ", ii8KeyValues0.get(new NamespaceModuleIdentifier(null, "module1", "other-leaf")));
+    }
+
+    @Test
+    public void test___json___resolver___ok() {
+
+        final ModuleAndNamespaceResolver namespaceResolver = new ModuleAndNamespaceResolver();
+        namespaceResolver.recordNamespaceMapping("namespace1", "module1");
+        namespaceResolver.recordNamespaceMapping("namespace2", "module2");
+        namespaceResolver.recordModuleMapping("module1", "namespace1");
+        namespaceResolver.recordModuleMapping("module2", "namespace2");
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii1 = InstanceIdentifier.parseJsonEncodedString("/module1:node1");
+        ii1.resolveModuleOrNamespace(namespaceResolver);
+
+        assertEquals(1, ii1.getSteps().size());
+
+        assertEquals("node1", ii1.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii1.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertEquals("module1", ii1.getSteps().get(0).getDataNodeNsai().getModuleName());
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii2 = InstanceIdentifier.parseJsonEncodedString("/module1:node1[module2:leaf='ABC']");
+        ii2.resolveModuleOrNamespace(namespaceResolver);
+
+        assertEquals(1, ii2.getSteps().size());
+
+        assertEquals("node1", ii2.getSteps().get(0).getDataNodeNsai().getIdentifier());
+        assertEquals("namespace1", ii2.getSteps().get(0).getDataNodeNsai().getNamespace());
+        assertEquals("module1", ii2.getSteps().get(0).getDataNodeNsai().getModuleName());
+
+        final Map<NamespaceModuleIdentifier, String> ii2KeyValues0 = ii2.getSteps().get(0).getPredicateKeyValues();
+        assertTrue(ii2KeyValues0.containsKey(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertEquals("ABC", ii2KeyValues0.get(new NamespaceModuleIdentifier("namespace2", null, "leaf")));
+        assertTrue(ii2KeyValues0.containsKey(new NamespaceModuleIdentifier(null, "module2", "leaf")));
+        assertEquals("ABC", ii2KeyValues0.get(new NamespaceModuleIdentifier(null, "module2", "leaf")));
+    }
+
+    @Test
+    public void test___errors___npe() {
+
+        final PrefixResolver prefixResolver = new PrefixResolver();
+
+        try {
+            InstanceIdentifier.parseXmlEncodedString(null, prefixResolver);
+            fail("Expected NullPointerException");
+        } catch (final NullPointerException ex) {
+        } catch (final Exception ex) {
+            fail("Expected NullPointerException");
+        }
+
+        try {
+            InstanceIdentifier.parseXmlEncodedString("", null);
+            fail("Expected NullPointerException");
+        } catch (final NullPointerException ex) {
+        } catch (final Exception ex) {
+            fail("Expected NullPointerException");
+        }
+
+        try {
+            InstanceIdentifier.parseXmlEncodedString(null, null);
+            fail("Expected NullPointerException");
+        } catch (final NullPointerException ex) {
+        } catch (final Exception ex) {
+            fail("Expected NullPointerException");
+        }
+
+        try {
+            InstanceIdentifier.parseJsonEncodedString(null);
+            fail("Expected NullPointerException");
+        } catch (final NullPointerException ex) {
+        } catch (final Exception ex) {
+            fail("Expected NullPointerException");
+        }
+    }
+
+    @Test
+    public void test___xml___errors() {
+
+        final PrefixResolver prefixResolver = new PrefixResolver();
+        prefixResolver.addMapping("ns1", "namespace1");
+        prefixResolver.addMapping("ns2", "namespace2");
+        prefixResolver.addMapping("ns3", "namespace3");
+
+        expectException("=", prefixResolver, "slash");
+        expectException("leaf1", prefixResolver, "slash");
+        expectException("ns1:leaf1", prefixResolver, "slash");
+        expectException(".", prefixResolver, "slash");
+        expectException("[]", prefixResolver, "slash");
+
+        expectException("/", prefixResolver, "syntax");
+        expectException("/ns1:", prefixResolver, "syntax");
+
+        expectException("/=", prefixResolver, "data node");
+        expectException("/ns1::", prefixResolver, "data node");
+        expectException("/ns1:leaf1/:", prefixResolver, "data node");
+        expectException("/ns1:leaf1/ns2==", prefixResolver, "data node");
+
+        expectException("/leaf1", prefixResolver, "first step");
+
+        expectException("/nsX:leaf1", prefixResolver, "prefix");
+
+        expectException("/ns1:list1[a]", prefixResolver, "not parseable");
+        expectException("/ns1:list1[-1]", prefixResolver, "larger/equal to 1");
+        expectException("/ns1:list1[0]", prefixResolver, "larger/equal to 1");
+
+        expectException("/ns1:list1[ns2:leaf2:'abc']", prefixResolver, "data node");
+        expectException("/ns1:list1[ns2:leaf2=='abc']", prefixResolver, "single- or double-quoted string");
+        expectException("/ns1:list1[ns2:leaf2='abc'[", prefixResolver, "closing square brace");
+
+        expectException("/ns1:list1[ns2:leaf2=ab'c]", prefixResolver, "quote");
+        expectException("/ns1:list1[ns2:leaf2=ab\"c]", prefixResolver, "quote");
+
+        expectException("/ns1:list1[ns2:leaf2='abc", prefixResolver, "terminated");
+        expectException("/ns1:list1[ns2:leaf2=\"abc", prefixResolver, "terminated");
+
+        expectException("/ns1:list1[ns2:leaf2", prefixResolver, "syntax");
+        expectException("/ns1:list1[ns2:leaf2=", prefixResolver, "syntax");
+        expectException("/ns1:list1[ns2:leaf2=''", prefixResolver, "syntax");
+    }
+
+    private void expectException(final String xPath, final PrefixResolver prefixResolver, final String expectedString) {
+        try {
+            InstanceIdentifier.parseXmlEncodedString(xPath, prefixResolver);
+            fail("Expected exception.");
+        } catch (final Exception ex) {
+            if (!ex.getMessage().contains(expectedString)) {
+                fail("Expected exception to contain string '" + expectedString + "'; exception message is: " + ex
+                        .getMessage());
+            }
+        }
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test___instance_identifier___equals() {
+
+        final PrefixResolver prefixResolver = new PrefixResolver();
+        prefixResolver.addMapping("ns1", "namespace1");
+        prefixResolver.addMapping("ns2", "namespace2");
+        prefixResolver.addMapping("ns9", "namespace1");
+
+        final ModuleAndNamespaceResolver namespaceResolver = new ModuleAndNamespaceResolver();
+        namespaceResolver.recordNamespaceMapping("namespace1", "module1");
+        namespaceResolver.recordNamespaceMapping("namespace2", "module2");
+        namespaceResolver.recordModuleMapping("module1", "namespace1");
+        namespaceResolver.recordModuleMapping("module2", "namespace2");
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii1 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1", prefixResolver);
+
+        assertTrue(ii1.equals(ii1));
+        assertFalse(ii1.equals(null));
+        assertFalse(ii1.equals(""));
+
+        assertTrue(ii1.equals(InstanceIdentifier.parseXmlEncodedString("/ns1:node1", prefixResolver)));
+        assertTrue(ii1.equals(InstanceIdentifier.parseXmlEncodedString("/ns9:node1", prefixResolver)));
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii2 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1/ns2:node2/node3",
+                prefixResolver);
+
+        assertTrue(ii2.equals(InstanceIdentifier.parseXmlEncodedString("/ns1:node1/ns2:node2/ns2:node3", prefixResolver)));
+        assertTrue(ii2.equals(InstanceIdentifier.parseXmlEncodedString("/ns9:node1/ns2:node2/node3", prefixResolver)));
+
+        // - - - - - - - - - - - -
+
+        final InstanceIdentifier ii3 = InstanceIdentifier.parseXmlEncodedString("/ns1:node1/ns2:node2/node3",
+                prefixResolver);
+        assertFalse(ii3.equals(InstanceIdentifier.parseJsonEncodedString("/module1:node1/module2:node2/module2:node3")));
+        ii3.resolveModuleOrNamespace(namespaceResolver);
+        assertTrue(ii3.equals(InstanceIdentifier.parseJsonEncodedString("/module1:node1/module2:node2/module2:node3")));
+    }
+
+    @SuppressWarnings("unlikely-arg-type")
+    @Test
+    public void test___step___equals() {
+
+        final ModuleAndNamespaceResolver namespaceResolver = new ModuleAndNamespaceResolver();
+        namespaceResolver.recordNamespaceMapping("namespace1", "module1");
+        namespaceResolver.recordNamespaceMapping("namespace2", "module2");
+        namespaceResolver.recordNamespaceMapping("namespace3", "module3");
+        namespaceResolver.recordModuleMapping("module1", "namespace1");
+        namespaceResolver.recordModuleMapping("module2", "namespace2");
+        namespaceResolver.recordModuleMapping("module3", "namespace3");
+
+        final NamespaceModuleIdentifier nsaiNs = new NamespaceModuleIdentifier("namespace1", null, "node1");
+
+        final Step step1 = new Step(nsaiNs);
+
+        assertTrue(step1.equals(step1));
+        assertTrue(step1.equals(new Step(nsaiNs)));
+        assertTrue(step1.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1"))));
+        assertFalse(step1.equals(null));
+        assertFalse(step1.equals(""));
+        assertFalse(step1.equals(new Step(new NamespaceModuleIdentifier(null, "module1", "node1"))));
+
+        step1.resolveModuleOrNamespace(namespaceResolver);
+        assertTrue(step1.equals(new Step(new NamespaceModuleIdentifier(null, "module1", "node1"))));
+
+        // - - - - - - - - - - -
+
+        final NamespaceModuleIdentifier nsaiPred2 = new NamespaceModuleIdentifier("namespace2", null, "leaf2");
+
+        final Step step2 = new Step(nsaiNs);
+        step2.addPredicateKeyValue(nsaiPred2, "Hello");
+
+        assertTrue(step2.equals(step2));
+        assertTrue(step2.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                nsaiPred2, "Hello")));
+        assertTrue(step2.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                new NamespaceModuleIdentifier("namespace2", null, "leaf2"), "Hello")));
+        assertFalse(step2.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1"))));
+        assertFalse(step2.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                nsaiPred2, "hello")));
+        assertFalse(step2.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                nsaiPred2, "XXX")));
+
+        assertFalse(step2.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                new NamespaceModuleIdentifier(null, "module2", "leaf2"), "Hello")));
+        step2.resolveModuleOrNamespace(namespaceResolver);
+        assertTrue(step2.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                new NamespaceModuleIdentifier(null, "module2", "leaf2"), "Hello")));
+
+        // - - - - - - - - - - -
+
+        final NamespaceModuleIdentifier nsaiPred3 = new NamespaceModuleIdentifier("namespace3", null, "leaf3");
+
+        final Step step3 = new Step(nsaiNs);
+        step3.addPredicateKeyValue(nsaiPred2, "Hello");
+        step3.addPredicateKeyValue(nsaiPred3, "World");
+
+        assertTrue(step3.equals(step3));
+        assertTrue(step3.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                nsaiPred2, "Hello").addPredicateKeyValue(nsaiPred3, "World")));
+        assertTrue(step3.equals(new Step(new NamespaceModuleIdentifier("namespace1", null, "node1")).addPredicateKeyValue(
+                nsaiPred3, "World").addPredicateKeyValue(nsaiPred2, "Hello")));
+
+        // - - - - - - - - - - -
+
+        final Step step4 = new Step(nsaiNs);
+        step4.setPredicateLeafListMemberValue("value1");
+
+        assertTrue(step4.equals(step4));
+        assertTrue(step4.equals(new Step(nsaiNs).setPredicateLeafListMemberValue("value1")));
+        assertFalse(step4.equals(new Step(nsaiNs)));
+        assertFalse(step4.equals(new Step(nsaiNs).setPredicateLeafListMemberValue("valueXxxx")));
+        assertFalse(step4.equals(new Step(nsaiNs).addPredicateKeyValue(nsaiPred2, "Hello")));
+
+        // - - - - - - - - - - -
+
+        final Step step5 = new Step(nsaiNs);
+        step5.setPredicateListEntryOrLeafListMemberIndex(1);
+
+        assertTrue(step5.equals(step5));
+        assertTrue(step5.equals(new Step(nsaiNs).setPredicateListEntryOrLeafListMemberIndex(1)));
+        assertFalse(step5.equals(new Step(nsaiNs)));
+        assertFalse(step5.equals(new Step(nsaiNs).setPredicateListEntryOrLeafListMemberIndex(2)));
+        assertFalse(step5.equals(new Step(nsaiNs).addPredicateKeyValue(nsaiPred2, "Hello")));
+        assertFalse(step5.equals(new Step(nsaiNs).setPredicateLeafListMemberValue("value1")));
+    }
+
+    @Test
+    public void test___step___exceptions() {
+
+        try {
+            new Step(null);
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        final NamespaceModuleIdentifier nsai = new NamespaceModuleIdentifier("namespace1", null, "node1");
+
+        try {
+            new Step(nsai).addPredicateKeyValue(null, "value1");
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).addPredicateKeyValue(nsai, null);
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).addPredicateKeyValue(null, null);
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).setPredicateLeafListMemberValue(null);
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).setPredicateListEntryOrLeafListMemberIndex(0);
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).addPredicateKeyValue(nsai, "value1").setPredicateLeafListMemberValue("value1");
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).setPredicateLeafListMemberValue("value1").addPredicateKeyValue(nsai, "value1");
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).setPredicateListEntryOrLeafListMemberIndex(10).addPredicateKeyValue(nsai, "value1");
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).setPredicateListEntryOrLeafListMemberIndex(10).setPredicateLeafListMemberValue("value1");
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+
+        try {
+            new Step(nsai).setPredicateLeafListMemberValue("value1").setPredicateListEntryOrLeafListMemberIndex(10);
+            fail("Expected exception.");
+        } catch (final Exception expected) {
+        }
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/NamespaceAndIdentifierTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/NamespaceAndIdentifierTest.java
new file mode 100644
index 0000000..6b273c6
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/NamespaceAndIdentifierTest.java
@@ -0,0 +1,73 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.util.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.model.schema.ModuleAndNamespaceResolver;
+import org.oran.smo.yangtools.parser.util.NamespaceModuleIdentifier;
+
+public class NamespaceAndIdentifierTest {
+
+    @Test
+    public void test_all_ok() {
+
+        final NamespaceModuleIdentifier nsai1 = new NamespaceModuleIdentifier("namespace", "module", "identifier");
+
+        assertTrue(nsai1.getNamespace().equals("namespace"));
+        assertTrue(nsai1.getModuleName().equals("module"));
+        assertTrue(nsai1.getIdentifier().equals("identifier"));
+        assertTrue(nsai1.hashCode() == "identifier".hashCode());
+        assertTrue(nsai1.toString().equals("namespace/module/identifier"));
+        assertTrue(nsai1.equals(new NamespaceModuleIdentifier("namespace", "module", "identifier")));
+        assertFalse(nsai1.equals(new NamespaceModuleIdentifier("namespace", "module", "identifier2")));
+        assertFalse(nsai1.equals(new NamespaceModuleIdentifier("namespace2", "module2", "identifier")));
+        assertFalse(nsai1.equals(""));
+        assertFalse(nsai1.equals(null));
+
+        final ModuleAndNamespaceResolver namespaceResolver = new ModuleAndNamespaceResolver();
+        namespaceResolver.recordModuleMapping("module", "namespace");
+        namespaceResolver.recordNamespaceMapping("namespace", "module");
+
+        final NamespaceModuleIdentifier nsai2 = new NamespaceModuleIdentifier("namespace", null, "identifier");
+        assertTrue(nsai2.getNamespace().equals("namespace"));
+        assertTrue(nsai2.getModuleName() == null);
+        assertTrue(nsai2.getIdentifier().equals("identifier"));
+        assertTrue(nsai2.equals(new NamespaceModuleIdentifier("namespace", "module", "identifier")));
+        assertFalse(nsai2.equals(new NamespaceModuleIdentifier(null, "module", "identifier")));
+
+        nsai2.resolveModuleOrNamespace(namespaceResolver);
+        assertTrue(nsai2.getModuleName().equals("module"));
+
+        final NamespaceModuleIdentifier nsai3 = new NamespaceModuleIdentifier(null, "module", "identifier");
+        assertTrue(nsai3.getNamespace() == null);
+        assertTrue(nsai3.getModuleName().equals("module"));
+        assertTrue(nsai3.getIdentifier().equals("identifier"));
+        assertTrue(nsai3.equals(new NamespaceModuleIdentifier("namespace", "module", "identifier")));
+        assertFalse(nsai3.equals(new NamespaceModuleIdentifier("namespace", null, "identifier")));
+
+        nsai3.resolveModuleOrNamespace(namespaceResolver);
+        assertTrue(nsai3.getNamespace().equals("namespace"));
+    }
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/QNameHelperTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/QNameHelperTest.java
new file mode 100644
index 0000000..27e774b
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/util/test/QNameHelperTest.java
@@ -0,0 +1,57 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.PrefixResolver;
+import org.oran.smo.yangtools.parser.util.QNameHelper;
+
+public class QNameHelperTest {
+
+    @Test
+    public void test_all_ok() {
+
+        assertTrue(QNameHelper.hasPrefix("ns1:name1") == true);
+        assertTrue(QNameHelper.hasPrefix(":name1") == false);
+        assertTrue(QNameHelper.hasPrefix("name1") == false);
+        assertTrue(QNameHelper.hasPrefix("") == false);
+        assertTrue(QNameHelper.hasPrefix(":") == false);
+        assertTrue(QNameHelper.hasPrefix(null) == false);
+
+        assertTrue(QNameHelper.extractPrefix("ns1:name1").equals("ns1"));
+        assertTrue(QNameHelper.extractPrefix(":name1").equals(PrefixResolver.NO_PREFIX));
+        assertTrue(QNameHelper.extractPrefix("name1").equals(PrefixResolver.NO_PREFIX));
+        assertTrue(QNameHelper.extractPrefix("").equals(PrefixResolver.NO_PREFIX));
+        assertTrue(QNameHelper.extractPrefix(":").equals(PrefixResolver.NO_PREFIX));
+        assertTrue(QNameHelper.extractPrefix(null).equals(PrefixResolver.NO_PREFIX));
+
+        assertTrue(QNameHelper.extractName("ns1:name1").equals("name1"));
+        assertTrue(QNameHelper.extractName(":name1").equals("name1"));
+        assertTrue(QNameHelper.extractName("name1").equals("name1"));
+        assertTrue(QNameHelper.extractName("").equals(""));
+        assertTrue(QNameHelper.extractName(":").equals(""));
+        assertTrue(QNameHelper.extractName(null) == null);
+    }
+
+}
diff --git a/yang-parser/src/test/java/org/oran/smo/yangtools/parser/yanglibrary/test/IetfYangLibraryParserTest.java b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/yanglibrary/test/IetfYangLibraryParserTest.java
new file mode 100644
index 0000000..134d380
--- /dev/null
+++ b/yang-parser/src/test/java/org/oran/smo/yangtools/parser/yanglibrary/test/IetfYangLibraryParserTest.java
@@ -0,0 +1,553 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 Ericsson
+ *  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+package org.oran.smo.yangtools.parser.yanglibrary.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+
+import org.oran.smo.yangtools.parser.data.util.IdentityRefValue;
+import org.oran.smo.yangtools.parser.findings.ParserFindingType;
+import org.oran.smo.yangtools.parser.input.FileBasedYangInputResolver;
+import org.oran.smo.yangtools.parser.model.ModuleIdentity;
+import org.oran.smo.yangtools.parser.model.util.YangFeature;
+import org.oran.smo.yangtools.parser.testutils.YangTestCommon;
+import org.oran.smo.yangtools.parser.yanglibrary.Datastore;
+import org.oran.smo.yangtools.parser.yanglibrary.IetfYangLibraryParser;
+import org.oran.smo.yangtools.parser.yanglibrary.Module;
+import org.oran.smo.yangtools.parser.yanglibrary.YangLibrary;
+
+public class IetfYangLibraryParserTest extends YangTestCommon {
+
+    @Test
+    public void testRFC7895() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibrary = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertNoFindings(ietfYangLibrary.getFindingsManager().getAllFindings());
+
+        assertTrue(yangLibrary != null);
+        assertTrue(yangLibrary.getContentId().equals("10445"));
+        assertTrue(yangLibrary.containsTopLevelSchema() == true);
+
+        final Datastore runningDatastore = yangLibrary.getRunningDatastore();
+        assertTrue(runningDatastore != null);
+
+        assertTrue(runningDatastore.getAllModules().size() == 3);
+        assertTrue(runningDatastore.getImplementingModules().size() == 2);
+        assertTrue(runningDatastore.getImportOnlyModules().size() == 1);
+
+        final Module testModule1 = runningDatastore.getImplementingModules().stream().filter(m -> m.getName().equals(
+                "test-module1")).findFirst().get();
+
+        assertTrue(testModule1.getName().equals("test-module1"));
+        assertTrue(testModule1.getNamespace().equals("com:foo:test-module1"));
+        assertTrue(testModule1.getRevision().equals("2020-01-01"));
+        assertTrue(testModule1.getSchemaLocations().size() == 1);
+        assertTrue(testModule1.getSchemaLocations().get(0).equals("www.acme.com/test-module1.yang"));
+        assertTrue(testModule1.getFeatures().size() == 3);
+        assertTrue(testModule1.getFeatures().get(0).equals("feature1"));
+        assertTrue(testModule1.getFeatures().get(1).equals("feature2"));
+        assertTrue(testModule1.getFeatures().get(2).equals("feature3"));
+        assertTrue(testModule1.getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+        assertTrue(testModule1.getSubmodules().size() == 1);
+        assertTrue(testModule1.getSubmodules().get(0).getName().equals("test-module1-submodule"));
+        assertTrue(testModule1.getSubmodules().get(0).getRevision().equals("2020-02-02"));
+        assertTrue(testModule1.getSubmodules().get(0).getSchemaLocations().size() == 1);
+        assertTrue(testModule1.getSubmodules().get(0).getSchemaLocations().get(0).equals(
+                "www.acme.com/test-module1-submodule.yang"));
+        assertTrue(testModule1.getDeviatedByModuleNames().size() == 1);
+        assertTrue(testModule1.getDeviatedByModuleNames().get(0).equals("test-module1-ext"));
+
+        final Module testModule1ext = runningDatastore.getImplementingModules().stream().filter(m -> m.getName().equals(
+                "test-module1-ext")).findFirst().get();
+
+        assertTrue(testModule1ext.getName().equals("test-module1-ext"));
+        assertTrue(testModule1ext.getRevision().equals("2020-05-20"));
+        assertTrue(testModule1ext.getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+
+        final Module importOnlyModule = runningDatastore.getImportOnlyModules().stream().findFirst().get();
+
+        assertTrue(importOnlyModule.getName().equals("test-module2"));
+        assertTrue(importOnlyModule.getNamespace().equals("com:foo:test-module2"));
+        assertTrue(importOnlyModule.getRevision() == null);
+        assertTrue(importOnlyModule.getSchemaLocations().size() == 0);
+        assertTrue(importOnlyModule.getFeatures().size() == 1);
+        assertTrue(importOnlyModule.getConformanceType() == Module.IetfYangLibraryConformanceType.IMPORT);
+
+        final Set<YangFeature> supportedFeatures = runningDatastore.getSupportedFeatures();
+
+        assertTrue(supportedFeatures.size() == 4);
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module1", "test-module1", "feature1")));
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module1", "test-module1", "feature2")));
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module1", "test-module1", "feature3")));
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module2", "test-module2", "feature6")));
+    }
+
+    @Test
+    public void testRFC7895_json() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.json"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibrary = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertNoFindings(ietfYangLibrary.getFindingsManager().getAllFindings());
+
+        assertTrue(yangLibrary != null);
+        assertTrue(yangLibrary.getContentId().equals("10445"));
+        assertTrue(yangLibrary.containsTopLevelSchema() == true);
+
+        final Datastore runningDatastore = yangLibrary.getRunningDatastore();
+        assertTrue(runningDatastore != null);
+
+        assertTrue(runningDatastore.getAllModules().size() == 3);
+        assertTrue(runningDatastore.getImplementingModules().size() == 2);
+        assertTrue(runningDatastore.getImportOnlyModules().size() == 1);
+
+        final Module testModule1 = runningDatastore.getImplementingModules().stream().filter(m -> m.getName().equals(
+                "test-module1")).findFirst().get();
+
+        assertTrue(testModule1.getName().equals("test-module1"));
+        assertTrue(testModule1.getNamespace().equals("com:foo:test-module1"));
+        assertTrue(testModule1.getRevision().equals("2020-01-01"));
+        assertTrue(testModule1.getSchemaLocations().size() == 1);
+        assertTrue(testModule1.getSchemaLocations().get(0).equals("www.acme.com/test-module1.yang"));
+        assertTrue(testModule1.getFeatures().size() == 3);
+        assertTrue(testModule1.getFeatures().get(0).equals("feature1"));
+        assertTrue(testModule1.getFeatures().get(1).equals("feature2"));
+        assertTrue(testModule1.getFeatures().get(2).equals("feature3"));
+        assertTrue(testModule1.getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+        assertTrue(testModule1.getSubmodules().size() == 1);
+        assertTrue(testModule1.getSubmodules().get(0).getName().equals("test-module1-submodule"));
+        assertTrue(testModule1.getSubmodules().get(0).getRevision().equals("2020-02-02"));
+        assertTrue(testModule1.getSubmodules().get(0).getSchemaLocations().size() == 1);
+        assertTrue(testModule1.getSubmodules().get(0).getSchemaLocations().get(0).equals(
+                "www.acme.com/test-module1-submodule.yang"));
+        assertTrue(testModule1.getDeviatedByModuleNames().size() == 1);
+        assertTrue(testModule1.getDeviatedByModuleNames().get(0).equals("test-module1-ext"));
+
+        final Module testModule1ext = runningDatastore.getImplementingModules().stream().filter(m -> m.getName().equals(
+                "test-module1-ext")).findFirst().get();
+
+        assertTrue(testModule1ext.getName().equals("test-module1-ext"));
+        assertTrue(testModule1ext.getRevision().equals("2020-05-20"));
+        assertTrue(testModule1ext.getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+
+        final Module importOnlyModule = runningDatastore.getImportOnlyModules().stream().findFirst().get();
+
+        assertTrue(importOnlyModule.getName().equals("test-module2"));
+        assertTrue(importOnlyModule.getNamespace().equals("com:foo:test-module2"));
+        assertTrue(importOnlyModule.getRevision() == null);
+        assertTrue(importOnlyModule.getSchemaLocations().size() == 0);
+        assertTrue(importOnlyModule.getFeatures().size() == 1);
+        assertTrue(importOnlyModule.getConformanceType() == Module.IetfYangLibraryConformanceType.IMPORT);
+
+        final Set<YangFeature> supportedFeatures = runningDatastore.getSupportedFeatures();
+
+        assertTrue(supportedFeatures.size() == 4);
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module1", "test-module1", "feature1")));
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module1", "test-module1", "feature2")));
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module1", "test-module1", "feature3")));
+        assertTrue(supportedFeatures.contains(new YangFeature("com:foo:test-module2", "test-module2", "feature6")));
+    }
+
+    @Test
+    public void testRFC7895_json_modulesetid_is_number_instead_of_string() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-modulesetid_is_number.json"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(yangDataFiles));
+
+        assertHasFindingOfType(ietfYangLibrary.getFindingsManager().getAllFindings(),
+                ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA.toString());
+    }
+
+    @Test
+    public void testRFC7895_with_issues() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-with-issues.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(yangDataFiles));
+
+        assertHasFindingOfType(ietfYangLibrary.getFindingsManager().getAllFindings(),
+                ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA.toString());
+    }
+
+    @Test
+    public void testRFC7895_with_empty_names() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-empty-names.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(yangDataFiles));
+
+        assertHasFindingOfType(ietfYangLibrary.getFindingsManager().getAllFindings(),
+                ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString());
+    }
+
+    @Test
+    public void testRFC8525() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibraryInstance = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertNoFindings(ietfYangLibrary.getFindingsManager().getAllFindings());
+
+        assertTrue(yangLibraryInstance != null);
+        assertTrue(yangLibraryInstance.getContentId().equals("9876"));
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getSchemaName().equals("schema1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().size() == 2);
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getName().equals("set1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().size() == 2);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getName().equals("test-module1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getRevision().equals("2020-01-01"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getNamespace().equals("com:foo:test-module1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSchemaLocations().size() == 2);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSchemaLocations().get(0).equals("www.acme.com/test-module1.yang"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSchemaLocations().get(1).equals("www.modules.acme.com/test-module1.yang"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getName().equals("test-module1-submodule"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getRevision() == null);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getSchemaLocations().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getModuleIdentity().equals(new ModuleIdentity("test-module1-submodule", null)));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().size() == 3);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().get(0).equals("feature1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().get(1).equals("feature2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().get(2).equals("feature3"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getDeviatedByModuleNames().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getDeviatedByModuleNames().get(0).equals("test-module1-ext"));
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(1)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(1)
+                .getName().equals("test-module1-ext"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(1)
+                .getRevision().equals("2020-03-03"));
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPORT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0).getName()
+                .equals("test-module2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getRevision() == null);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getNamespace().equals("com:foo:test-module2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getSchemaLocations().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getSubmodules().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getFeatures().size() == 0);
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getName().equals("set2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImplementingModules().size() == 0);
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPORT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0).getName()
+                .equals("test-module6"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getRevision().equals("2019-06-06"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getNamespace().equals("com:foo:test-module6"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getSchemaLocations().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getSubmodules().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getFeatures().size() == 0);
+
+        final Datastore operDatastore = yangLibraryInstance.getDatastore(new IdentityRefValue(
+                "urn:ietf:params:xml:ns:yang:ietf-datastores", "ietf-datastores", "operational"));
+        assertTrue(operDatastore != null);
+
+        assertTrue(operDatastore.getModuleSets().get(0).getName().equals("set2"));
+        assertTrue(operDatastore.getModuleSets().get(1).getName().equals("set3"));
+
+        final Datastore unknownDatastore = yangLibraryInstance.getDatastore(new IdentityRefValue(
+                "urn:ietf:params:xml:ns:yang:ietf-datastores", "ietf-datastores", "unknown"));
+        assertTrue(unknownDatastore == null);
+    }
+
+    @Test
+    public void testRFC8525_json() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.json"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibraryInstance = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertNoFindings(ietfYangLibrary.getFindingsManager().getAllFindings());
+
+        assertTrue(yangLibraryInstance != null);
+        assertTrue(yangLibraryInstance.getContentId().equals("9876"));
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getSchemaName().equals("schema1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().size() == 2);
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getName().equals("set1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().size() == 2);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getName().equals("test-module1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getRevision().equals("2020-01-01"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getNamespace().equals("com:foo:test-module1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSchemaLocations().size() == 2);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSchemaLocations().get(0).equals("www.acme.com/test-module1.yang"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSchemaLocations().get(1).equals("www.modules.acme.com/test-module1.yang"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getName().equals("test-module1-submodule"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getRevision() == null);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getSchemaLocations().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getSubmodules().get(0).getModuleIdentity().equals(new ModuleIdentity("test-module1-submodule", null)));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().size() == 3);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().get(0).equals("feature1"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().get(1).equals("feature2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getFeatures().get(2).equals("feature3"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getDeviatedByModuleNames().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0)
+                .getDeviatedByModuleNames().get(0).equals("test-module1-ext"));
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(1)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPLEMENT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(1)
+                .getName().equals("test-module1-ext"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(1)
+                .getRevision().equals("2020-03-03"));
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPORT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0).getName()
+                .equals("test-module2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getRevision() == null);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getNamespace().equals("com:foo:test-module2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getSchemaLocations().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getSubmodules().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(0).getImportOnlyModules().get(0)
+                .getFeatures().size() == 0);
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getName().equals("set2"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImplementingModules().size() == 0);
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().size() == 1);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getConformanceType() == Module.IetfYangLibraryConformanceType.IMPORT);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0).getName()
+                .equals("test-module6"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getRevision().equals("2019-06-06"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getNamespace().equals("com:foo:test-module6"));
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getSchemaLocations().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getSubmodules().size() == 0);
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().get(1).getImportOnlyModules().get(0)
+                .getFeatures().size() == 0);
+
+        final Datastore operDatastore = yangLibraryInstance.getDatastore(new IdentityRefValue(
+                "urn:ietf:params:xml:ns:yang:ietf-datastores", "ietf-datastores", "operational"));
+        assertTrue(operDatastore != null);
+
+        assertTrue(operDatastore.getModuleSets().get(0).getName().equals("set2"));
+        assertTrue(operDatastore.getModuleSets().get(1).getName().equals("set3"));
+    }
+
+    @Test
+    public void testRFC8525_no_schema_no_datastore() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-no-schema-no-datastore.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibraryInstance = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertTrue(yangLibraryInstance != null);
+        assertTrue(yangLibraryInstance.getContentId().equals("9876"));
+
+        assertTrue(yangLibraryInstance.getRunningDatastore().getModuleSets().size() == 3);
+    }
+
+    @Test
+    public void testRFC8525_with_issues() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-with-issues.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(yangDataFiles));
+
+        assertHasFindingOfType(ietfYangLibrary.getFindingsManager().getAllFindings(),
+                ParserFindingType.P081_INCORRECT_YANG_LIBRARY_DATA.toString());
+    }
+
+    @Test
+    public void testRFC8525_empty_names() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-empty-names.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibraryInstance = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertHasFindingOfType(ietfYangLibrary.getFindingsManager().getAllFindings(),
+                ParserFindingType.P082_YANG_LIBRARY_MANDATORY_VALUE_MISSING.toString());
+
+        assertTrue(yangLibraryInstance != null);
+    }
+
+    @Test
+    public void test_duplicate_modules() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-8525_duplicates.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibrary = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertTrue(yangLibrary != null);
+    }
+
+    @Test
+    public void test_empty_data() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-empty.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        List<YangLibrary> yangLibrary = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles));
+
+        assertHasFindingOfType(ietfYangLibrary.getFindingsManager().getAllFindings(), ParserFindingType.P079_EMPTY_DATA_FILE
+                .toString());
+
+        assertTrue(yangLibrary.isEmpty());
+    }
+
+    @Test
+    public void test_with_other_data() {
+
+        final List<File> yangDataFiles = Arrays.asList(new File(
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-7895_and_other_data.xml"));
+
+        final IetfYangLibraryParser ietfYangLibrary = new IetfYangLibraryParser();
+        final YangLibrary yangLibrary = ietfYangLibrary.parseIntoYangLibraries(new FileBasedYangInputResolver(
+                yangDataFiles)).get(0);
+
+        assertNoFindings(ietfYangLibrary.getFindingsManager().getAllFindings());
+
+        assertTrue(yangLibrary != null);
+        assertTrue(yangLibrary.getContentId().equals("10445"));
+        assertTrue(yangLibrary.getRunningDatastore().getModuleSets().get(0).getImplementingModules().size() == 1);
+        assertTrue(yangLibrary.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0).getName()
+                .equals("test-module1"));
+        assertTrue(yangLibrary.getRunningDatastore().getModuleSets().get(0).getImplementingModules().get(0).getRevision()
+                .equals("2020-01-01"));
+    }
+
+    @Test
+    public void test_multiple_yang_libraries_in_input() {
+
+        severityCalculator.suppressFinding(ParserFindingType.P114_TYPEDEF_NOT_USED.toString());
+        severityCalculator.suppressFinding(ParserFindingType.P115_TYPEDEF_USED_ONCE_ONLY.toString());
+
+        parseAbsoluteImplementsYangModels(Arrays.asList(
+                "src/test/resources/_orig-modules/ietf-yang-library-2019-01-04.yang",
+                "src/test/resources/_orig-modules/ietf-yang-types-2019-11-04.yang",
+                "src/test/resources/_orig-modules/ietf-inet-types-2019-11-04.yang",
+                "src/test/resources/_orig-modules/ietf-datastores-2018-02-14.yang"));
+        parseAbsoluteYangData(Arrays.asList("src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.xml",
+                "src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.xml"));
+
+        assertHasFindingOfType(ParserFindingType.P084_MULTIPLE_YANG_LIBRARIES_IN_INPUT.toString());
+    }
+}
diff --git a/yang-parser/src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-extensions@2023-12-12.yang b/yang-parser/src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-extensions@2023-12-12.yang
new file mode 100644
index 0000000..1d5876f
--- /dev/null
+++ b/yang-parser/src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-extensions@2023-12-12.yang
@@ -0,0 +1,130 @@
+module o-ran-smo-teiv-common-yang-extensions {
+
+  yang-version 1.1;
+  namespace "urn:o-ran:smo-teiv-common-yang-extensions";
+  prefix or-teiv-ext;
+
+
+  organization "ORAN";
+  contact "The Authors";
+  description
+  "Topology and Inventory YANG extensions model
+
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+  This model contains extensions to the YANG language that topology and
+  inventory models will use to define and annotate types and relationships.";
+
+  revision "2023-12-12" {
+    description "First draft.";
+    or-teiv-ext:label 0.2.0;
+  }
+
+  extension biDirectionalTopologyRelationship {
+
+    description
+      "Defines a bi-directional relationship in the topology.
+
+       A bi-directional-association (BDA) is a relationship comprising of an
+       A-side and a B-side. The A-side is considered the originating side of
+       the relationship; the B-side is considered the terminating side of the
+       relationship. The order of A-side and B-side is of importance and MUST
+       NOT be changed once defined.
+
+       Both A-side and B-side are defined on a type, and are given a role. A
+       type may have multiple originating and/or terminating sides of a
+       relationship, all distinguished by role name.
+
+       The statement MUST only be a substatement of the 'module' statement.
+       Multiple 'bi-directional-topology-relationship' statements are allowed
+       per parent statement.
+
+       Substatements to the 'bi-directional-topology-relationship' define the
+       A-side and the B-side, respectively, and optionally properties of the
+       relationship. Data nodes of types 'leaf' and 'leaf-list' are used for
+       this purpose. One of the data nodes MUST be annotated with the 'a-side'
+       extension; another data node MUST be annotated with the 'b-side'
+       extension. Other data nodes define properties of the relationship.
+
+       The argument is the name of the relationship. The relationship name is
+       scoped to the namespace of the declaring module and MUST be unique
+       within the scope.";
+
+    argument relationshipName;
+  }
+
+  extension aSide {
+    description
+      "Defines the A-side of a relationship.
+
+       The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+       statement, which itself must be a substatement of the
+       'uni-directional-topology-relationship' statement.
+
+       The data type of the parent 'leaf' or 'leaf-list' MUST be
+       'instance-identifier'. Constraints MAY be used as part of the parent
+       'leaf' or 'leaf-list' to enforce cardinality.
+
+       The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+       the role of the A-side of the relationship. The name of the role is
+       scoped to the type on which the A-side is defined and MUST be unique
+       within the scope.
+
+       While the parent 'leaf' or 'leaf-list' does not result in a property of
+       the relationship, it is RECOMMENDED to avoid using the name of an
+       existing type property as role name to avoid potential ambiguities
+       between properties of a type, and roles of a relationship on the type.
+
+       The argument is the name of the type on which the A-side resides. If the
+       type is declared in another module, the type must be prefixed, and a
+       corresponding 'import' statement be used to declare the prefix.";
+
+    argument aSideType;
+  }
+
+  extension bSide {
+    description "Defines the B-side of a relationship.
+
+       The statement MUST only be a substatement of a 'leaf' or 'leaf-list'
+       statement, which itself must be a substatement of the
+       'uni-directional-topology-relationship' statement.
+
+       The data type of the parent 'leaf' or 'leaf-list' MUST be
+       'instance-identifier'. Constraints MAY be used as part of the parent
+       'leaf' or 'leaf-list' to enforce cardinality.
+
+       The identifier of the parent 'leaf' or 'leaf-list' is used as name of
+       the role of the B-side of the relationship. The name of the role is
+       scoped to the type on which the B-side is defined and MUST be unique
+       within the scope.
+
+       While the parent 'leaf' or 'leaf-list' does not result in a property of
+       the relationship, it is RECOMMENDED to avoid using the name of an
+       existing type property as role name to avoid potential ambiguities
+       between properties of a type, and roles of a relationship on the type.
+
+       The argument is the name of the type on which the B-side resides. If the
+       type is declared in another module, the type must be prefixed, and a
+       corresponding 'import' statement be used to declare the prefix.";
+
+    argument bSideType;
+  }
+
+  extension domain {
+    description "Keyword used to carry domain information.";
+    argument domainName;
+  }
+
+  extension label {
+    description "The label can be used to give modules and submodules a semantic version, in addition to their revision.
+
+      The format of the label is ‘x.y.z’ – expressed as pattern, it is [0-9]+\.[0-9]+\.[0-9]+
+
+      The statement MUST only be a substatement of the revision statement.  Zero or one revision label statements
+      per parent statement are allowed.
+
+      Revision labels MUST be unique amongst all revisions of a module or submodule.";
+    argument semversion;
+  }
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-types@2023-12-12.yang b/yang-parser/src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-types@2023-12-12.yang
new file mode 100644
index 0000000..7f23938
--- /dev/null
+++ b/yang-parser/src/test/resources/_orig-modules/o-ran-smo-teiv-common-yang-types@2023-12-12.yang
@@ -0,0 +1,67 @@
+module o-ran-smo-teiv-common-yang-types {
+
+  yang-version 1.1;
+  namespace "urn:o-ran:smo-teiv-common-yang-types";
+  prefix or-teiv-types;
+
+  import o-ran-smo-teiv-common-yang-extensions {prefix or-teiv-ext; }
+
+
+  organization "ORAN";
+  contact "The Authors";
+  description
+  "Topology and Inventory common types model
+
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+
+  This model contains re-usable data types that topology and inventory models
+  will frequently use as part of types and relationships.";
+
+  revision "2023-12-12" {
+    description "First draft.";
+    or-teiv-ext:label 0.2.0;
+  }
+
+  grouping Top_Grp_Type {
+
+    description
+      "Grouping containing the key attribute common to all types. All types
+       MUST use this grouping.";
+
+    leaf id {
+      type string;
+      description "Unique identifier of topology entities. Represents the Entity Instance Identifier. Using types MAY
+                        restrict the allowed values for keys.";
+    }
+  }
+
+  container ties-consumer-data {
+    description "This container defines the TIES consumer-data. Consumer-data may be attached to Topology Entity or
+    Topology Relation instance, outside of the declared Topology Entity or Topology Relationship's attributes.
+    This container cannot be instantiated, and it MUST NOT be augmented or deviated in any way, unless stated
+    otherwise.";
+
+    container decorators {
+      description "This container serves as extension point for applications wishing to define their own decorators.
+      This is done via augmentations.";
+    }
+
+    leaf-list classifiers {
+      description "Consumer defined tags to topology entities and relationships. The ability to apply classifier is
+      supported through TIES REST API";
+      type identityref { base classifier; }
+    }
+
+    leaf-list source-ids {
+      description "An ordered list of identities that represent the set of native source identifiers for participating
+      entities.";
+      type string;
+      ordered-by user;
+    }
+  }
+
+  identity classifier{
+    description  "The classifier is used as a base to provide all classifiers with identity";
+  }
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/data-module-data-only.xml b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-module-data-only.xml
new file mode 100644
index 0000000..0ac29e6
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-module-data-only.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <cont1 xmlns="test:simple-module">
+      <leaf1>10</leaf1>
+    </cont1>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-conformance-mismatch.xml b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-conformance-mismatch.xml
new file mode 100644
index 0000000..cde7289
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-conformance-mismatch.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>123</module-set-id>
+      <module>
+        <name>simple-module</name>
+        <revision>2020-12-10</revision>
+        <namespace>test:simple-module</namespace>
+        <conformance-type>implement</conformance-type>		<!-- mismatch here -->
+      </module>
+      <module>
+        <name>ietf-yang-library</name>
+        <revision>2019-01-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-yang-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-inet-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-datastores</name>
+        <revision>2018-02-14</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-feature-mismatch.xml b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-feature-mismatch.xml
new file mode 100644
index 0000000..6b8f5d6
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-feature-mismatch.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>123</module-set-id>
+      <module>
+        <name>simple-module</name>
+        <revision>2020-12-10</revision>
+        <namespace>test:simple-module</namespace>
+        <conformance-type>implement</conformance-type>
+        <feature>unknown-feature</feature>
+      </module>
+      <module>
+        <name>ietf-yang-library</name>
+        <revision>2019-01-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-yang-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-inet-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-datastores</name>
+        <revision>2018-02-14</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-features-ok.xml b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-features-ok.xml
new file mode 100644
index 0000000..dd0c097
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-features-ok.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>123</module-set-id>
+      <module>
+        <name>simple-module</name>
+        <revision>2020-12-10</revision>
+        <namespace>test:simple-module</namespace>
+        <conformance-type>implement</conformance-type>
+        <feature>feature1</feature>
+        <feature>feature2</feature>
+      </module>
+      <module>
+        <name>ietf-yang-library</name>
+        <revision>2019-01-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-yang-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-inet-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-datastores</name>
+        <revision>2018-02-14</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-namespace-mismatch.xml b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-namespace-mismatch.xml
new file mode 100644
index 0000000..eb5c44c
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed-namespace-mismatch.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>123</module-set-id>
+      <module>
+        <name>simple-module</name>
+        <revision>2020-12-10</revision>
+        <namespace>namespace-mismatch-here</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-yang-library</name>
+        <revision>2019-01-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-yang-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-inet-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-datastores</name>
+        <revision>2018-02-14</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed.xml b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed.xml
new file mode 100644
index 0000000..5cef8b2
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-all-listed.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>123</module-set-id>
+      <module>
+        <name>simple-module</name>
+        <revision>2020-12-10</revision>
+        <namespace>test:simple-module</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-yang-library</name>
+        <revision>2019-01-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-library</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-yang-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-yang-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-inet-types</name>
+        <revision>2019-11-04</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-inet-types</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>ietf-datastores</name>
+        <revision>2018-02-14</revision>
+        <namespace>urn:ietf:params:xml:ns:yang:ietf-datastores</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-simple-module-only.xml b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-simple-module-only.xml
new file mode 100644
index 0000000..9b25d3b
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/data-yang-library-simple-module-only.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>123</module-set-id>
+      <module>
+        <name>simple-module</name>
+        <revision>2020-12-10</revision>
+        <namespace>test:simple-module</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/simple-module.yang b/yang-parser/src/test/resources/basics/check-yl-against-schema/simple-module.yang
new file mode 100644
index 0000000..25c5507
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/simple-module.yang
@@ -0,0 +1,25 @@
+module simple-module {
+
+	namespace "test:simple-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	 Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-12-10";
+
+	feature feature1;
+	feature feature2;
+
+	container cont1 {
+		leaf leaf1 {
+			type uint32;
+			if-feature feature1;
+		}
+		leaf leaf2 {
+			type uint32;
+			if-feature feature2;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-datastores-2018-02-14.yang b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-datastores-2018-02-14.yang
new file mode 100644
index 0000000..9e875ab
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-datastores-2018-02-14.yang
@@ -0,0 +1,117 @@
+module ietf-datastores {
+  yang-version 1.1;
+  namespace "urn:ietf:params:xml:ns:yang:ietf-datastores";
+  prefix ds;
+
+  organization
+    "IETF Network Modeling (NETMOD) Working Group";
+
+  contact
+    "WG Web:   <https://datatracker.ietf.org/wg/netmod/>
+
+     WG List:  <mailto:netmod@ietf.org>
+
+     Author:   Martin Bjorklund
+               <mailto:mbj@tail-f.com>
+
+     Author:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>
+
+     Author:   Phil Shafer
+               <mailto:phil@juniper.net>
+
+     Author:   Kent Watsen
+               <mailto:kwatsen@juniper.net>
+
+     Author:   Rob Wilton
+               <rwilton@cisco.com>";
+
+  description
+    "This YANG module defines a set of identities for identifying
+     datastores.
+
+     Copyright (c) 2018 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject to
+     the license terms contained in, the Simplified BSD License set
+     forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (https://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 8342
+     (https://www.rfc-editor.org/info/rfc8342); see the RFC itself
+     for full legal notices.";
+
+  revision 2018-02-14 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 8342: Network Management Datastore Architecture (NMDA)";
+  }
+
+  /*
+   * Identities
+   */
+
+  identity datastore {
+    description
+      "Abstract base identity for datastore identities.";
+  }
+
+  identity conventional {
+    base datastore;
+    description
+      "Abstract base identity for conventional configuration
+       datastores.";
+  }
+
+  identity running {
+    base conventional;
+    description
+      "The running configuration datastore.";
+  }
+
+  identity candidate {
+    base conventional;
+    description
+      "The candidate configuration datastore.";
+  }
+
+  identity startup {
+    base conventional;
+    description
+      "The startup configuration datastore.";
+  }
+
+  identity intended {
+    base conventional;
+    description
+      "The intended configuration datastore.";
+  }
+
+  identity dynamic {
+    base datastore;
+    description
+      "Abstract base identity for dynamic configuration datastores.";
+  }
+
+  identity operational {
+    base datastore;
+    description
+      "The operational state datastore.";
+  }
+
+  /*
+   * Type definitions
+   */
+
+  typedef datastore-ref {
+    type identityref {
+      base datastore;
+    }
+    description
+      "A datastore identity reference.";
+  }
+}
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-inet-types-2019-11-04.yang b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-inet-types-2019-11-04.yang
new file mode 100644
index 0000000..dffb111
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-inet-types-2019-11-04.yang
@@ -0,0 +1,589 @@
+module ietf-inet-types {
+
+  namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+  prefix "inet";
+
+  organization
+   "IETF Network Modeling (NETMOD) Working Group";
+
+  contact
+   "WG Web:   <https://datatracker.ietf.org/wg/netmod/>
+    WG List:  <mailto:netmod@ietf.org>
+
+    Editor:   Juergen Schoenwaelder
+              <mailto:j.schoenwaelder@jacobs-university.de>";
+
+  description
+   "This module contains a collection of generally useful derived
+    YANG data types for Internet addresses and related things.
+
+    The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
+    NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
+    'MAY', and 'OPTIONAL' in this document are to be interpreted as
+    described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
+    they appear in all capitals, as shown here.
+
+    Copyright (c) 2019 IETF Trust and the persons identified as
+    authors of the code.  All rights reserved.
+
+    Redistribution and use in source and binary forms, with or
+    without modification, is permitted pursuant to, and subject
+    to the license terms contained in, the Simplified BSD License
+    set forth in Section 4.c of the IETF Trust's Legal Provisions
+    Relating to IETF Documents
+    (http://trustee.ietf.org/license-info).
+
+    This version of this YANG module is part of RFC XXXX;
+    see the RFC itself for full legal notices.";
+  revision 2019-11-04 {
+    description
+     "This revision adds the following new data types:
+      - ip-address-and-prefix
+      - ipv4-address-and-prefix
+      - ipv6-address-and-prefix
+      - email-address";
+    reference
+     "RFC XXXX: Common YANG Data Types";
+  }
+
+  revision 2013-07-15 {
+    description
+     "This revision adds the following new data types:
+      - ip-address-no-zone
+      - ipv4-address-no-zone
+      - ipv6-address-no-zone";
+    reference
+     "RFC 6991: Common YANG Data Types";
+  }
+
+  revision 2010-09-24 {
+    description
+     "Initial revision.";
+    reference
+     "RFC 6021: Common YANG Data Types";
+  }
+
+  /*** collection of types related to protocol fields ***/
+
+  typedef ip-version {
+    type enumeration {
+      enum unknown {
+        value "0";
+        description
+         "An unknown or unspecified version of the Internet
+          protocol.";
+      }
+      enum ipv4 {
+        value "1";
+        description
+         "The IPv4 protocol as defined in RFC 791.";
+      }
+      enum ipv6 {
+        value "2";
+        description
+         "The IPv6 protocol as defined in RFC 2460.";
+      }
+    }
+    description
+     "This value represents the version of the IP protocol.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetVersion textual convention of the SMIv2.";
+    reference
+     "RFC  791: Internet Protocol
+      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+      RFC 4001: Textual Conventions for Internet Network Addresses";
+  }
+
+  typedef dscp {
+    type uint8 {
+      range "0..63";
+    }
+    description
+     "The dscp type represents a Differentiated Services Code Point
+      that may be used for marking packets in a traffic stream.
+
+      In the value set and its semantics, this type is equivalent
+      to the Dscp textual convention of the SMIv2.";
+    reference
+     "RFC 3289: Management Information Base for the Differentiated
+                Services Architecture
+      RFC 2474: Definition of the Differentiated Services Field
+                (DS Field) in the IPv4 and IPv6 Headers
+      RFC 2780: IANA Allocation Guidelines For Values In
+                the Internet Protocol and Related Headers";
+  }
+
+  typedef ipv6-flow-label {
+    type uint32 {
+      range "0..1048575";
+    }
+    description
+     "The ipv6-flow-label type represents the flow identifier or
+      Flow Label in an IPv6 packet header that may be used to
+      discriminate traffic flows.
+
+      In the value set and its semantics, this type is equivalent
+      to the IPv6FlowLabel textual convention of the SMIv2.";
+    reference
+     "RFC 3595: Textual Conventions for IPv6 Flow Label
+      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+  }
+
+  typedef port-number {
+    type uint16 {
+      range "0..65535";
+    }
+    description
+     "The port-number type represents a 16-bit port number of an
+      Internet transport-layer protocol such as UDP, TCP, DCCP, or
+      SCTP.  Port numbers are assigned by IANA.  A current list of
+      all assignments is available from <http://www.iana.org/>.
+
+      Note that the port number value zero is reserved by IANA.  In
+      situations where the value zero does not make sense, it can
+      be excluded by subtyping the port-number type.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetPortNumber textual convention of the SMIv2.";
+    reference
+     "RFC  768: User Datagram Protocol
+      RFC  793: Transmission Control Protocol
+      RFC 4960: Stream Control Transmission Protocol
+      RFC 4340: Datagram Congestion Control Protocol (DCCP)
+      RFC 4001: Textual Conventions for Internet Network Addresses";
+  }
+
+  /*** collection of types related to autonomous systems ***/
+
+  typedef as-number {
+    type uint32;
+    description
+     "The as-number type represents autonomous system numbers
+      which identify an Autonomous System (AS).  An AS is a set
+      of routers under a single technical administration, using
+      an interior gateway protocol and common metrics to route
+      packets within the AS, and using an exterior gateway
+      protocol to route packets to other ASes.  IANA maintains
+      the AS number space and has delegated large parts to the
+      regional registries.
+
+      Autonomous system numbers were originally limited to 16
+      bits.  BGP extensions have enlarged the autonomous system
+      number space to 32 bits.  This type therefore uses an uint32
+      base type without a range restriction in order to support
+      a larger autonomous system number space.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetAutonomousSystemNumber textual convention of
+      the SMIv2.";
+    reference
+     "RFC 1930: Guidelines for creation, selection, and registration
+                of an Autonomous System (AS)
+      RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+      RFC 4001: Textual Conventions for Internet Network Addresses
+      RFC 6793: BGP Support for Four-Octet Autonomous System (AS)
+                Number Space";
+  }
+
+  /*** collection of types related to IP addresses and hostnames ***/
+
+  typedef ip-address {
+    type union {
+      type inet:ipv4-address;
+      type inet:ipv6-address;
+    }
+    description
+     "The ip-address type represents an IP address and is IP
+      version neutral.  The format of the textual representation
+      implies the IP version.  This type supports scoped addresses
+      by allowing zone identifiers in the address format.";
+    reference
+     "RFC 4007: IPv6 Scoped Address Architecture";
+  }
+
+  typedef ipv4-address {
+    type string {
+      pattern
+        '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+      +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+      + '(%[\p{N}\p{L}]+)?';
+    }
+    description
+      "The ipv4-address type represents an IPv4 address in
+       dotted-quad notation.  The IPv4 address may include a zone
+       index, separated by a % sign.
+
+       The zone index is used to disambiguate identical address
+       values.  For link-local addresses, the zone index will
+       typically be the interface index number or the name of an
+       interface.  If the zone index is not present, the default
+       zone of the device will be used.
+
+       The canonical format for the zone index is the numerical
+       format";
+  }
+
+  typedef ipv6-address {
+    type string {
+      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+            + '(%[\p{N}\p{L}]+)?';
+      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+            + '(%.+)?';
+    }
+    description
+     "The ipv6-address type represents an IPv6 address in full,
+      mixed, shortened, and shortened-mixed notation.  The IPv6
+      address may include a zone index, separated by a % sign.
+
+      The zone index is used to disambiguate identical address
+      values.  For link-local addresses, the zone index will
+      typically be the interface index number or the name of an
+      interface.  If the zone index is not present, the default
+      zone of the device will be used.
+
+      The canonical format of IPv6 addresses uses the textual
+      representation defined in Section 4 of RFC 5952.  The
+      canonical format for the zone index is the numerical
+      format as described in Section 11.2 of RFC 4007.";
+    reference
+     "RFC 4291: IP Version 6 Addressing Architecture
+      RFC 4007: IPv6 Scoped Address Architecture
+      RFC 5952: A Recommendation for IPv6 Address Text
+                Representation";
+  }
+
+  typedef ip-address-no-zone {
+    type union {
+      type inet:ipv4-address-no-zone;
+      type inet:ipv6-address-no-zone;
+    }
+    description
+     "The ip-address-no-zone type represents an IP address and is
+      IP version neutral.  The format of the textual representation
+      implies the IP version.  This type does not support scoped
+      addresses since it does not allow zone identifiers in the
+      address format.";
+    reference
+     "RFC 4007: IPv6 Scoped Address Architecture";
+  }
+
+  typedef ipv4-address-no-zone {
+    type inet:ipv4-address {
+      pattern '[0-9\.]*';
+    }
+    description
+      "An IPv4 address without a zone index.  This type, derived from
+       ipv4-address, may be used in situations where the zone is known
+       from the context and hence no zone index is needed.";
+  }
+
+  typedef ipv6-address-no-zone {
+    type inet:ipv6-address {
+      pattern '[0-9a-fA-F:\.]*';
+    }
+    description
+      "An IPv6 address without a zone index.  This type, derived from
+       ipv6-address, may be used in situations where the zone is known
+       from the context and hence no zone index is needed.";
+    reference
+     "RFC 4291: IP Version 6 Addressing Architecture
+      RFC 4007: IPv6 Scoped Address Architecture
+      RFC 5952: A Recommendation for IPv6 Address Text
+                Representation";
+  }
+
+  typedef ip-prefix {
+    type union {
+      type inet:ipv4-prefix;
+      type inet:ipv6-prefix;
+    }
+    description
+     "The ip-prefix type represents an IP prefix and is IP
+      version neutral.  The format of the textual representations
+      implies the IP version.";
+  }
+
+  typedef ipv4-prefix {
+    type string {
+      pattern
+         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+       + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+    }
+    description
+     "The ipv4-prefix type represents an IPv4 prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal to 32.
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.
+      The canonical format of an IPv4 prefix has all bits of
+      the IPv4 address set to zero that are not part of the
+      IPv4 prefix.
+
+      The definition of ipv4-prefix does not require that bits,
+      which are not part of the prefix, are set to zero. However,
+      implementations have to return values in canonical format,
+      which requires non-prefix bits to be set to zero. This means
+      that 192.0.2.1/24 must be accepted as a valid value but it
+      will be converted into the canonical format 192.0.2.0/24.";
+  }
+
+  typedef ipv6-prefix {
+    type string {
+      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+            + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+            + '(/.+)';
+    }
+    description
+     "The ipv6-prefix type represents an IPv6 prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal to 128.
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.
+
+      The canonical format of an IPv6 prefix has all bits of
+      the IPv6 address set to zero that are not part of the
+      IPv6 prefix.  Furthermore, the IPv6 address is represented
+      as defined in Section 4 of RFC 5952.
+
+      The definition of ipv6-prefix does not require that bits,
+      which are not part of the prefix, are set to zero. However,
+      implementations have to return values in canonical format,
+      which requires non-prefix bits to be set to zero. This means
+      that 2001:db8::1/64 must be accepted as a valid value but it
+      will be converted into the canonical format 2001:db8::/64.";
+    reference
+     "RFC 5952: A Recommendation for IPv6 Address Text
+                Representation";
+  }
+
+  typedef ip-address-and-prefix {
+    type union {
+      type inet:ipv4-address-and-prefix;
+      type inet:ipv6-address-and-prefix;
+    }
+    description
+     "The ip-address-and-prefix type represents an IP address and
+      prefix and is IP version neutral.  The format of the textual
+      representations implies the IP version.";
+  }
+
+  typedef ipv4-address-and-prefix {
+    type string {
+      pattern
+         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+       + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+    }
+    description
+     "The ipv4-address-and-prefix type represents an IPv4
+      address and an associated ipv4 prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal to 32.
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.";
+  }
+
+  typedef ipv6-address-and-prefix {
+    type string {
+      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+            + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+            + '(/.+)';
+    }
+    description
+     "The ipv6-address-and-prefix type represents an IPv6
+      address and an associated ipv4 prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal to 128.
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.
+
+      The canonical format requires that the IPv6 address is
+      represented as defined in Section 4 of RFC 5952.";
+    reference
+     "RFC 5952: A Recommendation for IPv6 Address Text
+                Representation";
+  }
+
+  /*** collection of domain name and URI types ***/
+
+  typedef domain-name {
+    type string {
+      length "1..253";
+      pattern
+        '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+      + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+      + '|\.';
+    }
+    description
+     "The domain-name type represents a DNS domain name.  The
+      name SHOULD be fully qualified whenever possible. This
+      type does not support wildcards (see RFC 4592) or
+      classless in-addr.arpa delegations (see RFC 2317).
+
+      Internet domain names are only loosely specified.  Section
+      3.5 of RFC 1034 recommends a syntax (modified in Section
+      2.1 of RFC 1123).  The pattern above is intended to allow
+      for current practice in domain name use, and some possible
+      future expansion.  Note that Internet host names have a
+      stricter syntax (described in RFC 952) than the DNS
+      recommendations in RFCs 1034 and 1123, and that systems
+      that want to store host names in schema node instances
+      using the domain-name type are recommended to adhere to
+      this stricter standard to ensure interoperability.
+
+      The encoding of DNS names in the DNS protocol is limited
+      to 255 characters.  Since the encoding consists of labels
+      prefixed by a length bytes and there is a trailing NULL
+      byte, only 253 characters can appear in the textual dotted
+      notation.
+
+      The description clause of schema nodes using the domain-name
+      type MUST describe when and how these names are resolved to
+      IP addresses.  Note that the resolution of a domain-name value
+      may require to query multiple DNS records (e.g., A for IPv4
+      and AAAA for IPv6).  The order of the resolution process and
+      which DNS record takes precedence can either be defined
+      explicitly or may depend on the configuration of the
+      resolver.
+
+      Domain-name values use the US-ASCII encoding.  Their canonical
+      format uses lowercase US-ASCII characters.  Internationalized
+      domain names MUST be A-labels as per RFC 5890.";
+    reference
+     "RFC  952: DoD Internet Host Table Specification
+      RFC 1034: Domain Names - Concepts and Facilities
+      RFC 1123: Requirements for Internet Hosts -- Application
+                and Support
+      RFC 2317: Classless IN-ADDR.ARPA delegation
+      RFC 2782: A DNS RR for specifying the location of services
+                (DNS SRV)
+      RFC 4592: The Role of Wildcards in the Domain Name System
+      RFC 5890: Internationalized Domain Names in Applications
+                (IDNA): Definitions and Document Framework";
+  }
+
+  typedef host {
+    type union {
+      type inet:ip-address;
+      type inet:domain-name;
+    }
+    description
+     "The host type represents either an IP address or a DNS
+      domain name.";
+  }
+
+  /*
+   * DISCUSS:
+   * - Lada suggested to replace the inet:domain-name usage in
+   *   the union with a new host-name definition that follows
+   *   the NR-LDH definition in RFC 5890.
+   */
+
+  typedef uri {
+    type string;
+    description
+     "The uri type represents a Uniform Resource Identifier
+      (URI) as defined by STD 66.
+
+      Objects using the uri type MUST be in US-ASCII encoding,
+      and MUST be normalized as described by RFC 3986 Sections
+      6.2.1, 6.2.2.1, and 6.2.2.2.  All unnecessary
+      percent-encoding is removed, and all case-insensitive
+      characters are set to lowercase except for hexadecimal
+      digits, which are normalized to uppercase as described in
+      Section 6.2.2.1.
+
+      The purpose of this normalization is to help provide
+      unique URIs.  Note that this normalization is not
+      sufficient to provide uniqueness.  Two URIs that are
+      textually distinct after this normalization may still be
+      equivalent.
+
+      Objects using the uri type may restrict the schemes that
+      they permit.  For example, 'data:' and 'urn:' schemes
+      might not be appropriate.
+
+      A zero-length URI is not a valid URI.  This can be used to
+      express 'URI absent' where required.
+
+      In the value set and its semantics, this type is equivalent
+      to the Uri SMIv2 textual convention defined in RFC 5017.";
+    reference
+     "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+      RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+                Group: Uniform Resource Identifiers (URIs), URLs,
+                and Uniform Resource Names (URNs): Clarifications
+                and Recommendations
+      RFC 5017: MIB Textual Conventions for Uniform Resource
+                Identifiers (URIs)";
+  }
+
+  typedef email-address {
+    type string {
+      // dot-atom-text "@" ...
+      pattern '[a-zA-Z0-9!#$%&'+"'"+'*+/=?^_`{|}~-]+'
+            + '(\.[a-zA-Z0-9!#$%&'+"'"+'*+/=?^_`{|}~-]+)*'
+            + '@'
+            + '[a-zA-Z0-9!#$%&'+"'"+'*+/=?^_`{|}~-]+'
+            + '(\.[a-zA-Z0-9!#$%&'+"'"+'*+/=?^_`{|}~-]+)*';
+    }
+    description
+      "The email-address type represents an email address as
+       defined as addr-spec in RFC 5322 section 3.4.1.";
+    reference
+      "RFC 5322: Internet Message Format";
+  }
+
+  /*
+   * DISCUSS:
+   * - It was suggested to add email types following RFC 5322
+   *   email-address        (addr-spec, per Section 3.4.1)
+   *   named-email-address  (name-addr, per Section 3.4)
+   * - This sounds useful but the devil is in the details,
+   *   in particular name-addr is a quite complex construct;
+   *   perhaps addr-spec is sufficient, this is also the
+   *   format allowed in mailto: URIs (mailto: seems to use
+   *   only a subset of addr-spec which may be good enough
+   *   here as well).
+   * - Need to define a pattern that has a meaningful trade-off
+   *   between precision and complexity (there are very tight
+   *   pattern that are very long and complex). The current
+   *   pattern does not take care of quoted-string, obs-local-part,
+   *   domain-literal, obs-domain.
+   */
+
+  /*
+   * DISCUSS:
+   * - There was a request to add types for URI fields (scheme,
+   *   authority, path, query, fragment) but it is not clear how
+   *   commonly useful these types are, the WG was pretty silent
+   *   about this proposal. On the technical side, it is unclear
+   *   whether data is represented with percent escapes resolved
+   *   or not. (Mahesh's proposal does not spell this out, the
+   *   pattern does not allow the % character, which may be wrong.)
+   */
+}
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-yang-library-2019-01-04.yang b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-yang-library-2019-01-04.yang
new file mode 100644
index 0000000..dac53a1
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-yang-library-2019-01-04.yang
@@ -0,0 +1,544 @@
+module ietf-yang-library {
+  yang-version 1.1;
+  namespace "urn:ietf:params:xml:ns:yang:ietf-yang-library";
+  prefix yanglib;
+
+  import ietf-yang-types {
+    prefix yang;
+    reference
+      "RFC 6991: Common YANG Data Types";
+  }
+  import ietf-inet-types {
+    prefix inet;
+    reference
+      "RFC 6991: Common YANG Data Types";
+  }
+  import ietf-datastores {
+    prefix ds;
+    reference
+      "RFC 8342: Network Management Datastore Architecture
+                 (NMDA)";
+  }
+
+  organization
+    "IETF NETCONF (Network Configuration) Working Group";
+  contact
+    "WG Web:   <https://datatracker.ietf.org/wg/netconf/>
+     WG List:  <mailto:netconf@ietf.org>
+
+     Author:   Andy Bierman
+               <mailto:andy@yumaworks.com>
+
+     Author:   Martin Bjorklund
+               <mailto:mbj@tail-f.com>
+
+     Author:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>
+
+     Author:   Kent Watsen
+               <mailto:kent+ietf@watsen.net>
+
+     Author:   Robert Wilton
+               <mailto:rwilton@cisco.com>";
+  description
+    "This module provides information about the YANG modules,
+     datastores, and datastore schemas used by a network
+     management server.
+     The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
+     NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
+     'MAY', and 'OPTIONAL' in this document are to be interpreted as
+     described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
+     they appear in all capitals, as shown here.
+
+     Copyright (c) 2019 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (https://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 8525; see
+     the RFC itself for full legal notices.";
+
+  revision 2019-01-04 {
+    description
+      "Added support for multiple datastores according to the
+       Network Management Datastore Architecture (NMDA).";
+    reference
+      "RFC 8525: YANG Library";
+  }
+  revision 2016-04-09 {
+    description
+      "Initial revision.";
+    reference
+      "RFC 7895: YANG Module Library";
+  }
+
+  /*
+   * Typedefs
+   */
+
+  typedef revision-identifier {
+    type string {
+      pattern '\d{4}-\d{2}-\d{2}';
+    }
+    description
+      "Represents a specific date in YYYY-MM-DD format.";
+  }
+
+  /*
+   * Groupings
+   */
+  grouping module-identification-leafs {
+    description
+      "Parameters for identifying YANG modules and submodules.";
+    leaf name {
+      type yang:yang-identifier;
+      mandatory true;
+      description
+        "The YANG module or submodule name.";
+    }
+    leaf revision {
+      type revision-identifier;
+      description
+        "The YANG module or submodule revision date.  If no revision
+         statement is present in the YANG module or submodule, this
+         leaf is not instantiated.";
+    }
+  }
+
+  grouping location-leaf-list {
+    description
+      "Common leaf-list parameter for the locations of modules and
+       submodules.";
+    leaf-list location {
+      type inet:uri;
+      description
+        "Contains a URL that represents the YANG schema
+         resource for this module or submodule.
+
+         This leaf will only be present if there is a URL
+         available for retrieval of the schema for this entry.";
+    }
+  }
+
+  grouping module-implementation-parameters {
+    description
+      "Parameters for describing the implementation of a module.";
+    leaf-list feature {
+      type yang:yang-identifier;
+      description
+        "List of all YANG feature names from this module that are
+         supported by the server, regardless whether they are defined
+         in the module or any included submodule.";
+    }
+    leaf-list deviation {
+      type leafref {
+        path "../../module/name";
+      }
+
+      description
+        "List of all YANG deviation modules used by this server to
+         modify the conformance of the module associated with this
+         entry.  Note that the same module can be used for deviations
+         for multiple modules, so the same entry MAY appear within
+         multiple 'module' entries.
+
+         This reference MUST NOT (directly or indirectly)
+         refer to the module being deviated.
+
+         Robust clients may want to make sure that they handle a
+         situation where a module deviates itself (directly or
+         indirectly) gracefully.";
+    }
+  }
+
+  grouping module-set-parameters {
+    description
+      "A set of parameters that describe a module set.";
+    leaf name {
+      type string;
+      description
+        "An arbitrary name of the module set.";
+    }
+    list module {
+      key "name";
+      description
+        "An entry in this list represents a module implemented by the
+         server, as per Section 5.6.5 of RFC 7950, with a particular
+         set of supported features and deviations.";
+      reference
+        "RFC 7950: The YANG 1.1 Data Modeling Language";
+      uses module-identification-leafs;
+      leaf namespace {
+        type inet:uri;
+        mandatory true;
+        description
+          "The XML namespace identifier for this module.";
+      }
+      uses location-leaf-list;
+      list submodule {
+        key "name";
+        description
+          "Each entry represents one submodule within the
+           parent module.";
+        uses module-identification-leafs;
+        uses location-leaf-list;
+      }
+      uses module-implementation-parameters;
+    }
+    list import-only-module {
+      key "name revision";
+      description
+        "An entry in this list indicates that the server imports
+         reusable definitions from the specified revision of the
+         module but does not implement any protocol-accessible
+         objects from this revision.
+
+         Multiple entries for the same module name MAY exist.  This
+         can occur if multiple modules import the same module but
+         specify different revision dates in the import statements.";
+      leaf name {
+        type yang:yang-identifier;
+        description
+          "The YANG module name.";
+      }
+      leaf revision {
+        type union {
+          type revision-identifier;
+          type string {
+            length "0";
+          }
+        }
+        description
+          "The YANG module revision date.
+           A zero-length string is used if no revision statement
+           is present in the YANG module.";
+      }
+      leaf namespace {
+        type inet:uri;
+        mandatory true;
+        description
+          "The XML namespace identifier for this module.";
+      }
+      uses location-leaf-list;
+      list submodule {
+        key "name";
+        description
+          "Each entry represents one submodule within the
+           parent module.";
+        uses module-identification-leafs;
+        uses location-leaf-list;
+      }
+    }
+  }
+
+  grouping yang-library-parameters {
+    description
+      "The YANG library data structure is represented as a grouping
+       so it can be reused in configuration or another monitoring
+       data structure.";
+    list module-set {
+      key "name";
+      description
+        "A set of modules that may be used by one or more schemas.
+
+         A module set does not have to be referentially complete,
+         i.e., it may define modules that contain import statements
+         for other modules not included in the module set.";
+      uses module-set-parameters;
+    }
+    list schema {
+      key "name";
+      description
+        "A datastore schema that may be used by one or more
+         datastores.
+
+         The schema must be valid and referentially complete, i.e.,
+         it must contain modules to satisfy all used import
+         statements for all modules specified in the schema.";
+      leaf name {
+        type string;
+        description
+          "An arbitrary name of the schema.";
+      }
+      leaf-list module-set {
+        type leafref {
+          path "../../module-set/name";
+        }
+        description
+          "A set of module-sets that are included in this schema.
+           If a non-import-only module appears in multiple module
+           sets, then the module revision and the associated features
+           and deviations must be identical.";
+      }
+    }
+    list datastore {
+      key "name";
+      description
+        "A datastore supported by this server.
+
+         Each datastore indicates which schema it supports.
+
+         The server MUST instantiate one entry in this list per
+         specific datastore it supports.
+         Each datastore entry with the same datastore schema SHOULD
+         reference the same schema.";
+      leaf name {
+        type ds:datastore-ref;
+        description
+          "The identity of the datastore.";
+      }
+      leaf schema {
+        type leafref {
+          path "../../schema/name";
+        }
+        mandatory true;
+        description
+          "A reference to the schema supported by this datastore.
+           All non-import-only modules of the schema are implemented
+           with their associated features and deviations.";
+      }
+    }
+  }
+
+  /*
+   * Top-level container
+   */
+
+  container yang-library {
+    config false;
+    description
+      "Container holding the entire YANG library of this server.";
+    uses yang-library-parameters;
+    leaf content-id {
+      type string;
+      mandatory true;
+      description
+        "A server-generated identifier of the contents of the
+         '/yang-library' tree.  The server MUST change the value of
+         this leaf if the information represented by the
+         '/yang-library' tree, except '/yang-library/content-id', has
+         changed.";
+    }
+  }
+
+  /*
+   * Notifications
+   */
+
+  notification yang-library-update {
+    description
+      "Generated when any YANG library information on the
+       server has changed.";
+    leaf content-id {
+      type leafref {
+        path "/yanglib:yang-library/yanglib:content-id";
+      }
+      mandatory true;
+      description
+        "Contains the YANG library content identifier for the updated
+         YANG library at the time the notification is generated.";
+    }
+  }
+
+  /*
+   * Legacy groupings
+   */
+
+  grouping module-list {
+    status deprecated;
+    description
+      "The module data structure is represented as a grouping
+       so it can be reused in configuration or another monitoring
+       data structure.";
+
+    grouping common-leafs {
+      status deprecated;
+      description
+        "Common parameters for YANG modules and submodules.";
+      leaf name {
+        type yang:yang-identifier;
+        status deprecated;
+        description
+          "The YANG module or submodule name.";
+      }
+      leaf revision {
+        type union {
+          type revision-identifier;
+          type string {
+            length "0";
+          }
+        }
+        status deprecated;
+        description
+          "The YANG module or submodule revision date.
+           A zero-length string is used if no revision statement
+           is present in the YANG module or submodule.";
+      }
+    }
+
+    grouping schema-leaf {
+      status deprecated;
+      description
+        "Common schema leaf parameter for modules and submodules.";
+      leaf schema {
+        type inet:uri;
+        description
+          "Contains a URL that represents the YANG schema
+           resource for this module or submodule.
+
+           This leaf will only be present if there is a URL
+           available for retrieval of the schema for this entry.";
+      }
+    }
+    list module {
+      key "name revision";
+      status deprecated;
+      description
+        "Each entry represents one revision of one module
+         currently supported by the server.";
+      uses common-leafs {
+        status deprecated;
+      }
+      uses schema-leaf {
+        status deprecated;
+      }
+      leaf namespace {
+        type inet:uri;
+        mandatory true;
+        status deprecated;
+        description
+          "The XML namespace identifier for this module.";
+      }
+      leaf-list feature {
+        type yang:yang-identifier;
+        status deprecated;
+        description
+          "List of YANG feature names from this module that are
+           supported by the server, regardless of whether they are
+           defined in the module or any included submodule.";
+      }
+      list deviation {
+        key "name revision";
+        status deprecated;
+
+        description
+          "List of YANG deviation module names and revisions
+           used by this server to modify the conformance of
+           the module associated with this entry.  Note that
+           the same module can be used for deviations for
+           multiple modules, so the same entry MAY appear
+           within multiple 'module' entries.
+
+           The deviation module MUST be present in the 'module'
+           list, with the same name and revision values.
+           The 'conformance-type' value will be 'implement' for
+           the deviation module.";
+        uses common-leafs {
+          status deprecated;
+        }
+      }
+      leaf conformance-type {
+        type enumeration {
+          enum implement {
+            description
+              "Indicates that the server implements one or more
+               protocol-accessible objects defined in the YANG module
+               identified in this entry.  This includes deviation
+               statements defined in the module.
+
+               For YANG version 1.1 modules, there is at most one
+               'module' entry with conformance type 'implement' for a
+               particular module name, since YANG 1.1 requires that
+               at most one revision of a module is implemented.
+
+               For YANG version 1 modules, there SHOULD NOT be more
+               than one 'module' entry for a particular module
+               name.";
+          }
+          enum import {
+            description
+              "Indicates that the server imports reusable definitions
+               from the specified revision of the module but does
+               not implement any protocol-accessible objects from
+               this revision.
+
+               Multiple 'module' entries for the same module name MAY
+               exist.  This can occur if multiple modules import the
+               same module but specify different revision dates in
+               the import statements.";
+          }
+        }
+        mandatory true;
+        status deprecated;
+        description
+          "Indicates the type of conformance the server is claiming
+           for the YANG module identified by this entry.";
+      }
+      list submodule {
+        key "name revision";
+        status deprecated;
+        description
+          "Each entry represents one submodule within the
+           parent module.";
+        uses common-leafs {
+          status deprecated;
+        }
+        uses schema-leaf {
+          status deprecated;
+        }
+      }
+    }
+  }
+
+  /*
+   * Legacy operational state data nodes
+   */
+
+  container modules-state {
+    config false;
+    status deprecated;
+    description
+      "Contains YANG module monitoring information.";
+    leaf module-set-id {
+      type string;
+      mandatory true;
+      status deprecated;
+      description
+        "Contains a server-specific identifier representing
+         the current set of modules and submodules.  The
+         server MUST change the value of this leaf if the
+         information represented by the 'module' list instances
+         has changed.";
+    }
+    uses module-list {
+      status deprecated;
+    }
+  }
+
+  /*
+   * Legacy notifications
+   */
+
+  notification yang-library-change {
+    status deprecated;
+    description
+      "Generated when the set of modules and submodules supported
+       by the server has changed.";
+    leaf module-set-id {
+      type leafref {
+        path "/yanglib:modules-state/yanglib:module-set-id";
+      }
+      mandatory true;
+      status deprecated;
+      description
+        "Contains the module-set-id value representing the
+         set of modules and submodules supported at the server
+         at the time the notification is generated.";
+    }
+  }
+}
diff --git a/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-yang-types-2019-11-04.yang b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-yang-types-2019-11-04.yang
new file mode 100644
index 0000000..d33eced
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/check-yl-against-schema/yang-library-module-and-dependencies/ietf-yang-types-2019-11-04.yang
@@ -0,0 +1,767 @@
+module ietf-yang-types {
+
+  namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+  prefix "yang";
+
+  organization
+   "IETF Network Modeling (NETMOD) Working Group";
+
+  contact
+   "WG Web:   <https://datatracker.ietf.org/wg/netmod/>
+    WG List:  <mailto:netmod@ietf.org>
+
+    Editor:   Juergen Schoenwaelder
+              <mailto:j.schoenwaelder@jacobs-university.de>";
+
+  description
+   "This module contains a collection of generally useful derived
+    YANG data types.
+
+    The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
+    NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
+    'MAY', and 'OPTIONAL' in this document are to be interpreted as
+    described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
+    they appear in all capitals, as shown here.
+
+    Copyright (c) 2019 IETF Trust and the persons identified as
+    authors of the code.  All rights reserved.
+
+    Redistribution and use in source and binary forms, with or
+    without modification, is permitted pursuant to, and subject
+    to the license terms contained in, the Simplified BSD License
+    set forth in Section 4.c of the IETF Trust's Legal Provisions
+    Relating to IETF Documents
+    (http://trustee.ietf.org/license-info).
+
+    This version of this YANG module is part of RFC XXXX;
+    see the RFC itself for full legal notices.";
+
+  revision 2019-11-04 {
+    description
+     "This revision adds the following new data types:
+      - date, time
+      - hours32, minutes32, seconds32, centiseconds32, milliseconds32,
+      - microseconds32, microseconds64, nanoseconds32, nanoseconds64
+      - revision-identifier, node-instance-identifier";
+    reference
+     "RFC XXXX: Common YANG Data Types";
+  }
+
+  revision 2013-07-15 {
+    description
+     "This revision adds the following new data types:
+      - yang-identifier
+      - hex-string
+      - uuid
+      - dotted-quad";
+    reference
+     "RFC 6991: Common YANG Data Types";
+  }
+
+  revision 2010-09-24 {
+    description
+     "Initial revision.";
+    reference
+     "RFC 6021: Common YANG Data Types";
+  }
+
+  /*** collection of counter and gauge types ***/
+
+  typedef counter32 {
+    type uint32;
+    description
+     "The counter32 type represents a non-negative integer
+      that monotonically increases until it reaches a
+      maximum value of 2^32-1 (4294967295 decimal), when it
+      wraps around and starts increasing again from zero.
+
+      Counters have no defined 'initial' value, and thus, a
+      single value of a counter has (in general) no information
+      content.  Discontinuities in the monotonically increasing
+      value normally occur at re-initialization of the
+      management system, and at other times as specified in the
+      description of a schema node using this type.  If such
+      other times can occur, for example, the instantiation of
+      a schema node of type counter32 at times other than
+      re-initialization, then a corresponding schema node
+      should be defined, with an appropriate type, to indicate
+      the last discontinuity.
+      The counter32 type should not be used for configuration
+      schema nodes.  A default statement SHOULD NOT be used in
+      combination with the type counter32.
+
+      In the value set and its semantics, this type is equivalent
+      to the Counter32 type of the SMIv2.";
+    reference
+     "RFC 2578: Structure of Management Information Version 2
+                (SMIv2)";
+  }
+
+  typedef zero-based-counter32 {
+    type yang:counter32;
+    default "0";
+    description
+     "The zero-based-counter32 type represents a counter32
+      that has the defined 'initial' value zero.
+
+      A schema node instance of this type will be set to zero (0)
+      on creation and will thereafter increase monotonically until
+      it reaches a maximum value of 2^32-1 (4294967295 decimal),
+      when it wraps around and starts increasing again from zero.
+
+      Provided that an application discovers a new schema node
+      instance of this type within the minimum time to wrap, it
+      can use the 'initial' value as a delta.  It is important for
+      a management station to be aware of this minimum time and the
+      actual time between polls, and to discard data if the actual
+      time is too long or there is no defined minimum time.
+
+      In the value set and its semantics, this type is equivalent
+      to the ZeroBasedCounter32 textual convention of the SMIv2.";
+    reference
+      "RFC 4502: Remote Network Monitoring Management Information
+                 Base Version 2";
+  }
+
+  typedef counter64 {
+    type uint64;
+    description
+     "The counter64 type represents a non-negative integer
+      that monotonically increases until it reaches a
+      maximum value of 2^64-1 (18446744073709551615 decimal),
+      when it wraps around and starts increasing again from zero.
+
+      Counters have no defined 'initial' value, and thus, a
+      single value of a counter has (in general) no information
+      content.  Discontinuities in the monotonically increasing
+      value normally occur at re-initialization of the
+      management system, and at other times as specified in the
+      description of a schema node using this type.  If such
+      other times can occur, for example, the instantiation of
+      a schema node of type counter64 at times other than
+      re-initialization, then a corresponding schema node
+      should be defined, with an appropriate type, to indicate
+      the last discontinuity.
+
+      The counter64 type should not be used for configuration
+      schema nodes.  A default statement SHOULD NOT be used in
+      combination with the type counter64.
+
+      In the value set and its semantics, this type is equivalent
+      to the Counter64 type of the SMIv2.";
+    reference
+     "RFC 2578: Structure of Management Information Version 2
+                (SMIv2)";
+  }
+
+  typedef zero-based-counter64 {
+    type yang:counter64;
+    default "0";
+    description
+     "The zero-based-counter64 type represents a counter64 that
+      has the defined 'initial' value zero.
+
+      A schema node instance of this type will be set to zero (0)
+      on creation and will thereafter increase monotonically until
+      it reaches a maximum value of 2^64-1 (18446744073709551615
+      decimal), when it wraps around and starts increasing again
+      from zero.
+
+      Provided that an application discovers a new schema node
+      instance of this type within the minimum time to wrap, it
+      can use the 'initial' value as a delta.  It is important for
+      a management station to be aware of this minimum time and the
+      actual time between polls, and to discard data if the actual
+      time is too long or there is no defined minimum time.
+
+      In the value set and its semantics, this type is equivalent
+      to the ZeroBasedCounter64 textual convention of the SMIv2.";
+    reference
+     "RFC 2856: Textual Conventions for Additional High Capacity
+                Data Types";
+  }
+
+  typedef gauge32 {
+    type uint32;
+    description
+     "The gauge32 type represents a non-negative integer, which
+      may increase or decrease, but shall never exceed a maximum
+      value, nor fall below a minimum value.  The maximum value
+      cannot be greater than 2^32-1 (4294967295 decimal), and
+      the minimum value cannot be smaller than 0.  The value of
+      a gauge32 has its maximum value whenever the information
+      being modeled is greater than or equal to its maximum
+      value, and has its minimum value whenever the information
+      being modeled is smaller than or equal to its minimum value.
+      If the information being modeled subsequently decreases
+      below (increases above) the maximum (minimum) value, the
+      gauge32 also decreases (increases).
+
+      In the value set and its semantics, this type is equivalent
+      to the Gauge32 type of the SMIv2.";
+    reference
+     "RFC 2578: Structure of Management Information Version 2
+                (SMIv2)";
+  }
+
+  typedef gauge64 {
+    type uint64;
+    description
+     "The gauge64 type represents a non-negative integer, which
+      may increase or decrease, but shall never exceed a maximum
+      value, nor fall below a minimum value.  The maximum value
+      cannot be greater than 2^64-1 (18446744073709551615), and
+      the minimum value cannot be smaller than 0.  The value of
+      a gauge64 has its maximum value whenever the information
+      being modeled is greater than or equal to its maximum
+      value, and has its minimum value whenever the information
+      being modeled is smaller than or equal to its minimum value.
+      If the information being modeled subsequently decreases
+      below (increases above) the maximum (minimum) value, the
+      gauge64 also decreases (increases).
+
+      In the value set and its semantics, this type is equivalent
+      to the CounterBasedGauge64 SMIv2 textual convention defined
+      in RFC 2856";
+    reference
+     "RFC 2856: Textual Conventions for Additional High Capacity
+                Data Types";
+  }
+
+  /*** collection of identifier-related types ***/
+
+  typedef object-identifier {
+    type string {
+      pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+            + '(\.(0|([1-9]\d*)))*';
+    }
+    description
+     "The object-identifier type represents administratively
+      assigned names in a registration-hierarchical-name tree.
+
+      Values of this type are denoted as a sequence of numerical
+      non-negative sub-identifier values.  Each sub-identifier
+      value MUST NOT exceed 2^32-1 (4294967295).  Sub-identifiers
+      are separated by single dots and without any intermediate
+      whitespace.
+
+      The ASN.1 standard restricts the value space of the first
+      sub-identifier to 0, 1, or 2.  Furthermore, the value space
+      of the second sub-identifier is restricted to the range
+      0 to 39 if the first sub-identifier is 0 or 1.  Finally,
+      the ASN.1 standard requires that an object identifier
+      has always at least two sub-identifiers.  The pattern
+      captures these restrictions.
+
+      Although the number of sub-identifiers is not limited,
+      module designers should realize that there may be
+      implementations that stick with the SMIv2 limit of 128
+      sub-identifiers.
+
+      This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+      since it is not restricted to 128 sub-identifiers.  Hence,
+      this type SHOULD NOT be used to represent the SMIv2 OBJECT
+      IDENTIFIER type; the object-identifier-128 type SHOULD be
+      used instead.";
+    reference
+     "ISO9834-1: Information technology -- Open Systems
+      Interconnection -- Procedures for the operation of OSI
+      Registration Authorities: General procedures and top
+      arcs of the ASN.1 Object Identifier tree";
+  }
+
+  typedef object-identifier-128 {
+    type object-identifier {
+      pattern '\d*(\.\d*){1,127}';
+    }
+    description
+     "This type represents object-identifiers restricted to 128
+      sub-identifiers.
+
+      In the value set and its semantics, this type is equivalent
+      to the OBJECT IDENTIFIER type of the SMIv2.";
+    reference
+     "RFC 2578: Structure of Management Information Version 2
+                (SMIv2)";
+  }
+
+  /*** collection of types related to date and time ***/
+
+  typedef date-and-time {
+    type string {
+      pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+            + '(Z|[\+\-]\d{2}:\d{2})';
+    }
+    description
+     "The date-and-time type is a profile of the ISO 8601
+      standard for representation of dates and times using the
+      Gregorian calendar.  The profile is defined by the
+      date-time production in Section 5.6 of RFC 3339.
+
+      The date-and-time type is compatible with the dateTime XML
+      schema type with the following notable exceptions:
+
+      (a) The date-and-time type does not allow negative years.
+
+      (b) The date-and-time time-offset -00:00 indicates an unknown
+          time zone (see RFC 3339) while -00:00 and +00:00 and Z
+          all represent the same time zone in dateTime.
+
+      (c) The canonical format (see below) of date-and-time values
+          differs from the canonical format used by the dateTime XML
+          schema type, which requires all times to be in UTC using
+          the time-offset 'Z'.
+
+      This type is not equivalent to the DateAndTime textual
+      convention of the SMIv2 since RFC 3339 uses a different
+      separator between full-date and full-time and provides
+      higher resolution of time-secfrac.
+
+      The canonical format for date-and-time values with a known time
+      zone uses a numeric time zone offset that is calculated using
+      the device's configured known offset to UTC time.  A change of
+      the device's offset to UTC time will cause date-and-time values
+      to change accordingly.  Such changes might happen periodically
+      in case a server follows automatically daylight saving time
+      (DST) time zone offset changes.  The canonical format for
+      date-and-time values with an unknown time zone (usually
+      referring to the notion of local time) uses the time-offset
+      -00:00.";
+    reference
+     "RFC 3339: Date and Time on the Internet: Timestamps
+      RFC 2579: Textual Conventions for SMIv2
+      XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+  }
+
+  typedef date {
+    type string {
+      pattern '\d{4}-\d{2}-\d{2}'
+            + '(Z|[\+\-]\d{2}:\d{2})';
+    }
+    description
+     "The date type represents a time-interval of the length
+      of a day, i.e., 24 hours.
+
+      The date type is compatible with the date XML schema
+      type with the following notable exceptions:
+
+      (a) The date type does not allow negative years.
+
+      (b) The date time-offset -00:00 indicates an unknown
+          time zone (see RFC 3339) while -00:00 and +00:00 and Z
+          all represent the same time zone in date.
+
+      (c) The canonical format (see below) of data values
+          differs from the canonical format used by the date XML
+          schema type, which requires all times to be in UTC using
+          the time-offset 'Z'.
+
+      The canonical format for date values with a known time
+      zone uses a numeric time zone offset that is calculated using
+      the device's configured known offset to UTC time.  A change of
+      the device's offset to UTC time will cause date values
+      to change accordingly.  Such changes might happen periodically
+      in case a server follows automatically daylight saving time
+      (DST) time zone offset changes.  The canonical format for
+      date values with an unknown time zone (usually referring
+      to the notion of local time) uses the time-offset -00:00.";
+    reference
+     "RFC 3339: Date and Time on the Internet: Timestamps
+      XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+  }
+
+  /*
+   * DISCUSS:
+   * - XML schema seems to use a different canonical format, we
+   *   need to take a closer look how to define the canonical format
+   *   given that a data really identifies a 24 hour interval and
+   *   what XSD means with 'interval midpoint'.
+   */
+
+  typedef time {
+    type string {
+      pattern '\d{2}:\d{2}:\d{2}(\.\d+)?'
+            + '(Z|[\+\-]\d{2}:\d{2})';
+    }
+    description
+     "The time type represents an instance of time of zero-duration
+      that recurs every day.
+
+      The time type is compatible with the time XML schema
+      type with the following notable exceptions:
+
+      (a) The time time-offset -00:00 indicates an unknown
+          time zone (see RFC 3339) while -00:00 and +00:00 and Z
+          all represent the same time zone in time.
+
+      (c) The canonical format (see below) of time values
+          differs from the canonical format used by the time XML
+          schema type, which requires all times to be in UTC using
+          the time-offset 'Z'.
+
+      The canonical format for time values with a known time
+      zone uses a numeric time zone offset that is calculated using
+      the device's configured known offset to UTC time.  A change of
+      the device's offset to UTC time will cause time values
+      to change accordingly.  Such changes might happen periodically
+      in case a server follows automatically daylight saving time
+      (DST) time zone offset changes.  The canonical format for
+      time values with an unknown time zone (usually referring
+      to the notion of local time) uses the time-offset -00:00.";
+    reference
+     "RFC 3339: Date and Time on the Internet: Timestamps
+      XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+  }
+
+  typedef hours32 {
+    type int32;
+    units "hours";
+    description
+        "A period of time, measured in units of hours.
+
+         The maximum time period that can be expressed is in the
+         range [89478485 days 08:00:00 to 89478485 days 07:00:00].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef minutes32 {
+    type int32;
+    units "minutes";
+    description
+        "A period of time, measured in units of minutes.
+
+         The maximum time period that can be expressed is in the
+         range [-1491308 days 2:08:00 to 1491308 days 2:07:00].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef seconds32 {
+    type int32;
+    units "seconds";
+    description
+        "A period of time, measured in units of seconds.
+
+         The maximum time period that can be expressed is in the
+         range [-24855 days 03:14:08 to 24855 days 03:14:07].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef centiseconds32 {
+    type int32;
+    units "centiseconds";
+    description
+        "A period of time, measured in units of 10^-2 seconds.
+
+         The maximum time period that can be expressed is in the
+         range [-248 days 13:13:56 to 248 days 13:13:56].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef milliseconds32 {
+    type int32;
+    units "milliseconds";
+    description
+        "A period of time, measured in units of 10^-3 seconds.
+
+         The maximum time period that can be expressed is in the
+         range [-24 days 20:31:23 to 24 days 20:31:23].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef microseconds32 {
+    type int32;
+    units "microseconds";
+    description
+        "A period of time, measured in units of 10^-6 seconds.
+
+         The maximum time period that can be expressed is in the
+         range [-00:35:47 to 00:35:47].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef microseconds64 {
+    type int64;
+    units "microseconds";
+    description
+        "A period of time, measured in units of 10^-6 seconds.
+
+         The maximum time period that can be expressed is in the
+         range [-106751991 days 04:00:54 to 106751991 days 04:00:54].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef nanoseconds32 {
+    type int32;
+    units "nanoseconds";
+    description
+        "A period of time, measured in units of 10^-9 seconds.
+
+         The maximum time period that can be expressed is in the
+         range [-00:00:02 to 00:00:02].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef nanoseconds64 {
+    type int64;
+    units "nanoseconds";
+    description
+        "A period of time, measured in units of 10^-9 seconds.
+
+         The maximum time period that can be expressed is in the
+         range [-106753 days 23:12:44 to 106752 days 0:47:16].
+
+         This type should be range restricted in situations
+         where only non-negative time periods are desirable,
+         (i.e., range '0..max').";
+  }
+
+  typedef timeticks {
+    type uint32;
+    description
+     "The timeticks type represents a non-negative integer that
+      represents the time, modulo 2^32 (4294967296 decimal), in
+      hundredths of a second between two epochs.  When a schema
+      node is defined that uses this type, the description of
+      the schema node identifies both of the reference epochs.
+
+      In the value set and its semantics, this type is equivalent
+      to the TimeTicks type of the SMIv2.";
+    reference
+     "RFC 2578: Structure of Management Information Version 2
+                (SMIv2)";
+  }
+
+  typedef timestamp {
+    type yang:timeticks;
+    description
+     "The timestamp type represents the value of an associated
+      timeticks schema node instance at which a specific occurrence
+      happened.  The specific occurrence must be defined in the
+      description of any schema node defined using this type.  When
+      the specific occurrence occurred prior to the last time the
+      associated timeticks schema node instance was zero, then the
+      timestamp value is zero.
+
+      Note that this requires all timestamp values to be reset to
+      zero when the value of the associated timeticks schema node
+      instance reaches 497+ days and wraps around to zero.
+
+      The associated timeticks schema node must be specified
+      in the description of any schema node using this type.
+
+      In the value set and its semantics, this type is equivalent
+      to the TimeStamp textual convention of the SMIv2.";
+    reference
+     "RFC 2579: Textual Conventions for SMIv2";
+  }
+
+  /*** collection of generic address types ***/
+
+  typedef phys-address {
+    type string {
+      pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+    }
+    description
+     "Represents media- or physical-level addresses represented
+      as a sequence octets, each octet represented by two hexadecimal
+      numbers.  Octets are separated by colons.  The canonical
+      representation uses lowercase characters.
+
+      In the value set and its semantics, this type is equivalent
+      to the PhysAddress textual convention of the SMIv2.";
+    reference
+     "RFC 2579: Textual Conventions for SMIv2";
+  }
+
+  typedef mac-address {
+    type string {
+      pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+    }
+    description
+     "The mac-address type represents an IEEE 802 MAC address.
+      The canonical representation uses lowercase characters.
+
+      In the value set and its semantics, this type is equivalent
+      to the MacAddress textual convention of the SMIv2.";
+    reference
+     "IEEE 802: IEEE Standard for Local and Metropolitan Area
+                Networks: Overview and Architecture
+      RFC 2579: Textual Conventions for SMIv2";
+  }
+
+  /*** collection of XML-specific types ***/
+  typedef xpath1.0 {
+    type string;
+    description
+     "This type represents an XPATH 1.0 expression.
+
+      When a schema node is defined that uses this type, the
+      description of the schema node MUST specify the XPath
+      context in which the XPath expression is evaluated.";
+    reference
+     "XPATH: XML Path Language (XPath) Version 1.0";
+  }
+
+  /*
+   * DISCUSS:
+   * - How do we deal with xpath expressions in other encodings
+   *   such as JSON. Do we assume an xpath context populated with
+   *   module names such that module names can be used to qualify
+   *   path expressions. This may need discussion and/or a new
+   *   definition.
+   * - This interacts with the definition of node-instance-identifier.
+   */
+
+  /*** collection of string types ***/
+
+  typedef hex-string {
+    type string {
+      pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+    }
+    description
+     "A hexadecimal string with octets represented as hex digits
+      separated by colons.  The canonical representation uses
+      lowercase characters.";
+  }
+
+  typedef uuid {
+    type string {
+      pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-'
+            + '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
+    }
+    description
+     "A Universally Unique IDentifier in the string representation
+      defined in RFC 4122.  The canonical representation uses
+      lowercase characters.
+
+      The following is an example of a UUID in string representation:
+      f81d4fae-7dec-11d0-a765-00a0c91e6bf6
+      ";
+    reference
+     "RFC 4122: A Universally Unique IDentifier (UUID) URN
+                Namespace";
+  }
+
+  typedef dotted-quad {
+    type string {
+      pattern
+        '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+      + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
+    }
+    description
+      "An unsigned 32-bit number expressed in the dotted-quad
+       notation, i.e., four octets written as decimal numbers
+       and separated with the '.' (full stop) character.";
+  }
+
+  /*** collection of YANG specific types ***/
+
+  typedef yang-identifier {
+    type string {
+      length "1..max";
+      pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*';
+      pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*';
+    }
+    description
+      "A YANG identifier string as defined by the 'identifier'
+       rule in Section 12 of RFC 6020. An identifier must
+       start with an alphabetic character or an underscore
+       followed by an arbitrary sequence of alphabetic or
+       numeric characters, underscores, hyphens, or dots.
+
+       A YANG identifier MUST NOT start with any possible
+       combination of the lowercase or uppercase character
+       sequence 'xml'.";
+    reference
+      "RFC 6020: YANG - A Data Modeling Language for the Network
+                 Configuration Protocol (NETCONF)";
+  }
+
+  typedef revision-identifier {
+    type date {
+      pattern '\d{4}-\d{2}-\d{2}';
+    }
+    description
+     "Represents a specific revision of a YANG module by means of
+      a date value without a time zone.";
+  }
+
+  typedef node-instance-identifier {
+    type xpath1.0;
+    description
+     "Path expression used to represent a data node, action,
+      or notification instance-identifier string.
+
+      A node-instance-identifier value is an unrestricted
+      YANG instance-identifier expression or the special
+      value '/', which refers to the entire accessible tree.
+
+      All the rules for instance-identifier apply, except that
+      predicates for keys are optional.  If a key predicate is
+      missing, then the node-instance-identifier represents all
+      possible server instances for that key.
+
+      This XML Path Language (XPath) expression is evaluated in the
+      following context:
+
+         o  The set of namespace declarations are those in scope on
+            the leaf element where this type is used.
+
+         o  The set of variable bindings contains one variable,
+            'USER', which contains the name of the user of the
+            current session.
+
+         o  The function library is the core function library, but
+            note that due to the syntax restrictions of an
+            instance-identifier, no functions are allowed.
+
+         o  The context node is the root node in the data tree.
+
+      The accessible tree includes actions and notifications tied
+      to data nodes.";
+  }
+
+  /*
+   * DISCUSS:
+   * - This is taken from RFC 8341 and the idea is that this definition
+   *   is useful without requiring a dependency on NACM
+   * - What does the second bullet actually do? Do we keep this?
+   * - This interacts with the definition of xpath1.0.
+   */
+
+  /* DISCUSS:
+   * - It was suggested to add types for longitude, latitude,
+   *   postal code, country-code. Do we go there or do we leave
+   *   these for other modules to define? It seems such definitions
+   *   should go into draft-ietf-netmod-geo-location.
+   */
+
+  /* DISCUSS:
+   * - It was suggested to add percentage types but they tend to differ
+   *   widely. However, percentages are also widely used.
+   */
+}
diff --git a/yang-parser/src/test/resources/basics/fail-fast-test/bad-module.yang b/yang-parser/src/test/resources/basics/fail-fast-test/bad-module.yang
new file mode 100644
index 0000000..474dfde
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/fail-fast-test/bad-module.yang
@@ -0,0 +1,21 @@
+module bad-module {
+
+	namespace "test:bad-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	 Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-10-15" {
+		description "initial revision";
+	}
+
+	include unknown-submodule {
+		revision-date 2020-10-02;
+	}
+
+	container cont1 {
+		uses "unknown-prefix:some-grouping";
+	}
+}
diff --git a/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file1.yang b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file1.yang
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file1.yang
diff --git a/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file2.xml b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file2.xml
new file mode 100644
index 0000000..ebd886c
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file2.xml
@@ -0,0 +1,20 @@
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
diff --git a/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file3.txt b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file3.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder1/file3.txt
diff --git a/yang-parser/src/test/resources/basics/file-based-resolver-test/folder2/file4.yang b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder2/file4.yang
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder2/file4.yang
diff --git a/yang-parser/src/test/resources/basics/file-based-resolver-test/folder2/file5 b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder2/file5
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/file-based-resolver-test/folder2/file5
diff --git a/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/module1.yang b/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/module1.yang
new file mode 100644
index 0000000..165b00b
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/module1.yang
@@ -0,0 +1,188 @@
+module module1 {
+
+	namespace "urn:test:module1";
+	prefix "this";
+
+	include submodule3;
+
+	import module2 {
+		prefix mod2;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2021-02-12" {
+		description "initial revision";
+	}
+
+	feature feature11;
+	feature feature12;
+	feature feature13;
+
+	feature feature14 {
+		if-feature "feature11 and feature12";
+	}
+
+	container cont1 {
+
+		leaf leaf11 {
+			if-feature feature11;
+			type boolean;
+		}
+
+		leaf leaf12 {
+			if-feature feature12;
+			type boolean;
+		}
+
+		leaf leaf13 {
+			if-feature "this:feature11 or feature12 and this:feature13";
+			type boolean;
+		}
+
+		leaf leaf14 {
+			if-feature feature13;
+			if-feature feature14;
+			type boolean;
+		}
+	}
+
+	feature feature16;
+	feature feature17;
+	feature feature18;
+	feature feature19;
+
+	container cont2 {
+
+		choice choice21 {
+			case case211 {
+				if-feature feature16;
+				leaf leaf211 {
+					type boolean;
+				}
+			}
+			case case212 {
+				if-feature feature17;
+				leaf leaf212 {
+					type boolean;
+				}
+			}
+			case case213 {
+				if-feature feature18;
+				leaf leaf213 {
+					type boolean;
+				}
+			}
+			case case214 {
+				if-feature feature19;
+				leaf leaf214 {
+					type boolean;
+				}
+			}
+			leaf leaf215 {
+				if-feature feature18;
+				if-feature this:feature19;
+				type boolean;
+			}
+		}
+	}
+
+	feature feature21;
+	feature feature22;
+	feature feature23;
+	feature feature24;
+
+	grouping grouping1 {
+		leaf leaf51 {
+			type boolean;
+		}
+		leaf leaf52 {
+			if-feature feature21;
+			type boolean;
+		}
+		leaf leaf53 {
+			type enumeration {
+				enum one;
+				enum two {
+					if-feature feature22;
+				}
+				enum three;
+			}
+		}
+	}
+
+	container cont3 {
+		uses grouping1 {
+			if-feature feature23;
+		}
+	}
+
+	feature feature31;
+
+	container cont4 {
+		uses mod2:grouping91 {
+			if-feature feature31;
+		}
+	}
+
+	feature feature58;
+	feature feature59;
+
+	container cont5 {
+
+		leaf leaf51 {
+			if-feature feature51;
+			type boolean;
+		}
+
+		leaf leaf52 {
+			if-feature feature58;
+			type boolean;
+		}
+
+		leaf leaf53 {
+			if-feature this:feature52;
+			type boolean;
+		}
+	}
+
+	container cont6 {
+
+		leaf leaf61 {
+			if-feature "has invalid syntax, will always be false";
+			type boolean;
+		}
+	}
+
+	feature feature71;
+	feature feature72;
+	feature feature73;
+	feature feature74;
+	feature feature75;
+	feature feature76;
+
+	container cont7 {
+
+		leaf leaf71 {
+			if-feature "feature71 and not feature72";
+			type boolean;
+		}
+
+		leaf leaf72 {
+			if-feature "feature71 and feature72 and (feature73 or feature74)";
+			type boolean;
+		}
+
+		leaf leaf73 {
+			if-feature "feature71 and ((feature72 or feature73) and (feature74 or feature75))";
+			type boolean;
+		}
+
+		leaf leaf74 {
+			if-feature "not feature71 and (feature74 or feature75) and not feature76";
+			type boolean;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/module2.yang b/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/module2.yang
new file mode 100644
index 0000000..a51afe5
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/module2.yang
@@ -0,0 +1,42 @@
+module module2 {
+
+    namespace "urn:test:module2";
+    prefix "this";
+
+	import module1 {
+		prefix mod1;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-02-12" {
+        description "initial revision";
+    }
+
+    feature feature11;
+    feature feature12;
+    feature feature13;
+
+    feature feature99;
+
+	grouping grouping91 {
+		leaf leaf91 {
+			type boolean;
+		}
+		leaf leaf92 {
+			if-feature feature11;		// should resolve to this module here, even if used elsehwere
+			type boolean;
+		}
+		leaf leaf93 {
+			if-feature this:feature11;
+			type boolean;
+		}
+		leaf leaf94 {
+			if-feature mod1:feature11;	// in module1
+			type boolean;
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/submodule3.yang b/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/submodule3.yang
new file mode 100644
index 0000000..5716497
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/unsatisfied-if-feature-remove-test/submodule3.yang
@@ -0,0 +1,21 @@
+submodule submodule3 {
+
+	belongs-to module1 {
+		prefix this;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-02-12" {
+        description "initial revision";
+    }
+
+	feature feature51;
+	feature feature52 {
+		if-feature "feature58 or feature59";	// defined in owning module.
+	}
+
+
+}
diff --git a/yang-parser/src/test/resources/basics/yang-device-model-test/empty-file.yang b/yang-parser/src/test/resources/basics/yang-device-model-test/empty-file.yang
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/yang-device-model-test/empty-file.yang
diff --git a/yang-parser/src/test/resources/basics/yang-device-model-test/module-missing-prefix.yang b/yang-parser/src/test/resources/basics/yang-device-model-test/module-missing-prefix.yang
new file mode 100644
index 0000000..6b2b87d
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/yang-device-model-test/module-missing-prefix.yang
@@ -0,0 +1,11 @@
+module module-missing-prefix {
+
+    namespace "urn:module1";
+
+    description
+    "Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-04";
+
+}
diff --git a/yang-parser/src/test/resources/basics/yang-device-model-test/module1.yang b/yang-parser/src/test/resources/basics/yang-device-model-test/module1.yang
new file mode 100644
index 0000000..6ff67c7
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/yang-device-model-test/module1.yang
@@ -0,0 +1,26 @@
+module module1 {
+
+    namespace "urn:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-04";
+
+    import module2 {
+    	prefix other;
+    }
+
+	container cont1 {
+		uses other:grouping1;
+	}
+
+	container cont2 {
+		leaf leaf7 {
+			type other:typedef1;
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/basics/yang-device-model-test/module2.yang b/yang-parser/src/test/resources/basics/yang-device-model-test/module2.yang
new file mode 100644
index 0000000..03b7d9c
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/yang-device-model-test/module2.yang
@@ -0,0 +1,22 @@
+module module2 {
+
+    namespace "urn:module2";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-04";
+
+	grouping grouping1 {
+		leaf leaf1 {
+			type string;
+		}
+	}
+
+	typedef typedef1 {
+		type uint32;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/basics/yang-input-test/module1-2020-01-01.yang b/yang-parser/src/test/resources/basics/yang-input-test/module1-2020-01-01.yang
new file mode 100644
index 0000000..fa6c166
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/yang-input-test/module1-2020-01-01.yang
@@ -0,0 +1,13 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+    description
+    "Copyright (C) 2024 Ericsson
+    Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/basics/yangdom-write-out-test/module1.yang b/yang-parser/src/test/resources/basics/yangdom-write-out-test/module1.yang
new file mode 100644
index 0000000..be1adf6
--- /dev/null
+++ b/yang-parser/src/test/resources/basics/yangdom-write-out-test/module1.yang
@@ -0,0 +1,143 @@
+module module1 {
+
+	yang-version "1.1";
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+
+    container cont1 {
+
+    	action action11 {
+    		input {
+    			container cont112 {
+    				leaf leaf1121 {
+    					type string;
+    				}
+    			}
+    		}
+    	}
+
+    	leaf leaf12 {
+    		type uint16;
+    	}
+    }
+
+    container cont2 {
+
+    	leaf leaf21 {
+    		type string;
+    		description "simple string with space character";
+    	}
+
+    	leaf leaf22 {
+    		type string;
+    		description "simple string	with tab character";
+    	}
+
+    	leaf leaf23 {
+    		type string;
+    		description "simple string with \" escaped quote character";
+    	}
+
+    	leaf leaf24 {
+    		type string;
+    		description "simple string with \' escaped single-quote character";		// yang 1.1 module, so the backslash should cause a finding
+    	}
+
+    	leaf leaf25 {
+    		type string;
+    		description 'exact characters	tab and quote "';
+    	}
+
+    	leaf leaf26 {
+    		type string;
+    		description 'exact characters stretching over
+   multiple lines - note three spaces at start of line';
+    	}
+
+    	leaf leaf27 {
+    		type string;
+    		description "+";		// Strange...
+    	}
+
+   		leaf leaf28 {
+    		type string;
+    		description ";";		// Also strange...
+    	}
+
+   		leaf leaf29 {
+    		type string;
+    		description ';;';		// Also strange...
+    	}
+
+   		leaf leaf30 {
+    		type string;
+    		description Hello+World!;
+    	}
+
+   		leaf leaf31 {
+    		type string;
+    		description
+    			"on next line";
+    	}
+
+   		leaf leaf32 {
+    		type string;
+    		description "some on this line
+				some on the next line";
+    	}
+
+   		leaf leaf33 {
+    		type string;
+    		description
+    			"First paragraph.
+
+    			Second paragraph.";
+    	}
+
+   		leaf leaf34 {
+    		type string;
+    		description "this_is_//_not_a_comment";
+    	}
+
+   		leaf leaf35 {
+    		type string;
+    		description "this_is_/*_not_a_comment";
+    	}
+
+   		leaf leaf36 {
+    		type string;
+    		description "this_is_*/_not_a_comment";
+    	}
+
+  		leaf leaf37 {
+    		type string;
+    		description "";
+    	}
+
+   		leaf leaf38 {
+    		type string;
+    		description "{";
+    	}
+
+   		leaf leaf39 {
+    		type string;
+    		description "}";
+    	}
+
+  		leaf leaf40 {
+    		type string;
+    		description "\"";
+    	}
+
+    }
+
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error1.json b/yang-parser/src/test/resources/data-dom/json-test/json_error1.json
new file mode 100644
index 0000000..b52c488
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error1.json
@@ -0,0 +1,9 @@
+{
+    "module1:cont1": {
+        "leaf1": "the annotation below is not encoded as JSON object",
+        "@leaf1": [
+            "this should really be",
+            "a JSON object!"
+        ]
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error2.json b/yang-parser/src/test/resources/data-dom/json-test/json_error2.json
new file mode 100644
index 0000000..a914f4c
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error2.json
@@ -0,0 +1,11 @@
+{
+    "module1:cont1": {
+        "leaf1": "the array below contains a mixture of primitive and object",
+        "element2": [
+            "should be all primitive or all objects",
+            {
+                "member1": null
+            }
+        ]
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error3.json b/yang-parser/src/test/resources/data-dom/json-test/json_error3.json
new file mode 100644
index 0000000..061ba2d
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error3.json
@@ -0,0 +1,11 @@
+{
+    "module1:cont1": {
+        "leaf-list1": [
+            "the annotation below",
+            "is not encoded as JSON array"
+        ],
+        "@leaf-list1": {
+            "module2:anno1": "this should be an array, not an object"
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error4.json b/yang-parser/src/test/resources/data-dom/json-test/json_error4.json
new file mode 100644
index 0000000..cd3789b
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error4.json
@@ -0,0 +1,11 @@
+{
+    "module1:cont1": {
+        "leaf-list1": [
+            "the annotation below",
+            "is not encoded as JSON array of JSON objects"
+        ],
+        "@leaf-list1": [
+            "this should have been an object"
+        ]
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error5.json b/yang-parser/src/test/resources/data-dom/json-test/json_error5.json
new file mode 100644
index 0000000..9a17625
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error5.json
@@ -0,0 +1,15 @@
+{
+    "module1:cont1": {
+        "leaf-list1": [
+            "size of the annotation array below is too big"
+        ],
+        "@leaf-list1": [
+            {
+
+            },
+            {
+
+            }
+        ]
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error6.json b/yang-parser/src/test/resources/data-dom/json-test/json_error6.json
new file mode 100644
index 0000000..dca736c
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error6.json
@@ -0,0 +1,8 @@
+{
+    "module1:cont1": {
+        "leaf1": "there is no leaf2, hence the annotation below is wrong",
+        "@leaf2": {
+
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error7.json b/yang-parser/src/test/resources/data-dom/json-test/json_error7.json
new file mode 100644
index 0000000..9cbbe03
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error7.json
@@ -0,0 +1,8 @@
+{
+    "module1:cont1": {
+        "module2:leaf1": "the name of the annotation must match the anme of the member, hence the annotation below is wrong",
+        "@leaf1": {
+
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error8.json b/yang-parser/src/test/resources/data-dom/json-test/json_error8.json
new file mode 100644
index 0000000..0e2828c
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error8.json
@@ -0,0 +1,8 @@
+{
+    "module1:cont1": {
+        "leaf1": "the name of the annotation member below is not prefixed with the module name",
+        "@leaf1": {
+            "unprefixed-member": "should be prefixed with module name"
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_error9.json b/yang-parser/src/test/resources/data-dom/json-test/json_error9.json
new file mode 100644
index 0000000..0acdb7f
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_error9.json
@@ -0,0 +1,5 @@
+{
+    "cont1": {
+        "leaf1": "the cont1 object is missing the module name."
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_ok1.json b/yang-parser/src/test/resources/data-dom/json-test/json_ok1.json
new file mode 100644
index 0000000..8e138bc
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_ok1.json
@@ -0,0 +1,63 @@
+{
+    "module1:cont1": {
+        "leaf11": "hello",
+        "leaf12": "",
+        "leaf13": null,
+        "leaf14": 123,
+        "leaf15": true,
+        "leaflist21": [
+            "one",
+            "two"
+        ],
+        "leaflist22": [
+            "",
+            null
+        ],
+        "leaflist23": [
+            null,
+            true
+        ],
+        "leaflist24": [
+            10,
+            -999,
+            1234567890.123456
+        ]
+    },
+    "module2:cont2": {
+        "leaf31": "world",
+        "module99:leaf32": false,
+        "cont3": {
+            "leaf33": [
+                null
+            ],
+            "leaflist34": [
+                "one",
+                "two"
+            ],
+            "leaflist35": [
+                [
+                    null
+                ],
+                true
+            ]
+        }
+    },
+    "module5:list5": [
+        {
+            "leaf51": 1234,
+            "leaf52": null,
+            "leaflist53": [
+                false,
+                true
+            ]
+        },
+        {
+            "leaf51": 1235,
+            "leaf52": "hello",
+            "leaflist53": [
+                false,
+                false
+            ]
+        }
+    ]
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_ok2.json b/yang-parser/src/test/resources/data-dom/json-test/json_ok2.json
new file mode 100644
index 0000000..3e26498
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_ok2.json
@@ -0,0 +1,47 @@
+{
+    "module6:cont6": {
+        "@": {
+            "anno-module1:anno1": "hello",
+            "anno-module1:anno2": 12345
+        },
+        "leaf61": "hello",
+        "leaf62": "",
+        "@leaf61": {
+            "anno-module6:anno61": true,
+            "anno-module6:anno62": null
+        },
+        "@leaf62": {
+
+        },
+        "leaflist81": [
+            "one",
+            "two",
+            "three"
+        ],
+        "leaflist82": [
+            "",
+            null
+        ],
+        "@leaflist81": [
+            {
+                "anno-module8:anno81": false,
+                "anno-module8:anno82": -99987
+            },
+            null,
+            {
+                "anno-module8:anno81": true,
+                "anno-module8:anno82": 12345678.12345678
+            }
+        ]
+    },
+    "module7:list7": [
+        {
+            "@": {
+                "anno-module1:anno71": "hello",
+                "anno-module2:anno72": null
+            },
+            "leaf71": 1234,
+            "leaf72": null
+        }
+    ]
+}
diff --git a/yang-parser/src/test/resources/data-dom/json-test/json_ok3.json b/yang-parser/src/test/resources/data-dom/json-test/json_ok3.json
new file mode 100644
index 0000000..ff3b265
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/json-test/json_ok3.json
@@ -0,0 +1,15 @@
+{
+    "module1:cont1": {
+        "@": {
+            "module3:anno1": "hello",
+            "module4:anno2": 12345
+        },
+        "leaf11": "hello",
+        "module2:leaf12": "",
+        "leaflist5": [
+            "one",
+            "two",
+            "three"
+        ]
+    }
+}
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/multiple_namespaces.xml b/yang-parser/src/test/resources/data-dom/xml-test/multiple_namespaces.xml
new file mode 100644
index 0000000..9a103f5
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/multiple_namespaces.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+    <cont1 xmlns="namespace0" xmlns:ns1="namespace1" xmlns:ns2="namespace2">
+      <leaf1>42</leaf1>
+      <ns1:leaf2>43</ns1:leaf2>
+      <ns2:leaf3>44</ns2:leaf3>
+      <cont2 xmlns="namespace4" xmlns:ns4="namespace4" xmlns:ns2="namespace9">	<!-- note: ns2 re-defined -->
+        <leaf4>40</leaf4>
+        <ns1:leaf5>50</ns1:leaf5>
+        <ns2:leaf6>60</ns2:leaf6>
+        <leaf7 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+        <ns4:leaf8 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="false"></ns4:leaf8>
+        <leaf9 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="string">90</leaf9>
+      </cont2>
+
+      <ns2:cont3>
+        <leaf10 xmlns:comfoo="www.foo.com" comfoo:myanno="anno-value1" comfoo:myanno2="anno-value2" comfoo:unknownanno="unknown">10</leaf10>
+        <nsxx:leaf11>??</nsxx:leaf11>
+        <leaf12 nsxx:myanno="anno-value">12</leaf12>
+        <ns1:leaf13>   13   </ns1:leaf13>
+        <ns1:leaf14>
+                     1
+               4
+                        		</ns1:leaf14>
+        <ns1:leaf15>First line
+            Second line
+                Third line
+                                </ns1:leaf15>
+
+
+
+        <leaf21><![CDATA[11
+ 22		]]></leaf21>
+
+      </ns2:cont3>
+    </cont1>
+  </content-data>
+</instance-data-set>
+
+
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/prefixes_on_instance_data_set.xml b/yang-parser/src/test/resources/data-dom/xml-test/prefixes_on_instance_data_set.xml
new file mode 100644
index 0000000..4939d70
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/prefixes_on_instance_data_set.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<ids:instance-data-set xmlns="namespace0" xmlns:ids="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <ids:name>test instance data</ids:name>
+  <ids:content-data>
+    <cont1 xmlns:ns1="namespace1" xmlns:ns2="namespace2">
+      <leaf1>42</leaf1>
+      <ns1:leaf2>43</ns1:leaf2>
+      <ns2:leaf3>44</ns2:leaf3>
+    </cont1>
+  </ids:content-data>
+</ids:instance-data-set>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-assume-module-root-element.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-assume-module-root-element.xml
new file mode 100644
index 0000000..5eca192
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-assume-module-root-element.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<cont1 xmlns="test:module">
+  <leaf1>42</leaf1>
+</cont1>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-config.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-config.xml
new file mode 100644
index 0000000..fe72674
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<config>
+  <cont1 xmlns="test:module">
+    <leaf1>42</leaf1>
+  </cont1>
+</config>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-data-no-namespace.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-data-no-namespace.xml
new file mode 100644
index 0000000..e660c42
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-data-no-namespace.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<data>
+  <cont1>		<!-- missing namespace -->
+    <leaf1>42</leaf1>
+  </cont1>
+</data>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-data.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-data.xml
new file mode 100644
index 0000000..6a8958c
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-data.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<data>
+  <cont1 xmlns="test:module">
+    <leaf1>42</leaf1>
+  </cont1>
+</data>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-instance-data-set-wrong.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-instance-data-set-wrong.xml
new file mode 100644
index 0000000..f27fa19
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-instance-data-set-wrong.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <cont1 xmlns="test:module">
+    <leaf1>42</leaf1>
+  </cont1>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-instance-data-set.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-instance-data-set.xml
new file mode 100644
index 0000000..3c78472
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-instance-data-set.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+    <cont1 xmlns="test:module">
+      <leaf1>42</leaf1>
+    </cont1>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-rpc-reply-wrong-no-data.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-rpc-reply-wrong-no-data.xml
new file mode 100644
index 0000000..cdf51c7
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-rpc-reply-wrong-no-data.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<rpc-reply message-id="42" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <xyz>
+    <cont1 xmlns="test:module">
+      <leaf1>42</leaf1>
+    </cont1>
+  </xyz>
+</rpc-reply>
diff --git a/yang-parser/src/test/resources/data-dom/xml-test/root-rpc-reply.xml b/yang-parser/src/test/resources/data-dom/xml-test/root-rpc-reply.xml
new file mode 100644
index 0000000..099a6d2
--- /dev/null
+++ b/yang-parser/src/test/resources/data-dom/xml-test/root-rpc-reply.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<rpc-reply message-id="42" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <data>
+    <cont1 xmlns="test:module">
+      <leaf1>42</leaf1>
+    </cont1>
+  </data>
+</rpc-reply>
diff --git a/yang-parser/src/test/resources/data-parser/json-error-but-continue1.json b/yang-parser/src/test/resources/data-parser/json-error-but-continue1.json
new file mode 100644
index 0000000..5832b85
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error-but-continue1.json
@@ -0,0 +1,3 @@
+{
+    "attr1": "comma missing after this string""attr2":"comma after this string not needed"
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error-but-continue2.json b/yang-parser/src/test/resources/data-parser/json-error-but-continue2.json
new file mode 100644
index 0000000..04cc2d2
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error-but-continue2.json
@@ -0,0 +1,4 @@
+[
+    "comma missing after this string"
+"comma after this string not needed",
+]
diff --git a/yang-parser/src/test/resources/data-parser/json-error1.json b/yang-parser/src/test/resources/data-parser/json-error1.json
new file mode 100644
index 0000000..ad1fe0b
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error1.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",attr2:
+    "missing quotes around object member name"
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error10.json b/yang-parser/src/test/resources/data-parser/json-error10.json
new file mode 100644
index 0000000..81b26f7
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error10.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2": "\u123K"
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error2.json b/yang-parser/src/test/resources/data-parser/json-error2.json
new file mode 100644
index 0000000..c58377d
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error2.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2"="usingequalsinsteadofcolon"
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error3.json b/yang-parser/src/test/resources/data-parser/json-error3.json
new file mode 100644
index 0000000..ddd9ba4
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error3.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2": ]
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error4.json b/yang-parser/src/test/resources/data-parser/json-error4.json
new file mode 100644
index 0000000..3e77cbd
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error4.json
@@ -0,0 +1,3 @@
+[
+    1
+, 2 , } ]
diff --git a/yang-parser/src/test/resources/data-parser/json-error5.json b/yang-parser/src/test/resources/data-parser/json-error5.json
new file mode 100644
index 0000000..60e2416
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error5.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2": not-a-number-at-all
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error6.json b/yang-parser/src/test/resources/data-parser/json-error6.json
new file mode 100644
index 0000000..4698eb0
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error6.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2": "nodoublequoteatend
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error7.json b/yang-parser/src/test/resources/data-parser/json-error7.json
new file mode 100644
index 0000000..fb534e1
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error7.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2": "missingcharafterreversesolidus\
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error8.json b/yang-parser/src/test/resources/data-parser/json-error8.json
new file mode 100644
index 0000000..13e9602
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error8.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2": "\x"
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-error9.json b/yang-parser/src/test/resources/data-parser/json-error9.json
new file mode 100644
index 0000000..0285352
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-error9.json
@@ -0,0 +1,4 @@
+{
+    "attr1": "value1",
+    "attr2": "\u123
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-ok1.json b/yang-parser/src/test/resources/data-parser/json-ok1.json
new file mode 100644
index 0000000..0fdfe74
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-ok1.json
@@ -0,0 +1,26 @@
+{
+    "attr1": "some string",
+    "attr2": true,
+    "attr3": 12,
+    "attr4": null,
+    "attr5": false,
+    "attr6": 123456789.123456789,
+    "attr7": 1234567890123,
+    "attr8": 9223372036854775807,
+    "attr9": 9223372036854775808,
+    "attr10": -9223372036854775808,
+    "attr11": -9223372036854775809,
+    "attr12": {
+
+    },
+    "attr13": {
+        "attr17": "hello",
+        "module:attr18": -1.0
+    },
+    "attr21": [],
+    "attr22": [
+        1.0,
+        2,
+        -99.0
+    ]
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-ok2.json b/yang-parser/src/test/resources/data-parser/json-ok2.json
new file mode 100644
index 0000000..09403d1
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-ok2.json
@@ -0,0 +1,63 @@
+{
+    "attr1": [],
+    "attr2": [],
+    "attr3": [],
+    "attr4": [
+        "hello",
+        true,
+        false,
+        null,
+        123456789.123456789
+    ],
+    "attr5": [
+        [
+            null
+        ],
+        [
+            null,
+            true
+        ],
+        [],
+        "hello"
+    ],
+    "attr6": [
+        [],
+        {
+
+        }
+    ],
+    "attr7": [
+        {
+
+        },
+        {
+
+        }
+    ],
+    "attr8": [
+        {
+            "attr21": "hello",
+            "attr22": []
+        },
+        {
+
+        }
+    ],
+    "attr9": [
+        {
+            "attr31": "hello",
+            "attr32": [
+                {
+
+                },
+                {
+                    "attr33": true,
+                    "attr34": -99999999999
+                }
+            ]
+        },
+        {
+
+        }
+    ]
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-ok3.json b/yang-parser/src/test/resources/data-parser/json-ok3.json
new file mode 100644
index 0000000..e86b47d
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-ok3.json
@@ -0,0 +1,13 @@
+{
+    "attr1": "",
+    "attr2": " ",
+    "attr3": "\t",
+    "attr4": "\n",
+    "attr5": "\"",
+    "attr6": "\\",
+    "attr7": "\/",
+    "attr8": "\b",
+    "attr9": "\f",
+    "attr10": "\r",
+    "attr21": "\u0020"
+}
diff --git a/yang-parser/src/test/resources/data-parser/json-ok4.json b/yang-parser/src/test/resources/data-parser/json-ok4.json
new file mode 100644
index 0000000..3580093
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-ok4.json
@@ -0,0 +1 @@
+"hello"
diff --git a/yang-parser/src/test/resources/data-parser/json-ok5.json b/yang-parser/src/test/resources/data-parser/json-ok5.json
new file mode 100644
index 0000000..19765bd
--- /dev/null
+++ b/yang-parser/src/test/resources/data-parser/json-ok5.json
@@ -0,0 +1 @@
+null
diff --git a/yang-parser/src/test/resources/data/data-tree-builder-predicate-test/two-namespaces.xml b/yang-parser/src/test/resources/data/data-tree-builder-predicate-test/two-namespaces.xml
new file mode 100644
index 0000000..ea0e3c1
--- /dev/null
+++ b/yang-parser/src/test/resources/data/data-tree-builder-predicate-test/two-namespaces.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <cont1 xmlns="namespace1">
+      <leaf1>10</leaf1>
+    </cont1>
+    <cont2 xmlns="namespace2">
+      <leaf1>10</leaf1>
+    </cont2>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data-tree-builder-test/data-in-single-file.xml b/yang-parser/src/test/resources/data/instance-data-tree-builder-test/data-in-single-file.xml
new file mode 100644
index 0000000..0a6777e
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data-tree-builder-test/data-in-single-file.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+    <cont1 xmlns="test:module">
+      <list11>
+      	<leaf111>key-value-1</leaf111>
+      	<leaf112>some string</leaf112>
+      	<leaflist113>20</leaflist113>
+      	<leaflist113>30</leaflist113>
+      	<leaflist113>40</leaflist113>
+      </list11>
+      <list11>
+      	<leaf111>key-value-2</leaf111>
+      	<leaf112>some other string</leaf112>
+      	<leaflist113>50</leaflist113>
+      </list11>
+      <leaf12>42</leaf12>
+      <cont13>
+        <leaf131>true</leaf131>
+      </cont13>
+    </cont1>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data-tree-builder-test/module1.yang b/yang-parser/src/test/resources/data/instance-data-tree-builder-test/module1.yang
new file mode 100644
index 0000000..b41f83c
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data-tree-builder-test/module1.yang
@@ -0,0 +1,40 @@
+module module1 {
+
+	namespace "test:module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-07-21" {
+		description "initial revision";
+	}
+
+	container cont1 {
+
+		list list11 {
+			key "leaf111";
+
+			leaf leaf111 {
+				type string;
+			}
+			leaf leaf112 {
+				type string;
+			}
+			leaf-list leaflist113 {
+				type int32;
+			}
+		}
+
+		leaf leaf12 {
+			type uint32;
+		}
+
+		container cont13 {
+			leaf leaf131 {
+				type boolean;
+			}
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/data/instance-data/data1.json b/yang-parser/src/test/resources/data/instance-data/data1.json
new file mode 100644
index 0000000..53a686e
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data1.json
@@ -0,0 +1,50 @@
+{
+    "module1:cont1": {
+        "leaf11": 42,
+        "leaf14": [
+            null
+        ]
+    },
+    "module1:list2": [
+        {
+            "leaf21": 4,
+            "cont22": {
+                "leaf23": "One",
+                "leaf24": "Two"
+            },
+            "leaf25": "Three",
+            "leaflist26": [
+                "Six"
+            ]
+        },
+        {
+            "leaf21": 5,
+            "cont22": {
+                "leaf23": "One"
+            }
+        },
+        {
+            "leaf21": 6
+        }
+    ],
+    "module1:cont5": {
+        "leaf51": [
+            null
+        ]
+    },
+    "module1:cont6": {
+        "anydata61": {
+            "aa": "aaaaaa",
+            "bb": "bbbbbb"
+        },
+        "anyxml62": {
+            "dd": "dddddd",
+            "ee": "eeeeee"
+        }
+    },
+    "module1:cont8": {
+        "leaf81": "should ignore whitespaces",
+        "leaf82": "should also ignore whitespaces",
+        "leaf83": "  should be 2 whitespaces either side  "
+    }
+}
diff --git a/yang-parser/src/test/resources/data/instance-data/data1.xml b/yang-parser/src/test/resources/data/instance-data/data1.xml
new file mode 100644
index 0000000..063d3da
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data1.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+  	<!-- Simple stuff -->
+
+    <cont1 xmlns="test:module1">
+      <leaf11>42</leaf11>
+      <leaf14 />
+    </cont1>
+
+    <!-- A few NPs and defaults -->
+
+    <list2 xmlns="test:module1">
+      <leaf21>4</leaf21>
+      <cont22>
+        <leaf23>One</leaf23>
+        <leaf24>Two</leaf24>
+      </cont22>
+      <leaf25>Three</leaf25>
+      <leaflist26>Six</leaflist26>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>5</leaf21>
+      <cont22>
+        <leaf23>One</leaf23>
+      </cont22>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>6</leaf21>
+    </list2>
+
+    <!-- anydata / anyxml -->
+
+    <cont6 xmlns="test:module1">
+      <anydata61>
+        <aa>aaaaaa</aa>
+        <bb>bbbbbb</bb>
+      </anydata61>
+      <anyxml62>
+        <dd>dddddd</dd>
+        <ee>eeeeee</ee>
+      </anyxml62>
+    </cont6>
+
+	<cont8 xmlns="test:module1">
+		<leaf81>    should ignore whitespaces      </leaf81>
+		<leaf82>
+					should also ignore whitespaces
+		   </leaf82>
+		<leaf83><![CDATA[  should be 2 whitespaces either side  ]]></leaf83>
+		<leaf84>Before<![CDATA[  should be 2 whitespaces either side  ]]>After</leaf84>
+		<leaf85>
+
+
+					</leaf85>
+		<leaf86>blurb<!-- comment --> more blurb</leaf86>
+	</cont8>
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/data2.json b/yang-parser/src/test/resources/data/instance-data/data2.json
new file mode 100644
index 0000000..e36e0f4
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data2.json
@@ -0,0 +1,6 @@
+{
+    "module1:cont1": {
+        "leaf12": 58,
+        "leaf13": "Hello!"
+    }
+}
diff --git a/yang-parser/src/test/resources/data/instance-data/data2.xml b/yang-parser/src/test/resources/data/instance-data/data2.xml
new file mode 100644
index 0000000..6340d51
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data2.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+  	<!-- Simple stuff -->
+
+    <cont1 xmlns="test:module1">
+      <leaf12>58</leaf12>
+      <leaf13>Hello!</leaf13>
+    </cont1>
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/data3.xml b/yang-parser/src/test/resources/data/instance-data/data3.xml
new file mode 100644
index 0000000..1a1cc40
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data3.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+    <!-- A few NPs and defaults -->
+
+    <list2 xmlns="test:module1">
+  	  <leaf21>35</leaf21>
+      <cont22>
+    	<leaf23>hello</leaf23>
+      </cont22>
+      <leaflist26>four</leaflist26>
+      <leaflist26>five</leaflist26>
+    </list2>
+
+    <!-- Some choice handling -->
+
+    <cont3 xmlns="test:module1">
+      <cont39/>
+    </cont3>
+
+    <!-- for augmentation -->
+
+    <cont7 xmlns="test:module1" xmlns:ns2="test:module2">
+      <ns2:leaf72>-90</ns2:leaf72>
+    </cont7>
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/data4.xml b/yang-parser/src/test/resources/data/instance-data/data4.xml
new file mode 100644
index 0000000..ca23a23
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data4.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+    <!-- A few NPs and defaults -->
+
+    <list2 xmlns="test:module1">
+  	  <leaf21>35</leaf21>
+      <cont22>
+    	<leaf24>world</leaf24>
+      </cont22>
+      <leaf25>sure</leaf25>
+    </list2>
+
+    <list2 xmlns="test:module1">
+  	  <leaf21>48</leaf21>
+    </list2>
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/data5.xml b/yang-parser/src/test/resources/data/instance-data/data5.xml
new file mode 100644
index 0000000..ede8f80
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data5.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+    <!-- merging of leaf-lists -->
+
+    <list2 xmlns="test:module1">
+  	  <leaf21>501</leaf21>
+      <cont22>
+    	<leaf24>hi</leaf24>
+      </cont22>
+      <leaf25>world</leaf25>
+    </list2>
+
+    <list2 xmlns="test:module1">
+  	  <leaf21>502</leaf21>
+  	  <leaflist26>red</leaflist26>
+  	  <leaflist26>yellow</leaflist26>
+    </list2>
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/data6.xml b/yang-parser/src/test/resources/data/instance-data/data6.xml
new file mode 100644
index 0000000..2c4070c
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/data6.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+    <!-- merging of leaf-lists -->
+
+    <list2 xmlns="test:module1">
+  	  <leaf21>501</leaf21>
+      <cont22>
+    	<leaf23>hello</leaf23>
+      </cont22>
+    </list2>
+
+    <list2 xmlns="test:module1">
+  	  <leaf21>502</leaf21>
+  	  <leaflist26>green</leaflist26>
+  	  <leaflist26>blue</leaflist26>
+  	  <leaflist26>red</leaflist26>
+    </list2>
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/error-data10.json b/yang-parser/src/test/resources/data/instance-data/error-data10.json
new file mode 100644
index 0000000..6553bd8
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/error-data10.json
@@ -0,0 +1,17 @@
+{
+    "module1:cont1": {
+        "leaf11": [
+            null
+        ]
+    },
+    "module1:list2": [
+        {
+            "leaf21": 10,
+            "leaflist26": [
+                [
+                    null
+                ]
+            ]
+        }
+    ]
+}
diff --git a/yang-parser/src/test/resources/data/instance-data/error-data7.xml b/yang-parser/src/test/resources/data/instance-data/error-data7.xml
new file mode 100644
index 0000000..4d2f913
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/error-data7.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+	<!-- duplicate container -->
+
+    <cont1 xmlns="test:module1">
+      <leaf11>42</leaf11>
+    </cont1>
+
+    <cont1 xmlns="test:module1">
+      <leaf11>43</leaf11>
+    </cont1>
+
+	<!-- duplicate list with same key -->
+
+    <list2 xmlns="test:module1">
+      <leaf21>4</leaf21>
+      <leaf25>hello</leaf25>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>4</leaf21>
+      <leaf25>hello</leaf25>
+    </list2>
+
+	<!-- list missing key -->
+
+    <list2 xmlns="test:module1">
+      <leaf25>hello</leaf25>
+    </list2>
+
+	<!-- list key value null -->
+
+    <list2 xmlns="test:module1">
+      <leaf21 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+      <leaf25>hello</leaf25>
+    </list2>
+
+	<!-- duplicate leaf -->
+
+    <cont4 xmlns="test:module1">
+      <leaf41>42</leaf41>
+      <leaf41>42</leaf41>
+    </cont4>
+
+	<!-- unknown namespace -->
+
+	<cont7 xmlns="unknown-namespace">
+	</cont7>
+
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/error-data8.xml b/yang-parser/src/test/resources/data/instance-data/error-data8.xml
new file mode 100644
index 0000000..62001a5
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/error-data8.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+    <list2 xmlns="test:module1">
+      <leaf21>1</leaf21>
+      <leaf25 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+      <leaflist26 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>2</leaf21>
+      <leaf25 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>3</leaf21>
+      <leaf25>abc 456</leaf25>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>4</leaf21>
+      <leaf25>abc 123</leaf25>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>5</leaf21>
+      <leaf25>abc 123</leaf25>
+    </list2>
+
+	<!--  ==========================  -->
+
+    <list2 xmlns="test:module1">
+      <leaf21>51</leaf21>
+      <leaflist26>abc</leaflist26>
+      <leaflist26>def</leaflist26>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>52</leaf21>
+      <leaflist26>abc</leaflist26>
+      <leaflist26>def</leaflist26>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>53</leaf21>
+      <leaflist26>abc</leaflist26>
+      <leaflist26>def</leaflist26>
+    </list2>
+
+	<!--  ==========================  -->
+
+	<cont6>
+		<anydata61 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+		<anyxml62 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+	</cont6>
+
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/error-data9.xml b/yang-parser/src/test/resources/data/instance-data/error-data9.xml
new file mode 100644
index 0000000..1c2b172
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/error-data9.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data</name>
+  <content-data>
+
+    <list2 xmlns="test:module1">
+      <leaf21>1</leaf21>
+      <leaf25 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>2</leaf21>
+      <leaf25>abc 123</leaf25>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>3</leaf21>
+      <leaf25 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
+    </list2>
+
+    <list2 xmlns="test:module1">			<!-- same -->
+      <leaf21>4</leaf21>
+      <leaf25>abc 123</leaf25>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>5</leaf21>
+      <leaf25>def 789</leaf25>
+    </list2>
+
+	<!--  ==========================  -->
+
+    <list2 xmlns="test:module1">			<!-- same -->
+      <leaf21>51</leaf21>
+      <leaflist26>abc</leaflist26>
+      <leaflist26>def</leaflist26>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>52</leaf21>
+      <leaflist26>abc</leaflist26>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>53</leaf21>
+      <leaflist26>def</leaflist26>
+      <leaflist26>abc</leaflist26>
+    </list2>
+
+    <list2 xmlns="test:module1">
+      <leaf21>54</leaf21>
+      <leaflist26>abc</leaflist26>
+      <leaflist26>abc</leaflist26>
+    </list2>
+
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/data/instance-data/module1.yang b/yang-parser/src/test/resources/data/instance-data/module1.yang
new file mode 100644
index 0000000..8e3aa30
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/module1.yang
@@ -0,0 +1,254 @@
+module module1 {
+
+	namespace "test:module1";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2021-02-14" {
+		description "initial revision";
+	}
+
+	// -------------- Simple stuff ----------------
+
+	container cont1 {
+		leaf leaf11 {
+			type uint32;
+		}
+		leaf leaf12 {
+			type uint32;
+		}
+		leaf leaf13 {
+			type string;
+		}
+		leaf leaf14 {
+			type empty;
+		}
+	}
+
+	// -------------- A few NPs and defaults ----------------
+
+	list list2 {
+		key leaf21;
+
+		leaf leaf21 {
+			type int16;
+		}
+
+		container cont22 {
+
+			leaf leaf23 {
+				type string;
+			}
+
+			leaf leaf24 {
+				type string;
+				default "World";
+			}
+		}
+
+		leaf leaf25 {
+			type string;
+			default "Nice Day";
+		}
+
+		leaf-list leaflist26 {
+			type string;
+			default "one";
+			default "two";
+			default "three";
+		}
+	}
+
+	// -------------- Some choice handling ----------------
+
+	container cont3 {
+
+		choice choice31 {
+			default case32;
+
+			case case32 {
+				leaf leaf33 {
+					type string;
+				}
+				leaf leaf34 {
+					type string;
+					default "where";
+				}
+				container cont35 {
+					leaf leaf36 {
+						type string;
+						default "here";
+					}
+				}
+			}
+
+			case case37 {
+				leaf leaf38 {
+					type string;
+					default "there";
+				}
+				container cont39 {
+					presence "";
+				}
+			}
+		}
+	}
+
+	// -------------- Some default values with different formats ----------------
+
+	container cont4 {
+
+		leaf leaf41 {
+			type uint32;
+			default "+0";
+		}
+
+		leaf leaf42 {
+			type uint32;
+			default "0x0010";		// hexadecimal = 16
+		}
+
+		leaf leaf43 {
+			type uint32;
+			default "010";			// octal = 8
+		}
+
+		leaf leaf44 {
+			type boolean;
+			default true;
+		}
+
+		leaf leaf45 {
+			type enumeration {
+				enum one { value 1; }
+				enum two { value 2; }
+				enum three { value 3; }
+			}
+			default two;
+		}
+
+		leaf leaf46 {
+			type decimal64 {
+				fraction-digits 3;
+			}
+			default 123.456;
+		}
+	}
+
+	// -------------- Unions ----------------
+
+	container cont5 {
+
+		leaf leaf51 {
+			type union {
+				type uint32;
+				type string;
+				type empty;
+			}
+			default "+0";
+		}
+
+		leaf leaf52 {
+			type union {
+				type uint16 {
+					range "0..100";
+				}
+				type string;
+			}
+			default "+0x100";		// hex 256, so not in range of the unint16
+		}
+
+		leaf leaf53 {
+			type union {
+				type enumeration {
+					enum one { value 1; }
+					enum two { value 2; }
+					enum three { value 3; }
+				}
+				type uint8;
+			}
+			default "+10";
+		}
+
+		leaf leaf54 {
+			type union {
+				type enumeration {
+					enum one { value 1; }
+					enum two { value 2; }
+					enum three { value 3; }
+				}
+				type uint8;
+			}
+			default "+1000";		// not possible for either data types, will use as-is.
+		}
+
+		leaf leaf55 {
+			type union {
+				type bits {
+					bit one { position 1; }
+					bit two { position 2; }
+					bit three { position 3; }
+				}
+				type string;
+			}
+			default "one	 two";
+		}
+
+		leaf leaf56 {
+			type union {
+				type bits {
+					bit one { position 1; }
+					bit two { position 2; }
+					bit three { position 3; }
+				}
+				type string;
+			}
+			default "one   two   seven";
+		}
+	}
+
+	// -------------- anydata / anyxml ----------------
+
+	container cont6 {
+
+		anydata anydata61;
+
+		anyxml anyxml62;
+	}
+
+	// -------------- for augmentation ----------------
+
+	container cont7;
+
+	// ------------------ CDATA -----------------------
+
+	container cont8 {
+
+		leaf leaf81 {
+			type string;
+		}
+
+		leaf leaf82 {
+			type string;
+		}
+
+		leaf leaf83 {
+			type string;
+		}
+
+		leaf leaf84 {
+			type string;
+		}
+
+		leaf leaf85 {
+			type string;
+		}
+
+		leaf leaf86 {
+			type string;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/data/instance-data/module2.yang b/yang-parser/src/test/resources/data/instance-data/module2.yang
new file mode 100644
index 0000000..b3ebb52
--- /dev/null
+++ b/yang-parser/src/test/resources/data/instance-data/module2.yang
@@ -0,0 +1,31 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module1 {
+		prefix mod1;
+	}
+
+    revision "2021-02-14" {
+        description "initial revision";
+    }
+
+
+	augment "/mod1:cont7" {
+
+		leaf leaf71 {
+			type int32;
+			default -12345;
+		}
+
+		leaf leaf72 {
+			type int32;
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/findings/module1.yang b/yang-parser/src/test/resources/findings/module1.yang
new file mode 100644
index 0000000..a85b63c
--- /dev/null
+++ b/yang-parser/src/test/resources/findings/module1.yang
@@ -0,0 +1,17 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+
+	leaf leaf1 {
+		type string;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-schema/annotation-registry-test/module1.yang b/yang-parser/src/test/resources/model-schema/annotation-registry-test/module1.yang
new file mode 100644
index 0000000..df32021
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/annotation-registry-test/module1.yang
@@ -0,0 +1,26 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-03-23" {
+        description "initial revision";
+    }
+
+	import ietf-yang-metadata {
+		prefix "md";
+	}
+
+	md:annotation created {
+		type string;
+	}
+
+	md:annotation last-modified {
+		type uint64;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-schema/annotation-registry-test/module2.yang b/yang-parser/src/test/resources/model-schema/annotation-registry-test/module2.yang
new file mode 100644
index 0000000..9a64fdd
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/annotation-registry-test/module2.yang
@@ -0,0 +1,22 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-03-23" {
+        description "initial revision";
+    }
+
+	import ietf-yang-metadata {
+		prefix "md";
+	}
+
+	md:annotation modified-user {
+		type string;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-schema/identity-registry-test/module1.yang b/yang-parser/src/test/resources/model-schema/identity-registry-test/module1.yang
new file mode 100644
index 0000000..e0c2135
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/identity-registry-test/module1.yang
@@ -0,0 +1,48 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module2 {
+		prefix mod2;
+	}
+
+	import module3 {
+		prefix mod3;
+	}
+
+	include submodule4;
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+
+    identity identity11;
+    identity identity12;
+    identity identity13;
+
+    identity identity14 {
+    	base this:identity11;
+    	base identity12;
+    	base identity13;
+    }
+
+	identity identity15 {
+		base identity14;
+	}
+
+
+	identity identity61 {
+		base identity14;
+		base identity42;		// from submodule
+	}
+
+
+    identity identity99 {
+    	base mod2:identity99;
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/identity-registry-test/module2.yang b/yang-parser/src/test/resources/model-schema/identity-registry-test/module2.yang
new file mode 100644
index 0000000..f0cf9d8
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/identity-registry-test/module2.yang
@@ -0,0 +1,32 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module1 {
+		prefix mod1;
+	}
+
+	import module3 {
+		prefix mod3;
+	}
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+
+    identity identity21;
+    identity identity22 {
+    	base identity21;
+    }
+
+    identity identity23 {
+    	base mod1:identity11;
+    }
+
+    identity identity99;
+}
diff --git a/yang-parser/src/test/resources/model-schema/identity-registry-test/module3.yang b/yang-parser/src/test/resources/model-schema/identity-registry-test/module3.yang
new file mode 100644
index 0000000..c59ab45
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/identity-registry-test/module3.yang
@@ -0,0 +1,32 @@
+module module3 {
+
+    namespace "test:module3";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module1 {
+		prefix mod1;
+	}
+
+	import module2 {
+		prefix mod2;
+	}
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+
+    identity identity31;
+    identity identity32 {
+    	base this:identity31;
+    }
+
+    identity identity33 {
+    	base mod2:identity21;
+    }
+
+    identity identity99;
+}
diff --git a/yang-parser/src/test/resources/model-schema/identity-registry-test/submodule4.yang b/yang-parser/src/test/resources/model-schema/identity-registry-test/submodule4.yang
new file mode 100644
index 0000000..7387108
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/identity-registry-test/submodule4.yang
@@ -0,0 +1,30 @@
+submodule submodule4 {
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	belongs-to module1 {
+		prefix mod1;
+	}
+
+	import module2 {
+		prefix mod2;
+	}
+
+	import module3 {
+		prefix mod3;
+	}
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+
+    identity identity41;
+    identity identity42;
+
+    identity identity43 {
+    	base identity41;
+    	base mod1:identity42;
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang b/yang-parser/src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang
new file mode 100644
index 0000000..3170529
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/module-registry-test/module1-2020-01-01.yang
@@ -0,0 +1,13 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/module-registry-test/module1-2020-02-02.yang b/yang-parser/src/test/resources/model-schema/module-registry-test/module1-2020-02-02.yang
new file mode 100644
index 0000000..3d40989
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/module-registry-test/module1-2020-02-02.yang
@@ -0,0 +1,13 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-02-02" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/module-registry-test/module1-no-revision.yang b/yang-parser/src/test/resources/model-schema/module-registry-test/module1-no-revision.yang
new file mode 100644
index 0000000..6f68368
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/module-registry-test/module1-no-revision.yang
@@ -0,0 +1,11 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+
+}
diff --git a/yang-parser/src/test/resources/model-schema/module-registry-test/module2-2020-01-01.yang b/yang-parser/src/test/resources/model-schema/module-registry-test/module2-2020-01-01.yang
new file mode 100644
index 0000000..e314ccc
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/module-registry-test/module2-2020-01-01.yang
@@ -0,0 +1,13 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/module-registry-test/module3-2020-01-01.yang b/yang-parser/src/test/resources/model-schema/module-registry-test/module3-2020-01-01.yang
new file mode 100644
index 0000000..721c5be
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/module-registry-test/module3-2020-01-01.yang
@@ -0,0 +1,18 @@
+module module3 {
+
+    namespace "test:module3";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+
+    include module3-submodule1 {
+        revision-date "1999-09-09";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-schema/module-registry-test/module3-submodule1-1999-09-09.yang b/yang-parser/src/test/resources/model-schema/module-registry-test/module3-submodule1-1999-09-09.yang
new file mode 100644
index 0000000..b9ab1a9
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/module-registry-test/module3-submodule1-1999-09-09.yang
@@ -0,0 +1,15 @@
+submodule module3-submodule1 {
+
+    belongs-to module3 {
+        prefix mod3;
+    }
+
+    revision "1999-09-09" {
+        description "initial revision";
+    }
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+}
diff --git a/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module1.yang b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module1.yang
new file mode 100644
index 0000000..ad44fe5
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module1.yang
@@ -0,0 +1,23 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module2 {
+		prefix mod2;
+	}
+
+	import module3 {
+		prefix mod3;
+	}
+
+	include submodule4;
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module2.yang b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module2.yang
new file mode 100644
index 0000000..163a504
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module2.yang
@@ -0,0 +1,21 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module1 {
+		prefix mod1;
+	}
+
+	import module3 {
+		prefix mod3;
+	}
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module3.yang b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module3.yang
new file mode 100644
index 0000000..aded4b6
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/module3.yang
@@ -0,0 +1,21 @@
+module module3 {
+
+    namespace "test:module3";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module1 {
+		prefix mod1;
+	}
+
+	import module2 {
+		prefix mod2;
+	}
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/submodule4.yang b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/submodule4.yang
new file mode 100644
index 0000000..6ddbe5b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/prefix-and-namespace-test/submodule4.yang
@@ -0,0 +1,22 @@
+submodule submodule4 {
+
+	belongs-to module1 {
+		prefix mod1;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module2 {
+		prefix mod2;
+	}
+
+	import module3 {
+		prefix mod3;
+	}
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/remove-findings-on-unused-schema-nodes/simple/simple-module.yang b/yang-parser/src/test/resources/model-schema/remove-findings-on-unused-schema-nodes/simple/simple-module.yang
new file mode 100644
index 0000000..612bb8b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/remove-findings-on-unused-schema-nodes/simple/simple-module.yang
@@ -0,0 +1,38 @@
+module simple-module {
+
+	namespace "urn:test:simple-module";
+	prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision 2023-02-27;
+
+	typedef typedef01 {				// references unknown type but the typedef itself is not used.
+		type unknown-type;
+	}
+
+	grouping grouping01 {			// contains wrong statement, but the grouping is never used.
+		unknown-statement "Hello!";
+	}
+
+	container cont1 {
+
+		leaf leaf01 {
+			type string;
+		}
+
+		leaf leaf02 {				// uses unknown type but will be deviated-out.
+			type unknown-type;
+		}
+
+		leaf leaf03 {				// uses unknown type
+			type unknown-type;
+		}
+	}
+
+	deviation /this:cont1/leaf02 {
+		deviate not-supported;
+	}
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/augmenting-module.yang b/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/augmenting-module.yang
new file mode 100644
index 0000000..b99972c
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/augmenting-module.yang
@@ -0,0 +1,30 @@
+module augmenting-module {
+
+	namespace "test:augmenting-module";
+	prefix "this";
+	revision 2024-01-30;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import base-module {
+		prefix base;
+	}
+
+	import other-module {
+		prefix other;
+	}
+
+	augment "/base:cont1" {
+		leaf leaf12 {
+			type int32;
+		}
+	}
+
+	augment "/other:cont5" {
+		leaf leaf52 {
+			type int32;
+		}
+	}
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/base-module.yang b/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/base-module.yang
new file mode 100644
index 0000000..403b37f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/base-module.yang
@@ -0,0 +1,24 @@
+module base-module {
+
+	namespace "test:base-module";
+	prefix "this";
+	revision 2024-01-30;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	container cont1 {
+
+		leaf leaf11 {
+			type string;
+		}
+	}
+
+	container cont2 {
+
+		leaf leaf21 {
+			type string;
+		}
+	}
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/other-module.yang b/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/other-module.yang
new file mode 100644
index 0000000..38897b7
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/remove-protocol-accessible-objects/other-module.yang
@@ -0,0 +1,24 @@
+module other-module {
+
+	namespace "test:other-module";
+	prefix "this";
+	revision 2024-01-30;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	container cont5 {
+
+		leaf leaf51 {
+			type string;
+		}
+	}
+
+	container cont6 {
+
+		leaf leaf61 {
+			type string;
+		}
+	}
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-schema/stop-after-initial-parse-test/module1.yang b/yang-parser/src/test/resources/model-schema/stop-after-initial-parse-test/module1.yang
new file mode 100644
index 0000000..b6ac886
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/stop-after-initial-parse-test/module1.yang
@@ -0,0 +1,24 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import module2 { prefix mod2; }
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+
+    container cont1 {
+
+    	leaf leaf2 {
+    		type string;
+    	}
+
+		uses mod2:grouping1;
+    }
+}
diff --git a/yang-parser/src/test/resources/model-schema/stop-after-initial-parse-test/module2.yang b/yang-parser/src/test/resources/model-schema/stop-after-initial-parse-test/module2.yang
new file mode 100644
index 0000000..1bd62d2
--- /dev/null
+++ b/yang-parser/src/test/resources/model-schema/stop-after-initial-parse-test/module2.yang
@@ -0,0 +1,20 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+
+    grouping grouping1 {
+
+    	leaf leaf99 {
+    		type boolean;
+    	}
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-oran/oran-smo-teiv-extension-test.yang b/yang-parser/src/test/resources/model-statements-oran/oran-smo-teiv-extension-test.yang
new file mode 100644
index 0000000..24ab5ce
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-oran/oran-smo-teiv-extension-test.yang
@@ -0,0 +1,118 @@
+module oran-smo-teiv-extension-test {
+
+	namespace "test:teiv-topology-inventory-extension-test";
+
+	prefix this {
+		yexte:original-prefix "other";
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2023-08-14" {
+		description "Initial revision";
+		or-teiv-ext:label 2.3.4;
+	}
+
+	revision "2023-07-12" {
+		or-teiv-ext:label '06.34.12345';
+	}
+
+	import o-ran-smo-teiv-common-yang-extensions {
+		prefix or-teiv-ext;
+	}
+
+	import o-ran-smo-teiv-common-yang-types {
+		prefix or-teiv-types;
+	}
+
+	or-teiv-ext:biDirectionalTopologyRelationship relationship-1 {			// just fine
+		leaf leaf-a-side {
+			or-teiv-ext:aSide role-a-side;
+			type instance-identifier;
+		}
+		leaf-list leaf-b-side {
+			or-teiv-ext:bSide role-b-side;
+			type instance-identifier;
+		}
+
+		uses or-teiv-types:Top_Grp_Type;
+		key id;
+
+		leaf      leaf-prop { type string; }
+		leaf-list leaf-list-prop { type string; }
+	}
+
+	or-teiv-ext:biDirectionalTopologyRelationship relationship-2;				// NOK - empty
+
+	or-teiv-ext:biDirectionalTopologyRelationship relationship-3 {			// NOK - missing B-side
+		leaf leaf-a-side {
+			or-teiv-ext:aSide role-a-side;
+			type instance-identifier;
+		}
+	}
+
+	or-teiv-ext:biDirectionalTopologyRelationship relationship-4 {			// NOK - missing A-side
+		leaf-list leaf-b-side {
+			or-teiv-ext:bSide role-b-side;
+			type instance-identifier;
+		}
+	}
+
+	or-teiv-ext:biDirectionalTopologyRelationship relationship-5 {			// NOK - a-side twice
+		leaf leaf-a-side {
+			or-teiv-ext:aSide role-a-side;
+			type instance-identifier;
+		}
+		leaf-list leaf-b-side {
+			or-teiv-ext:bSide role-b-side;
+			type instance-identifier;
+		}
+		leaf leaf-a-side2 {
+			or-teiv-ext:aSide role-a-side;
+			type instance-identifier;
+		}
+	}
+
+	or-teiv-ext:biDirectionalTopologyRelationship relationship-6 {			// NOK - b-side twice
+		leaf leaf-a-side {
+			or-teiv-ext:aSide role-a-side;
+			type instance-identifier;
+		}
+		leaf-list leaf-b-side {
+			or-teiv-ext:bSide role-b-side;
+			type instance-identifier;
+		}
+		leaf leaf-b-side2 {
+			or-teiv-ext:bSide role-b-side;
+			type instance-identifier;
+		}
+	}
+
+	container cont1 {
+		or-teiv-ext:biDirectionalTopologyRelationship relationship-7 {			// NOK - not at module-level.
+			leaf leaf-a-side {
+				or-teiv-ext:aSide role-a-side;
+				type instance-identifier;
+			}
+			leaf-list leaf-b-side {
+				or-teiv-ext:bSide role-b-side;
+				type instance-identifier;
+			}
+		}
+	}
+
+	or-teiv-ext:biDirectionalTopologyRelationship relationship-8 {			// NOK - can't be child of container or list.
+		container cont2 {
+			or-teiv-ext:aSide role-a-side;
+			type instance-identifier;
+		}
+		list list2 {
+			or-teiv-ext:bSide role-b-side;
+			type instance-identifier;
+			key id;
+			leaf id { type string; }
+		}
+	}
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-statements-other/other-extension-test.yang b/yang-parser/src/test/resources/model-statements-other/other-extension-test.yang
new file mode 100644
index 0000000..2bd0234
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-other/other-extension-test.yang
@@ -0,0 +1,43 @@
+module other-extension-test {
+
+	namespace "test:other-extension-test";
+	prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-08-12" {
+		description "Initial revision";
+	}
+
+	import ietf-yang-metadata {
+		prefix md;
+	}
+
+	import _3gpp-common-yang-extensions {
+		prefix yext3gpp;
+	}
+
+	import ietf-netconf-acm {
+		prefix nacm;
+	}
+
+	md:annotation last-modified {
+		type uint64;
+	}
+
+	container cont1 {
+		nacm:default-deny-write;
+
+		leaf leaf1 {
+			yext3gpp:inVariant;
+			yext3gpp:initial-value "Hello";
+			yext3gpp:notNotifyable;
+
+			nacm:default-deny-all;
+
+			type int32;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-augmenting-module.yang b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-augmenting-module.yang
new file mode 100644
index 0000000..88625ea
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-augmenting-module.yang
@@ -0,0 +1,28 @@
+module augment-intosub-augmenting-module {
+
+    namespace "test:augment-intosub-augmenting-module";
+    prefix augmenting;
+
+    revision "2020-12-10";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	import augment-intosub-module {
+		prefix module;
+	}
+
+	augment "/module:cont1" {
+		leaf leaf11 {
+			type string;
+		}
+	}
+
+	augment "/module:cont2" {		// this sits in the submodule
+		leaf leaf12 {
+			type string;
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-module.yang b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-module.yang
new file mode 100644
index 0000000..1d0305d
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-module.yang
@@ -0,0 +1,18 @@
+module augment-intosub-module {
+
+    namespace "test:augment-intosub-module-test";
+    prefix module;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-10";
+
+	include augment-intosub-submodule;
+
+	container cont1;
+
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-submodule.yang b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-submodule.yang
new file mode 100644
index 0000000..08d629f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-intosub-submodule.yang
@@ -0,0 +1,17 @@
+submodule augment-intosub-submodule {
+
+	belongs-to augment-intosub-module {
+	    prefix module;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-10";
+
+	container cont2;
+
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module.yang
new file mode 100644
index 0000000..33a2487
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module.yang
@@ -0,0 +1,170 @@
+module augment-test-module {
+
+    namespace "test:augment-test";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-21" {
+        description "initial revision";
+    }
+
+	import not-supplied-module {
+		prefix nsm;
+	}
+
+	feature rpc1;
+
+	rpc rpc1 {
+		input {
+			container cont1 {
+				choice choice1 {
+					case case1 {
+						leaf case1-leaf1 {
+							type string;
+						}
+					}
+					case case2 {
+						leaf case2-leaf1 {
+							type int32;
+						}
+					}
+				}
+			}
+			container cont2 {
+				choice choice2 {
+					leaf leaf5 {
+						type string;
+					}
+					leaf leaf6 {
+						type int16;
+					}
+				}
+			}
+		}
+	}
+
+	container cont1 {
+	    action action1;
+	}
+
+	augment /this:rpc1/input {
+	    leaf inputLeaf1 {
+	        type string;
+	    }
+	}
+
+	augment /this:rpc1/output {
+	    leaf outputLeaf2 {
+	        type string;
+	    }
+	}
+
+	augment /this:cont1/this:action1/input {
+	    leaf inputLeaf3 {
+	        type string;
+	    }
+	}
+
+	augment /this:cont1/this:action1/output {
+	    leaf outputLeaf4 {
+	        type string;
+	    }
+	}
+
+	augment "/this:rpc1/this:input/this:cont1/this:choice1" {
+		leaf inserted-case-leaf {
+			type boolean;
+		}
+	}
+
+	// - - - - in different order - - - - - -
+
+	augment /this:cont1/cont11 {
+	    leaf leaf5 {
+	        type string;
+	    }
+	}
+
+	augment /this:cont1 {
+	    container cont11;
+	}
+
+	// - - - - some other different target nodes - - - - - -
+
+	container cont2 {
+		list list1 {
+			key leaf11;
+			leaf leaf11 {
+				type int32;
+			}
+			leaf leaf12 {
+				type string;
+			}
+		}
+
+		notification notification1;
+	}
+
+	// - - - - - status - - - - - -
+
+	container cont3 {
+		status current;
+
+	}
+
+	// - - - - - strange path syntax - - - - - -
+
+	augment "/this:cont1/" {		// Technically wrong, but we accept it.
+	    container cont18;
+	}
+
+	augment "/:cont1" {			// Poor syntax, but will work
+	    container cont19;
+	}
+
+	augment "/cont1" {			// Should be ok
+	    container cont20;
+	}
+
+	augment "//this:cont1" {	// Wrong
+	    container cont21;
+	}
+
+	augment "//this:cont1/" {	// Wrong
+	    container cont22;
+	}
+
+	augment "/" {				// Wrong
+	    container cont23;
+	}
+
+	augment {					// Wrong
+	    container cont24;
+	}
+
+	augment "" {				// Wrong
+	    container cont25;
+	}
+
+	// - - - - - - - - - issues with prefixes - - - - - -
+
+	augment "/nsm:some-cont" {				// Wrong Module not in import
+	    container cont28;
+	}
+
+	augment "/this:cont1/nsm:some-cont" {	// Wrong Module not in import
+	    container cont29;
+	}
+
+	augment "/this:cont1/unknown-prefix:some-cont" {		// Unknown prefix
+	    container cont30;
+	}
+
+	augment "/this:cont1/:some-cont" {		// Missing prefix
+	    container cont31;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module2.yang b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module2.yang
new file mode 100644
index 0000000..463b712
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module2.yang
@@ -0,0 +1,69 @@
+module augment-test-module2 {
+
+    namespace "test:augment-test2";
+    prefix this;
+
+	import augment-test-module {
+		prefix other;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-21" {
+        description "initial revision";
+    }
+
+	augment "/other:rpc1/other:input/other:cont1/other:choice1" {
+		leaf inserted-case-leaf-from-second-module {
+			type boolean;
+		}
+	}
+
+	// - - - - some other different target nodes - - - - - -
+
+	augment /other:cont2/list1 {
+		leaf leaf15 {
+			type boolean;
+		}
+	}
+
+	augment /other:cont2/other:notification1 {
+		leaf leaf18 {
+			type string;
+		}
+	}
+
+	// - - - - - status - - - - - -
+
+	augment /other:cont3 {
+		status deprecated;
+
+		container cont11;
+
+		container cont12 {
+			status deprecated;
+		}
+
+		container cont13 {
+			status obsolete;
+		}
+	}
+
+	augment /other:cont3 {
+		status current;
+
+		container cont15;
+
+		container cont16 {
+			status deprecated;
+		}
+
+		container cont17 {
+			status obsolete;
+		}
+	}
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module3.yang b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module3.yang
new file mode 100644
index 0000000..8141955
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/augment-test/augment-test-module3.yang
@@ -0,0 +1,105 @@
+module augment-test-module3 {
+
+    namespace "test:augment-test3";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-21" {
+        description "initial revision";
+    }
+
+	container cont1 {
+	    action action1;
+	}
+
+	augment /this:cont1/list2 {
+	    action action3;
+	}
+
+	augment /this:cont1 {
+	    list list2 {
+	    	key leaf6;
+
+	    	leaf leaf6 {
+		        type string;
+	    	}
+	    	leaf leaf7 {
+		        type string;
+	    	}
+	    }
+	    choice choice8 {
+	    	case case1 {
+	    		container cont96;
+	    	}
+	    	case case2 {
+	    		container cont97;
+	    	}
+	    }
+	}
+
+	augment /cont1/action1/this:input {
+		container input-container;
+		when "leaf-at-root = true";
+	}
+
+	augment /this:cont1/choice8 {
+		if-feature feature1;
+		container shorthand-container;
+	}
+
+	augment /this:cont1/choice8 {
+		if-feature feature2;
+		case case3 {
+			if-feature feature3;
+			container case-container;
+		}
+	}
+
+	augment /this:cont1/choice8/case3 {
+		container second-case-container;
+	}
+
+	// -------------------------- failure cases -------------------------
+
+	leaf leaf-at-root {
+		type boolean;
+	}
+
+	augment /leaf-at-root {			// should not be possible to augment that
+	    container cont1;
+	}
+
+	augment /unknownprefix:somenode {		// prefix not resolvable.
+	    container cont1;
+	}
+
+	augment /this:unknown-node {			// data node not resolvable.
+	    container cont1;
+	}
+
+	augment "" {							// empty path.
+	    container cont1;
+	}
+
+	augment "cont1" {						// relative path
+	    container cont1;
+	}
+
+	augment {								// null path to target node
+	    container cont1;
+	}
+
+	// -------------------------- not-allowed statements -------------------------
+
+	augment /this:cont1/choice8/case1 {
+		action action1;
+	}
+
+	augment /this:cont1/choice8/case2 {
+		notification notification1;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-module.yang b/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-module.yang
new file mode 100644
index 0000000..042f1dc
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-module.yang
@@ -0,0 +1,14 @@
+module test-module {
+
+    namespace "test:test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-submodule.yang b/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-submodule.yang
new file mode 100644
index 0000000..be8df1c
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-submodule.yang
@@ -0,0 +1,15 @@
+submodule test-submodule {
+
+	belongs-to test-module {
+		prefix this;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-submodule2.yang b/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-submodule2.yang
new file mode 100644
index 0000000..bda6ef5
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/belongs-to-test/test-submodule2.yang
@@ -0,0 +1,15 @@
+submodule test-submodule2 {
+
+	belongs-to test-submodule {
+		prefix this;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/bits-test/bits-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/bits-test/bits-test-module.yang
new file mode 100644
index 0000000..e172b0c
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/bits-test/bits-test-module.yang
@@ -0,0 +1,123 @@
+module bits-test-module {
+
+	namespace "urn:o-ran:yang:bits-module";
+	prefix "ebits";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision 2019-10-07 {
+		description "Initial revision";
+	}
+
+	typedef typedef1 {
+		type bits {
+			bit first;
+			bit second;
+			bit third;
+		}
+	}
+
+	typedef typedef2 {
+		type bits {
+			bit first { position 7 ; }
+			bit second { position 23 ; }
+			bit third { position 195 ; }
+		}
+	}
+
+	typedef typedef3 {
+		type bits {
+			bit first { position 98 ; }
+			bit second;
+			bit third;
+		}
+	}
+
+	typedef typedef4 {
+		type bits {
+			bit first;
+			bit second { position 10 ; }
+			bit third;
+		}
+	}
+
+	typedef typedef-duplicate-position1 {
+		type bits {
+			bit first;
+			bit second { position 10 ; }
+			bit third { position 10 ; }
+		}
+	}
+
+	typedef typedef-duplicate-position2 {
+		type bits {
+			bit first;
+			bit second { position 0 ; }
+			bit third;
+		}
+	}
+
+	typedef typedef-too-large1 {
+		type bits {
+			bit first;
+			bit second { position 4294967295 ; }
+			bit third;
+		}
+	}
+
+	typedef typedef-too-large2 {
+		type bits {
+			bit first;
+			bit second { position 9999999999999998 ; }
+			bit third;
+		}
+	}
+
+	typedef typedef-not-bits {
+		type uint32;
+	}
+
+// ------------------------------- leafs using the typedefs above --------------------------
+
+	leaf leaf1 {
+		type typedef1;
+	}
+
+	leaf leaf2 {
+		type typedef2 {
+			bit second { position 23 ; }
+		}
+	}
+
+	leaf leaf-wrong-position1 {
+		type typedef2 {
+			bit first { position 7 ; }
+			bit second { position 24 ; }
+		}
+	}
+
+	leaf leaf-wrong-position2 {
+		type typedef2 {
+			bit first;
+			bit second { position 24 ; }
+		}
+	}
+
+	leaf leaf-new-bit {
+		type typedef2 {
+			bit first { position 7 ; }
+			bit second { position 23 ; }
+			bit third { position 195 ; }
+			bit fourth { position 34 ; }
+		}
+	}
+
+	leaf leaf-not-bits {
+		type typedef-not-bits {
+			bit first;
+			bit second { position 24 ; }
+		}
+	}
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/including-module.yang b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/including-module.yang
new file mode 100644
index 0000000..2feedca
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/including-module.yang
@@ -0,0 +1,22 @@
+module including-module {
+
+    namespace "test:including-module";
+    prefix "this";
+
+	include submodule;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-21" {
+        description "initial revision";
+    }
+
+    container cont1 {
+        leaf leaf1 {
+            type uint32;
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/module1.yang b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/module1.yang
new file mode 100644
index 0000000..2199e82
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/module1.yang
@@ -0,0 +1,35 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix "this";
+
+    import module2 {
+        prefix "module2";
+    }
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-21" {
+        description "initial revision";
+    }
+
+    container cont1 {
+        leaf leaf1 {
+            type uint32;
+        }
+    }
+
+    uses module2:grouping2;
+
+    module2:ext ext1;
+
+    container cont2 {
+        presence "important";
+        if-feature module2:feature1;
+    }
+
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/module2.yang b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/module2.yang
new file mode 100644
index 0000000..b0bee07
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/module2.yang
@@ -0,0 +1,46 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-21" {
+        description "initial revision";
+    }
+
+    extension ext {
+        argument name;
+    }
+
+    grouping grouping2 {
+        container contgroup2 {
+            leaf leafgroup2 {
+                type string;
+            }
+        }
+    }
+
+    container cont2 {
+        leaf leaf2 {
+            type uint32;
+        }
+    }
+
+    uses this:grouping2;
+
+    rpc rpc1;
+
+    list list1 {
+        key leaf1;
+        leaf leaf1 {
+            type string;
+        }
+    }
+
+    feature feature1;
+
+    this:ext ext1;
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/submodule.yang b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/submodule.yang
new file mode 100644
index 0000000..dca1858
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/conformance-type-test/submodule.yang
@@ -0,0 +1,20 @@
+submodule submodule {
+
+	belongs-to including-module {
+		prefix other;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-21" {
+        description "initial revision";
+    }
+
+    container cont2 {
+        leaf leaf2 {
+            type uint32;
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/data-type-test/data-type-test.yang b/yang-parser/src/test/resources/model-statements-yang/data-type-test/data-type-test.yang
new file mode 100644
index 0000000..4e6a8d0
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/data-type-test/data-type-test.yang
@@ -0,0 +1,260 @@
+module data-type-test-module {
+
+	namespace "test:data-type-test-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-11-11" {
+		description "initial revision";
+	}
+
+	container cont1 {
+
+		leaf leaf1 {
+			type int8 {
+				range min..max;
+			}
+		}
+		leaf leaf2 {
+			type int16 {
+				range 10..20;
+			}
+		}
+		leaf leaf3 {
+			type int32 {
+				range "-30 .. 20";
+			}
+		}
+		leaf leaf4 {
+			type int64 {
+				range 20..max;
+			}
+		}
+
+		leaf leaf5 {
+			type uint8 {
+				range 10;		// makes no sense, but allowed in YANG
+			}
+		}
+		leaf leaf6 {
+			type uint16 {
+				range "min..20 | 40";
+			}
+		}
+		leaf leaf7 {
+			type uint32 {
+				range "0..20 | 40..60";
+			}
+		}
+		leaf leaf8 {
+			type uint64 {
+				range "0 .. 20 | 30 | 40 .. 60";
+			}
+		}
+
+		leaf leaf9 {
+			type decimal64 {
+				fraction-digits 1;
+				range "0.0 .. 10.0 | 20.2 .. max";
+			}
+		}
+
+		leaf leaf21 {
+			type string {
+				length "10 .. 20";
+				pattern "ab*c" {
+					modifier invert-match;
+				}
+			}
+		}
+
+		leaf leaf22 {
+			type boolean;
+		}
+
+		leaf leaf23 {
+			type enumeration {
+				enum one {
+					value 10;
+					status deprecated;
+					if-feature feature1;
+				}
+				enum two;
+				enum three;
+			}
+		}
+
+		leaf leaf24 {
+			type bits {
+				bit one {
+					position 10;
+					status deprecated;
+					if-feature feature1;
+				}
+				bit two;
+				bit three;
+			}
+		}
+
+		leaf leaf25 {
+			type binary {
+				length "90 .. 1010";
+			}
+		}
+
+		leaf leaf26 {
+			type leafref {
+				path "/this:cont1/this:leaf1";
+				require-instance true;
+			}
+		}
+
+		leaf leaf27 {
+			type identityref {
+				base identity1;
+			}
+		}
+
+		leaf leaf28 {
+			type empty;
+		}
+
+		leaf leaf29 {
+			type union {
+				type int32;
+				type string;
+			}
+		}
+
+		leaf leaf30 {
+			type instance-identifier {
+				require-instance false;
+			}
+		}
+	}
+
+	container cont2 {
+
+		leaf leaf51 {
+			type decimal64 {
+				fraction-digits 0;		// Wrong
+			}
+		}
+
+		leaf leaf52 {
+			type decimal64 {
+				fraction-digits 19;		// Wrong
+			}
+		}
+
+		leaf leaf53 {
+			type decimal64 {
+				fraction-digits "Hello";	// Wrong
+			}
+		}
+
+		leaf leaf54 {
+			type decimal64 {
+				fraction-digits;			// Wrong
+			}
+		}
+
+		leaf leaf58 {
+			type bits {
+				bit zero {
+					position -1;			// Wrong
+				}
+				bit one {
+					position 9999999999999999;			// Wrong
+				}
+				bit two {
+					position "Hello";			// Wrong
+				}
+				bit three {
+					position;			// Wrong
+				}
+			}
+		}
+
+		leaf-list leaflist62 {
+			type string;
+			min-elements 0;		// OK
+		}
+
+		leaf-list leaflist63 {
+			type string;
+			min-elements -1;		// Wrong
+		}
+
+		leaf-list leaflist64 {
+			type string;
+			min-elements "Hello";		// Wrong
+		}
+
+		leaf-list leaflist65 {
+			type string;
+			min-elements;		// Wrong
+		}
+
+		leaf-list leaflist71 {
+			type string;
+			max-elements unbounded;		// OK
+		}
+
+		leaf-list leaflist72 {
+			type string;
+			max-elements 1;		// OK
+		}
+
+		leaf-list leaflist73 {
+			type string;
+			max-elements 0;		// Wrong
+		}
+
+		leaf-list leaflist74 {
+			type string;
+			max-elements -1;		// Wrong
+		}
+
+		leaf-list leaflist75 {
+			type string;
+			max-elements "Hello";		// Wrong
+		}
+
+		leaf-list leaflist76 {
+			type string;
+			max-elements;		// Wrong
+		}
+
+		leaf leaf81 {
+			type string {
+				pattern "ab*c" {
+					modifier invert-match;		// OK
+				}
+			}
+		}
+
+		leaf leaf82 {
+			type string {
+				pattern "ab*c" {
+					modifier blurb;		// Wrong
+				}
+			}
+		}
+
+		leaf leaf83 {
+			type string {
+				pattern "ab*c" {
+					modifier;		// Wrong
+				}
+			}
+		}
+	}
+
+	feature feature1;
+
+	identity identity1;
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-add-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-add-test-module.yang
new file mode 100644
index 0000000..26cfaa0
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-add-test-module.yang
@@ -0,0 +1,88 @@
+module deviate-add-test-module {
+
+	namespace "urn:ietf:params:xml:ns:yang:deviate-add-test-module";
+	prefix dev;
+
+	import deviation-host-test-module {
+		prefix host;
+	}
+
+	import _3gpp-common-yang-extensions {
+		prefix yext3gpp;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2019-10-09" {
+		description "initial revision";
+	}
+
+// ---------------- These deviations are just fine ---------------------
+
+	deviation /host:cont1/host:leaf11 {
+		deviate add {
+			default "Hello World!";
+			must "strlen(.) > 5";
+			units "seconds";
+			yext3gpp:initial-value "Hello World";
+		}
+	}
+
+	deviation /host:list11 {
+		deviate add {
+			unique "leaf111 leaf112";
+		}
+	}
+
+	deviation /host:list11/host:leaflist113 {
+		deviate add {
+			must ". < 98";
+		}
+	}
+
+// ---------------- These deviations try to add things which already exist in the host model ---------------------
+
+	deviation /host:cont2/host:leaf21 {
+		deviate add {
+			type string;
+			config true;
+			mandatory false;
+			units "hours";
+		}
+	}
+
+	deviation /host:list21 {
+		deviate add {
+			min-elements 67;
+			max-elements 82;
+		}
+	}
+
+// ---------------- Various other findings ---------------------
+
+	deviation /host:unknownelement {		// schema node unknown
+		deviate add {
+			default "";
+		}
+	}
+
+	deviation /host:cont4 {
+		deviate add;		// Missing substatements
+	}
+
+	deviation /host:cont3 {
+		deviate add {
+			min-elements 67;		// not allowed under 'container'
+			max-elements 82;		// same
+		}
+	}
+
+	deviation /host:list11/host:leaf112 {
+		deviate add {
+			default 34;		// It's a leaf so only a single 'default' can be supplied here.
+			default 37;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-delete-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-delete-test-module.yang
new file mode 100644
index 0000000..a383c09
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-delete-test-module.yang
@@ -0,0 +1,63 @@
+module deviate-delete-test-module {
+
+	namespace "urn:ietf:params:xml:ns:yang:deviate-delete-test-module";
+	prefix dev;
+
+	import deviation-host-test-module {
+		prefix host;
+	}
+
+	import _3gpp-common-yang-extensions {
+		prefix yext3gpp;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-09" {
+        description "initial revision";
+    }
+
+// ---------------- These deviations are just fine ---------------------
+
+    deviation /host:cont2/host:leaf21 {
+        deviate delete {
+            units "minutes";
+        }
+    }
+
+    deviation /host:list11/host:leaflist113 {
+        deviate delete {
+            default 18;
+            yext3gpp:initial-value "50";
+        }
+    }
+
+// ---------------- These deviations try to delete things that don't exist in the host model or that are properties ---------------------
+
+    deviation /host:cont1/host:leaf11 {
+        deviate delete {
+            config false;
+        }
+    }
+
+    deviation /host:list11 {
+        deviate delete {
+            min-elements 0;
+            max-elements unbounded;
+        }
+    }
+
+// ---------------- Various other findings ---------------------
+
+    deviation /host:cont4 {
+        deviate delete;		// Missing substatements
+    }
+
+    deviation /host:list11/host:leaf112 {
+        deviate delete {
+            type int16;			// should throw a finding as 'type' is a mandatory child under 'leaf'.
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-not-supported-multi-level-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-not-supported-multi-level-test-module.yang
new file mode 100644
index 0000000..076443c
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-not-supported-multi-level-test-module.yang
@@ -0,0 +1,40 @@
+module deviate-not-supported-multi-level-test-module {
+
+    namespace "test:deviate-not-supported-multi-level-test-module";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-09" {
+        description "initial revision";
+    }
+
+	container cont1 {
+		container cont2 {
+			container cont3 {
+				container cont4;
+			}
+		}
+	}
+
+	/*
+		Deviations happen to be processed in the order in which they are defined in
+		the model, so we can provoke a deviation where we try to not-support a
+		container that a different deviation has already not-supported.
+	*/
+
+	deviation /this:cont1/this:cont2/this:cont3/this:cont4 {
+        deviate not-supported;
+	}
+
+	deviation /this:cont1/this:cont2 {
+        deviate not-supported;
+	}
+
+	deviation /this:cont1/this:cont2/this:cont3 {
+        deviate not-supported;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-not-supported-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-not-supported-test-module.yang
new file mode 100644
index 0000000..94ce487
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-not-supported-test-module.yang
@@ -0,0 +1,52 @@
+module deviate-not-supported-test-module {
+
+    namespace "urn:ietf:params:xml:ns:yang:deviate-not-supported-test-module";
+    prefix dev;
+
+    import deviation-host-test-module {
+        prefix host;
+    }
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-09" {
+        description "initial revision";
+    }
+
+// ---------------- These deviations are just fine ---------------------
+
+    deviation /host:cont2/host:leaf21 {
+        deviate not-supported;
+    }
+
+	deviation /host:list21 {
+        deviate not-supported;
+	}
+
+	deviation /host:cont1 {
+        deviate not-supported {
+            yexte:updated-description "blurb";		// should be ok, extensions are allowed under deviate not-supported
+        }
+	}
+
+// ---------------- These deviations try to not-support things that don't exist in the host model ---------------------
+
+    deviation /host:unknownElement {
+        deviate not-supported;
+    }
+
+    deviation /host:cont3/host:unknownElement {
+        deviate not-supported;
+    }
+
+// ---------------- Various other findings ---------------------
+
+    deviation /host:cont4 {
+        deviate not-supported {
+            type int16;			// cannot have child statements
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-other-tests-module.yang b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-other-tests-module.yang
new file mode 100644
index 0000000..95facac
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-other-tests-module.yang
@@ -0,0 +1,174 @@
+module deviate-other-tests-module {
+
+    namespace "urn:ietf:params:xml:ns:yang:deviate-other-tests-module";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-09" {
+        description "initial revision";
+    }
+
+// ---------------- Deviate something augmented ---------------------
+
+    container cont01 {
+    }
+
+    augment /this:cont01 {
+        leaf leaf11 {
+            type string;
+        }
+        leaf-list leaflist12 {
+            type int16;
+        }
+    }
+
+    deviation /this:cont01/this:leaf11 {
+        deviate add {
+            mandatory true;
+            config false;
+        }
+    }
+
+    deviation /this:cont01/this:leaflist12 {
+        deviate add {
+            min-elements 20;
+            max-elements 25;
+        }
+    }
+
+// ---------------- Deviate-replace something that was deviate-added ---------------------
+
+    container cont02 {
+    }
+
+    deviation /this:cont02 {
+        deviate add {
+            config false;
+        }
+        deviate replace {
+            config true;
+        }
+    }
+
+// ---------------- Deviate-add something that was deviate-added ---------------------
+
+    container cont03 {
+    }
+
+    deviation /this:cont03 {
+        deviate add {
+            config false;
+        }
+        deviate add {
+            config true;
+        }
+    }
+
+// ---------------- Deviate-replace something that was deviate-replaced ---------------------
+
+    container cont04 {
+        config true;
+    }
+
+    deviation /this:cont04 {
+        deviate replace {
+            config false;
+        }
+        deviate replace {
+            config true;
+        }
+    }
+
+// ---------------- Deviate-delete something that was deviate-replaced ---------------------
+
+    container cont05 {
+        config true;
+    }
+
+    deviation /this:cont05 {
+        deviate replace {
+            config false;
+        }
+        deviate delete {
+            config false;
+        }
+    }
+
+// ---------------- Deviate-delete something that was deviate-added ---------------------
+
+    container cont06 {
+    }
+
+    deviation /this:cont06 {
+        deviate add {
+            config false;
+        }
+        deviate delete {
+            config false;
+        }
+    }
+
+// ---------------- Some error scenarios ---------------------
+
+    container cont07;
+
+    deviation /this:cont07 {
+    	deviate blurb;
+	}
+
+    container cont08;
+
+    deviation /this:cont08 {
+    	deviate;
+	}
+
+	deviation "//this:cont08" {		// Wrong path
+		deviate add {
+			config true;
+		}
+	}
+
+    container cont09;
+
+	deviation "/this:cont09/" {		// This actually works...
+		deviate add {
+			config false;
+		}
+	}
+
+	deviation "/" {					// Wrong path
+		deviate add {
+			config false;
+		}
+	}
+
+	deviation "" {					// Wrong path
+		deviate add {
+			config false;
+		}
+	}
+
+	deviation "  " {				// Wrong path
+		deviate add {
+			config false;
+		}
+	}
+
+	deviation  {					// Wrong path
+		deviate add {
+			config false;
+		}
+	}
+
+    container cont10;
+
+	deviation "  /this:cont10  " {		// OK (will be trimmed)
+		deviate add {
+			config false;
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-replace-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-replace-test-module.yang
new file mode 100644
index 0000000..f2098fd
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviate-replace-test-module.yang
@@ -0,0 +1,89 @@
+module deviate-replace-test-module {
+
+    namespace "urn:ietf:params:xml:ns:yang:deviate-replace-test-module";
+    prefix dev;
+
+    import deviation-host-test-module {
+        prefix host;
+    }
+
+	import _3gpp-common-yang-extensions {
+		prefix yext3gpp;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-09" {
+        description "initial revision";
+    }
+
+// ---------------- These deviations are just fine ---------------------
+
+    deviation /host:cont2/host:leaf21 {
+        deviate replace {
+            config true;
+            mandatory false;
+            units "days";
+        }
+    }
+
+    deviation /host:list11/host:leaflist113 {
+        deviate replace {
+            default 1234;
+            default 7890;
+            yext3gpp:initial-value 70;
+        }
+    }
+
+	deviation /host:list21 {
+	    deviate replace {
+            min-elements 2;
+            max-elements 36;
+	    }
+	}
+
+    deviation /host:cont5/host:leaf51 {
+        deviate replace {
+            type string {
+                length 10..40;
+            }
+        }
+    }
+
+// ---------------- These deviations try to replace things that don't exist in the host model ---------------------
+
+    deviation /host:cont1/host:leaf11 {
+        deviate replace {
+            units "hours";
+        }
+    }
+
+// ---------------- Various other findings ---------------------
+
+    deviation /host:cont4 {
+        deviate replace;		// Missing substatements
+    }
+
+    deviation /host:list11/host:leaf112 {
+        deviate replace {
+            type string;			// Should throw a finding as data type has changed.
+        }
+    }
+
+    deviation /host:list22 {
+        deviate replace {
+            min-elements 6;		// shrinking boundary
+            max-elements 10;	// same
+        }
+    }
+
+    deviation /host:list11/host:leaf114 {
+        deviate replace {
+            default 23;		// target is a leaf so only a single default can occur.
+            default 95;
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviation-host-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviation-host-test-module.yang
new file mode 100644
index 0000000..0647259
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/deviation-test/deviation-host-test-module.yang
@@ -0,0 +1,105 @@
+module deviation-host-test-module {
+
+    namespace "urn:ietf:params:xml:ns:yang:deviation-host-test-module";
+    prefix test;
+
+	import _3gpp-common-yang-extensions {
+		prefix yext3gpp;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-09" {
+        description "initial revision";
+    }
+
+    container cont1 {
+        leaf leaf11 {
+            type string;
+        }
+    }
+
+    container cont2 {
+        leaf leaf21 {
+            type int16;
+            config false;
+            mandatory true;
+            units "minutes";
+        }
+    }
+
+    container cont3 {
+    }
+
+    container cont4 {
+    }
+
+    container cont5 {
+        leaf leaf51 {
+            type string;
+        }
+        choice choice1 {
+            case case11 {
+                container cont55 {
+                }
+                container cont56 {
+                    config false;
+                }
+            }
+            case case12 {
+                container cont67 {
+                }
+                container cont68 {
+                }
+            }
+        }
+    }
+
+    list list11 {
+        key leaf111;
+
+        leaf leaf111 {
+            type string {
+                length 7..23;
+            }
+        }
+        leaf leaf112 {
+            type int16;
+        }
+        leaf-list leaflist113 {
+            type int16;
+            default 10;
+            default 13;
+            default 18;
+            must ". > 4";
+            yext3gpp:initial-value 50;
+        }
+        leaf leaf114 {
+            type int16;
+            default 48;
+        }
+    }
+
+    list list21 {
+        key leaf211;
+        min-elements 4;
+        max-elements 16;
+
+        leaf leaf211 {
+            type string;
+        }
+    }
+
+     list list22 {
+        key leaf221;
+        min-elements 4;
+        max-elements 16;
+
+        leaf leaf221 {
+            type string;
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-constraints.yang b/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-constraints.yang
new file mode 100644
index 0000000..b8793f7
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-constraints.yang
@@ -0,0 +1,283 @@
+module general-syntax-test-constraints {
+
+    namespace "test:general-syntax-test-constraints";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-22" {
+        description "Initial revision";
+    }
+
+    // - - - - length - - - -
+
+    container cont1 {
+
+    	leaf leaf1 {
+    		type string {
+    			length 1..10 {
+    				error-app-tag "some-app-tag";
+    				error-message "wrong length";
+    			}
+    		}
+    	}
+
+	   	leaf leaf2 {
+    		type string {
+    			length min..max;
+    		}
+    	}
+
+	   	leaf leaf3 {
+    		type string {
+    			length "min..10 | 15 | 20..max";
+    		}
+    	}
+
+ 	   	leaf leaf4 {
+    		type string {
+    			length "min .. min | max ..max";		// doesn't really make sense, but technically allowed
+    		}
+    	}
+
+	   	leaf leaf5 {
+    		type string {
+    			length min..max|;		// Wrong
+    		}
+    	}
+
+	   	leaf leaf6 {
+    		type string {
+    			length |min..max;		// Wrong
+    		}
+    	}
+
+    	leaf leaf7 {
+    		type string {
+    			length zero..1.1;		// Wrong
+    		}
+    	}
+
+    	leaf leaf8 {
+    		type string {
+    			length "10..20 | 21..30";		// OK
+    		}
+    	}
+
+    	leaf leaf9 {
+    		type string {
+    			length "10..20 | 20..30";		// Wrong, overlap
+    		}
+    	}
+
+    	leaf leaf10 {
+    		type string {
+    			length "19..30 | 10..20";		// Wrong order
+    		}
+    	}
+
+   		leaf leaf11 {
+    		type string {
+    			length "-1..-3";		// Wrong, negative.
+    		}
+    	}
+
+    	leaf leaf12 {
+    		type string {
+    			length "..10..20 | 21..30";		// Wrong
+    		}
+    	}
+
+    	leaf leaf13 {
+    		type string {
+    			length "10..20 | 21..30..";		// Wrong
+    		}
+    	}
+    }
+
+	// -------------- Range for integer -------------------
+
+    container cont2 {
+
+    	leaf leaf1 {
+    		type int32 {
+    			range 1..10 {
+    				error-app-tag "some-app-tag";
+    				error-message "wrong length";
+    			}
+    		}
+    	}
+
+	   	leaf leaf2 {
+    		type uint8 {
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf3 {
+    		type uint16 {
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf4 {
+    		type uint32 {
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf5 {
+    		type uint64 {
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf6 {
+    		type int8 {
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf7 {
+    		type int16 {
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf8 {
+    		type int32 {
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf9 {
+    		type int64 {
+    			range min..max;
+    		}
+    	}
+
+    	leaf leaf10 {
+    		type int32 {
+    			range 10.0..20.0;
+    		}
+    	}
+
+    	leaf leaf11 {
+    		type int32 {
+    			range "10..20 | 30 .. 40";
+    		}
+    	}
+
+    	leaf leaf12 {
+    		type int32 {
+    			range "10..20 | 25 | 30 .. 40";
+    		}
+    	}
+
+    	leaf leaf13 {
+    		type uint8 {
+    			range "min..min | max .. max";
+    		}
+    	}
+
+    	leaf leaf14 {
+    		type uint8 {
+    			range " | 10";
+    		}
+    	}
+
+    	leaf leaf15 {
+    		type uint8 {
+    			range "10 | ";
+    		}
+    	}
+
+    	leaf leaf16 {
+    		type uint8 {
+    			range "zero .. 10";
+    		}
+    	}
+
+   		leaf leaf17 {
+    		type uint8 {
+    			range "10 .. 20 | .. 30";
+    		}
+    	}
+
+   		leaf leaf18 {
+    		type uint8 {
+    			range "10 .. | 20 .. 30";
+    		}
+    	}
+
+   		leaf leaf19 {
+    		type uint8 {
+    			range "10 .. 20 | 20 .. 30";
+    		}
+    	}
+
+   		leaf leaf20 {
+    		type uint8 {
+    			range "20 .. 10 | 25 .. 30";
+    		}
+    	}
+
+   		leaf leaf21 {
+    		type uint8 {
+    			range "30 .. 40 | 10 .. 20";
+    		}
+    	}
+
+   		leaf leaf22 {
+    		type uint8 {
+    			range "-100 .. -90 | -80 .. -70";
+    		}
+    	}
+
+   		leaf leaf23 {
+    		type uint8 {
+    			range "400 .. 410 | 610 .. 620";
+    		}
+    	}
+
+   		leaf leaf24 {
+    		type uint8 {
+    			range "10.5 .. 20.8";
+    		}
+    	}
+
+   		leaf leaf25 {
+    		type boolean {
+    			range "10 .. 20";
+    		}
+    	}
+    }
+
+	// -------------- Range for decimal64 -------------------
+
+    container cont3 {
+
+	   	leaf leaf1 {
+    		type decimal64 {
+    			fraction-digits 1;
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf2 {
+    		type decimal64 {
+    			fraction-digits 18;
+    			range min..max;
+    		}
+    	}
+
+	   	leaf leaf3 {
+    		type decimal64 {		// missing fraction digits statement, should issue finding
+    			range min..max;
+    		}
+    	}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-rpc.yang b/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-rpc.yang
new file mode 100644
index 0000000..77bbd76
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-rpc.yang
@@ -0,0 +1,96 @@
+module general-syntax-test-rpc {
+
+    namespace "test:general-syntax-test-rpc";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-22" {
+        description "Initial revision";
+    }
+
+	feature feature1;
+
+    // -------------- RPCs -------------------
+
+	rpc rpc1;
+
+	rpc rpc2 {
+		input {
+			container cont1;
+		}
+	}
+
+	rpc rpc3 {
+		output {
+			container cont2;
+		}
+	}
+
+	rpc rpc4 {
+		status deprecated;
+		if-feature feature1;
+
+		typedef typedef1 {
+			type string;
+		}
+		grouping grouping1 {
+			leaf grouping-leaf {
+				type int32;
+			}
+		}
+		output {
+			leaf leaf1 {
+				type typedef1;
+			}
+			anyxml anyxml1;
+			anydata anydata1;
+			list list1 {
+				key leaf2;
+				leaf leaf2 {
+					type int32;
+				}
+			}
+			leaf-list leaflist3 {
+				type boolean;
+			}
+			choice choice1 {
+				container cont6;
+				container cont7;
+			}
+			must "../contX";
+			typedef typedef2 {
+				type int16;
+			}
+		}
+		input {
+			container cont4;
+			uses grouping1;
+			anyxml anyxml1;
+			anydata anydata1;
+			list list1 {
+				key leaf2;
+				leaf leaf2 {
+					type int32;
+				}
+			}
+			leaf-list leaflist3 {
+				type boolean;
+			}
+			choice choice1 {
+				container cont6;
+				container cont7;
+			}
+			must "../contX";
+			typedef typedef2 {
+				type int16;
+			}
+		}
+	}
+
+
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-various.yang b/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-various.yang
new file mode 100644
index 0000000..1d66252
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/general-syntax-test/general-syntax-test-various.yang
@@ -0,0 +1,278 @@
+module general-syntax-test-various {
+
+    namespace "test:general-syntax-test-various";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-07-22" {
+        description "Initial revision";
+    }
+
+	// - - - - enums - - - - -
+
+	container cont1 {
+		leaf leaf1 {
+			type enumeration {
+				enum zero {
+					value 0;
+				}
+				enum one {
+					status deprecated;
+				}
+				enum two;
+
+				enum "thr ee";		// Whitespace
+
+				enum "fo.ur";		// OK
+
+				enum "fi/ve";		// Weird characters
+
+				enum six {
+					value;			// Omitted value
+				}
+
+				enum seven {
+					value "Hello!";	// not numeric
+				}
+			}
+		}
+	}
+
+ 	// - - - - status - - - - -
+
+    container cont2 {
+
+    	leaf leaf11 {
+    		type string;
+    		status current;
+    	}
+
+    	leaf leaf12 {
+    		type string;
+    		status deprecated;
+    	}
+
+    	leaf leaf13 {
+    		type string;
+    		status obsolete;
+    	}
+
+    	leaf leaf14 {
+    		type string;
+    		status blurb;
+    	}
+
+    	leaf leaf15 {
+    		type string;
+    		status;
+    	}
+    }
+
+    // - - - - - container - - - - -
+
+    container cont3 {
+
+    	grouping grouping1 {
+    		leaf leaf21 {
+    			type uint16;
+    		}
+    	}
+
+    	typedef typedef1 {
+    		type boolean;
+    	}
+
+    	leaf leaf22 {
+    		type uint16;
+    	}
+
+    	leaf leaf23 {
+    		type uint16;
+    	}
+
+    	choice choice1 {
+    		case case1 {
+    			leaf leaf24 {
+    				type string;
+    			}
+    		}
+    		case case2 {
+    			leaf leaf25 {
+    				type string;
+    			}
+    		}
+    	}
+
+    	list list1 {
+    		key "name";
+    		leaf name {
+    			type string;
+    		}
+    	}
+
+    	notification notification1 {
+   			leaf leaf26 {
+   				type string;
+   			}
+    	}
+
+    	leaf-list leaflist1 {
+    		type uint32;
+    	}
+
+    	anydata anydata1;
+    	anydata anydata2;
+
+		anyxml anyxml1;
+		anyxml anyxml2;
+		anyxml anyxml3;
+    }
+
+    // - - - - - choice and case - - - - -
+
+    choice choice1 {
+		when "../cont3";
+		status deprecated;
+
+		config true;
+		default case2;
+
+    	leaf leaf27 {
+    		type uint16;
+    	}
+
+    	leaf leaf28 {
+    		type uint16;
+    	}
+
+    	list list4 {
+    		key "name";
+    		leaf name {
+    			type string;
+    		}
+    	}
+
+    	leaf-list leaflist1 {
+    		type uint32;
+    	}
+
+    	anydata anydata1;
+		anyxml anyxml1;
+		anyxml anyxml2;
+
+		case case2 {
+			when "../cont2";
+			status obsolete;
+
+			leaf leaf29 {
+				type string;
+			}
+
+			leaf-list leaflist3 {
+				type int32;
+			}
+
+		   	anydata anydata1;
+
+			anyxml anyxml1;
+			anyxml anyxml2;
+		}
+    }
+
+    // - - - - - list - - - - -
+
+    list list4 {
+
+    	key leaf22;
+    	config true;
+    	ordered-by system;
+    	status current;
+
+    	grouping grouping1 {
+    		leaf leaf21 {
+    			type uint16;
+    		}
+    	}
+
+    	typedef typedef1 {
+    		type boolean;
+    	}
+
+    	action action1;
+    	action action2;
+    	action action3;
+
+    	leaf leaf22 {
+    		type uint16;
+    	}
+
+    	leaf leaf23 {
+    		type uint16;
+    	}
+
+    	choice choice1 {
+    		case case1 {
+    			leaf leaf24 {
+    				type string;
+    			}
+    		}
+    		case case2 {
+    			leaf leaf25 {
+    				type string;
+    			}
+    		}
+    	}
+
+    	list list1 {
+    		key "name";
+    		leaf name {
+    			type string;
+    		}
+    	}
+
+    	notification notification1 {
+   			leaf leaf26 {
+   				type string;
+   			}
+    	}
+
+    	leaf-list leaflist1 {
+    		type uint32;
+    	}
+
+    	anydata anydata1;
+    	anydata anydata2;
+
+		anyxml anyxml1;
+		anyxml anyxml2;
+		anyxml anyxml3;
+    }
+
+    // - - - - - leaf-list - - - - -
+
+	container cont5 {
+
+		leaf-list leaflist51 {
+			type string;
+			ordered-by user;
+		}
+
+		leaf-list leaflist52 {
+			type string;
+			ordered-by system;
+		}
+
+		leaf-list leaflist53 {
+			type string;
+			ordered-by something-else;
+		}
+
+		leaf-list leaflist54 {
+			type string;
+			ordered-by;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/grouping-test/faulty-grouping-module.yang b/yang-parser/src/test/resources/model-statements-yang/grouping-test/faulty-grouping-module.yang
new file mode 100644
index 0000000..21287f8
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/grouping-test/faulty-grouping-module.yang
@@ -0,0 +1,135 @@
+module faulty-grouping-module {
+
+	namespace "test:faulty-grouping-module";
+	prefix this;
+
+	description "yang test module for uses / grouping";
+
+	import not-supplied-module {
+		prefix nsm;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2015-10-20" {
+		description "Initial revision";
+	}
+
+	grouping simple-grouping {
+		container cont91;
+		leaf leaf92 {
+			type string;
+		}
+	}
+
+	// - - - - grouping cannot be found
+
+	container cont1 {
+		uses unknown-prefix:some-grouping;
+	}
+
+	container cont2 {
+		uses this:unknown-grouping;
+	}
+
+	container cont3 {
+		uses unknown-grouping;
+	}
+
+	// - - - - obsolete usage
+
+	container cont4 {
+		uses this:simple-grouping {
+			status obsolete;
+		}
+	}
+
+	// - - - - self-referencing
+
+	grouping grouping1 {
+		container contX;
+		uses this:grouping1;
+	}
+
+	// - - - - circular usage
+
+	grouping grouping2 {
+		container contX;
+		uses this:grouping3;
+	}
+
+	grouping grouping3 {
+		container contY;
+		uses this:grouping2;
+	}
+
+	// ------ augment path cannot be found or syntax error
+
+	container cont5 {
+		uses this:simple-grouping {
+			augment /unknown-absolute-path {
+				container contX;
+			}
+		}
+	}
+
+	container cont6 {
+		uses this:simple-grouping {
+			augment container-that-does-not-exist-in-simple-grouping {
+				container contX;
+			}
+		}
+	}
+
+	// - - - - - - Invalid paths - - - - -
+
+	uses;
+
+	uses "";
+
+	uses " ";
+
+	uses "nsm:non-existing-grouping";
+
+	grouping grouping5 {
+		leaf leaf11 {
+			type int32;
+		}
+	}
+
+	grouping grouping6 {
+		leaf leaf12 {
+			type int32;
+		}
+	}
+
+	container cont8 {
+		uses this:grouping5 {
+			refine;
+			refine "";
+			refine "/absolute-path";
+			refine "unknown-leaf";
+		}
+
+		uses this:grouping6 {
+			augment;
+			augment "";
+			augment "/absolute-path";
+			augment "unknown-leaf";
+		}
+	}
+
+	// - - - - - - Nested unresolvable uses - - - - -
+
+	grouping grouping7 {
+
+		uses unknown-grouping1;
+		uses unknown-grouping2;
+	}
+
+	container cont9 {
+		uses grouping7;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/grouping-test/grouping-module.yang b/yang-parser/src/test/resources/model-statements-yang/grouping-test/grouping-module.yang
new file mode 100644
index 0000000..fbced5e
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/grouping-test/grouping-module.yang
@@ -0,0 +1,104 @@
+module grouping-module {
+
+    namespace "urn:o-ran:yang:grouping-module";
+    prefix this;
+
+    description "yang test module for uses / grouping
+    Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2015-10-20" {
+        description "Initial revision";
+    }
+
+    container cont999 {
+        leaf leaf9991 {
+            type string;
+        }
+    }
+
+    grouping grouping1 {
+        container contgroup1 {
+            leaf leafgroup1 {
+                type string;
+            }
+        }
+    }
+
+	// - - - augmenting a choice
+
+	grouping grouping2 {
+        leaf leaf21 {
+            type string;
+        }
+        leaf leaf22 {
+            type boolean;
+        }
+        choice choice23 {
+            leaf leaf41 {
+                type binary;
+            }
+            leaf leaf42 {
+                type empty;
+            }
+            case case43 {
+            	leaf leaf43 {
+            		type uint8;
+            	}
+            }
+        }
+    }
+
+    // - - - - refine handling
+
+    grouping grouping3 {
+    	container cont31 {
+    		leaf leaf35 {
+    			type string;
+    			default "hello";
+    		}
+    		leaf leaf36 {
+    			type boolean;
+    			config true;
+    			mandatory true;
+    		}
+    		leaf-list leaflist37 {
+    			type int32;
+    			default 10;
+    			default 20;
+    			default 30;
+    			min-elements 2;
+    			max-elements 5;
+    		}
+    	}
+   		container cont32 {
+   			description "this is a non-presence container";
+   			if-feature feature1;
+   			must "abc > 10";
+    	}
+    }
+
+    // - - - - refine handling (extensions)
+
+    extension extension1;
+
+    extension extension2 {
+    	argument extension2argument;
+    }
+
+    extension extension3;
+
+	grouping grouping4 {
+		container cont41 {
+			this:extension1;
+			this:extension2 "hello";
+			this:extension2 "world";
+		}
+		container cont42 {
+			this:extension3;
+		}
+	}
+
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/grouping-test/uses-module.yang b/yang-parser/src/test/resources/model-statements-yang/grouping-test/uses-module.yang
new file mode 100644
index 0000000..42d57fc
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/grouping-test/uses-module.yang
@@ -0,0 +1,113 @@
+module uses-module {
+
+    namespace "urn:o-ran:yang:uses-module";
+    prefix this;
+
+    import grouping-module {
+        revision-date "2015-10-20";
+        prefix gm;
+    }
+
+    description "yang test module for uses / grouping
+    Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2015-10-20" {
+        description "Initial revision";
+    }
+
+    container cont1 {
+        leaf leaf11 {
+            type string;
+        }
+
+        uses gm:grouping1 {
+        	if-feature "feature1 or feature2";
+        }
+    }
+
+    container cont2 {
+        leaf leaf21 {
+            type string;
+        }
+
+        uses gm:grouping1 {
+            when "leaf21 = 'Hello'";
+        }
+    }
+
+    container cont3 {
+        leaf leaf31 {
+            type string;
+        }
+
+        uses gm:grouping1 {
+            augment contgroup1 {
+            	when "abc > 10";
+                leaf leaf32 {
+                    type string;
+                }
+            }
+        }
+    }
+
+	// - - - augmenting a choice
+
+    container cont4 {
+    	uses gm:grouping2 {
+			augment choice23 {
+				container cont44 {
+                    presence "Meaningful container";
+				}
+			}
+    	}
+    }
+
+    // - - - - refine handling (once without, once with)
+
+    container cont5 {
+    	uses gm:grouping3;
+    }
+
+	container cont6 {
+    	uses gm:grouping3 {
+    		refine "cont31/leaf35" {
+    			default "world";
+    			mandatory true;
+    		}
+    		refine "cont31/leaf36" {
+    			config false;
+    			mandatory false;
+    		}
+    		refine "cont31/leaflist37" {
+    			default 80;
+    			default 90;
+    			min-elements 1;
+    			max-elements 6;
+    		}
+    		refine "cont32" {
+    			presence "now a presence container";
+   				if-feature feature99;
+   				must "xyz > 99";
+    		}
+    	}
+    }
+
+    // - - - - refine handling (extensions)
+
+    container cont7 {
+    	uses gm:grouping4 {
+     		refine "cont41" {
+				gm:extension2 "hello world";
+				gm:extension3;
+    		}
+     		refine "cont42" {
+				gm:extension1;
+				gm:extension2 "abc";
+				gm:extension2 "def";
+				gm:extension3;
+    		}
+    	}
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/grouping-test/uses-refine-module.yang b/yang-parser/src/test/resources/model-statements-yang/grouping-test/uses-refine-module.yang
new file mode 100644
index 0000000..d0bbda3
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/grouping-test/uses-refine-module.yang
@@ -0,0 +1,143 @@
+module uses-refine-module {
+
+	namespace "test:uses-refine-module";
+	prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2015-10-20" {
+		description "Initial revision";
+	}
+
+	feature feature1;
+	feature feature2;
+
+	grouping grouping1 {
+
+		leaf leaf1 {
+			type string;
+		}
+
+		leaf leaf2 {
+			type string;
+			default "Hello";
+			description "old description";
+			reference "old reference";
+			config true;
+			mandatory true;
+		}
+
+		leaf leaf3 {
+			type int32;
+		}
+
+		leaf leaf4 {
+			type int32;
+		}
+
+		leaf leaf5 {
+			type int32;
+			must ". > ../leaf3";
+		}
+
+		leaf-list leaflist14 {
+			type uint32;
+			if-feature feature1;
+		}
+
+		leaf-list leaflist15 {
+			type uint32;
+			default 10;
+			default 20;
+			default 30;
+			min-elements 2;
+			max-elements 6;
+		}
+
+		container cont74;
+
+		choice choice83 {
+			leaf leaf7 {
+				type string;
+			}
+			leaf leaf8 {
+				type string;
+			}
+		}
+	}
+
+// - - - - should be all ok - - - - - -
+
+	container cont1 {
+
+		uses grouping1 {
+
+			refine leaf1 {
+				description "new description";
+				reference "new reference";
+				config true;
+				default "world";
+				mandatory true;
+				if-feature feature2;
+			}
+
+			refine leaf2 {
+				config false;
+				default "world";
+				mandatory false;
+				if-feature feature1;
+			}
+
+			refine leaf5 {
+				must ". > ../leaf4";
+			}
+
+			refine leaflist14 {
+				default 50;
+				default 60;
+				min-elements 2;
+				max-elements 8;
+				if-feature feature2;
+			}
+
+			refine leaflist15 {
+				default 50;
+				default 60;
+				default 70;
+				min-elements 3;
+				max-elements 9;
+			}
+
+			refine cont74 {
+				presence "meaningful!";
+			}
+		}
+	}
+
+// - - - - - - error scenarios - - - - - -
+
+	container cont2 {
+
+		uses grouping1 {
+
+			refine leaf1 {
+				presence "meaningful!";
+			}
+
+			refine leaf4 {
+				default 22;
+				default 23;
+			}
+
+			refine cont74 {
+				min-elements 3;
+			}
+
+			refine choice83 {
+				must ". > 10";
+			}
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/identity-test/identity-test-module1.yang b/yang-parser/src/test/resources/model-statements-yang/identity-test/identity-test-module1.yang
new file mode 100644
index 0000000..1227353
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/identity-test/identity-test-module1.yang
@@ -0,0 +1,37 @@
+module identity-test-module1 {
+
+    namespace "test:identity-test-module1";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-11-11" {
+        description "initial revision";
+    }
+
+	identity identity1;
+
+	identity identity2 {
+		base identity1;
+	}
+
+	identity identity3 {
+		if-feature "blue-moon";
+		base identity2;
+	}
+
+	identity identity4;
+
+	identity identity5 {
+		status deprecated;
+		base identity1;
+		base this:identity4;
+	}
+
+	feature blue-moon {
+		description "It is a full blue moon.";
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/if-feature-test/if-feature-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/if-feature-test/if-feature-test-module.yang
new file mode 100644
index 0000000..8c90cb5
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/if-feature-test/if-feature-test-module.yang
@@ -0,0 +1,70 @@
+module if-feature-test-module {
+
+    namespace "urn:ietf:params:xml:ns:yang:if-feature-test-module";
+    prefix "module1";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27" {
+        description "initial revision";
+    }
+
+    feature feature1 {
+        description "feature1 desc";
+        reference "feature1 ref";
+    }
+
+    feature feature2;
+    feature feature3;
+
+    container cont1 {
+        if-feature feature1;
+
+        leaf leaf1 {
+            if-feature feature2;
+            type uint32;
+        }
+
+        leaf leaf2 {
+            if-feature "feature1 or feature2";
+            type string;
+        }
+
+        leaf leaf3 {
+            if-feature "feature1 and(feature2 or				not feature3)";
+            type string;
+        }
+
+        leaf leaf4 {
+            if-feature "(feature1 or feature2)and feature3 or feature1";
+            type string;
+        }
+
+        leaf leaf5 {
+            if-feature "(feature1";
+            type string;
+        }
+
+        leaf leaf6 {
+            if-feature "feature1 or";
+            type string;
+        }
+
+        leaf leaf7 {
+            if-feature "(feature1 or feature2)) or feature3 (";
+            type string;
+        }
+
+        leaf leaf8 {
+            if-feature "()";
+            type string;
+        }
+
+        leaf leaf9 {
+            if-feature;
+            type string;
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/import-itself-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/import-itself-test-module.yang
new file mode 100644
index 0000000..75fd07a
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/import-itself-test-module.yang
@@ -0,0 +1,19 @@
+module import-itself-test-module {
+
+    namespace "test:import-twice-first-no-revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import import-itself-test-module {
+		prefix prefix1;
+		revision-date 2020-10-02;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-first-no-revision-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-first-no-revision-test-module.yang
new file mode 100644
index 0000000..918074b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-first-no-revision-test-module.yang
@@ -0,0 +1,23 @@
+module import-twice-first-no-revision-test-module {
+
+    namespace "test:import-twice-first-no-revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import ietf-yang-metadata {
+		prefix prefix1;
+	}
+
+	import ietf-yang-metadata {
+		prefix prefix2;
+		revision-date 2016-08-05;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-no-revisions-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-no-revisions-test-module.yang
new file mode 100644
index 0000000..33f2521
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-no-revisions-test-module.yang
@@ -0,0 +1,22 @@
+module import-twice-no-revisions-test-module {
+
+    namespace "test:import-twice-no-revisions-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import ietf-yang-metadata {
+		prefix prefix1;
+	}
+
+	import ietf-yang-metadata {
+		prefix prefix2;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-same-revisions-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-same-revisions-test-module.yang
new file mode 100644
index 0000000..09d5e10
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-same-revisions-test-module.yang
@@ -0,0 +1,24 @@
+module import-twice-same-revisions-test-module {
+
+    namespace "test:import-twice-same-revisions-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import ietf-yang-metadata {
+		prefix prefix1;
+		revision-date 2016-08-05;
+	}
+
+	import ietf-yang-metadata {
+		prefix prefix2;
+		revision-date 2016-08-05;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-second-no-revision-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-second-no-revision-test-module.yang
new file mode 100644
index 0000000..ec79ba8
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/import-twice-second-no-revision-test-module.yang
@@ -0,0 +1,23 @@
+module import-twice-second-no-revision-test-module {
+
+    namespace "test:import-twice-second-no-revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import ietf-yang-metadata {
+		prefix prefix1;
+		revision-date 2016-08-05;
+	}
+
+	import ietf-yang-metadata {
+		prefix prefix2;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-ambiguous-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-ambiguous-test-module.yang
new file mode 100644
index 0000000..d74883f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-ambiguous-test-module.yang
@@ -0,0 +1,17 @@
+module unresolvable-import-ambiguous-test-module {
+
+	namespace "test:unresolvable-import-ambiguous-test-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-10-02" {
+		description "initial revision";
+	}
+
+	import ietf-yang-types {
+		prefix prefix1;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-no-revision-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-no-revision-test-module.yang
new file mode 100644
index 0000000..7b4b42d
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-no-revision-test-module.yang
@@ -0,0 +1,18 @@
+module unresolvable-import-no-revision-test-module {
+
+    namespace "test:unresolvable-import-no-revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import unresolvable-module {
+		prefix prefix1;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-with-revision-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-with-revision-test-module.yang
new file mode 100644
index 0000000..8cce538
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-with-revision-test-module.yang
@@ -0,0 +1,19 @@
+module unresolvable-import-with-revision-test-module {
+
+    namespace "test:unresolvable-import-with-revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import unresolvable-module {
+		prefix prefix1;
+		revision-date 2020-10-02;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-wrong-revision-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-wrong-revision-test-module.yang
new file mode 100644
index 0000000..e38e1ba
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/import-test/unresolvable-import-wrong-revision-test-module.yang
@@ -0,0 +1,18 @@
+module unresolvable-import-wrong-revision-test-module {
+
+    namespace "test:unresolvable-import-wrong-revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	import ietf-yang-types {
+		prefix prefix1;
+		revision-date 9999-01-01;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/include-test/include-test-module-correct-submodule-no-revision.yang b/yang-parser/src/test/resources/model-statements-yang/include-test/include-test-module-correct-submodule-no-revision.yang
new file mode 100644
index 0000000..3fa871a
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/include-test/include-test-module-correct-submodule-no-revision.yang
@@ -0,0 +1,20 @@
+module include-test-module {
+
+	yang-version "1.1";
+
+    namespace "test:include-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+	include test-submodule {
+		// no revision
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/include-test/other-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/include-test/other-test-module.yang
new file mode 100644
index 0000000..1a5db9b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/include-test/other-test-module.yang
@@ -0,0 +1,14 @@
+module test-submodule {
+
+    namespace "test:other-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-1999-01-01.yang b/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-1999-01-01.yang
new file mode 100644
index 0000000..a4a0cf5
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-1999-01-01.yang
@@ -0,0 +1,17 @@
+submodule test-submodule {
+
+	// yang-version "1.1";		so it's yang version 1
+
+	belongs-to include-test-module {
+		prefix this;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "1999-01-01" {
+        description "initial revision";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-2020-10-02.yang b/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-2020-10-02.yang
new file mode 100644
index 0000000..82dbe3f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-2020-10-02.yang
@@ -0,0 +1,17 @@
+submodule test-submodule {
+
+	yang-version "1.1";
+
+	belongs-to include-test-module {
+		prefix this;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-belongs-to-other-module.yang b/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-belongs-to-other-module.yang
new file mode 100644
index 0000000..9706264
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/include-test/test-submodule-belongs-to-other-module.yang
@@ -0,0 +1,17 @@
+submodule test-submodule {
+
+	yang-version "1.1";
+
+	belongs-to some-other-module {
+		prefix this;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-10-02" {
+        description "initial revision";
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-simple-faulty.yang b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-simple-faulty.yang
new file mode 100644
index 0000000..11010ee
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-simple-faulty.yang
@@ -0,0 +1,90 @@
+module length-test-module-simple-faulty {
+
+    namespace "urn:rdns:o-ran:oammodel:length-test-module-simple-faulty";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Simple lengths that are faulty for a variety of reasons --------------------
+
+    container cont1 {
+
+        leaf leaf1 {
+            type string {
+                length max..min;
+            }
+        }
+
+        leaf leaf2 {
+            type string {
+                length max..300;
+            }
+        }
+
+        leaf leaf3 {
+            type string {
+                length "-4000  ..   max";
+            }
+        }
+
+        leaf leaf4 {
+            type string {
+                length "min..max | min..max";
+            }
+        }
+
+        leaf leaf5 {
+            type string {
+                length "min  ..  100| 30..  max";
+            }
+        }
+
+        leaf leaf6 {
+            type string {
+                length -100..1000;
+            }
+        }
+
+        leaf leaf7 {
+            type string {
+                length "-50..-20 | -40..-30";
+            }
+        }
+
+        leaf leaf8 {
+            type string {
+                length "min..-20 | -30 | -40";
+            }
+        }
+
+        leaf leaf9 {
+            type string {
+                length min..-20|30|25;
+            }
+        }
+
+        leaf leaf10 {
+            type string {
+                length "min | 10 | 40000000000000000000000000000000";
+            }
+        }
+
+        leaf leaf11 {
+            type string {
+                length "blurb | 10..10 | 70";
+            }
+        }
+
+        leaf leaf12 {
+            type string {
+                length MIN..max;
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-simple.yang b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-simple.yang
new file mode 100644
index 0000000..f9ad144
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-simple.yang
@@ -0,0 +1,94 @@
+module length-test-module-simple {
+
+    namespace "urn:rdns:o-ran:oammodel:length-test-module-simple";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Simple lengths that are fine --------------------
+
+    container cont1 {
+
+        leaf leaf1 {
+            type string;
+        }
+
+        leaf leaf2 {
+            type string {
+                length min..max;
+            }
+        }
+
+        leaf leaf3 {
+            type string {
+                length "min  ..   max";
+            }
+        }
+
+        leaf leaf4 {
+            type string {
+                length "min..min | max..max";
+            }
+        }
+
+        leaf leaf5 {
+            type string {
+                length "min  ..  min| max..  max";
+            }
+        }
+
+        leaf leaf6 {
+            type string {
+                length 10..100;
+            }
+        }
+
+        leaf leaf7 {
+            type string {
+                length "10..20 | 30..60";
+            }
+        }
+
+        leaf leaf8 {
+            type string {
+                length "min..20 | 30..max";
+            }
+        }
+
+        leaf leaf9 {
+            type string {
+                length "min..20 | 30 | 80";
+            }
+        }
+
+        leaf leaf10 {
+            type string {
+                length min..20|30|80;
+            }
+        }
+
+        leaf leaf11 {
+            type string {
+                length "min | 10 | 40";
+            }
+        }
+
+        leaf leaf12 {
+            type string {
+                length "min | 10..10 | 70";
+            }
+        }
+
+        leaf leaf13 {
+            type string {
+                length min|2|3|max;
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-typedefs-faulty.yang b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-typedefs-faulty.yang
new file mode 100644
index 0000000..a33b353
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-typedefs-faulty.yang
@@ -0,0 +1,66 @@
+module length-test-module-typedefs-faulty {
+
+    namespace "urn:rdns:o-ran:oammodel:length-test-module-typedefs-faulty";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Ranges and typedefs that are incorrect --------------------
+
+    typedef typeStringNoLength {
+        type string;
+    }
+
+    typedef typeStringWithLength {
+        type string {
+            length 20..10;
+        }
+    }
+
+    typedef typeUsingTypeStringWithLength {
+        type this:typeStringWithLength;
+    }
+
+    container cont1 {
+
+        leaf leaf1 {
+            type this:typeStringNoLength {
+                length max..min;
+            }
+        }
+
+        leaf leaf2 {
+            type this:typeStringNoLength {
+                length "90..20";
+            }
+        }
+
+        leaf leaf3 {
+            type this:typeStringNoLength {
+                length "10|10";
+            }
+        }
+
+        leaf leaf4 {
+            type this:typeStringWithLength;
+        }
+
+        leaf leaf5 {
+            type this:typeUsingTypeStringWithLength;
+        }
+
+        leaf leaf6 {
+            type this:typeUsingTypeStringWithLength {
+                length "45..7";
+            }
+        }
+
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-typedefs.yang b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-typedefs.yang
new file mode 100644
index 0000000..baea7ec
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/length-test/length-test-module-typedefs.yang
@@ -0,0 +1,70 @@
+module length-test-module-typedefs {
+
+    namespace "urn:rdns:o-ran:oammodel:length-test-module-typedefs";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Lengths and typedefs that are fine --------------------
+
+    typedef typeStringNoLength {
+        type string;
+    }
+
+    typedef typeStringWithLength {
+        type string {
+            length 10..20;
+        }
+    }
+
+    typedef typeUsingTypeStringWithLength {
+        type this:typeStringWithLength;
+    }
+
+    container cont1 {
+
+        leaf leaf1 {
+            type this:typeStringNoLength;
+        }
+
+        leaf leaf2 {
+            type this:typeStringNoLength {
+                length min..max;
+            }
+        }
+
+        leaf leaf3 {
+            type this:typeStringWithLength;
+        }
+
+        leaf leaf4 {
+            type this:typeStringNoLength {
+                length "10..20 | 30..60";
+            }
+        }
+
+        leaf leaf5 {
+            type this:typeStringWithLength {
+                length "10 | 12..12 | 17";
+            }
+        }
+
+        leaf leaf6 {
+            type this:typeUsingTypeStringWithLength;
+        }
+
+        leaf leaf7 {
+            type this:typeUsingTypeStringWithLength {
+                length "17..19";
+            }
+        }
+
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/module-test/module-test.yang b/yang-parser/src/test/resources/model-statements-yang/module-test/module-test.yang
new file mode 100644
index 0000000..9f3b44e
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/module-test/module-test.yang
@@ -0,0 +1,43 @@
+module module-test {
+
+	yang-version 1.1;
+	namespace "test:module-test";
+	prefix "this";
+
+	contact "test-user";
+
+	organization "ORAN";
+
+	description "some description
+	Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2022-06-01" {
+		description "initial revision";
+	}
+
+	extension my-extension1 {
+		description "some extension description";
+		status deprecated;
+
+		argument some-arg {
+			description "some argument description";
+			yin-element true;
+		}
+	}
+
+	extension my-extension2;
+
+	anydata anydata1;
+	anydata anydata2;
+
+	anyxml anyxml1;
+	anyxml anyxml2;
+
+	grouping grouping1;
+	grouping grouping2;
+
+	uses this:grouping1;
+	uses this:grouping2;
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/prefixes-test/duplicate-prefixes-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/prefixes-test/duplicate-prefixes-test-module.yang
new file mode 100644
index 0000000..18ad2f3
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/prefixes-test/duplicate-prefixes-test-module.yang
@@ -0,0 +1,21 @@
+module duplicate-prefixes-test-module {
+
+	namespace "test:duplicate-prefixes-test-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-10-02" {
+		description "initial revision";
+	}
+
+	import ietf-origin {
+		prefix prefix1;
+	}
+
+	import ietf-yang-metadata {
+		prefix prefix1;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-simple-faulty.yang b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-simple-faulty.yang
new file mode 100644
index 0000000..809cc4b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-simple-faulty.yang
@@ -0,0 +1,90 @@
+module range-test-module-simple-faulty {
+
+    namespace "urn:rdns:o-ran:oammodel:range-test-module-simple-faulty";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Simple ranges that are faulty for a variety of reasons --------------------
+
+    container cont1 {
+
+        leaf leaf1 {
+            type int8 {
+                range max..min;
+            }
+        }
+
+        leaf leaf2 {
+            type int8 {
+                range 300..max;
+            }
+        }
+
+        leaf leaf3 {
+            type int8 {
+                range "-4000  ..   max";
+            }
+        }
+
+        leaf leaf4 {
+            type int8 {
+                range "min..max | min..max";
+            }
+        }
+
+        leaf leaf5 {
+            type int8 {
+                range "min  ..  100| 30..  max";
+            }
+        }
+
+        leaf leaf6 {
+            type int8 {
+                range -100..1000;
+            }
+        }
+
+        leaf leaf7 {
+            type int8 {
+                range "-50..-20 | -40..-30";
+            }
+        }
+
+        leaf leaf8 {
+            type int8 {
+                range "min..-20 | -30 | -40";
+            }
+        }
+
+        leaf leaf9 {
+            type int8 {
+                range min..-20|30|25;
+            }
+        }
+
+        leaf leaf10 {
+            type int8 {
+                range "min | 10 | 400";
+            }
+        }
+
+        leaf leaf11 {
+            type int8 {
+                range "blurb | 10..10 | 70";
+            }
+        }
+
+        leaf leaf12 {
+            type int8 {
+                range MIN..max;
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-simple.yang b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-simple.yang
new file mode 100644
index 0000000..8f0c216
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-simple.yang
@@ -0,0 +1,96 @@
+module range-test-module-simple {
+
+    namespace "urn:rdns:o-ran:oammodel:range-test-module-simple";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Simple ranges that are fine --------------------
+
+    container cont1 {
+
+        leaf leaf1 {
+            type int8;
+        }
+
+        leaf leaf2 {
+            type int8 {
+                range min..max {
+                	error-message "wrong!";
+                }
+            }
+        }
+
+        leaf leaf3 {
+            type int8 {
+                range "min  ..   max";
+            }
+        }
+
+        leaf leaf4 {
+            type int8 {
+                range "min..min | max..max";
+            }
+        }
+
+        leaf leaf5 {
+            type int8 {
+                range "min  ..  min| max..  max";
+            }
+        }
+
+        leaf leaf6 {
+            type int8 {
+                range -100..100;
+            }
+        }
+
+        leaf leaf7 {
+            type int8 {
+                range "-50..-20 | 30..60";
+            }
+        }
+
+        leaf leaf8 {
+            type int8 {
+                range "min..-20 | 30..max";
+            }
+        }
+
+        leaf leaf9 {
+            type int8 {
+                range "min..-20 | 30 | 80";
+            }
+        }
+
+        leaf leaf10 {
+            type int8 {
+                range min..-20|30|80;
+            }
+        }
+
+        leaf leaf11 {
+            type int8 {
+                range "min | 10 | 40";
+            }
+        }
+
+        leaf leaf12 {
+            type int8 {
+                range "min | 10..10 | 70";
+            }
+        }
+
+        leaf leaf13 {
+            type int8 {
+                range min|2|3|max;
+            }
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-typedefs-faulty.yang b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-typedefs-faulty.yang
new file mode 100644
index 0000000..b5c7be4
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-typedefs-faulty.yang
@@ -0,0 +1,78 @@
+module range-test-module-typedefs-faulty {
+
+    namespace "urn:rdns:o-ran:oammodel:range-test-module-typedefs-faulty";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Ranges and typedefs that are incorrect --------------------
+
+    typedef typeInt8noRange {
+        type int8;
+    }
+
+    typedef typeInt64noRange {
+        type int64;
+    }
+
+    typedef typeUint8noRange {
+        type uint8;
+    }
+
+    typedef typeUint64noRange {
+        type uint64;
+    }
+
+    typedef typeInt8WithRange {
+        type int8 {
+            range 20..10;
+        }
+    }
+
+    typedef typeUsingTypeInt8WithRange {
+        type this:typeInt8WithRange;
+    }
+
+    container cont1 {
+
+        leaf leaf1 {
+            type this:typeInt8noRange {
+                range max..min;
+            }
+        }
+
+        leaf leaf2 {
+            type this:typeInt8noRange {
+                range "90..20";
+            }
+        }
+
+        leaf leaf3 {
+            type this:typeUint64noRange {
+                range "10|10";
+            }
+        }
+
+        leaf leaf4 {
+            type this:typeInt8WithRange;
+        }
+
+        leaf leaf5 {
+            type this:typeUsingTypeInt8WithRange;
+        }
+
+        leaf leaf6 {
+            type this:typeUsingTypeInt8WithRange {
+                range "45..7";
+            }
+        }
+
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-typedefs.yang b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-typedefs.yang
new file mode 100644
index 0000000..2f0bd33
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/range-test/range-test-module-typedefs.yang
@@ -0,0 +1,100 @@
+module range-test-module-typedefs {
+
+    namespace "urn:rdns:o-ran:oammodel:range-test-module-typedefs";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-10-16" {
+        description "initial revision";
+    }
+
+// -------------------------- Ranges and typedefs that are fine --------------------
+
+    typedef typeInt8noRange {
+        type int8;
+    }
+
+    typedef typeInt64noRange {
+        type int64;
+    }
+
+    typedef typeUint8noRange {
+        type uint8;
+    }
+
+    typedef typeUint64noRange {
+        type uint64;
+    }
+
+    typedef typeInt8WithRange {
+        type int8 {
+            range 10..20;
+        }
+    }
+
+    typedef typeUsingTypeInt8WithRange {
+        type this:typeInt8WithRange;
+    }
+
+    container cont1 {
+
+        leaf leaf1 {
+            type this:typeInt8noRange;
+        }
+
+        leaf leaf2 {
+            type this:typeInt8noRange {
+                range min..max;
+            }
+        }
+
+        leaf leaf3 {
+            type this:typeInt64noRange {
+                range min..max;
+            }
+        }
+
+        leaf leaf4 {
+            type this:typeUint8noRange {
+                range min..max;
+            }
+        }
+
+        leaf leaf5 {
+            type this:typeUint64noRange {
+                range min..max;
+            }
+        }
+
+        leaf leaf6 {
+            type this:typeInt8WithRange;
+        }
+
+        leaf leaf7 {
+            type this:typeInt8noRange {
+                range "-50..-20 | 30..60";
+            }
+        }
+
+        leaf leaf8 {
+            type this:typeUint64noRange {
+                range "5 | 10..10 | 70";
+            }
+        }
+
+        leaf leaf9 {
+            type this:typeUsingTypeInt8WithRange;
+        }
+
+        leaf leaf10 {
+            type this:typeUsingTypeInt8WithRange {
+                range "17..19";
+            }
+        }
+
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-duplicate-revision-latest.yang b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-duplicate-revision-latest.yang
new file mode 100644
index 0000000..fa44318
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-duplicate-revision-latest.yang
@@ -0,0 +1,27 @@
+module revision-test-module {
+
+    namespace "test:revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27" {
+        description "lates revision with copy/paste error";
+    }
+
+    revision "2019-09-27" {
+        description "in-between revision";
+    }
+
+    revision "2018-05-05" {
+        description "initial revision";
+    }
+
+    container cont1 {
+        leaf leaf1 {
+            type uint32;
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-duplicate-revision-non-latest.yang b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-duplicate-revision-non-latest.yang
new file mode 100644
index 0000000..3407b8d
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-duplicate-revision-non-latest.yang
@@ -0,0 +1,27 @@
+module revision-test-module {
+
+    namespace "test:revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-05-05" {
+        description "latest revision";
+    }
+
+    revision "2019-09-27" {
+        description "in-between revision with copy/paste error";
+    }
+
+    revision "2019-09-27" {
+        description "initial revision";
+    }
+
+    container cont1 {
+        leaf leaf1 {
+            type uint32;
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-invalid-revision.yang b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-invalid-revision.yang
new file mode 100644
index 0000000..6deaf36
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-invalid-revision.yang
@@ -0,0 +1,47 @@
+module revision-test-module {
+
+    namespace "test:revision-test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27" {
+        description "valid revision";
+    }
+
+    revision "2019-9-27" {
+        description "invalid revision";
+    }
+
+    revision "20190927" {
+        description "invalid revision";
+    }
+
+    revision "2019.09.27" {
+        description "invalid revision";
+    }
+
+    revision "19-09-27" {
+        description "invalid revision";
+    }
+
+    revision "blurb" {
+        description "invalid revision";
+    }
+
+    revision "" {
+        description "invalid revision";
+    }
+
+    revision {
+        description "invalid revision";
+    }
+
+    container cont1 {
+        leaf leaf1 {
+            type uint32;
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-no-revision.yang b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-no-revision.yang
new file mode 100644
index 0000000..80c3aca
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/revision-test/revision-test-module-no-revision.yang
@@ -0,0 +1,15 @@
+module revision-test-module {
+
+	namespace "test:revision-test-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	container cont1 {
+		leaf leaf1 {
+			type uint32;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module1.yang b/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module1.yang
new file mode 100644
index 0000000..3c4bf10
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module1.yang
@@ -0,0 +1,109 @@
+module status-test-module1 {
+
+    namespace "test:module1";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-02-17" {
+        description "initial revision";
+    }
+
+  	// -------------------- simple stuff --------------------
+
+    container cont1 {
+
+    	status current;
+
+        leaf leaf11 {
+        	status current;
+            type uint32;
+        }
+
+        leaf leaf12 {
+        	status deprecated;
+            type uint32;
+        }
+
+        leaf leaf13 {
+        	status obsolete;
+            type uint32;
+        }
+    }
+
+    container cont2 {
+
+    	status deprecated;
+
+        leaf leaf21 {
+        	status current;
+            type uint32;
+        }
+
+        leaf leaf22 {
+        	status deprecated;
+            type uint32;
+        }
+
+        leaf leaf23 {
+        	status obsolete;
+            type uint32;
+        }
+    }
+
+    container cont3 {
+
+    	status obsolete;
+
+        leaf leaf31 {
+        	status current;
+            type uint32;
+        }
+
+        leaf leaf32 {
+        	status deprecated;
+            type uint32;
+        }
+
+        leaf leaf33 {
+        	status obsolete;
+            type uint32;
+        }
+    }
+
+  	// -------------------- simple, using groupings --------------------
+
+	grouping grouping1 {
+        leaf leaf97 {
+        	status current;
+            type uint32;
+        }
+
+        leaf leaf98 {
+        	status deprecated;
+            type uint32;
+        }
+
+        leaf leaf99 {
+        	status obsolete;
+            type uint32;
+        }
+	}
+
+	container cont4 {
+		status current;
+		uses grouping1;
+	}
+
+	container cont5 {
+		status deprecated;
+		uses grouping1;
+	}
+
+	container cont6 {
+		status obsolete;
+		uses grouping1;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module2.yang b/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module2.yang
new file mode 100644
index 0000000..2a54d01
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module2.yang
@@ -0,0 +1,102 @@
+module status-test-module2 {
+
+    namespace "test:module2";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-02-17" {
+        description "initial revision";
+    }
+
+  	// -------------------- status under uses --------------------
+
+	grouping grouping1 {
+        leaf leaf97 {
+        	status current;
+            type uint32;
+        }
+
+        leaf leaf98 {
+        	status deprecated;
+            type uint32;
+        }
+
+        leaf leaf99 {
+        	status obsolete;
+            type uint32;
+        }
+	}
+
+	container cont1 {
+		uses grouping1 {
+			status current;
+		}
+	}
+
+	container cont2 {
+		uses grouping1 {
+			status deprecated;
+		}
+	}
+
+	container cont3 {
+		uses grouping1 {
+			status obsolete;
+		}
+	}
+
+	  	// -------------------- status under grouping --------------------
+
+	grouping grouping3 {
+		status current;
+
+        leaf leaf91 {
+            type uint32;
+        }
+	}
+
+	grouping grouping4 {
+		status deprecated;
+
+        leaf leaf92 {
+            type uint32;
+        }
+	}
+
+	grouping grouping5 {
+		status obsolete;
+
+        leaf leaf93 {
+            type uint32;
+        }
+	}
+
+	container cont11 {
+		status current;
+
+		uses grouping3;
+		uses grouping4;
+		uses grouping5;
+	}
+
+	container cont12 {
+		status deprecated;
+
+		uses grouping3;
+		uses grouping4;
+		uses grouping5;
+	}
+
+	container cont13 {
+		status obsolete;
+
+		uses grouping3;
+		uses grouping4;
+		uses grouping5;
+	}
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module3.yang b/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module3.yang
new file mode 100644
index 0000000..8fe0e30
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/status-test/status-test-module3.yang
@@ -0,0 +1,77 @@
+module status-test-module3 {
+
+    namespace "test:module3";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-02-17" {
+        description "initial revision";
+    }
+
+	  	// -------------------- status under both grouping and uses --------------------
+
+	grouping grouping7 {
+		status current;
+
+        leaf leaf91 {
+            type uint32;
+        }
+	}
+
+	grouping grouping8 {
+		status deprecated;
+
+        leaf leaf92 {
+            type uint32;
+        }
+	}
+
+	grouping grouping9 {
+		status obsolete;
+
+        leaf leaf93 {
+            type uint32;
+        }
+	}
+
+	container cont31 {
+		uses grouping7 {
+			status current;
+		}
+		uses grouping8 {
+			status current;
+		}
+		uses grouping9 {
+			status current;
+		}
+	}
+
+	container cont32 {
+		uses grouping7 {
+			status deprecated;
+		}
+		uses grouping8 {
+			status deprecated;
+		}
+		uses grouping9 {
+			status deprecated;
+		}
+	}
+
+	container cont33 {
+		uses grouping7 {
+			status obsolete;
+		}
+		uses grouping8 {
+			status obsolete;
+		}
+		uses grouping9 {
+			status obsolete;
+		}
+	}
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/string-tokenization-test/string-tokenization-yang1-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/string-tokenization-test/string-tokenization-yang1-test-module.yang
new file mode 100644
index 0000000..ceb4d00
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/string-tokenization-test/string-tokenization-yang1-test-module.yang
@@ -0,0 +1,69 @@
+module string-tokenization-yang1-test-module {
+    namespace "urn:o-ran:yang:string-tokenization-yang1-test-module";
+    prefix "test";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision 2019-10-08 {
+        description "Initial revision.";
+    }
+
+    container cont1 {
+        description "valid YANG 1 double-quoted string";
+    }
+
+    container cont2 {
+        description "valid YANG 1 double-quoted string with special characters \n \t \" \\ \X \_";
+    }
+
+    container cont3 {
+        description "valid YANG 1
+                           double-quoted string";
+    }
+
+    container cont4 {
+        description "valid YANG 1
+
+                         double-quoted string";
+    }
+
+    container cont5 {
+        description "";
+    }
+
+    container cont6 {
+        description "invalid YANG 1 double-quoted string \
+                         because of trailing backslash";
+    }
+
+    container cont11 {
+        description 'valid YANG 1 single-quoted string';
+    }
+
+    container cont12 {
+        description 'valid YANG 1 single-quoted string " \n \t \\ \X';
+    }
+
+    container cont13 {
+        description 'valid YANG 1
+single-quoted string';
+    }
+
+    container cont14 {
+        description 'valid YANG 1
+                           single-quoted string';
+    }
+
+    container cont21 {
+        description valid_YANG_1_unquoted_string;
+    }
+
+    container cont22 {
+        description valid_YANG_1_unquoted_string_with_a_quote_at_the_end";
+    }
+
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/string-tokenization-test/string-tokenization-yang1.1-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/string-tokenization-test/string-tokenization-yang1.1-test-module.yang
new file mode 100644
index 0000000..b9f58e7
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/string-tokenization-test/string-tokenization-yang1.1-test-module.yang
@@ -0,0 +1,72 @@
+module string-tokenization-yang1.1-test-module {
+
+    yang-version 1.1;
+
+    namespace "urn:o-ran:yang:string-tokenization-yang1.1-test-module";
+    prefix "test";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision 2019-10-08 {
+        description "Initial revision.";
+    }
+
+    container cont1 {
+        description "valid YANG 1.1 double-quoted string";
+    }
+
+    container cont2 {
+        description "invalid YANG 1.1 double-quoted string with special characters \n \t \" \\ \X \_";
+    }
+
+    container cont3 {
+        description "valid YANG 1.1
+                           double-quoted string";
+    }
+
+    container cont4 {
+        description "valid YANG 1.1
+
+                         double-quoted string";
+    }
+
+    container cont5 {
+        description "";
+    }
+
+    container cont6 {
+        description "invalid YANG 1.1 double-quoted string \
+                         because of trailing backslash";
+    }
+
+    container cont11 {
+        description 'valid YANG 1.1 single-quoted string';
+    }
+
+    container cont12 {
+        description 'valid YANG 1.1 single-quoted string " \n \t \\ \X';
+    }
+
+    container cont13 {
+        description 'valid YANG 1.1
+single-quoted string';
+    }
+
+    container cont14 {
+        description 'valid YANG 1.1
+                           single-quoted string';
+    }
+
+    container cont21 {
+        description valid_YANG_1_1_unquoted_string;
+    }
+
+    container cont22 {
+        description invalid_YANG_1_1_unquoted_string_with_a_quote_at_the_end";
+    }
+
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-not-found/module.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-not-found/module.yang
new file mode 100644
index 0000000..252734b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-not-found/module.yang
@@ -0,0 +1,25 @@
+module submodule-test-module {
+
+    namespace "urn:o-ran:yang:submodule-test-module";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    include submodule-test-submodule {
+        revision-date "1999-09-09";		// does not exist
+    }
+
+    revision "2020-06-09" {
+        description "Initial revision";
+    }
+
+    container cont1 {
+        leaf leaf11 {
+            type string;
+        }
+    }
+
+    uses grouping1;
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-not-found/submodule.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-not-found/submodule.yang
new file mode 100644
index 0000000..d501a8f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-not-found/submodule.yang
@@ -0,0 +1,26 @@
+submodule submodule-test-submodule {
+
+    belongs-to submodule-test-module {
+        prefix owner;
+    }
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-06-01" {
+        description "Initial revision";
+    }
+
+    container cont2 {
+        leaf leaf21 {
+            type string;
+        }
+    }
+
+    grouping grouping1 {
+        leaf leaf31 {
+            type string;
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-ok/module.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-ok/module.yang
new file mode 100644
index 0000000..aa9e11e
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-ok/module.yang
@@ -0,0 +1,27 @@
+module submodule-test-module {
+
+    namespace "urn:o-ran:yang:submodule-test-module";
+    prefix this;
+
+    include submodule-test-submodule {
+        revision-date "2020-06-01";
+    }
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-06-09" {
+        description "Initial revision";
+    }
+
+    container cont1 {
+        leaf leaf11 {
+            type string;
+        }
+
+        uses grouping1;		// using the grouping twice to avoid a P133_GROUPING_USED_ONCE_ONLY
+    }
+
+    uses grouping1;
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-ok/submodule.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-ok/submodule.yang
new file mode 100644
index 0000000..d501a8f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/explicit-revision-ok/submodule.yang
@@ -0,0 +1,26 @@
+submodule submodule-test-submodule {
+
+    belongs-to submodule-test-module {
+        prefix owner;
+    }
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-06-01" {
+        description "Initial revision";
+    }
+
+    container cont2 {
+        leaf leaf21 {
+            type string;
+        }
+    }
+
+    grouping grouping1 {
+        leaf leaf31 {
+            type string;
+        }
+    }
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/importing-module.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/importing-module.yang
new file mode 100644
index 0000000..ea2ffb2
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/importing-module.yang
@@ -0,0 +1,28 @@
+module importing-module {
+
+    namespace "test:importing-module";
+    prefix importing;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-10";
+
+	import module {
+		prefix main;
+	}
+
+	augment "/main:cont2" {			// sits in module
+		leaf leaf81 {
+			type string;
+		}
+	}
+
+	augment "/main:cont23" {		// this sits in the submodule2
+		leaf leaf82 {
+			type main:typedef25;	// this sits in the submodule2
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/module.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/module.yang
new file mode 100644
index 0000000..4a72ddd
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/module.yang
@@ -0,0 +1,35 @@
+module module {
+
+    namespace "test:module";
+    prefix module;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-10";
+
+	include submodule1;
+	include submodule2;
+	include submodule3;
+
+	container cont1 {
+
+		container cont51;		// deviated-out
+		container cont52;
+	}
+
+	container cont2 {
+
+		container cont54;
+	}
+
+	leaf leaf1 {
+		type typedef31;		// sits in submodule3
+	}
+
+	leaf leaf2 {
+		type module:typedef31;		// sits in submodule3
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule1.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule1.yang
new file mode 100644
index 0000000..9ed3cd9
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule1.yang
@@ -0,0 +1,36 @@
+submodule submodule1 {
+
+	belongs-to module {
+	    prefix mod;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-10";
+
+	container cont11;
+
+	container cont12 {
+		container cont14;		// will be deviated out
+	}
+
+	augment "/mod:cont1" {		// sits in module
+		leaf leaf11 {
+			type string;
+		}
+	}
+
+	augment "/cont2" {		// sits in module
+		leaf leaf12 {
+			type uint32;
+		}
+	}
+
+	deviation "/mod:cont1/mod:cont51" {		// sits in module
+		deviate not-supported;
+	}
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule2.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule2.yang
new file mode 100644
index 0000000..94799f6
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule2.yang
@@ -0,0 +1,44 @@
+submodule submodule2 {
+
+	belongs-to module {
+	    prefix main-mod;			// using different prefix here to make things interesting
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-10";
+
+	container cont22 {
+		container cont61;
+	}
+
+	container cont23;
+
+	augment "/main-mod:cont11" {		// sits in submodule1
+		leaf leaf24 {
+			type boolean;
+		}
+	}
+
+	augment "/cont12" {		// sits in submodule1
+		leaf leaf25 {
+			type uint32;
+		}
+	}
+
+	deviation "/main-mod:cont12/main-mod:cont14" {		// sits in submodule1
+		deviate not-supported;
+	}
+
+	deviation "/main-mod:cont34/main-mod:cont37" {		// sits in submodule3
+		deviate not-supported;
+	}
+
+	typedef typedef25 {
+		type leafref {
+			path "/main-mod:leaf1";
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule3.yang b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule3.yang
new file mode 100644
index 0000000..1129de4
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/submodule-test/multiple-submodules/submodule3.yang
@@ -0,0 +1,30 @@
+submodule submodule3 {
+
+	belongs-to module {
+	    prefix main;			// using different prefix here to make things interesting
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-12-10";
+
+	container cont33;
+
+	container cont34 {
+		container cont37;
+	}
+
+	augment "/main:cont23" {	// sits in submodule2
+		leaf leaf31 {
+			type string;
+		}
+	}
+
+	typedef typedef31 {
+		type boolean;
+	}
+
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-importing-module.yang b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-importing-module.yang
new file mode 100644
index 0000000..d4f1a47
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-importing-module.yang
@@ -0,0 +1,47 @@
+module typedef-test-importing-module {
+
+	namespace "test:typedef-test-importing-module";
+	prefix "this";
+
+	import typedef-test-module {
+		prefix module;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-11-11" {
+		description "initial revision";
+	}
+
+	leaf leaf1 {
+		type module:typedef13;
+	}
+
+	leaf leaf2 {
+		type module:typedef92;
+	}
+
+	leaf leaf3 {
+		type module:typedef93;
+	}
+
+	leaf leaf4 {
+		type this:typedef51;
+	}
+
+	typedef typedef51 {
+		type module:typedef93;
+	}
+
+	grouping grouping52 {
+		leaf leaf5 {
+			type module:typedef93;
+		}
+	}
+
+	container cont6 {
+		uses this:grouping52;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-module.yang b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-module.yang
new file mode 100644
index 0000000..ac94804
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-module.yang
@@ -0,0 +1,134 @@
+module typedef-test-module {
+
+	namespace "test:typedef-test-module";
+	prefix "this";
+
+	include typedef-test-submodule;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-11-11" {
+		description "initial revision";
+	}
+
+	// - - - - lots of nesting - - - - - - -
+
+	typedef typedef5 {
+		type this:typedef4;
+	}
+
+	typedef typedef4 {
+		type this:typedef3;
+	}
+
+	typedef typedef3 {
+		type this:typedef2;
+	}
+
+	typedef typedef2 {
+		type this:typedef1;
+	}
+
+	typedef typedef1 {
+		type int32;
+	}
+
+	container cont1 {
+
+		leaf leaf01 { type typedef1; }
+		leaf leaf02 { type typedef2; }
+		leaf leaf05 { type typedef5; }
+	}
+
+	// - - - - circular - - - - - - -
+
+	typedef typedef7 {
+		type this:typedef7;
+	}
+
+	typedef typedef8 {
+		type this:typedef9;
+	}
+
+	typedef typedef9 {
+		type this:typedef8;
+	}
+
+	// - - - - bad typedef name - - - - - - -
+
+	typedef uint32 {
+		type string;
+	}
+
+	typedef {
+		type string;
+	}
+
+	typedef "" {
+		type string;
+	}
+
+	typedef "my custom type" {
+		type string;
+	}
+
+	// - - - - not resolvable - - - - - - -
+
+	typedef typedef11 {
+		type this:not-resolvable-type;
+	}
+
+	typedef typedef12 {
+		type this:typedef11;
+	}
+
+	// - - - - - resolvable - - - - -
+
+	typedef typedef13 {
+		type uint32;
+	}
+
+	typedef typedef14 {
+		type typedef13;
+	}
+
+	typedef typedef15 {
+		type this:typedef13;
+	}
+
+	// - - - - - from submodule - - - - -
+
+	typedef typedef16 {
+		type this:typedef91;
+	}
+
+	typedef typedef17 {
+		type this:typedef93;
+	}
+
+	container cont2 {
+
+		leaf leaf21 { type typedef16; }
+		leaf leaf22 { type typedef17; }
+	}
+
+	// - - - - - bad types - - - - -
+
+	typedef typedef18 {
+		type;
+	}
+
+	typedef typedef19 {
+		type "";
+	}
+
+	typedef typedef20 {
+		type "  ";
+	}
+
+	typedef typedef21 {
+		type ":typedef93";
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-nested-union.yang b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-nested-union.yang
new file mode 100644
index 0000000..9359fed
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-nested-union.yang
@@ -0,0 +1,144 @@
+module typedef-test-nested-union-module {
+
+	namespace "test:typedef-test-nested-union-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2022-06-08" {
+		description "initial revision";
+	}
+
+	container cont1 {
+
+		leaf leaf11 {
+			type union {
+				type int16;
+				type string;
+			}
+		}
+
+		leaf leaf12 {
+			type union {
+				type int16;
+				type string;
+				type union {
+					type empty;
+					type binary;
+				}
+			}
+		}
+
+		leaf leaf13 {
+			type union {
+				type union {
+					type empty;
+					type binary;
+				}
+				type int16;
+				type string;
+			}
+		}
+
+		leaf leaf14 {
+			type union {
+				type int16;
+				type union {
+					type empty;
+					type binary;
+				}
+				type string;
+			}
+		}
+
+		leaf leaf15 {
+			type union {
+				type int16;
+				type union {
+					type empty;
+					type union {
+						type int32;
+						type boolean;
+					}
+					type binary;
+				}
+				type string;
+			}
+		}
+	}
+
+	typedef typedef1 {
+		type union {
+			type binary;
+			type empty;
+		}
+	}
+
+	typedef typedef2 {
+		type union {
+			type int32;
+		}
+	}
+
+	typedef typedef3 {
+		type union {
+			type boolean;
+			type this:typedef1;
+		}
+	}
+
+	container cont2 {
+
+		leaf leaf21 {
+			type this:typedef1;
+		}
+
+		leaf leaf22 {
+			type union {
+				type uint64;
+				type this:typedef1;
+			}
+		}
+
+		leaf leaf23 {
+			type union {
+				type this:typedef1;
+				type uint64;
+			}
+		}
+
+		leaf leaf24 {
+			type this:typedef2;
+		}
+
+		leaf leaf25 {
+			type union {
+				type uint64;
+				type this:typedef2;
+			}
+		}
+
+		leaf leaf26 {
+			type this:typedef3;
+		}
+
+		leaf leaf27 {
+			type union {
+				type this:typedef3;
+				type uint64;
+			}
+		}
+
+		leaf leaf28 {
+			type union {
+				type uint64;
+				type this:typedef3;
+				type this:typedef2;
+				type string;
+			}
+		}
+
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-not-used-once-used.yang b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-not-used-once-used.yang
new file mode 100644
index 0000000..6aa6088
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-not-used-once-used.yang
@@ -0,0 +1,38 @@
+module typedef-test-not-used-once-used {
+
+	namespace "test:typedef-test-not-used-once-used";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2023-02-28";
+
+	typedef typedef1 {			// not used
+		type int32;
+	}
+
+	typedef typedef2 {			// used once only
+		type int32;
+	}
+
+	typedef typedef3 {			// used multiple times
+		type int32;
+	}
+
+	container cont1 {
+
+		leaf leaf01 {
+			type typedef2;
+		}
+
+		leaf leaf02 {
+			type typedef3;
+		}
+
+		leaf leaf03 {
+			type typedef3;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-restrictions-module.yang b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-restrictions-module.yang
new file mode 100644
index 0000000..3162a34
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-restrictions-module.yang
@@ -0,0 +1,452 @@
+module typedef-test-restrictions-module {
+
+	namespace "test:typedef-test-restrictions-module";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-11-11" {
+		description "initial revision";
+	}
+
+	typedef typedef1 {
+		type string {
+			length 10..20;
+			pattern "ab*c";
+		}
+		default "Hello";
+	}
+
+	typedef typedef2 {
+		type int32 {
+			range 30..40;
+		}
+		default 35;
+	}
+
+	typedef typedef3 {
+		type enumeration {
+			enum zero {
+				value 10;
+			}
+			enum one {
+				value 11;
+			}
+			enum two {
+				value 12;
+			}
+		}
+		default one;
+	}
+
+	typedef typedef4 {
+		type bits {
+			bit four {
+				position 16;
+			}
+			bit five {
+				position 17;
+			}
+			bit six {
+				position 18;
+			}
+		}
+	}
+
+// - - - - - - no changes - - - - - -
+
+	container cont1 {
+		leaf leaf1 {
+			type this:typedef1;
+		}
+		leaf leaf2 {
+			type this:typedef2;
+		}
+		leaf leaf3 {
+			type this:typedef3;
+		}
+		leaf leaf4 {
+			type this:typedef4;
+		}
+	}
+
+// - - - - - - some overrides - - - - - -
+
+	container cont2 {
+
+		leaf leaf7 {
+			type this:typedef1 {
+				length 12..15;
+				pattern "de*f";
+			}
+			default "World";
+		}
+
+		leaf leaf8 {
+			type this:typedef2 {
+				range 30..35;
+			}
+			default 32;
+		}
+
+		leaf leaf9 {
+			type this:typedef3 {
+				enum zero {
+					value 10;
+				}
+				enum one;
+			}
+			default zero;
+		}
+
+		leaf leaf10 {
+			type this:typedef4 {
+				bit five;
+				bit six {
+					position 18;
+				}
+			}
+			default six;
+		}
+	}
+
+// - - - - - - some multi-level overrides - - - - - -
+
+	typedef typedef13 {
+		type typedef1 {
+			length 5..8;
+			pattern "gh*i";
+			pattern "mn*o";
+		}
+	}
+
+	typedef typedef14 {
+		type typedef2 {
+			range 15..18;
+		}
+		default 20;
+	}
+
+	typedef typedef15 {
+		type this:typedef3 {
+			enum zero;
+			enum one;
+		}
+		default one;
+	}
+
+	container cont3 {
+
+		leaf leaf18 {
+			type this:typedef13 {
+				length 6..7;
+			}
+			default "Moon";
+		}
+
+		leaf leaf19 {
+			type this:typedef14 {
+				range 16..17;
+			}
+			default 13;
+		}
+
+		leaf leaf20 {
+			type this:typedef15 {
+				enum one;
+			}
+		}
+	}
+
+// - - - - - - some illegal statements for restriction - - - - - -
+
+	container cont4 {
+
+		leaf leaf28 {
+			type this:typedef1 {
+				range 12..15;		// Wrong, it's a string
+				enum one;			// Wrong, it's a string
+			}
+		}
+
+		leaf leaf29 {
+			type this:typedef2 {
+				length 12..15;		// Wrong, it's a numeric type
+				pattern "ab*c";		// Wrong, it's a numeric type
+				enum one;			// Wrong, it's a numeric type
+				bit two;			// Wrong, it's a numeric type
+			}
+		}
+
+		leaf leaf30 {
+			type this:typedef3 {
+				enum three {		// Wrong, does not exit in original
+					value 13;
+				}
+				enum two {
+					value 99;		// Wrong, assigning different value
+				}
+			}
+		}
+
+		leaf leaf31 {
+			type this:typedef4 {
+				bit seven {			// Wrong, does not exit in original
+					position 19;
+				}
+				bit six {
+					position 99;	// Wrong, assigning different position
+				}
+			}
+		}
+
+	}
+
+// - - - - - - some legal and illegal length restrictions - - - - - -
+
+	typedef typedef51 {
+		type string {
+			length 10..20;
+		}
+	}
+
+	typedef typedef52 {
+		type string {
+			length "10..20 | 50..60";
+		}
+	}
+
+	container cont5 {
+
+		leaf leaf51 {
+			type this:typedef51 {
+				length 0..15;		// Illegal, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf52 {
+			type this:typedef51 {
+				length 9..20;		// Illegal, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf53 {
+			type this:typedef51 {
+				length 0..6;		// Illegal, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf54 {
+			type this:typedef51 {
+				length 10..100;		// Illegal, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf55 {
+			type this:typedef51 {
+				length "10..12 | 18..30";		// Illegal, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf56 {
+			type this:typedef52 {
+				length 0..15;		// Illegal, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf57 {
+			type this:typedef52 {
+				length 55..65;		// Illegal, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf58 {
+			type this:typedef52 {
+				length 15..55;		// Illegal, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf59 {
+			type this:typedef52 {
+				length 5..55;		// Illegal, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf61 {
+			type this:typedef51 {
+				length 10..20;		// OK, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf62 {
+			type this:typedef51 {
+				length "10..10 | 20..20";		// OK, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf63 {
+			type this:typedef51 {
+				length 10..15;		// OK, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf64 {
+			type this:typedef51 {
+				length 15..20;		// OK, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf65 {
+			type this:typedef51 {
+				length "10..12 | 13..20";		// OK, Original restriction is [10-20]
+			}
+		}
+
+		leaf leaf66 {
+			type this:typedef52 {
+				length 10..20;		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf67 {
+			type this:typedef52 {
+				length 50..60;		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf68 {
+			type this:typedef52 {
+				length 10..15;		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf69 {
+			type this:typedef52 {
+				length 55..60;		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf70 {
+			type this:typedef52 {
+				length "10..20 | 50..50";		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf71 {
+			type this:typedef52 {
+				length "10..10";		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf72 {
+			type this:typedef52 {
+				length "11..13 | 15..20";		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+
+		leaf leaf73 {
+			type this:typedef52 {
+				length "11..13 | 15..17 | 50..52";		// OK, Original restriction is [10-20],[50-60]
+			}
+		}
+	}
+
+
+// - - - - - - some legal and illegal range restrictions - - - - - -
+
+	typedef typedef81 {
+		type int32 {
+			range -40..80;
+		}
+	}
+
+	typedef typedef82 {
+		type int32 {
+			range "-90..-40 | -10..20 | 40..70";
+		}
+	}
+
+	container cont8 {
+
+		leaf leaf81 {
+			type typedef81 {
+				range -50..-30;		// Illegal, original restriction is [-40..80]
+			}
+		}
+
+		leaf leaf82 {
+			type typedef81 {
+				range -40..90;		// Illegal, original restriction is [-40..80]
+			}
+		}
+
+		leaf leaf83 {
+			type typedef81 {
+				range -50..-45;		// Illegal, original restriction is [-40..80]
+			}
+		}
+
+		leaf leaf84 {
+			type typedef81 {
+				range 10..90;		// Illegal, original restriction is [-40..80]
+			}
+		}
+
+		leaf leaf85 {
+			type typedef81 {
+				range 80..90;		// Illegal, original restriction is [-40..80]
+			}
+		}
+
+		leaf leaf86 {
+			type typedef82 {
+				range -100..-80;		// Illegal, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+
+		leaf leaf87 {
+			type typedef82 {
+				range -30..-20;		// Illegal, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+
+		leaf leaf88 {
+			type typedef82 {
+				range 15..25;		// Illegal, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+
+		leaf leaf89 {
+			type typedef82 {
+				range 30..40;		// Illegal, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+
+		leaf leaf91 {
+			type typedef82 {
+				range -90..-40;		// OK, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+
+		leaf leaf92 {
+			type typedef82 {
+				range "-90..-40 | -10..20";		// OK, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+
+		leaf leaf93 {
+			type typedef82 {
+				range "0..10";		// OK, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+
+		leaf leaf94 {
+			type typedef82 {
+				range "3..4 | 50..60";		// OK, original restriction is [-90..-40] [-10..20] [40..70]
+			}
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-submodule.yang b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-submodule.yang
new file mode 100644
index 0000000..c2e474e
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-submodule.yang
@@ -0,0 +1,26 @@
+submodule typedef-test-submodule {
+
+	belongs-to typedef-test-module {
+		prefix module;
+	}
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2020-11-11" {
+		description "initial revision";
+	}
+
+	typedef typedef91 {
+		type typedef92;
+	}
+
+	typedef typedef92 {
+		type boolean;
+	}
+
+	typedef typedef93 {
+		type module:typedef13;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-used-twice.yang b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-used-twice.yang
new file mode 100644
index 0000000..41a47a8
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/typedef-test/typedef-test-used-twice.yang
@@ -0,0 +1,57 @@
+module typedef-test-used-twice {
+
+	namespace "test:typedef-test-used-twice";
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2021-08-11";
+
+	typedef typedef1 {
+		type int32;
+		default "5";
+	}
+
+	typedef typedef2 {
+		type this:typedef1;
+		default "20";
+	}
+
+	typedef typedef3 {
+		type this:typedef1;
+	}
+
+	container cont1 {
+
+		leaf leaf2 {
+			type this:typedef1;
+			default 10;
+		}
+
+		leaf leaf3 {				// default = 5
+			type this:typedef1;
+		}
+
+		leaf leaf4 {				// default = 5
+			type this:typedef1;
+		}
+
+		leaf leaf5 {				// default = 20
+			type this:typedef2;
+		}
+
+		leaf leaf6 {				// default = 20
+			type this:typedef2;
+		}
+
+		leaf leaf7 {				// default = 5
+			type this:typedef3;
+		}
+
+		leaf leaf8 {				// default = 5
+			type this:typedef3;
+		}
+	}
+}
diff --git a/yang-parser/src/test/resources/model-statements-yang/when-test/when-test.yang b/yang-parser/src/test/resources/model-statements-yang/when-test/when-test.yang
new file mode 100644
index 0000000..59c3eec
--- /dev/null
+++ b/yang-parser/src/test/resources/model-statements-yang/when-test/when-test.yang
@@ -0,0 +1,45 @@
+module when-test {
+
+    namespace "urn:o-ran:yang:when-test";
+    prefix this;
+
+    organization "ORAN";
+    contact "o-ran-sc.org";
+
+    description "yang test module for when
+    Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+
+    revision "2015-10-20" {
+        description "Initial revision";
+    }
+
+    container cont1 {
+        leaf leaf11 {
+            type string;
+        }
+        leaf leaf12 {
+            when "../leaf11 = 'Hello'";
+            type string;
+        }
+    }
+
+    container cont2 {
+
+    }
+
+    augment "/this:cont2" {
+        when "/this:cont1/this:leaf11 = 'World'";
+        leaf leaf22 {
+            type string;
+        }
+    }
+
+    augment "/this:cont2" {
+        leaf leaf23 {
+            type string;
+        }
+    }
+
+}
diff --git a/yang-parser/src/test/resources/model-util/module1.yang b/yang-parser/src/test/resources/model-util/module1.yang
new file mode 100644
index 0000000..eed263d
--- /dev/null
+++ b/yang-parser/src/test/resources/model-util/module1.yang
@@ -0,0 +1,56 @@
+module module1 {
+
+	yang-version "1.1";
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-09-30" {
+        description "initial revision";
+    }
+
+    leaf leaf1 {
+    	type bits {
+    		bit one;
+    		bit two;
+    		bit three;
+    	}
+    }
+
+    leaf leaf2 {
+    	type bits {
+    		bit one {
+    			position 71;
+    		}
+    		bit two;
+    		bit three {
+    			position 402;
+    		}
+    	}
+    }
+
+	leaf leaf3 {
+		type enumeration {
+			enum one;
+			enum two;
+			enum three;
+		}
+	}
+
+	leaf leaf4 {
+		type enumeration {
+			enum one {
+				value 71;
+			}
+			enum two;
+			enum three {
+				value 402;
+			}
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-util/stringefied-values-test.yang b/yang-parser/src/test/resources/model-util/stringefied-values-test.yang
new file mode 100644
index 0000000..4552880
--- /dev/null
+++ b/yang-parser/src/test/resources/model-util/stringefied-values-test.yang
@@ -0,0 +1,119 @@
+module stringefied-values-test {
+
+    namespace "test:stringefied-values-test";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2021-04-06" {
+        description "initial revision";
+    }
+
+	// ------------------------- integers ------------------------------
+
+	leaf leaf11 {
+		type int8;
+	}
+
+	leaf leaf12 {
+		type int16 {
+			range 10..20;
+		}
+	}
+
+	leaf leaf13 {
+		type int16 {
+			range "0..20 | 40..60";
+		}
+	}
+
+	// ------------------------- decimal64 ------------------------------
+
+	leaf leaf21 {
+		type decimal64 {
+			fraction-digits 1;
+		}
+	}
+
+	leaf leaf22 {
+		type decimal64 {
+			fraction-digits 3;
+			range "0.0 .. 10.0 | 20.2 .. max";
+		}
+	}
+
+	leaf leaf23 {
+		type decimal64 {
+			fraction-digits 17;
+		}
+	}
+
+	// ------------------------- boolean ------------------------------
+
+	leaf leaf31 {
+		type boolean;
+	}
+
+	// ------------------------- enumeration ------------------------------
+
+	leaf leaf41 {
+		type enumeration {
+			enum RED;
+			enum YELLOW;
+			enum GREEN;
+		}
+	}
+
+	// ------------------------- bits ------------------------------
+
+	leaf leaf51 {
+		type bits {
+			bit ONE;
+			bit TWO;
+			bit THREE;
+		}
+	}
+
+	// ------------------------- string ------------------------------
+
+	leaf leaf61 {
+		type string;
+	}
+
+	leaf leaf62 {
+		type string {
+			length 5..10;
+		}
+	}
+
+	leaf leaf63 {
+		type string {
+			length "2..4 | 8..10";
+		}
+	}
+
+	leaf leaf64 {
+		type string {
+			pattern "ab*c";
+		}
+	}
+
+	// ------------------------- empty ------------------------------
+
+	leaf leaf71 {
+		type empty;
+	}
+
+
+	// ------------------------- union ------------------------------
+
+	leaf leaf81 {
+		type union {
+			type uint8;
+			type string;
+		}
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/basic-empty-module.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/basic-empty-module.yang
new file mode 100644
index 0000000..6403c51
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/basic-empty-module.yang
@@ -0,0 +1,13 @@
+module basic-empty-module {
+	yang-version 1.0;
+
+    namespace "test:basic-empty-module";
+
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/basic-module-including.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/basic-module-including.yang
new file mode 100644
index 0000000..fa5ea5a
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/basic-module-including.yang
@@ -0,0 +1,15 @@
+module basic-module-including {
+	yang-version 1.0;
+
+    namespace "test:basic-module-including";
+
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    include basic-submodule;
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/block-comments.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/block-comments.yang
new file mode 100644
index 0000000..f4040a3
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/block-comments.yang
@@ -0,0 +1,17 @@
+/*
+
+This is a long block comment
+
+*/module block-comments-module {
+	yang-version 1.0;	/* note that 1.0 is wrong, but some designer will use it at some stage... */
+    namespace "test-module";
+    prefix "this";
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+    revision "2019-09-27";
+}/*
+
+This is a long block comment
+
+*/
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-block-comment.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-block-comment.yang
new file mode 100644
index 0000000..fe98d42
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-block-comment.yang
@@ -0,0 +1,10 @@
+module dangling-block-comment {
+    namespace "test-module";
+    prefix "this";
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+    revision "2019-09-27";
+}/*
+
+This block comment is not closed
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-double-quote.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-double-quote.yang
new file mode 100644
index 0000000..5fdac9f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-double-quote.yang
@@ -0,0 +1,10 @@
+module dangling-double-quote {
+    namespace "test-module";
+    prefix "this";
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+    revision "2019-09-27";
+}
+
+"unclosed double-quoted string
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-plus-token.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-plus-token.yang
new file mode 100644
index 0000000..8fa5955
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-plus-token.yang
@@ -0,0 +1,10 @@
+module dangling-plus-token {
+    namespace "test-module";
+    prefix "this";
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+    revision "2019-09-27";
+}
+
++
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-single-quote.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-single-quote.yang
new file mode 100644
index 0000000..b265ab1
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/dangling-single-quote.yang
@@ -0,0 +1,10 @@
+module dangling-single-quote {
+    namespace "test-module";
+    prefix "this";
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+    revision "2019-09-27";
+}
+
+'unclosed double-quoted string
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/document-end-missing.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/document-end-missing.yang
new file mode 100644
index 0000000..acd3b0b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/document-end-missing.yang
@@ -0,0 +1,13 @@
+module document-end-missing {
+
+    namespace "document-end-missing-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf1 {
+		type string;
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/double-left-brace.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/double-left-brace.yang
new file mode 100644
index 0000000..5485e28
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/double-left-brace.yang
@@ -0,0 +1,16 @@
+module double-left-brace {
+
+    namespace "double-left-brace-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf1 {{
+		type string;
+	}}
+
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/empty-file.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/empty-file.yang
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/empty-file.yang
@@ -0,0 +1 @@
+
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/hello-world.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/hello-world.yang
new file mode 100644
index 0000000..980a0d5
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/hello-world.yang
@@ -0,0 +1 @@
+Hello World!
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/incorrect-string-concatenation.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/incorrect-string-concatenation.yang
new file mode 100644
index 0000000..ce3ec41
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/incorrect-string-concatenation.yang
@@ -0,0 +1,14 @@
+module incorrect-string-concatenation {
+    namespace "test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	description "Quoted String" + {}
+}
+
+
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/junk-at-end.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/junk-at-end.yang
new file mode 100644
index 0000000..d606532
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/junk-at-end.yang
@@ -0,0 +1,12 @@
+module junk-at-end-module {
+    namespace "test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+}
+
+junk
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/line-comments.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/line-comments.yang
new file mode 100644
index 0000000..c736145
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/line-comments.yang
@@ -0,0 +1,14 @@
+// line comment
+// line comment
+module line-comment-module {
+    namespace "test-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+} // line comment
+// line comment
+// line comment
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-and-duplicate-statements.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-and-duplicate-statements.yang
new file mode 100644
index 0000000..2c30d4a
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-and-duplicate-statements.yang
@@ -0,0 +1,44 @@
+module missing-and-duplicate-statements {
+	yang-version 1.0;
+
+	namespace "test:missing-and-duplicate-statements";
+
+	prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+	revision "2019-09-27";
+
+	container cont1 {
+		presence "first presence";
+		presence "second presence";		// Wrong
+
+		leaf leaf1 {
+			type string;
+			type uint16;			// Wrong
+			mandatory yes;			// Wrong (doh!)
+		}
+
+		leaf leaf2 {
+			type identityref {
+				base this:weird_%%_characters;
+			}
+		}
+
+		leaf leaf3 {
+			type string;
+			mandatory;
+		}
+	}
+
+	container cont2_with_weird_%%_characters;
+
+	container cont3 {
+		container;			// Wrong
+		container "";		// Wrong
+	}
+
+	deviation /this:cont1;			// Wrong, missing 'deviate'
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto-name.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto-name.yang
new file mode 100644
index 0000000..903ef8f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto-name.yang
@@ -0,0 +1,13 @@
+submodule basic-submodule {
+	yang-version 1.0;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    belongs-to;
+
+    container cont2;
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto.yang
new file mode 100644
index 0000000..4d8408f
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-belongsto.yang
@@ -0,0 +1,11 @@
+submodule basic-submodule {
+	yang-version 1.0;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    container cont2;
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-import-name.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-import-name.yang
new file mode 100644
index 0000000..d5acb21
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-import-name.yang
@@ -0,0 +1,18 @@
+module missing-import-name {
+	yang-version 1.0;
+
+    namespace "test:missing-import-name";
+
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    import;		// name missing
+
+    container cont1;
+
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-include-name.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-include-name.yang
new file mode 100644
index 0000000..1e8c50e
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-include-name.yang
@@ -0,0 +1,18 @@
+module missing-include-name {
+	yang-version 1.0;
+
+    namespace "test:missing-include-name";
+
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    include;		// name missing
+
+    container cont1;
+
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-namespace-name.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-namespace-name.yang
new file mode 100644
index 0000000..c6a2b53
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-namespace-name.yang
@@ -0,0 +1,13 @@
+module missing-namespace-name {
+	yang-version 1.0;
+
+	namespace;
+
+	prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-namespace.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-namespace.yang
new file mode 100644
index 0000000..da11f2a
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-namespace.yang
@@ -0,0 +1,11 @@
+module missing-namespace {
+	yang-version 1.0;
+
+	prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-belongsto.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-belongsto.yang
new file mode 100644
index 0000000..2212aff
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-belongsto.yang
@@ -0,0 +1,15 @@
+submodule basic-submodule {
+	yang-version 1.0;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    belongs-to basic-module-including {
+    	prefix;
+    }
+
+    container cont2;
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-import.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-import.yang
new file mode 100644
index 0000000..30a842e
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name-under-import.yang
@@ -0,0 +1,20 @@
+module missing-prefix-name-under-import {
+	yang-version 1.0;
+
+    namespace "test:missing-prefix-name-under-import";
+
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    import basic-empty-module {
+    	prefix;
+    }
+
+    container cont1;
+
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name.yang
new file mode 100644
index 0000000..f8cf3e2
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-name.yang
@@ -0,0 +1,13 @@
+module missing-prefix-name {
+	yang-version 1.0;
+
+    namespace "test:missing-prefix";
+
+	prefix;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-belongsto.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-belongsto.yang
new file mode 100644
index 0000000..bf529e4
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-belongsto.yang
@@ -0,0 +1,13 @@
+submodule basic-submodule {
+	yang-version 1.0;
+
+    revision "2019-09-27";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    belongs-to basic-module-including;
+
+    container cont2;
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-import.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-import.yang
new file mode 100644
index 0000000..394c05d
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix-under-import.yang
@@ -0,0 +1,18 @@
+module missing-prefix-under-import {
+	yang-version 1.0;
+
+    namespace "test:missing-prefix-under-import";
+
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+    import basic-empty-module;
+
+    container cont1;
+
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix.yang
new file mode 100644
index 0000000..4425076
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-prefix.yang
@@ -0,0 +1,11 @@
+module missing-prefix {
+	yang-version 1.0;
+
+    namespace "test:missing-prefix";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-yangversion-version.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-yangversion-version.yang
new file mode 100644
index 0000000..d75d656
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/missing-yangversion-version.yang
@@ -0,0 +1,13 @@
+module missing-yangversion-version {
+	yang-version;
+
+	namespace "test:missing-yangversion-version";
+
+	prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+}
\ No newline at end of file
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-plus.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-plus.yang
new file mode 100644
index 0000000..71f2416
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-plus.yang
@@ -0,0 +1,17 @@
+module multiple-plus {
+
+    namespace "multiple-plus";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf2 {
+		type string;
+		description "Hello" + + "World!";
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-semicolons.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-semicolons.yang
new file mode 100644
index 0000000..a55f316
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-semicolons.yang
@@ -0,0 +1,16 @@
+module multiple-semicolons {
+
+    namespace "multiple-semicolons";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf2 {
+		type string;;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-statements-at-root.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-statements-at-root.yang
new file mode 100644
index 0000000..0d0d5df
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/multiple-statements-at-root.yang
@@ -0,0 +1,16 @@
+module multiple-statements-at-root;
+module multiple-statements-at-root {
+
+    namespace "document-end-missing-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf1 {
+		type string;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/no-left-brace.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/no-left-brace.yang
new file mode 100644
index 0000000..84c78bb
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/no-left-brace.yang
@@ -0,0 +1,2 @@
+module test-module }
+{
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/quoted-plus-unquoted.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/quoted-plus-unquoted.yang
new file mode 100644
index 0000000..ac5932b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/quoted-plus-unquoted.yang
@@ -0,0 +1,17 @@
+module quoted-plus-unquoted {
+
+    namespace "quoted-plus-unquoted";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf2 {
+		type string;
+		description "Hello" + World;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/semicolon-only.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/semicolon-only.yang
new file mode 100644
index 0000000..092bc2b
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/semicolon-only.yang
@@ -0,0 +1 @@
+;
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/simple-module.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/simple-module.yang
new file mode 100644
index 0000000..494492c
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/simple-module.yang
@@ -0,0 +1,53 @@
+module simple-module {
+
+	yang-version 1;
+
+    namespace "simple-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	rpc rpc1 {
+		input {
+			leaf leaf1 {
+				type string;
+			}
+			leaf leaf2 {
+				type string;
+			}
+		}
+	}
+
+	leaf leaf3 {
+		type string;
+	} ; ;				// semicolon after end of statement, pointless but we handle them.
+
+	leaf leaf4 {
+		when "../leaf3";
+		type string;
+	}
+
+	leaf leaf5 {
+		description "Hello " + "World";
+		type string;
+	}
+
+	leaf leaf6 {
+		description "Hello " +
+		"World";
+		type string;
+	}
+
+	leaf leaf7 {
+		description "Hello " + "World" + '!';
+		type string;
+	}
+
+	container cont9 {}		// A bit pointless, but we will allow it.
+
+	container cont10 {;}		// Same.
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/three-statements.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/three-statements.yang
new file mode 100644
index 0000000..00d92d8
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/three-statements.yang
@@ -0,0 +1,15 @@
+module three-statements {
+
+    namespace "three-statements-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf7 leaf7 {
+		type string;
+	}
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/unquoted-plus-unquoted.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/unquoted-plus-unquoted.yang
new file mode 100644
index 0000000..18b0e0c
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/unquoted-plus-unquoted.yang
@@ -0,0 +1,17 @@
+module quoted-plus-unquoted {
+
+    namespace "quoted-plus-unquoted";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf2 {
+		type string;
+		description Hello + World;
+	}
+
+}
diff --git a/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/weird-root.yang b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/weird-root.yang
new file mode 100644
index 0000000..01927f6
--- /dev/null
+++ b/yang-parser/src/test/resources/model-yangdom/basic-parsing-test/weird-root.yang
@@ -0,0 +1,15 @@
+container weird-root {
+
+    namespace "document-end-missing-module";
+    prefix "this";
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2019-09-27";
+
+	leaf leaf1 {
+		type string;
+	}
+}
diff --git a/yang-parser/src/test/resources/yanglibrary/modules/module1.yang b/yang-parser/src/test/resources/yanglibrary/modules/module1.yang
new file mode 100644
index 0000000..250ce8f
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/modules/module1.yang
@@ -0,0 +1,26 @@
+module module1 {
+
+    namespace "test:module1";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-01-01" {
+        description "initial revision";
+    }
+
+    include submodule12 {
+    	revision-date "1999-01-01";
+    }
+
+    import module2 {
+	    revision-date "2020-02-02";
+    	prefix mod2;
+    }
+
+	feature feature1;
+
+	feature feature2;
+}
diff --git a/yang-parser/src/test/resources/yanglibrary/modules/module2.yang b/yang-parser/src/test/resources/yanglibrary/modules/module2.yang
new file mode 100644
index 0000000..5441c9d
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/modules/module2.yang
@@ -0,0 +1,17 @@
+module module2 {
+
+    namespace "test:module2";
+    prefix this;
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "2020-02-02" {
+        description "initial revision";
+    }
+
+	feature feature1;
+
+	feature feature2;
+}
diff --git a/yang-parser/src/test/resources/yanglibrary/modules/submodule12.yang b/yang-parser/src/test/resources/yanglibrary/modules/submodule12.yang
new file mode 100644
index 0000000..2f27d57
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/modules/submodule12.yang
@@ -0,0 +1,18 @@
+submodule submodule12 {
+
+    belongs-to module1 {
+        prefix mod1;
+    }
+
+	description
+	"Copyright (C) 2024 Ericsson
+	Modifications Copyright (C) 2024 OpenInfra Foundation Europe";
+
+    revision "1999-01-01" {
+        description "initial revision";
+    }
+
+    feature feature3;
+
+    feature feature4;
+}
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-empty-names.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-empty-names.xml
new file mode 100644
index 0000000..38e26c1
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-empty-names.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>10445</module-set-id>
+      <module>
+        <name></name>
+        <revision>2020-01-01</revision>
+        <schema>www.acme.com/test-module1.yang</schema>
+        <namespace></namespace>
+        <feature>feature1</feature>
+        <feature>feature2</feature>
+        <feature>feature3</feature>
+        <conformance-type>implement</conformance-type>
+        <submodule>
+          <name></name>
+          <revision>2020-02-02</revision>
+          <schema>www.acme.com/test-module1-submodule.yang</schema>
+        </submodule>
+        <deviation>
+	        <name>test-module1-ext</name>
+    	    <revision>2020-05-20</revision>
+        </deviation>
+      </module>
+      <module>
+        <name>test-module3</name>
+        <revision>2020-05-20</revision>
+        <namespace>com:foo:test-module1</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>test-module3</name>
+        <revision>2020-05-22</revision>
+        <namespace>com:foo:test-module1</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-modulesetid_is_number.json b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-modulesetid_is_number.json
new file mode 100644
index 0000000..55a932b
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-modulesetid_is_number.json
@@ -0,0 +1,21 @@
+{
+    "ietf-yang-library:modules-state": [
+        {
+            "module-set-id": 1234567,
+            "module": [
+                {
+                    "name": "test-module1",
+                    "revision": "2020-01-01",
+                    "schema": "www.acme.com/test-module1.yang",
+                    "namespace": "com:foo:test-module1",
+                    "feature": [
+                        "feature1",
+                        "feature2",
+                        "feature3"
+                    ],
+                    "conformance-type": "implement"
+                }
+            ]
+        }
+    ]
+}
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-with-issues.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-with-issues.xml
new file mode 100644
index 0000000..7d11807
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895-with-issues.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id></module-set-id>
+      <module>
+        <name>test-module1</name>
+        <revision>2020-01-01</revision>
+        <schema>www.acme.com/test-module1.yang</schema>
+        <namespace>com:foo:test-module1</namespace>
+        <feature>feature1</feature>
+        <feature>feature2</feature>
+        <feature>feature3</feature>
+        <conformance-type>junk</conformance-type>
+        <submodule>
+          <name>test-module1-submodule</name>
+          <revision>2020-02-02</revision>
+          <schema>www.acme.com/test-module1-submodule.yang</schema>
+        </submodule>
+        <deviation>
+        	<name>test-module1</name>
+        	<revision>2020-01-01</revision>
+        </deviation>
+        <deviation>
+        	<name>module-does-not-exist</name>
+        	<revision>2222-01-01</revision>
+        </deviation>
+      </module>
+      <module>
+        <name>test-module2</name>
+        <revision></revision>
+        <namespace>com:foo:test-module2</namespace>
+        <deviation>
+	        <name>test-module2-ext</name>
+    	    <revision>2020-05-20</revision>
+        </deviation>
+        <conformance-type>import</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.json b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.json
new file mode 100644
index 0000000..087eea9
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.json
@@ -0,0 +1,49 @@
+{
+    "ietf-yang-library:modules-state": [
+        {
+            "module-set-id": "10445",
+            "module": [
+                {
+                    "name": "test-module1",
+                    "revision": "2020-01-01",
+                    "schema": "www.acme.com/test-module1.yang",
+                    "namespace": "com:foo:test-module1",
+                    "feature": [
+                        "feature1",
+                        "feature2",
+                        "feature3"
+                    ],
+                    "conformance-type": "implement",
+                    "submodule": [
+                        {
+                            "name": "test-module1-submodule",
+                            "revision": "2020-02-02",
+                            "schema": "www.acme.com/test-module1-submodule.yang"
+                        }
+                    ],
+                    "deviation": [
+                        {
+                            "name": "test-module1-ext",
+                            "revision": "2020-05-20"
+                        }
+                    ]
+                },
+                {
+                    "name": "test-module1-ext",
+                    "revision": "2020-05-20",
+                    "namespace": "com:foo:test-module1",
+                    "conformance-type": "implement"
+                },
+                {
+                    "name": "test-module2",
+                    "revision": "",
+                    "namespace": "com:foo:test-module2",
+                    "conformance-type": "import",
+                    "feature": [
+                        "feature6"
+                    ]
+                }
+            ]
+        }
+    ]
+}
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.xml
new file mode 100644
index 0000000..d0f1c8d
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>10445</module-set-id>
+      <module>
+        <name>test-module1</name>
+        <revision>2020-01-01</revision>
+        <schema>www.acme.com/test-module1.yang</schema>
+        <namespace>com:foo:test-module1</namespace>
+        <feature>feature1</feature>
+        <feature>feature2</feature>
+        <feature>feature3</feature>
+        <conformance-type>implement</conformance-type>
+        <submodule>
+          <name>test-module1-submodule</name>
+          <revision>2020-02-02</revision>
+          <schema>www.acme.com/test-module1-submodule.yang</schema>
+        </submodule>
+        <deviation>
+	        <name>test-module1-ext</name>
+    	    <revision>2020-05-20</revision>
+        </deviation>
+      </module>
+      <module>
+        <name>test-module1-ext</name>
+        <revision>2020-05-20</revision>
+        <namespace>com:foo:test-module1</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+      <module>
+        <name>test-module2</name>
+        <revision></revision>
+        <namespace>com:foo:test-module2</namespace>
+        <conformance-type>import</conformance-type>
+        <feature>feature6</feature>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895_and_other_data.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895_and_other_data.xml
new file mode 100644
index 0000000..be1ca99
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-7895_and_other_data.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <pm xmlns="o-ran.pm">
+      <pmGroup>
+        <name>pmGroup1</name>
+      </pmGroup>
+    </pm>
+    <modules-state xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <module-set-id>10445</module-set-id>
+      <module>
+        <name>test-module1</name>
+        <revision>2020-01-01</revision>
+        <namespace>com:foo:test-module1</namespace>
+        <conformance-type>implement</conformance-type>
+      </module>
+    </modules-state>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-empty-names.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-empty-names.xml
new file mode 100644
index 0000000..6219b0b
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-empty-names.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <content-id>9876</content-id>
+      <module-set>
+        <name>set1</name>
+        <module>
+          <name></name>
+          <revision>2020-01-01</revision>
+          <namespace></namespace>
+          <location>www.acme.com/test-module1.yang</location>
+          <location>www.modules.acme.com/test-module1.yang</location>
+          <submodule>
+            <name></name>
+            <revision></revision>
+          </submodule>
+          <feature>feature1</feature>
+          <feature>feature2</feature>
+          <feature>feature3</feature>
+          <deviation>test-module1-ext</deviation>
+        </module>
+        <module>
+          <name>test-module1-ext</name>
+          <revision>2020-03-03</revision>
+          <namespace>com:foo:test-module1</namespace>
+        </module>
+        <import-only-module>
+          <name>test-module2</name>
+          <revision></revision>
+          <namespace>com:foo:test-module2</namespace>
+        </import-only-module>
+      </module-set>
+      <module-set>
+        <name>set2</name>
+        <import-only-module>
+          <name>test-module6</name>
+          <revision>2019-06-06</revision>
+          <namespace>com:foo:test-module6</namespace>
+        </import-only-module>
+      </module-set>
+      <module-set>
+        <name>set3</name>
+        <import-only-module>
+          <name>test-module7</name>
+          <revision>2019-07-07</revision>
+          <namespace>com:foo:test-module7</namespace>
+        </import-only-module>
+      </module-set>
+      <schema>
+        <name></name>
+        <module-set>set1</module-set>
+        <module-set>set2</module-set>
+      </schema>
+      <schema>
+        <name>schema2</name>
+        <module-set>set2</module-set>
+        <module-set>set3</module-set>
+      </schema>
+      <datastore xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
+        <name>ds:running</name>
+        <schema>schema1</schema>
+      </datastore>
+      <datastore xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
+        <name></name>
+        <schema>schema2</schema>
+      </datastore>
+    </yang-library>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-no-schema-no-datastore.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-no-schema-no-datastore.xml
new file mode 100644
index 0000000..a5f8961
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-no-schema-no-datastore.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <content-id>9876</content-id>
+      <module-set>
+        <name>set1</name>
+        <module>
+          <name>test-module1</name>
+          <revision>2020-01-01</revision>
+          <namespace>com:foo:test-module1</namespace>
+          <location>www.acme.com/test-module1.yang</location>
+          <location>www.modules.acme.com/test-module1.yang</location>
+          <submodule>
+            <name>test-module1-submodule</name>
+            <revision></revision>
+          </submodule>
+          <feature>feature1</feature>
+          <feature>feature2</feature>
+          <feature>feature3</feature>
+          <deviation>test-module1-ext</deviation>
+        </module>
+        <module>
+          <name>test-module1-ext</name>
+          <revision>2020-03-03</revision>
+          <namespace>com:foo:test-module1</namespace>
+        </module>
+        <import-only-module>
+          <name>test-module2</name>
+          <revision></revision>
+          <namespace>com:foo:test-module2</namespace>
+        </import-only-module>
+      </module-set>
+      <module-set>
+        <name>set2</name>
+        <import-only-module>
+          <name>test-module6</name>
+          <revision>2019-06-06</revision>
+          <namespace>com:foo:test-module6</namespace>
+        </import-only-module>
+      </module-set>
+      <module-set>
+        <name>set3</name>
+        <import-only-module>
+          <name>test-module7</name>
+          <revision>2019-07-07</revision>
+          <namespace>com:foo:test-module7</namespace>
+        </import-only-module>
+      </module-set>
+    </yang-library>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-with-issues.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-with-issues.xml
new file mode 100644
index 0000000..df75590
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525-with-issues.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <content-id></content-id>
+      <module-set>
+        <name>set1</name>
+        <module>
+          <name>test-module1</name>
+          <revision>2020-01-01</revision>
+          <namespace>com:foo:test-module1</namespace>
+          <location>www.acme.com/test-module1.yang</location>
+          <location>www.modules.acme.com/test-module1.yang</location>
+          <submodule>
+            <name>test-module1-submodule</name>
+            <revision></revision>
+          </submodule>
+          <feature>feature1</feature>
+          <feature>feature2</feature>
+          <feature>feature3</feature>
+        </module>
+        <import-only-module>
+          <name>test-module2</name>
+          <revision></revision>
+          <namespace>com:foo:test-module2</namespace>
+        </import-only-module>
+      </module-set>
+      <module-set>
+        <name></name>
+        <import-only-module>
+          <name>test-module6</name>
+          <revision>2019-06-06</revision>
+          <namespace>com:foo:test-module6</namespace>
+        </import-only-module>
+      </module-set>
+      <schema>
+        <name></name>
+        <module-set>set1</module-set>
+        <module-set>set3</module-set>
+      </schema>
+      <datastore xmlns:dsx="junk">
+        <name>ds:running</name>				<!-- unknown prefix -->
+        <schema></schema>
+      </datastore>
+    </yang-library>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.json b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.json
new file mode 100644
index 0000000..b242525
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.json
@@ -0,0 +1,95 @@
+{
+    "ietf-yang-library:yang-library": [
+        {
+            "content-id": "9876",
+            "module-set": [
+                {
+                    "name": "set1",
+                    "module": [
+                        {
+                            "name": "test-module1",
+                            "revision": "2020-01-01",
+                            "namespace": "com:foo:test-module1",
+                            "location": [
+                                "www.acme.com/test-module1.yang",
+                                "www.modules.acme.com/test-module1.yang"
+                            ],
+                            "submodule": [
+                                {
+                                    "name": "test-module1-submodule",
+                                    "revision": ""
+                                }
+                            ],
+                            "feature": [
+                                "feature1",
+                                "feature2",
+                                "feature3"
+                            ],
+                            "deviation": [
+                                "test-module1-ext"
+                            ]
+                        },
+                        {
+                            "name": "test-module1-ext",
+                            "revision": "2020-03-03",
+                            "namespace": "com:foo:test-module1"
+                        }
+                    ],
+                    "import-only-module": [
+                        {
+                            "name": "test-module2",
+                            "revision": "",
+                            "namespace": "com:foo:test-module2"
+                        }
+                    ]
+                },
+                {
+                    "name": "set2",
+                    "import-only-module": [
+                        {
+                            "name": "test-module6",
+                            "revision": "2019-06-06",
+                            "namespace": "com:foo:test-module6"
+                        }
+                    ]
+                },
+                {
+                    "name": "set3",
+                    "import-only-module": [
+                        {
+                            "name": "test-module7",
+                            "revision": "2019-07-07",
+                            "namespace": "com:foo:test-module7"
+                        }
+                    ]
+                }
+            ],
+            "schema": [
+                {
+                    "name": "schema1",
+                    "module-set": [
+                        "set1",
+                        "set2"
+                    ]
+                },
+                {
+                    "name": "schema2",
+                    "module-set": [
+                        "set2",
+                        "set3"
+                    ]
+                }
+            ],
+            "datastore": [
+                {
+                    "name": "ietf-datastores:running",
+                    "schema": "schema1"
+                },
+                {
+                    "name": "ietf-datastores:operational",
+                    "schema": "schema2"
+                }
+            ]
+        }
+    ]
+}
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.xml
new file mode 100644
index 0000000..a10092e
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <content-id>9876</content-id>
+      <module-set>
+        <name>set1</name>
+        <module>
+          <name>test-module1</name>
+          <revision>2020-01-01</revision>
+          <namespace>com:foo:test-module1</namespace>
+          <location>www.acme.com/test-module1.yang</location>
+          <location>www.modules.acme.com/test-module1.yang</location>
+          <submodule>
+            <name>test-module1-submodule</name>
+            <revision></revision>
+          </submodule>
+          <feature>feature1</feature>
+          <feature>feature2</feature>
+          <feature>feature3</feature>
+          <deviation>test-module1-ext</deviation>
+        </module>
+        <module>
+          <name>test-module1-ext</name>
+          <revision>2020-03-03</revision>
+          <namespace>com:foo:test-module1</namespace>
+        </module>
+        <import-only-module>
+          <name>test-module2</name>
+          <revision></revision>
+          <namespace>com:foo:test-module2</namespace>
+        </import-only-module>
+      </module-set>
+      <module-set>
+        <name>set2</name>
+        <import-only-module>
+          <name>test-module6</name>
+          <revision>2019-06-06</revision>
+          <namespace>com:foo:test-module6</namespace>
+        </import-only-module>
+      </module-set>
+      <module-set>
+        <name>set3</name>
+        <import-only-module>
+          <name>test-module7</name>
+          <revision>2019-07-07</revision>
+          <namespace>com:foo:test-module7</namespace>
+        </import-only-module>
+      </module-set>
+      <schema>
+        <name>schema1</name>
+        <module-set>set1</module-set>
+        <module-set>set2</module-set>
+      </schema>
+      <schema>
+        <name>schema2</name>
+        <module-set>set2</module-set>
+        <module-set>set3</module-set>
+      </schema>
+      <datastore xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
+        <name>ds:running</name>
+        <schema>schema1</schema>
+      </datastore>
+      <datastore xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
+        <name>ds:operational</name>
+        <schema>schema2</schema>
+      </datastore>
+    </yang-library>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525_duplicates.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525_duplicates.xml
new file mode 100644
index 0000000..ca8944a
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-RFC-8525_duplicates.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+    <yang-library xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-library">
+      <content-id>9876</content-id>
+      <module-set>
+        <name>set1</name>
+        <module>
+          <name>test-module1</name>
+          <revision>2020-01-01</revision>
+          <namespace>com:foo:test-module1</namespace>
+        </module>
+        <module>
+          <name>test-module1</name>		<!-- duplicate entry -->
+          <revision>2020-01-01</revision>
+          <namespace>com:foo:test-module1</namespace>
+        </module>
+        <import-only-module>
+          <name>test-module2</name>
+          <revision></revision>
+          <namespace>com:foo:test-module2</namespace>
+        </import-only-module>
+      </module-set>
+      <schema>
+        <name>schema1</name>
+        <module-set>set1</module-set>
+      </schema>
+      <datastore xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
+        <name>ds:running</name>
+        <schema>schema1</schema>
+      </datastore>
+    </yang-library>
+  </content-data>
+</instance-data-set>
diff --git a/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-empty.xml b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-empty.xml
new file mode 100644
index 0000000..dbef9d1
--- /dev/null
+++ b/yang-parser/src/test/resources/yanglibrary/root-instance-data-set-empty.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  Copyright (C) 2024 Ericsson
+  Modifications Copyright (C) 2024 OpenInfra Foundation Europe
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+ -->
+<instance-data-set xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-instance-data">
+  <name>test instance data for IETF YANG Library</name>
+  <content-data>
+  </content-data>
+</instance-data-set>