"561698 -  Merge 'org.eclipse.mdm.nucleus/mkoller/contrib' into 'mkoller/contrib'"

Signed-off-by: Simon Skoczylas <simon.skoczylas@karakun.com>
diff --git a/org.eclipse.mdm.api.base/.gitignore b/org.eclipse.mdm.api.base/.gitignore
new file mode 100644
index 0000000..49678ad
--- /dev/null
+++ b/org.eclipse.mdm.api.base/.gitignore
@@ -0,0 +1,17 @@
+# eclipse
+.classpath
+.project
+.settings/
+bin/
+
+# gradle
+.gradle
+build/
+
+# intellij
+.idea/
+out/
+*.ipr
+*.iml
+*.iws
+/bin/
diff --git a/org.eclipse.mdm.api.base/LICENSE.txt b/org.eclipse.mdm.api.base/LICENSE.txt
new file mode 100644
index 0000000..e48e096
--- /dev/null
+++ b/org.eclipse.mdm.api.base/LICENSE.txt
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0
+
+    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a) in the case of the initial Contributor, the initial content
+     Distributed under this Agreement, and
+
+  b) in the case of each subsequent Contributor:
+     i) changes to the Program, and
+     ii) additions to the Program;
+  where such changes and/or additions to the Program originate from
+  and are Distributed by that particular Contributor. A Contribution
+  "originates" from a Contributor if it was added to the Program by
+  such Contributor itself or anyone acting on such Contributor's behalf.
+  Contributions do not include changes or additions to the Program that
+  are not Modified Works.
+
+"Contributor" means any person or entity that Distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which
+are necessarily infringed by the use or sale of its Contribution alone
+or when combined with the Program.
+
+"Program" means the Contributions Distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement
+or any Secondary License (as applicable), including Contributors.
+
+"Derivative Works" shall mean any work, whether in Source Code or other
+form, that is based on (or derived from) the Program and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship.
+
+"Modified Works" shall mean any work in Source Code or other form that
+results from an addition to, deletion from, or modification of the
+contents of the Program, including, for purposes of clarity any new file
+in Source Code form that contains any contents of the Program. Modified
+Works shall not include works that contain only declarations,
+interfaces, types, classes, structures, or files of the Program solely
+in each case in order to link to, bind by name, or subclass the Program
+or Modified Works thereof.
+
+"Distribute" means the acts of a) distributing or b) making available
+in any manner that enables the transfer of a copy.
+
+"Source Code" means the form of a Program preferred for making
+modifications, including but not limited to software source code,
+documentation source, and configuration files.
+
+"Secondary License" means either the GNU General Public License,
+Version 2.0, or any later versions of that license, including any
+exceptions or additional permissions as identified by the initial
+Contributor.
+
+2. GRANT OF RIGHTS
+
+  a) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free copyright
+  license to reproduce, prepare Derivative Works of, publicly display,
+  publicly perform, Distribute and sublicense the Contribution of such
+  Contributor, if any, and such Derivative Works.
+
+  b) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free patent
+  license under Licensed Patents to make, use, sell, offer to sell,
+  import and otherwise transfer the Contribution of such Contributor,
+  if any, in Source Code or other form. This patent license shall
+  apply to the combination of the Contribution and the Program if, at
+  the time the Contribution is added by the Contributor, such addition
+  of the Contribution causes such combination to be covered by the
+  Licensed Patents. The patent license shall not apply to any other
+  combinations which include the Contribution. No hardware per se is
+  licensed hereunder.
+
+  c) Recipient understands that although each Contributor grants the
+  licenses to its Contributions set forth herein, no assurances are
+  provided by any Contributor that the Program does not infringe the
+  patent or other intellectual property rights of any other entity.
+  Each Contributor disclaims any liability to Recipient for claims
+  brought by any other entity based on infringement of intellectual
+  property rights or otherwise. As a condition to exercising the
+  rights and licenses granted hereunder, each Recipient hereby
+  assumes sole responsibility to secure any other intellectual
+  property rights needed, if any. For example, if a third party
+  patent license is required to allow Recipient to Distribute the
+  Program, it is Recipient's responsibility to acquire that license
+  before distributing the Program.
+
+  d) Each Contributor represents that to its knowledge it has
+  sufficient copyright rights in its Contribution, if any, to grant
+  the copyright license set forth in this Agreement.
+
+  e) Notwithstanding the terms of any Secondary License, no
+  Contributor makes additional grants to any Recipient (other than
+  those set forth in this Agreement) as a result of such Recipient's
+  receipt of the Program under the terms of a Secondary License
+  (if permitted under the terms of Section 3).
+
+3. REQUIREMENTS
+
+3.1 If a Contributor Distributes the Program in any form, then:
+
+  a) the Program must also be made available as Source Code, in
+  accordance with section 3.2, and the Contributor must accompany
+  the Program with a statement that the Source Code for the Program
+  is available under this Agreement, and informs Recipients how to
+  obtain it in a reasonable manner on or through a medium customarily
+  used for software exchange; and
+
+  b) the Contributor may Distribute the Program under a license
+  different than this Agreement, provided that such license:
+     i) effectively disclaims on behalf of all other Contributors all
+     warranties and conditions, express and implied, including
+     warranties or conditions of title and non-infringement, and
+     implied warranties or conditions of merchantability and fitness
+     for a particular purpose;
+
+     ii) effectively excludes on behalf of all other Contributors all
+     liability for damages, including direct, indirect, special,
+     incidental and consequential damages, such as lost profits;
+
+     iii) does not attempt to limit or alter the recipients' rights
+     in the Source Code under section 3.2; and
+
+     iv) requires any subsequent distribution of the Program by any
+     party to be under a license that satisfies the requirements
+     of this section 3.
+
+3.2 When the Program is Distributed as Source Code:
+
+  a) it must be made available under this Agreement, or if the
+  Program (i) is combined with other material in a separate file or
+  files made available under a Secondary License, and (ii) the initial
+  Contributor attached to the Source Code the notice described in
+  Exhibit A of this Agreement, then the Program may be made available
+  under the terms of such Secondary Licenses, and
+
+  b) a copy of this Agreement must be included with each copy of
+  the Program.
+
+3.3 Contributors may not remove or alter any copyright, patent,
+trademark, attribution notices, disclaimers of warranty, or limitations
+of liability ("notices") contained within the Program from any copy of
+the Program which they Distribute, provided that Contributors may add
+their own appropriate notices.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While this
+license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product
+offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes
+the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every
+other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits
+and other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program
+in a commercial product offering. The obligations in this section do not
+apply to any claims or Losses relating to any actual or alleged
+intellectual property infringement. In order to qualify, an Indemnified
+Contributor must: a) promptly notify the Commercial Contributor in
+writing of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those performance
+claims and warranties, and if a court requires any other Contributor to
+pay any damages as a result, the Commercial Contributor must pay
+those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all
+risks associated with its exercise of rights under this Agreement,
+including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs
+or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software
+or hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted and
+may only be modified in the following manner. The Agreement Steward
+reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement
+Steward has the right to modify this Agreement. The Eclipse Foundation
+is the initial Agreement Steward. The Eclipse Foundation may assign the
+responsibility to serve as the Agreement Steward to a suitable separate
+entity. Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always be
+Distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to Distribute the Program (including its
+Contributions) under the new version.
+
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted
+under this Agreement are reserved. Nothing in this Agreement is intended
+to be enforceable by any entity that is not a Contributor or Recipient.
+No third-party beneficiary rights are created under this Agreement.
+
+Exhibit A - Form of Secondary Licenses Notice
+
+"This Source Code may also be made available under the following
+Secondary Licenses when the conditions for such availability set forth
+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+version(s), and exceptions or additional permissions here}."
+
+  Simply including a copy of this Agreement, including this Exhibit A
+  is not sufficient to license the Source Code under Secondary Licenses.
+
+  If it is not possible or desirable to put the notice in a particular
+  file, then You may include the notice in a location (such as a LICENSE
+  file in a relevant directory) where a recipient would be likely to
+  look for such a notice.
+
+  You may add additional accurate notices of copyright ownership.
diff --git a/org.eclipse.mdm.api.base/NOTICE.txt b/org.eclipse.mdm.api.base/NOTICE.txt
new file mode 100644
index 0000000..56281c6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/NOTICE.txt
@@ -0,0 +1,382 @@
+# Notices for Eclipse MDM|BL
+
+This content is produced and maintained by the Eclipse MDM|BL project,
+it is a project of the openMDM(R) Eclipse Working Group.
+
+* Project home: https://projects.eclipse.org/projects/technology.mdmbl
+
+## Trademarks
+
+Eclipse MDM|BL, MDM|BL and Eclipse openMDM(R) logo are registered trademarks
+of the Eclipse Foundation.
+
+## Copyright
+
+All content is the property of the following respective authors or their employers.
+For more information regarding authorship of content, please consult the listed
+source code repository logs.
+
+Copyright (c) 2016-2019 Gigatronik Ingolstadt GmbH
+Copyright (c) 2016-2020 Peak Solution GmbH
+Copyright (c) 2017-2018 science + computing AG Tuebingen (ATOS SE)
+Copyright (c) 2017-2018 Canoo Engineering AG
+Copyright (c) 2017 Florian Schmitt
+Copyright (c) 2017-2020 Angelika Wittek
+Copyright (c) 2018-2019 Elektronische Fahrwerksysteme GMBH
+Copyright (c) 2018-2020 Karakun AG
+Copyright (c) 2018-2020 Alexander Nehmer
+
+## Declared Project Licenses
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v. 2.0 which is available at
+http://www.eclipse.org/legal/epl-2.0.
+
+SPDX-License-Identifier: EPL-2.0
+
+## Source Code
+
+The project maintains the following source code repositories:
+
+org.eclipse.mdm.api.base.git	    - The openMDM(R) API.
+org.eclipse.mdm.api.default.git	    - Extension of the openMDM(R) API containing default elements.
+org.eclipse.mdm.api.odsadapter.git	- ODS implementation of persistence adapter.
+org.eclipse.mdm.nucleus.git	        - Core building blocks for the openMDM Business Logic and Web Frontend.
+
+## Third-party Content
+
+The Content includes items that have been sourced from third parties as set out below.
+If you did not receive this Content directly from the Eclipse Foundation, the following
+is provided for informational purposes only, and you should look to
+the Redistributor's license for terms and conditions of use.
+
+antlr4-4.5.3.jar(2.5.3)
+    * License: New BSD license
+
+aopalliance-repackaged-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+commons-codec-1.2.jar (1.2)
+    * License: Apache License, 2.0
+
+commons-httpclient-3.1.jar  (3.1)
+    * License: Apache License, 2.0
+
+commons-lang3-3.8.1.jar (3.8.1)
+    * License: Apache License, 2.0
+
+commons-text-1.6.jar (1.6)
+    * License: Apache License, 2.0
+
+gson-2.7.jar (2.7)
+    * License: Apache License, 2.0
+
+Google Guava Version: 25.0-jre  (25.0)
+    * License: Apache License, 2.0
+
+Gradle Wrapper (4.10.2)
+    * License: Apache License, 2.0
+
+hk2-api-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL-1.1
+
+hk2-locator-2.5.0-b05.jar(2.5.0-b05)
+    * License: CDDL
+
+hk2-utils-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+jackson-annotations-2.9.0.jar  (2.9.0)
+    * License: Apache License, 2.0
+
+jackson-core-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-databind-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-base-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-json-provider-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-module-jaxb-annotations-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+javassist-3.20.0-GA.jar  (2.20.0-GA)
+    * License: Apache 2.0
+
+jcl-over-slf4j-1.7.25.jar(1.7.25)
+    * License: MIT License
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL:  https://www.slf4j.org
+    * Source URL:   https://github.com/qos-ch/slf4j
+
+jersey-client-2.23.2.jar (2.23.2)
+     * License: CDDL
+
+jersey-common-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-2.23.2.jar  (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-core-2.23.3.jar(2.23.2)
+    * License: CDDL
+
+jersey-guava-2.23.2.jar  (2.23.2)
+    * License: Apache License, 2.0
+
+jersey-media-jaxb-2.23.2.jar(2.23.2)
+    * License: CDDL
+
+jersey-media-sse-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-media-multipart-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-server-2.23.2.jar (2.23.2)
+    * License: Apache-2.0
+
+log4j-over-slf4j-1.7.25.jar (1.7.25)
+    * License: Apache-2.0
+
+logback-classic-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+logback-core-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+mimepull-1.9.6.jar (1.9.4)
+    * License: CDDL
+
+openatfx-0.7.4.jar (0.7.4)
+    * License: Apache-2.0
+
+osgi-resource-locator-1.0.1.jar(1.0.1)
+    * License: CDDL
+
+protobuf-java-3.2.0.jar (3.2.0)
+    * License: New BSD license
+
+protobuf-java-util-3.2.0.jar  (3.2.0)
+    * License: New BSD license
+
+swagger-annotations-2.0.8.jar (2.0.8)
+    * License: Apache-2.0
+
+swagger-ui-3.23.0.jar (3.23.0)
+    * License: Apache-2.0
+
+slf4j-api-1.7.25.jar  (1.7.25)
+    * License: MIT license
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL: https://github.com/qos-ch/slf4j
+    * Source URL:  https://github.com/qos-ch/slf4j/releases/tag/v_1.7.25
+
+stax2-api-3.1.4.jar (3.1.4)
+    * License: BSD-2-Clause
+
+validation-api-1.1.0.Final.jar (1.1.0.Final)
+  * License: Apache License, 2.0
+
+vavr-0.9.1-sources.jar (0.9.1)
+  * License: Apache License, 2.0
+
+vavr-match-0.9.1.jar (0.9.1)
+  * License: Apache License, 2.0
+
+woodstox-core-asl-4.4.1.jar (4.4.1)
+  * License: Apache License, 2.0
+
+
+FFAMFAMFAM Silk Icon, Version 1.3
+    * License: Creative Commons Attribution 3.0 License
+    * Licence Path: https://creativecommons.org/licenses/by/3.0/
+    * Project: http://www.famfamfam.com/lab/icons/silk/
+    * Source:  http://www.famfamfam.com/lab/icons/silk/
+
+@angular/animations:7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/animations
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/cdk:7.1.1
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api
+    * Source:  https://github.com/angular/angular/releases/tag/7.1.1
+
+
+@angular/common@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/common
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4r
+
+@angular/compiler@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/core@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/forms@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/http@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser-dynamic@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/router@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+bootstrap@4.1.3
+    * License: MIT
+    * Licence Path: https://github.com/twbs/bootstrap/raw/master/LICENSE
+    * Project: https://getbootstrap.com/
+    * Source:  https://github.com/twbs/bootstrap
+
+class-transformer@0.1.6
+    * License: MIT
+    * Licence Path: https://github.com/typestack/class-transformer/blob/master/LICENSE
+    * Project: https://github.com/pleerock/class-transformer
+    * Source:  https://github.com/pleerock/class-transformer
+
+core-js@2.6.0
+    * License: MIT
+    * Licence Path: https://github.com/zloirock/core-js/raw/master/LICENSE
+    * Project: https://github.com/zloirock/core-js
+    * Source:  https://github.com/zloirock/core-js/releases/tag/v2.6.0
+
+file-saver@1.3.3
+    * License: MIT
+    * Licence Path: https://github.com/eligrey/FileSaver.js/raw/master/LICENSE.md
+    * Project: https://github.com/eligrey/FileSaver.js
+    * Source:  https://github.com/eligrey/FileSaver.js
+
+font-awesome@4.7.0
+    * License: MIT
+    * Licence Path: https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt
+    * Project: https://fontawesome.com/
+    * Source:  https://github.com/FortAwesome/Font-Awesome
+
+ng2-split-pane@1.3.1
+    * License: MIT
+    * Licence Path: https://github.com/wannabegeek/ng2-split-pane/raw/master/LICENSE
+    * Project: https://github.com/wannabegeek/ng2-split-pane
+    * Source:  https://github.com/wannabegeek/ng2-split-pane
+
+ngx-bootstrap@3.1.2
+    * License: MIT
+    * Licence Path: https://github.com/valor-software/ngx-bootstrap/blob/v3.1.2/LICENSE
+    * Project: https://valor-software.com/ngx-bootstrap
+    * Source:  https://github.com/valor-software/ngx-bootstrap/tree/v3.1.2
+
+@ngx-translate/core@11.0.1
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/core/blob/v11.0.1/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/core
+
+@ngx-translate/http-loader@4.0.0
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/http-loader/blob/v4.0.0/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/http-loader/tree/v4.0.0
+
+primeicons:1.0.0
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeicons/blob/1.0.0/LICENSE
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeicons/tree/1.0.0
+
+primeng@7.0.1
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeng/blob/7.0.1/LICENSE.md
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeng/tree/7.0.1
+
+rxjs@6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3
+
+rxjs-compat:6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3/compat
+
+tslib@1.9.0
+    * License: Apache-2.0
+    * Project: https://github.com/Microsoft/tslib
+    * Source:  https://github.com/Microsoft/tslib/tree/1.9.0
+
+zone.js@0.8.26
+    * License: MIT
+    * Licence Path: https://github.com/angular/zone.js/raw/master/LICENSE
+    * Project: https://github.com/angular
+    * Source:  https://github.com/angular/zone.js/releases/tag/v0.8.26
+
+OMG Event Service Specification (1.2)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/EVNT/1.2/
+* Source: https://www.omg.org/spec/EVNT/1.2/pdf
+
+OMG Notification Service Specification (1.1)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/NOT/
+* Source: https://www.omg.org/spec/NOT/1.1/PDF
+
+ods530.idl
+Date: Hoehenkirchen, 06/01/2016
+"The ASAM Board of Directors releases the IDL files for use under the EPL to the Eclipse IWG openMDM.
+This is valid for all versions of ASAM ODS 5.3.x.
+This permission is valid under the conditions of Eclipse will not modify the file."
+
+AvalonEvent.idl, CorbaFileServer.idl
+Date: 08/15/2016
+"Herewith, we release the generated Client-Source-Code generated from our CORBA IDLs, namely
+* CORBANotification Service (generated from „AvalonEvent.idl”)
+* CORBAFileServer (generated from „CorbaFileServer.idl“),
+Under the Eclipse Public License (EPL). This agreement does not include the „AvalonEvent.idl“ and
+„CorbaFileServer.idl“ itself, which remain protected property of HighQSoft. "
+
+## Cryptography
+
+Content may contain encryption software. The country in which you are currently
+may have restrictions on the import, possession, and use, and/or re-export to
+another country, of encryption software. BEFORE using any encryption software,
+please check the country's laws, regulations and policies concerning the import,
+possession, or use, and re-export of encryption software, to see if this is
+permitted.
diff --git a/org.eclipse.mdm.api.base/build.gradle b/org.eclipse.mdm.api.base/build.gradle
new file mode 100644
index 0000000..60e39f3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/build.gradle
@@ -0,0 +1,48 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+
+description = 'MDM API - Base Model'
+group = 'org.eclipse.mdm'
+version = '5.2.0M1-SNAPSHOT'
+
+apply plugin: 'java'
+apply plugin: 'maven'
+apply plugin: 'eclipse'
+
+repositories {
+    mavenLocal()
+    mavenCentral()
+}
+
+dependencies {
+    // testing
+    testCompile 'junit:junit:4.12'
+    testCompile 'org.mockito:mockito-core:2.13.0' 
+    testCompile 'org.assertj:assertj-core:3.6.2'
+}
+
+jar {
+	metaInf { from 'NOTICE.txt' }
+	metaInf { from 'LICENSE.txt' }
+}
+
+task sourcesJar(type: Jar, dependsOn: classes) {
+	classifier = 'sources'
+	from sourceSets.main.allSource
+}
+
+artifacts {
+	archives sourcesJar
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/gradle.properties b/org.eclipse.mdm.api.base/gradle.properties
new file mode 100644
index 0000000..2ab5436
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradle.properties
@@ -0,0 +1,16 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+ 
+sourceCompatibility=1.8
+targetCompatibility=1.8
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.jar b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.properties b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82e006
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME

+distributionPath=wrapper/dists

+zipStoreBase=GRADLE_USER_HOME

+zipStorePath=wrapper/dists

+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip

diff --git a/org.eclipse.mdm.api.base/gradlew b/org.eclipse.mdm.api.base/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/org.eclipse.mdm.api.base/gradlew.bat b/org.eclipse.mdm.api.base/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windows variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/org.eclipse.mdm.api.base/settings.gradle b/org.eclipse.mdm.api.base/settings.gradle
new file mode 100644
index 0000000..8e8ce19
--- /dev/null
+++ b/org.eclipse.mdm.api.base/settings.gradle
@@ -0,0 +1,15 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+rootProject.name = 'org.eclipse.mdm.api.base'
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContext.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContext.java
new file mode 100644
index 0000000..d3a3976
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContext.java
@@ -0,0 +1,130 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.file.FileService;
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchService;
+
+/**
+ * Base application context represents a connection/session to the underlying
+ * data store. It provides access to managers and services.
+ *
+ * @param <S> Type of the connected entity factory.
+ * @param <T> Type of the connected entity manager.
+ * @since 1.0.0
+ */
+public interface BaseApplicationContext<S extends BaseEntityFactory, T extends BaseEntityManager>
+		extends AutoCloseable {
+	/**
+	 * The returned service loads entities from the underlying data source.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 */
+	default Optional<T> getEntityManager() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service creates new entities.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 */
+	default Optional<S> getEntityFactory() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service provides access to the application model's meta data.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see ModelManager
+	 */
+	default Optional<ModelManager> getModelManager() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service provides advanced search capabilities for supported
+	 * entity types.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see SearchService
+	 */
+	default Optional<SearchService> getSearchService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service provides access to the low level query API.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see QueryService
+	 */
+	default Optional<QueryService> getQueryService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service allows to download linked files from the file storage.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see FileService
+	 */
+	default Optional<FileService> getFileService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service allows to register/unregister for events at a
+	 * registration service.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see NotificationService
+	 */
+	default Optional<NotificationService> getNotificationService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * Returns a map with all configuration parameters, which where given to
+	 * initialize this context.
+	 * 
+	 * @return map with configuration parameters
+	 */
+	Map<String, String> getParameters();
+
+	/**
+	 * Returns a string describing the type of the underlying API implementation.
+	 * The exact content is up to the individual adapter and it is intended to be
+	 * interpreted by the client.
+	 * 
+	 * @return a string describing the type of the underlying API implementation.
+	 */
+	String getAdapterType();
+
+	/**
+	 * Closes the BaseContext.
+	 * 
+	 * This closes all underlying managers and services.
+	 */
+	void close() throws ConnectionException;
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContextFactory.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContextFactory.java
new file mode 100644
index 0000000..eab20c5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContextFactory.java
@@ -0,0 +1,39 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+
+/**
+ * Takes connection parameters and produces a corresponding base application
+ * context.
+ *
+ * @param <T> Type of the connected entity manager.
+ * @since 1.0.0
+ */
+public interface BaseApplicationContextFactory<T extends BaseApplicationContext<? extends BaseEntityFactory, ? extends BaseEntityManager>> {
+
+	/**
+	 * Takes given connection parameters and creates a new context, which is
+	 * permanently connected with configured data source.
+	 *
+	 * @param connectionParameters The connection parameters.
+	 * @return The connected context is returned.
+	 * @throws ConnectionException Thrown if unable to connect to a data source.
+	 */
+	T connect(Map<String, String> connectionParameters) throws ConnectionException;
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseEntityManager.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseEntityManager.java
new file mode 100644
index 0000000..cf656d9
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseEntityManager.java
@@ -0,0 +1,285 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.massdata.ReadRequest;
+import org.eclipse.mdm.api.base.model.ContextDescribable;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Environment;
+import org.eclipse.mdm.api.base.model.MeasuredValues;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Provides business layer CRUD operations and services (CREATE, READ, UPDATE,
+ * INSERT).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface BaseEntityManager {
+
+	/**
+	 * Returns the {@link Environment} this entity manager is connected to.
+	 *
+	 * @return The {@code Environment} is returned.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code
+	 * 		Environment}        .
+	 */
+	Environment loadEnvironment() throws DataAccessException;
+
+	/**
+	 * Returns the {@link User} which was used to connect to the underlying data
+	 * source.
+	 *
+	 * @return {@code Optional} is empty if the data source connection is user
+	 *         independent, which is implementation specific.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code User}.
+	 */
+	default Optional<User> loadLoggedOnUser() throws DataAccessException {
+		return Optional.empty();
+	}
+
+	/**
+	 * Loads the entity identified by given entity class and its instance ID.
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entity.
+	 * @param instanceID  The instance ID.
+	 * @return The entity with given instance ID is returned.
+	 * @throws DataAccessException Thrown if unable to retrieve the entity.
+	 */
+	default <T extends Entity> T load(Class<T> entityClass, String instanceID) throws DataAccessException {
+		List<T> entities = load(entityClass, Collections.singletonList(instanceID));
+		if (entities.size() != 1) {
+			throw new DataAccessException("Failed to load entity by instance ID.");
+		}
+		return entities.get(0);
+	}
+
+	/**
+	 * Loads the entities identified by given entity class and its instance IDs.
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @param instanceIDs The instance IDs to load. If a instance ID does not exist,
+	 *                    it is ignored.
+	 * @return Entities are returned in a list.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 */
+	<T extends Entity> List<T> load(Class<T> entityClass, Collection<String> instanceIDs) throws DataAccessException;
+
+	/**
+	 * Loads all available entities of given type. This method is useful while
+	 * working with types whose amount is known to be fairly small (e.g.:
+	 * {@code Unit}, {@code Quantity}, etc.). If a type is given where thousand
+	 * instances exist (e.g.: {@code Test}) the behavior of this method is
+	 * implementation specific. The following invocation might take its time to
+	 * complete or even result in an exception as soon as too many results are
+	 * found:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	List<Test> tests = entityManager.loadAll(Test.class);
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @return Entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 * @see #loadAll(Class, String)
+	 */
+	default <T extends Entity> List<T> loadAll(Class<T> entityClass) throws DataAccessException {
+		return loadAll(entityClass, "*");
+	}
+
+	/**
+	 * Loads all available entities of given type whose name fulfills the given
+	 * pattern. This method is useful while working with types whose amount is known
+	 * to be fairly small (e.g.: {@code Unit}, {@code Quantity}, etc.). If a type is
+	 * given where thousand instances exist (e.g.: {@code Test}) the behavior of
+	 * this method is implementation specific. The following invocation might take
+	 * its time to complete or even result in an exception as soon as too many
+	 * results are found:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	// retrieve all tests whose name starts with 'Example'
+	 * 	List<Test> tests = entityManager.loadAll(Test.class, "Example*");
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @param pattern     Is always case sensitive and may contain wildcard
+	 *                    characters as follows: "?" for one matching character and
+	 *                    "*" for a sequence of matching characters.
+	 * @return Matched entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 * @see #loadAll(Class)
+	 */
+	<T extends Entity> List<T> loadAll(Class<T> entityClass, String pattern) throws DataAccessException;
+
+	/**
+	 * Loads the parent entity for given child. Each modeled entity provides public
+	 * fields for available parent entity types e.g.:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	Optional<Test> parentTest = entityManager.loadParent(testStep, TestStep.PARENT_TYPE_TEST);
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired parent type.
+	 * @param child       The child entity.
+	 * @param entityClass The desired parent entity type.
+	 * @return {@code Optional} is empty if parent entity could not be found.
+	 * @throws DataAccessException Thrown if unable to retrieve parent entity.
+	 */
+	<T extends Entity> Optional<T> loadParent(Entity child, Class<T> entityClass) throws DataAccessException;
+
+	/**
+	 * Loads all related children of given type for given parent entity. Each
+	 * modeled entity provides public fields for available child entity types e.g.:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	List<Channel> channels = entityManager.loadChildren(measurement, Measurement.CHILD_TYPE_CHANNEL);
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired child type.
+	 * @param parent      The parent entity.
+	 * @param entityClass The desired child entity type.
+	 * @return Related child entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the children.
+	 * @see #loadChildren(Entity, Class, String)
+	 */
+	default <T extends Entity> List<T> loadChildren(Entity parent, Class<T> entityClass) throws DataAccessException {
+		return loadChildren(parent, entityClass, "*");
+	}
+
+	/**
+	 * Loads all related children of given type for given parent entity whose name
+	 * fulfills the given pattern. Each modeled entity provides public fields for
+	 * available child entity types e.g.:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	List<TestStep> testSteps = entityManager.loadChildren(test, Test.CHILD_TYPE_TESTSTEP, "Example*");
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired child type.
+	 * @param parent      The parent entity.
+	 * @param entityClass The desired child entity type.
+	 * @param pattern     Is always case sensitive and may contain wildcard
+	 *                    characters as follows: "?" for one matching character and
+	 *                    "*" for a sequence of matching characters.
+	 * @return Matched child entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the children.
+	 * @see #loadChildren(Entity, Class)
+	 */
+	<T extends Entity> List<T> loadChildren(Entity parent, Class<T> entityClass, String pattern)
+			throws DataAccessException;
+
+	/**
+	 * Queries available {@link ContextType} for given {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or a {@link Measurement}
+	 * @return {@code List} contains the {@code ContextType} of each referenced
+	 *         {@link ContextRoot}.
+	 * @throws DataAccessException Thrown if unable to query the available
+	 *                             {@code ContextType}s.
+	 */
+	List<ContextType> loadContextTypes(ContextDescribable contextDescribable) throws DataAccessException;
+
+	/**
+	 * Loads the requested {@link ContextRoot}s for given
+	 * {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or {@link Measurement}.
+	 * @param contextTypes       The requested context types. If omitted, all types
+	 *                           are be loaded.
+	 * @return The ordered contexts for given {@code TestStep} or the measured ones
+	 *         for {@code Measurement} are returned in a {@code Map}.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code
+	 * 		ContextRoot}        s.
+	 * @see ContextType
+	 */
+	Map<ContextType, ContextRoot> loadContexts(ContextDescribable contextDescribable, ContextType... contextTypes)
+			throws DataAccessException;
+
+	/**
+	 * @param entity       The entity
+	 * @param relationName The name of the relation, which entities should be
+	 *                     loaded.
+	 * @param relatedClass Class of the related entities.
+	 * @return The related entities for the given {@link Entity} and relationName
+	 */
+	<T extends Entity> List<T> loadRelatedEntities(Entity entity, String relationName, Class<T> relatedClass);
+
+	/**
+	 * Retrieves the {@link MeasuredValues} as specified by the given
+	 * {@link ReadRequest}.
+	 *
+	 * @param readRequest Provides all required informations to process the request.
+	 * @return Returns the {@code MeasuredValues} in a {@code List} as specified in
+	 *         the given {@code ReadRequest}.
+	 * @throws DataAccessException Thrown if unable to access the measured values.
+	 */
+	List<MeasuredValues> readMeasuredValues(ReadRequest readRequest) throws DataAccessException;
+
+	/**
+	 * Creates a new {@link Transaction} for modifying access.
+	 *
+	 * @return A new {@code Transaction} is returned.
+	 * @throws DataAccessException Thrown if unable to create a new
+	 *                             {@code Transaction}.
+	 */
+	Transaction startTransaction() throws DataAccessException;
+
+	/**
+	 * Returns links to the given entities in the data store. The format of the
+	 * links is adapter specific and depends on the underlying data store. The links
+	 * can be used by the client to directly access the entities by bypassing the
+	 * MDM API, if the client is capable of accessing the adapters data store. The
+	 * client can invoke {@link BaseApplicationContext#getAdapterType()} to get the
+	 * type of the adapter.
+	 * 
+	 * @param entities the Entities for which the links are retrieved
+	 * @return the links to the given entities in the data store abstracted by the
+	 *         current adapter. The map contains the requested entities as keys and
+	 *         the corresponding links as values.
+	 */
+	Map<Entity, String> getLinks(Collection<Entity> entities);
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ConnectionException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ConnectionException.java
new file mode 100644
index 0000000..0d71120
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ConnectionException.java
@@ -0,0 +1,54 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+/**
+ * Thrown to indicate (dis-)connect errors with a data source.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ConnectionException extends Exception {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final long serialVersionUID = -1299685705186484972L;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The error message.
+	 */
+	public ConnectionException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message   The error message.
+	 * @param throwable The origin cause.
+	 */
+	public ConnectionException(String message, Throwable throwable) {
+		super(message, throwable);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ServiceNotProvidedException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ServiceNotProvidedException.java
new file mode 100644
index 0000000..1a4b5e3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ServiceNotProvidedException.java
@@ -0,0 +1,32 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+/**
+ * This exception indicates that a service is not provided by an adapter.
+ */
+public class ServiceNotProvidedException extends RuntimeException {
+
+	private static final long serialVersionUID = -4829618036958929415L;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param clazz the service that is not provided
+	 */
+	public ServiceNotProvidedException(Class<?> clazz) {
+		super("The service '" + clazz + "' is not implemented!");
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/Transaction.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/Transaction.java
new file mode 100644
index 0000000..10b78fb
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/Transaction.java
@@ -0,0 +1,94 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Collection;
+
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.MeasuredValues;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Provides business layer write operations (CREATE, UPDATE, DELETE).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface Transaction {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	// TODO: it should be possible to a attach a listener
+	// -> progress notification updates while uploading files
+	// -> any other useful informations?!
+
+	/**
+	 * Persists given entities and implicitly updates their instance IDs.
+	 *
+	 * @param <T>      Most common type of the given entities.
+	 * @param entities Entities that will be persisted.
+	 * @throws DataAccessException Thrown in case of errors while writing entities.
+	 */
+	<T extends Entity> void create(Collection<T> entities) throws DataAccessException;
+
+	/**
+	 * Updates given entities.
+	 *
+	 * @param <T>      Most common type of the given entities.
+	 * @param entities Entities that will be updated.
+	 * @throws DataAccessException Thrown in case of errors while writing entities.
+	 */
+	<T extends Entity> void update(Collection<T> entities) throws DataAccessException;
+
+	/**
+	 * Deletes given entities. Related children will be searched and automatically
+	 * removed.
+	 *
+	 * @param <T>      Most common type of the given entities.
+	 * @param entities Entities that will be deleted (including their children).
+	 * @throws DataAccessException Thrown in case of errors while deleting entities.
+	 */
+	<T extends Deletable> void delete(Collection<T> entities) throws DataAccessException;
+
+	/**
+	 * Creates {@link MeasuredValues} as specified by the given
+	 * {@link WriteRequest}s.
+	 *
+	 * @param writeRequests Provides all required informations to process the
+	 *                      request.
+	 * @throws DataAccessException Thrown if unable to create specified measured
+	 *                             values.
+	 */
+	void writeMeasuredValues(Collection<WriteRequest> writeRequests) throws DataAccessException;
+
+	/**
+	 * Commit this transaction. Any changes made within this transaction become
+	 * permanent.
+	 *
+	 * @throws DataAccessException Thrown if unable to commit this transaction.
+	 */
+	void commit() throws DataAccessException;
+
+	/**
+	 * Aborts (rollback) this transaction. Any changes made within this transaction
+	 * will be lost.
+	 */
+	void abort();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Attribute.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Attribute.java
new file mode 100644
index 0000000..206829a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Attribute.java
@@ -0,0 +1,171 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.lang.reflect.Field;
+
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Represents a modeled attribute.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see ValueType
+ * @see Value
+ */
+public interface Attribute {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link EntityType} this attribute belongs to.
+	 *
+	 * @return The owning {@code EntityType} is returned.
+	 */
+	EntityType getEntityType();
+
+	/**
+	 * Returns the name of this attribute.
+	 *
+	 * @return The name is returned.
+	 */
+	String getName();
+
+	/**
+	 * Returns the unit name of this attribute.
+	 *
+	 * @return The unit name is returned.
+	 */
+	String getUnit();
+
+	/**
+	 * Returns the {@link ValueType} of this attribute.
+	 *
+	 * @return The {@code ValueType} is returned.
+	 */
+	ValueType getValueType();
+
+	/**
+	 * Returns the enumeration {@code Class} associated with this {@code Attribute}.
+	 *
+	 * @return The enumeration {@code Class} associated with this {@code Attribute}
+	 *         is returned.
+	 * @throws IllegalStateException Thrown if the {@link ValueType} of this
+	 *                               {@code Attribute} is neither
+	 *                               {@link ValueType#ENUMERATION} nor
+	 *                               {@link ValueType#ENUMERATION_SEQUENCE}.
+	 */
+	Enumeration<?> getEnumObj();
+
+	/**
+	 * Creates a new and empty {@link Value}.
+	 *
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue() {
+		ValueType valueType = getValueType();
+		if (valueType.isEnumerationType()) {
+			return valueType.create(getEnumObj(), getName());
+		} else {
+			return valueType.create(getName());
+		}
+	}
+
+	/**
+	 * Creates a new {@link Value} with given initial value.
+	 *
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue(Object input) {
+		return createValue("", input);
+	}
+
+	/**
+	 * Creates a new {@link Value} with given unit name and initial value.
+	 *
+	 * @param unit  The name of unit.
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue(String unit, Object input) {
+		return createValue(unit, true, input);
+	}
+
+	/**
+	 * Creates a new sequence {@link Value} with given unit name and initial value.
+	 *
+	 * @param unit  The name of unit.
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValueSeq(String unit, Object input) {
+		if (getValueType().isEnumerationType()) {
+			return createEnumerationSequence(unit, input);
+		}
+		return createValueSequence(unit, input);
+	}
+
+	default Value createValueSequence(String unit, Object input) {
+		ValueType valueType = getValueType();
+		try {
+			Field field = valueType.getClass().getField(valueType.name() + "_SEQUENCE");
+			ValueType<?> sequenceValueType = (ValueType<?>) field.get(valueType);
+			return sequenceValueType.create(getName(), unit, true, input);
+
+		} catch (NoSuchFieldException | ClassCastException | IllegalAccessException e) {
+			throw new RuntimeException("Can't figure out sequence type for " + valueType.name());
+		}
+	}
+
+	default Value createEnumerationSequence(String unit, Object input) {
+		ValueType valueType = getValueType().toSequenceType();
+		return valueType.create(getName(), unit, true, input, getEnumObj().getName());
+	}
+
+	/**
+	 * Creates a new {@link Value} with given unit name, initial valid flag and
+	 * value.
+	 *
+	 * @param unit  The name of unit.
+	 * @param valid The initial valid flag.
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue(String unit, boolean valid, Object input) {
+		ValueType<?> valueType = getValueType();
+		if (valueType.isEnumerationType()) {
+			return valueType.create(getName(), unit, valid, input, getEnumObj().getName());
+		} else {
+			return valueType.create(getName(), unit, valid, input);
+		}
+	}
+
+	/**
+	 * Returns the name of this attribute.
+	 *
+	 * @return The name of this attribute is returned.
+	 */
+	@Override
+	String toString();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ChildrenStore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ChildrenStore.java
new file mode 100644
index 0000000..b02a638
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ChildrenStore.java
@@ -0,0 +1,110 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+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 org.eclipse.mdm.api.base.model.Deletable;
+
+/**
+ * Holds related entities of any kind and keeps track of modifications.
+ */
+public final class ChildrenStore {
+
+	private final Map<Class<? extends Deletable>, List<? extends Deletable>> current = new HashMap<>(0);
+	private final Map<Class<? extends Deletable>, List<? extends Deletable>> removed = new HashMap<>(0);
+
+	/**
+	 * Returns current set of related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<Class<? extends Deletable>, List<? extends Deletable>> getCurrent() {
+		return Collections.unmodifiableMap(current);
+	}
+
+	/**
+	 * Returns current set of removed related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<Class<? extends Deletable>, List<? extends Deletable>> getRemoved() {
+		return Collections.unmodifiableMap(removed);
+	}
+
+	/**
+	 * Returns related child entities of given type.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @return Returned {@code List} is unmodifiable.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> List<T> get(Class<T> entityClass) {
+		return Collections.unmodifiableList((List<T>) current.computeIfAbsent(entityClass, k -> new ArrayList<>()));
+	}
+
+	/**
+	 * Sorts the child entities with given {@code Comparator}.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @param comparator  Used for sorting.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> void sort(Class<T> entityClass, Comparator<? super T> comparator) {
+		List<T> children = (List<T>) current.get(entityClass);
+		if (children != null) {
+			children.sort(comparator);
+		}
+	}
+
+	/**
+	 * Adds given child entity.
+	 *
+	 * @param child The new child.
+	 */
+	@SuppressWarnings("unchecked")
+	public void add(Deletable child) {
+		removed.getOrDefault(child.getClass(), new ArrayList<>()).remove(child);
+		((List<Deletable>) current.computeIfAbsent(child.getClass(), k -> new ArrayList<>())).add(child);
+	}
+
+	/**
+	 * Removes given child entity.
+	 *
+	 * @param child The child which will be removed.
+	 */
+	@SuppressWarnings("unchecked")
+	public void remove(Deletable child) {
+		List<Deletable> children = (List<Deletable>) current.getOrDefault(child.getClass(), new ArrayList<>());
+		if (children.remove(child) && child.getID() != null && child.getID().length() > 0) {
+			((List<Deletable>) removed.computeIfAbsent(child.getClass(), k -> new ArrayList<>())).add(child);
+		}
+	}
+
+	/**
+	 * Clean up list of removed entities.
+	 */
+	void apply() {
+		removed.clear();
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Core.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Core.java
new file mode 100644
index 0000000..33a71d0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Core.java
@@ -0,0 +1,202 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Provides access to the internals of any entity:
+ *
+ * <ul>
+ * <li>name of the data source</li>
+ * <li>name of the type</li>
+ * <li>instance ID</li>
+ * <li>values</li>
+ * <li>added/removed file links</li>
+ * <li>related entities</li>
+ * <li>parent/child entities</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface Core {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of the data source this entity was retrieved from.
+	 *
+	 * @return Name of the data source.
+	 */
+	String getSourceName();
+
+	/**
+	 * Returns the name of the entity type.
+	 *
+	 * @return Name of the entity type is returned.
+	 */
+	String getTypeName();
+
+	/**
+	 * Returns the instance ID or {@code 0} if this instance is not yet persisted.
+	 *
+	 * @return The instance ID is returned.
+	 */
+	String getID();
+
+	/**
+	 * Sets an instance ID.
+	 *
+	 * @param instanceID The new instance ID.
+	 */
+	void setID(String instanceID);
+
+	/**
+	 * Returns <i>all</i> {@link Value} containers of this entity.
+	 *
+	 * @return Values mapped by their name are returned.
+	 */
+	Map<String, Value> getValues();
+
+	/**
+	 * Hides {@link Value} containers whose name is contained in the given names
+	 * {@code Collection}. E.g. hide attributes from a CatalogComponent when not
+	 * used in a TemplateComponent.
+	 *
+	 * @param names Names of the {@code Value} which shall be hidden.
+	 */
+	void hideValues(Collection<String> names);
+
+	/**
+	 * Returns <i>all</i> {@link Value} containers, including the hidden ones.
+	 *
+	 * @return All {@code Value} containers are returned.
+	 */
+	Map<String, Value> getAllValues();
+
+	/**
+	 * Returns all newly added {@link FileLink}.
+	 *
+	 * @return New {@code FileLink}s are returned.
+	 */
+	default List<FileLink> getAddedFileLinks() {
+		Predicate<FileLink> isRemote = FileLink::isRemote;
+
+		List<FileLink> fileLinks = getValues().values().stream().filter(v -> v.getValueType().isFileLink())
+				.filter(Value::isValid).map(v -> (FileLink) v.extract()).filter(isRemote.negate())
+				.collect(Collectors.toList());
+
+		List<Value> values = getValues().values().stream().filter(v -> v.getValueType().isFileLinkSequence())
+				.filter(Value::isValid).collect(Collectors.toList());
+
+		for (Value value : values) {
+			Arrays.stream((FileLink[]) value.extract()).filter(isRemote.negate()).forEach(fileLinks::add);
+		}
+
+		return fileLinks;
+	}
+
+	/**
+	 * Returns all removed {@link FileLink}s.
+	 *
+	 * @return Removed {@code FileLink}s are returned.
+	 */
+	default List<FileLink> getRemovedFileLinks() {
+		Predicate<FileLink> isRemote = FileLink::isRemote;
+
+		List<FileLink> fileLinks = getValues().values().stream().filter(v -> v.getValueType().isFileLink())
+				.filter(Value::isModified).map(v -> (FileLink) v.extractInitial()).filter(Objects::nonNull)
+				.filter(isRemote).collect(Collectors.toList());
+
+		List<Value> values = getValues().values().stream().filter(v -> v.getValueType().isFileLinkSequence())
+				.filter(Value::wasValid).filter(Value::isModified).collect(Collectors.toList());
+
+		for (Value value : values) {
+			List<FileLink> current = Arrays.asList((FileLink[]) value.extract());
+			Arrays.stream((FileLink[]) value.extractInitial()).filter(fl -> !current.contains(fl))
+					.forEach(fileLinks::add);
+		}
+
+		return fileLinks;
+	}
+
+	/**
+	 * Applies modifications made to the entity stores and {@link Value} containers.
+	 * This method is called when a transaction is finalized (all operations
+	 * completed successfully) to reflect the new state in the core.
+	 */
+	default void apply() {
+		// apply the removed state to mutable entities
+		getMutableStore().apply();
+
+		// apply the removed state to children
+		getChildrenStore().apply();
+
+		// apply modified values
+		getValues().values().stream().filter(Value::isModified).forEach(Value::apply);
+	}
+
+	/**
+	 * Returns the mutable {@link EntityStore}. Holds entities with mutable
+	 * (editable) relations to the entity bound to this core instance. This store
+	 * only contains always only one relation for one entity. For child relations
+	 * use {@link ChildrenStore}.
+	 *
+	 * @return The mutable {@code EntityStore} is returned.
+	 */
+	EntityStore getMutableStore();
+
+	/**
+	 * Returns the permanent {@link EntityStore}. Holds entities with immutable
+	 * (non-editable) relations to the entity bound to this core instance. E.g.
+	 * relations to the parent entity.
+	 *
+	 * @return The permanent {@code EntityStore} is returned.
+	 */
+	EntityStore getPermanentStore();
+
+	/**
+	 * Returns the {@link ChildrenStore}. This store holds child entities with
+	 * relations to the entity bound to this core instance.
+	 * 
+	 * @return The {@code ChildrenStore} is returned.
+	 */
+	// TODO (8.11.2017; Florian Schmitt, Angelika Wittek)
+	// Entities with more than one related entity that do not refer to children,
+	// have also to go here,
+	// as it is not permitted to go to the other stores. Does this work at all?
+	ChildrenStore getChildrenStore();
+
+	/**
+	 * Returns the {@link RelationStore}. This store holds related entities for N to
+	 * M relations.
+	 * 
+	 * @return The {@link RelationStore} is returned
+	 */
+	RelationStore getNtoMStore();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/DefaultCore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/DefaultCore.java
new file mode 100644
index 0000000..d66d41c
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/DefaultCore.java
@@ -0,0 +1,203 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.Record;
+
+/**
+ * Provides access to the internals of any entity:
+ *
+ * <ul>
+ * <li>name of the data source</li>
+ * <li>name of the type</li>
+ * <li>instance ID</li>
+ * <li>values</li>
+ * <li>added/removed file links</li>
+ * <li>related entities</li>
+ * <li>parent/child entities</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class DefaultCore implements Core {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final EntityStore permanentEntityStorage = new EntityStore();
+	private final EntityStore mutableEntityStorage = new EntityStore();
+	private final ChildrenStore childrenStore = new ChildrenStore();
+	private final RelationStore ntoMStore = new RelationStore();
+
+	private final Map<String, Value> values = new HashMap<>();
+	private final Map<String, Value> hiddenValues = new HashMap<>();
+
+	private final String sourceName;
+	private final String typeName;
+
+	private String instanceID;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructs a new {@link Core} initialized with a queried {@link Record}.
+	 *
+	 * @param record The queried {@code Record}.
+	 */
+	public DefaultCore(Record record) {
+		setID(record.getID());
+		values.putAll(record.getValues());
+		values.remove(Entity.ATTR_ID);
+
+		// remove any contained relation attributes
+		EntityType entityType = record.getEntityType();
+		entityType.getRelations().stream().map(Relation::getName).forEach(values::remove);
+
+		sourceName = entityType.getSourceName();
+		typeName = entityType.getName();
+	}
+
+	/**
+	 * Constructs a new empty {@link Core}. The ID is set to an empty String.
+	 *
+	 * @param entityType The associated {@link EntityType}.
+	 */
+	public DefaultCore(EntityType entityType) {
+		setID("");
+		values.putAll(entityType.createValues());
+		values.remove(Entity.ATTR_ID);
+
+		sourceName = entityType.getSourceName();
+		typeName = entityType.getName();
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getSourceName() {
+		return sourceName;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getTypeName() {
+		return typeName;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getID() {
+		return instanceID;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setID(String instanceID) {
+		this.instanceID = instanceID;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<String, Value> getValues() {
+		return values;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void hideValues(Collection<String> names) {
+		if (names.isEmpty()) {
+			return;
+		}
+
+		for (String name : names) {
+			Value value = values.remove(name);
+			if (name != null) {
+				hiddenValues.put(name, value);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<String, Value> getAllValues() {
+		if (hiddenValues.isEmpty()) {
+			return values;
+		}
+
+		Map<String, Value> allValues = new HashMap<>(values);
+		allValues.putAll(hiddenValues);
+		return allValues;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityStore getMutableStore() {
+		return mutableEntityStorage;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityStore getPermanentStore() {
+		return permanentEntityStorage;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public ChildrenStore getChildrenStore() {
+		return childrenStore;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public RelationStore getNtoMStore() {
+		return ntoMStore;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityStore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityStore.java
new file mode 100644
index 0000000..129ee3d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityStore.java
@@ -0,0 +1,178 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+
+/**
+ * Holds related entities of any kind and keeps track of modifications.
+ */
+public final class EntityStore {
+
+	private final Map<String, Entity> current = new HashMap<>(0);
+	private final Map<String, Entity> removed = new HashMap<>(0);
+
+	/**
+	 * Returns current set of related entities.
+	 *
+	 * @return Returned {@code Collection} is unmodifiable.
+	 */
+	public Collection<Entity> getCurrent() {
+		return Collections.unmodifiableCollection(current.values());
+	}
+
+	/**
+	 * Returns current set of removed related entities.
+	 *
+	 * @return Returned {@code Collection} is unmodifiable.
+	 */
+	public Collection<Entity> getRemoved() {
+		return Collections.unmodifiableCollection(removed.values());
+	}
+
+	/**
+	 * Returns related entity identified by given entity class.
+	 *
+	 * @param <T>         The desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @return The related entity is returned or null of not defined.
+	 */
+	public <T extends Entity> T get(Class<T> entityClass) {
+		return get(entityClass.getSimpleName(), entityClass);
+	}
+
+	/**
+	 * Returns related entity identified by given entity class.
+	 *
+	 * @param <T>          The desired entity type.
+	 * @param relationName The relation name the entity is referenced by.
+	 * @param entityClass  Used as identifier.
+	 * @return The related entity is returned or null of not defined.
+	 */
+	public <T extends Entity> T get(String relationName, Class<T> entityClass) {
+		return entityClass.cast(current.get(relationName));
+	}
+
+	/**
+	 * Replaces a related entity with the given one.
+	 *
+	 * @param entity The new related entity.
+	 */
+	public void set(Entity entity) {
+		set(entity.getClass().getSimpleName(), entity);
+	}
+
+	/**
+	 * Replaces a related entity with the given one.
+	 *
+	 * @param name   The name of the relation the entity is referenced by.
+	 * @param entity The new related entity.
+	 */
+	public void set(String name, Entity entity) {
+		Entity old = current.put(name, entity);
+		if (old != null) {
+			removed.put(name, old);
+		}
+	}
+
+	/**
+	 * Removes a related entity for given entity class.
+	 *
+	 * @param entityClass Used as identifier.
+	 */
+	public void remove(Class<? extends Entity> entityClass) {
+		String key = entityClass.getSimpleName();
+		remove(key, entityClass);
+	}
+
+	/**
+	 * Removes a related entity for given relation name and entity class.
+	 *
+	 * @param name        The name of the relation the entity is referenced by.
+	 * @param entityClass Used as identifier.
+	 */
+	public void remove(String name, Class<? extends Entity> entityClass) {
+		Entity old = current.remove(name);
+		if (old != null) {
+			removed.put(name, old);
+		}
+	}
+
+	/**
+	 * Returns related entity identified by given entity class and
+	 * {@link ContextType}.
+	 *
+	 * @param <T>         The desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @param contextType Used as identifier.
+	 * @return The related entity is returned or null of not defined.
+	 */
+	public <T extends Entity> T get(Class<T> entityClass, ContextType contextType) {
+		return entityClass.cast(current.get(createContextTypeKey(entityClass, contextType)));
+	}
+
+	/**
+	 * Replaces a related entity with the given one.
+	 *
+	 * @param entity      The new related entity.
+	 * @param contextType Used as identifier.
+	 */
+	public void set(Entity entity, ContextType contextType) {
+		String key = createContextTypeKey(entity.getClass(), contextType);
+		Entity old = current.put(key, entity);
+		if (old != null) {
+			removed.put(key, old);
+		}
+	}
+
+	/**
+	 * Removes a related entity for given entity class and {@link ContextType}.
+	 *
+	 * @param entityClass Used as identifier.
+	 * @param contextType Used as identifier.
+	 */
+	public void remove(Class<? extends Entity> entityClass, ContextType contextType) {
+		String key = createContextTypeKey(entityClass, contextType);
+		Entity old = current.remove(key);
+		if (old != null) {
+			removed.put(key, old);
+		}
+	}
+
+	/**
+	 * Clean up list of removed entities.
+	 */
+	void apply() {
+		removed.clear();
+	}
+
+	/**
+	 * Generates a key from given entity class and {@link ContextType}.
+	 *
+	 * @param entityClass Identifier part 1.
+	 * @param contextType Identifier part 2.
+	 * @return A context type dependent key is returned.
+	 */
+	private static String createContextTypeKey(Class<? extends Entity> entityClass, ContextType contextType) {
+		return entityClass.getSimpleName() + '_' + contextType;
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityType.java
new file mode 100644
index 0000000..d4567eb
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityType.java
@@ -0,0 +1,196 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Represents a modeled entity type.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Attribute
+ * @see Relation
+ * @see RelationType
+ */
+public interface EntityType {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of the data source.
+	 *
+	 * @return Name of the data source is returned.
+	 */
+	String getSourceName();
+
+	/**
+	 * Returns the name of this entity type.
+	 *
+	 * @return The name is returned.
+	 */
+	String getName();
+
+	/**
+	 * Returns the ID of this entity type.
+	 *
+	 * @return The ID is returned.
+	 */
+	String getId();
+
+	/**
+	 * Returns all {@link Attribute}s of this entity type.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> Relation attributes are <i>not</i> part of the returned
+	 * {@code List}.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Attribute> getAttributes();
+
+	/**
+	 * Returns the ID {@link Attribute} of this entity type.
+	 *
+	 * @return The ID {@code Attribute} is returned.
+	 * @see Entity#ATTR_ID
+	 */
+	default Attribute getIDAttribute() {
+		return getAttribute(Entity.ATTR_ID);
+	}
+
+	/**
+	 * Returns the name {@link Attribute} of this entity type.
+	 *
+	 * @return The name {@code Attribute} is returned.
+	 * @see Entity#ATTR_NAME
+	 */
+	default Attribute getNameAttribute() {
+		return getAttribute(Entity.ATTR_NAME);
+	}
+
+	/**
+	 * Returns the mime type {@link Attribute} for this entity type.
+	 *
+	 * @return The mime type {@code Attribute} is returned.
+	 * @see Entity#ATTR_MIMETYPE
+	 */
+	default Attribute getMimeTypeAttribute() {
+		return getAttribute(Entity.ATTR_MIMETYPE);
+	}
+
+	/**
+	 * Returns either the {@link Attribute} identified by the given name or the
+	 * corresponding relation {@code Attribute} (foreign key) as returned by
+	 * {@link Relation#getAttribute()}.
+	 *
+	 * @param name The {@code Attribute} identifier.
+	 * @return The associated {@code Attribute} is returned.
+	 * @throws IllegalArgumentException Thrown if neither an {@code Attribute} nor a
+	 *                                  {@link Relation} with given name exists.
+	 */
+	Attribute getAttribute(String name);
+
+	/**
+	 * Returns all {@link Relation}s to other entity types.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getRelations();
+
+	/**
+	 * Returns all {@link Relation}s to allowed parent entity types.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getParentRelations();
+
+	/**
+	 * Returns all available child {@link Relation}s whose relationship is
+	 * {@link RelationType#FATHER_CHILD}.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getChildRelations();
+
+	/**
+	 * Returns all child {@link Relation}s whose relationship is
+	 * {@link RelationType#INFO}.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getInfoRelations();
+
+	/**
+	 * Returns all {@link Relation}s whose relationship is of the given type.
+	 *
+	 * @param relationType The relationship type.
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getRelations(RelationType relationType);
+
+	/**
+	 * Returns a {@link Relation} to given target entity type. At first it is tried
+	 * to find a unambiguous {@code Relation} to given {@code EntityType}. If this
+	 * fails it is tried to identify it by the name of the given {@link EntityType}.
+	 *
+	 * @param target Used as identifier.
+	 * @return The associated {@code Relation} is returned.
+	 * @throws IllegalArgumentException Thrown if a relation to given target entity
+	 *                                  type does not exist.
+	 */
+	Relation getRelation(EntityType target);
+
+	/**
+	 * Returns the {@link Relation} with given target entity type and relation name.
+	 *
+	 * @param target The target entity type of the requested {@code Relation}.
+	 * @param name   The name of the requested {@code Relation}.
+	 * @return The associated {@code Relation} is returned.
+	 * @throws IllegalArgumentException Thrown if {@code Relation} with given target
+	 *                                  entity type and name does not exist.
+	 * @see #getRelation(EntityType)
+	 */
+	Relation getRelation(EntityType target, String name);
+
+	/**
+	 * Creates for each {@link Attribute} a corresponding empty {@link Value} and
+	 * returns them mapped by their name.
+	 *
+	 * @return Returns created empty {@code Value}s mapped by their name.
+	 */
+	default Map<String, Value> createValues() {
+		return getAttributes().stream().map(Attribute::createValue)
+				.collect(Collectors.toMap(Value::getName, Function.identity()));
+	}
+
+	/**
+	 * Returns the name of this entity type.
+	 *
+	 * @return The name of this entity type is returned.
+	 */
+	@Override
+	String toString();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ModelManager.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ModelManager.java
new file mode 100644
index 0000000..2a68f8d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ModelManager.java
@@ -0,0 +1,97 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.Query;
+
+/**
+ * Provides access to any modeled {@link EntityType} within an underlying
+ * application model. A {@link Query}, created by this service, uses these
+ * {@code EntityType}s to access corresponding records.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface ModelManager {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns all available {@link EntityType}s.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	List<EntityType> listEntityTypes();
+
+	/**
+	 * Returns the {@link EntityType} associated with given {@link Entity}.
+	 *
+	 * @param entity Its type name is used as identifier.
+	 * @return {@code EntityType} associated with given entity is returned.
+	 */
+	default EntityType getEntityType(Entity entity) {
+		return getEntityType(entity.getTypeName());
+	}
+
+	/**
+	 * Returns the {@link EntityType} associated with given entity class type.
+	 *
+	 * @param entityClass Used as identifier.
+	 * @return {@code EntityType} associated with given entity class is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} for given type
+	 *                                  does not exist.
+	 */
+	EntityType getEntityType(Class<? extends Entity> entityClass);
+
+	/**
+	 * Returns the {@link EntityType} associated with given entity class and
+	 * {@link ContextType}.
+	 *
+	 * @param entityClass Used as identifier.
+	 * @param contextType Used as identifier.
+	 * @return {@code EntityType} associated with given entity class and {@code
+	 * 		ContextType} is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} for given type
+	 *                                  does not exist.
+	 */
+	EntityType getEntityType(Class<? extends Entity> entityClass, ContextType contextType);
+
+	/**
+	 * Returns the {@link EntityType} identified by given name.
+	 *
+	 * @param name Used as identifier.
+	 * @return {@code EntityType} with given name is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} with given name
+	 *                                  does not exist.
+	 */
+	EntityType getEntityType(String name);
+
+	/**
+	 * Returns the {@link EntityType} identified by given ID.
+	 *
+	 * @param id Used as ID.
+	 * @return {@code EntityType} with given ID is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} with given ID
+	 *                                  does not exist.
+	 */
+	EntityType getEntityTypeById(String id);
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Relation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Relation.java
new file mode 100644
index 0000000..7800bc0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Relation.java
@@ -0,0 +1,116 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Represents a modeled relation.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see RelationType
+ */
+public interface Relation {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * The name of this relation.
+	 *
+	 * @return The name is returned.
+	 */
+	String getName();
+
+	/**
+	 * The source {@link EntityType} of this relation.
+	 *
+	 * @return The source {@code EntityType} is returned.
+	 */
+	EntityType getSource();
+
+	/**
+	 * The target {@link EntityType} of this relation.
+	 *
+	 * @return The target {@code EntityType} is returned.
+	 */
+	EntityType getTarget();
+
+	/**
+	 * Returns the {@link RelationType} type for this relation.
+	 *
+	 * @return The {@code RelationType} is returned.
+	 */
+	RelationType getRelationType();
+
+	/**
+	 * Returns the foreign key {@link Attribute} for this {@link Relation}.
+	 *
+	 * @return The foreign key {@code Attribute} is returned.
+	 */
+	Attribute getAttribute();
+
+	/**
+	 * Creates a new and empty {@link Value} with {@link ValueType#LONG}.
+	 *
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue() {
+		return ValueType.STRING.create(getName());
+	}
+
+	/**
+	 * Returns the name of this relation.
+	 *
+	 * @return Name of this relation is returned.
+	 */
+	@Override
+	String toString();
+
+	/**
+	 * Checks whether this relation is of the same {@link RelationType} as the given
+	 * one and whether the foreign key is in the table of the source entity type
+	 * (or, in other words, if there may be at most 1 related destination object).
+	 *
+	 * @param relationType The {@code RelationType}.
+	 * @return Returns {@code true} this relation's {@code RelationType} is equal
+	 *         with the given one and it is is an outgoing relation.
+	 */
+	boolean isOutgoing(RelationType relationType);
+
+	/**
+	 * Checks whether this relation is of the same {@link RelationType} as the given
+	 * one and whether the foreign key is in the table of the target entity type
+	 * (or, in other words, if there may be more than one related destination
+	 * objects).
+	 *
+	 * @param relationType The {@code RelationType}.
+	 * @return Returns {@code true} this relation's {@code RelationType} is equal
+	 *         with the given one and it is is an incoming relation.
+	 */
+	boolean isIncoming(RelationType relationType);
+
+	/**
+	 * Checks whether this relation is a N to M relation.
+	 * 
+	 * @return Returns {@code true} if this relation is N to M.
+	 */
+	boolean isNtoM();
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationStore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationStore.java
new file mode 100644
index 0000000..3fb0c6c
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationStore.java
@@ -0,0 +1,108 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+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 org.eclipse.mdm.api.base.model.Deletable;
+
+/**
+ * Holds related entities of any kind and keeps track of modifications.
+ */
+public final class RelationStore {
+
+	private final Map<String, List<? extends Deletable>> added = new HashMap<>(0);
+	private final Map<String, List<? extends Deletable>> removed = new HashMap<>(0);
+
+	/**
+	 * Returns current set of related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<String, List<? extends Deletable>> getAdded() {
+		return Collections.unmodifiableMap(added);
+	}
+
+	/**
+	 * Returns current set of removed related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<String, List<? extends Deletable>> getRemoved() {
+		return Collections.unmodifiableMap(removed);
+	}
+
+	/**
+	 * Returns related child entities of given type.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @return Returned {@code List} is unmodifiable.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> List<T> get(String relation) {
+		return Collections.unmodifiableList((List<T>) added.computeIfAbsent(relation, k -> new ArrayList<>()));
+	}
+
+	/**
+	 * Sorts the child entities with given {@code Comparator}.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @param comparator  Used for sorting.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> void sort(String relation, Comparator<? super T> comparator) {
+		List<T> children = (List<T>) added.get(relation);
+		if (children != null) {
+			children.sort(comparator);
+		}
+	}
+
+	/**
+	 * Adds given child entity.
+	 *
+	 * @param child The new child.
+	 */
+	@SuppressWarnings("unchecked")
+	public void add(String relation, Deletable relatedEntity) {
+		removed.getOrDefault(relation, new ArrayList<>()).remove(relatedEntity);
+		((List<Deletable>) added.computeIfAbsent(relation, k -> new ArrayList<>())).add(relatedEntity);
+	}
+
+	/**
+	 * Removes given child entity.
+	 *
+	 * @param relatedEntity The child which will be removed.
+	 */
+	@SuppressWarnings("unchecked")
+	public void remove(String relation, Deletable relatedEntity) {
+		added.getOrDefault(relation, new ArrayList<>()).remove(relatedEntity);
+		((List<Deletable>) removed.computeIfAbsent(relation, k -> new ArrayList<>())).add(relatedEntity);
+	}
+
+	/**
+	 * Clean up list of removed entities.
+	 */
+	void apply() {
+		removed.clear();
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationType.java
new file mode 100644
index 0000000..26b9cd5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationType.java
@@ -0,0 +1,49 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+/**
+ * RelationType enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Relation
+ */
+public enum RelationType {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Represents a hierarchical relation between two {@link EntityType}s e.g.:
+	 * {@code Test} and {@code TestStep}.
+	 */
+	FATHER_CHILD,
+
+	/**
+	 * Represents an informational relation between two {@link EntityType}s e.g.:
+	 * {@code Measurement} and {@code ParameterSet}.
+	 */
+	INFO,
+
+	/**
+	 * Represents an inheritance relation between two {@link EntityType}s.
+	 */
+	INHERITANCE
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/file/FileService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/file/FileService.java
new file mode 100644
index 0000000..9a552cc
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/file/FileService.java
@@ -0,0 +1,239 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.file;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Collection;
+
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+
+/**
+ * Provides stream and download operations to access externally linked files.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface FileService {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Sequential download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once.
+	 *
+	 * @param entity    Used for security checks.
+	 * @param target    Must be a directory.
+	 * @param fileLinks Collection of {@code FileLink}s to download.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	default void downloadSequential(Entity entity, Path target, Collection<FileLink> fileLinks) throws IOException {
+		downloadSequential(entity, target, fileLinks, null);
+	}
+
+	/**
+	 * Sequential download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once. The
+	 * download progress may be traced with a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param target           Must be a directory.
+	 * @param fileLinks        Collection of {@code FileLink}s to download.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	void downloadSequential(Entity entity, Path target, Collection<FileLink> fileLinks,
+			ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Parallel download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once.
+	 *
+	 * @param entity    Used for security checks.
+	 * @param target    Must be a directory.
+	 * @param fileLinks Collection of {@code FileLink}s to download.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	default void downloadParallel(Entity entity, Path target, Collection<FileLink> fileLinks) throws IOException {
+		downloadParallel(entity, target, fileLinks, null);
+	}
+
+	/**
+	 * Parallel download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once. The
+	 * download progress may be traced with a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param target           Must be a directory.
+	 * @param fileLinks        Collection of {@code FileLink}s to download.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	void downloadParallel(Entity entity, Path target, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException;
+
+
+	/**
+	 * Downloads given {@link FileLink} into given target {@code Path}.
+	 *
+	 * @param entity   Used for security checks.
+	 * @param target   Must be a directory.
+	 * @param fileLink The {@code FileLink} to download.
+	 * @throws IOException Thrown if unable to download file.
+	 */
+	default void download(Entity entity, Path target, FileLink fileLink) throws IOException {
+		download(entity, target, fileLink, null);
+	}
+
+	/**
+	 * Downloads given {@link FileLink} into given target {@code Path}. The download
+	 * progress may be traced with a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param target           Must be a directory.
+	 * @param fileLink         The {@code FileLink} to download.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to download file.
+	 */
+	void download(Entity entity, Path target, FileLink fileLink, ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Opens an {@code InputStream} for given {@link FileLink}. The returned stream
+	 * should be consumed with a try-with-resources statement to ensure the stream
+	 * is closed properly, e.g:
+	 *
+	 * <pre>
+	 * try (InputStream is = openStream(entity, fileLink)) {
+	 * 	// do something useful
+	 * }
+	 * </pre>
+	 *
+	 * @param entity   Used for security checks.
+	 * @param fileLink The {@code FileLink} to be provided as a stream.
+	 * @return A consumable {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to provide as stream.
+	 */
+	default InputStream openStream(Entity entity, FileLink fileLink) throws IOException {
+		return openStream(entity, fileLink, null);
+	}
+
+	/**
+	 * Opens an {@code InputStream} for given {@link FileLink}. The progress of the
+	 * stream consumption may be traced with a progress listener. The returned
+	 * stream should be consumed with a try-with-resources statement to ensure the
+	 * stream is closed properly, e.g:
+	 *
+	 * <pre>
+	 * try (InputStream is = openStream(entity, fileLink)) {
+	 * 	// do something useful
+	 * }
+	 * </pre>
+	 *
+	 * @param entity           Used for security checks.
+	 * @param fileLink         The {@code FileLink} to be provided as a stream.
+	 * @param progressListener The progress listener.
+	 * @return A consumable {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to provide as stream.
+	 */
+	InputStream openStream(Entity entity, FileLink fileLink, ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Loads the file size for given {@link FileLink}. The file size is stored in
+	 * the given {@code FileLink}.
+	 *
+	 * @param entity   Used for security checks.
+	 * @param fileLink The {@code FileLink} whose file size is requested.
+	 * @throws IOException Thrown if unable to load file size.
+	 */
+	void loadSize(Entity entity, FileLink fileLink) throws IOException;
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * A {@link FileService} consumer may implement this interface to get notified
+	 * about stream or download progress.
+	 */
+	@FunctionalInterface
+	interface ProgressListener {
+
+		/**
+		 * Progress notification.
+		 *
+		 * @param bytes   Number of transferred bytes since last notification.
+		 * @param percent The overall percentage, where percent p &isin; [0.0, 1.0].
+		 */
+		void progress(int bytes, float percent);
+
+	}
+	
+	/**
+	 * Sequential upload of given {@link FileLink}s. Local {@link Path}s linked
+	 * multiple times are uploaded only once. The upload progress may be traced with
+	 * a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param fileLinks        Collection of {@code FileLink}s to upload.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to upload files.
+	 */
+	public void uploadSequential(Entity entity, Collection<FileLink> fileLinks, ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Parallel upload of given {@link FileLink}s. Local {@link Path}s linked
+	 * multiple times are uploaded only once. The upload progress may be traced with
+	 * a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param fileLinks        Collection of {@code FileLink}s to upload.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to upload files.
+	 */
+	public void uploadParallel(Entity entity, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException;
+
+	/**
+	 * Deletes given {@link FileLink}s form the remote storage.
+	 *
+	 * @param entity    Used for security checks.
+	 * @param fileLinks Collection of {@code FileLink}s to delete.
+	 */
+	public void delete(Entity entity, Collection<FileLink> fileLinks);
+
+	/**
+	 * Deletes given {@link FileLink} form the remote storage.
+	 *
+	 * @param entity   Used for security checks.
+	 * @param fileLink The {@code FileLink}s to delete.
+	 */
+	public void delete(Entity entity, FileLink fileLink);
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/AnyTypeValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/AnyTypeValuesBuilder.java
new file mode 100644
index 0000000..1c2d1ed
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/AnyTypeValuesBuilder.java
@@ -0,0 +1,207 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.time.LocalDateTime;
+
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder adds values to the {@link WriteRequest} of types listed below.
+ * It is possible to add a sequence where all of its values are valid.
+ * Additionally it is possible to provide a validity flag for each single value.
+ * In either case neither values nor flags are allowed to be {@code
+ * null}. Furthermore if values and flags are given, then their length must be
+ * equal.
+ *
+ * <ul>
+ * <li>{@link ScalarType#STRING}</li>
+ * <li>{@link ScalarType#DATE}</li>
+ * <li>{@link ScalarType#BOOLEAN}</li>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * <li>{@link ScalarType#BYTE_STREAM}</li>
+ * <li>{@link ScalarType#FLOAT_COMPLEX}</li>
+ * <li>{@link ScalarType#DOUBLE_COMPLEX}</li>
+ * <li>{@link ScalarType#FILE_LINK}</li>
+ * <li>{@link ScalarType#BLOB}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class AnyTypeValuesBuilder extends ComplexNumericalValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values will be added to.
+	 */
+	AnyTypeValuesBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@code String} values to the {@link WriteRequest} with a global
+	 * validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code String} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer stringValues(String[] values) {
+		createValues(ScalarType.STRING, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code String} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code String} array sequence.
+	 * @param flags  The validity flags for each {@code String} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer stringValues(String[] values, boolean[] flags) {
+		createValues(ScalarType.STRING, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code LocalDateTime} values to the {@link WriteRequest} with a
+	 * global validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code LocalDateTime} array sequence.
+	 * @return The {@link IndependentBuilder} is returned.
+	 */
+	public IndependentBuilder dateValues(LocalDateTime[] values) {
+		createValues(ScalarType.DATE, values);
+		return new IndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code LocalDateTime} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code LocalDateTime} array sequence.
+	 * @param flags  The validity flags for each {@code LocalDateTime} value.
+	 * @return The {@link IndependentBuilder} is returned.
+	 */
+	public IndependentBuilder dateValues(LocalDateTime[] values, boolean[] flags) {
+		createValues(ScalarType.DATE, values, flags);
+		return new IndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code boolean} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code boolean} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer booleanValues(boolean[] values) {
+		createValues(ScalarType.BOOLEAN, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code boolean} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code boolean} array sequence.
+	 * @param flags  The validity flags for each {@code boolean} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer booleanValues(boolean[] values, boolean[] flags) {
+		createValues(ScalarType.BOOLEAN, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code byte[]} values to the {@link WriteRequest} with a global
+	 * validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code byte[]} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer byteStreamValues(byte[][] values) {
+		createValues(ScalarType.BYTE_STREAM, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code byte[]} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code byte[]} array sequence.
+	 * @param flags  The validity flags for each {@code byte[]} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer byteStreamValues(byte[][] values, boolean[] flags) {
+		createValues(ScalarType.BYTE_STREAM, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link FileLink} values to the {@link WriteRequest} with a global
+	 * validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code FileLink} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer fileLinkValues(FileLink[] values) {
+		createValues(ScalarType.FILE_LINK, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link FileLink} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code FileLink} array sequence.
+	 * @param flags  The validity flags for each {@code FileLink} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer fileLinkValues(FileLink[] values, boolean[] flags) {
+		createValues(ScalarType.FILE_LINK, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	// TODO: is it possible to provide a blob for each row or is the blob for
+	// the whole column?!
+	// we assume the latter - one blob for the whole column!
+	public WriteRequestFinalizer blobValue(Object values) {
+		createValues(ScalarType.BLOB, values);
+		throw new UnsupportedOperationException("Not implemented.");
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/BaseValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/BaseValuesBuilder.java
new file mode 100644
index 0000000..a9f3bca
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/BaseValuesBuilder.java
@@ -0,0 +1,100 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.lang.reflect.Array;
+
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This is a base values builder provides methods for configuring values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+abstract class BaseValuesBuilder {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final WriteRequest writeRequest;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values and corresponding
+	 *                     {@link ScalarType} will be applied to.
+	 */
+	BaseValuesBuilder(WriteRequest writeRequest) {
+		this.writeRequest = writeRequest;
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Adds given value sequence and sets the corresponding {@link ScalarType} as
+	 * the raw {@code ScalarType}.
+	 *
+	 * @param scalarType The {@code ScalarType}.
+	 * @param values     The array value sequence must be assignment compatible with
+	 *                   the type represented by the given {@code ScalarType}.
+	 */
+	protected final void createValues(ScalarType scalarType, Object values) {
+		if (values == null) {
+			throw new IllegalArgumentException("Values is not allowed to be null.");
+		}
+
+		getWriteRequest().setRawScalarType(scalarType);
+		getWriteRequest().setValues(values);
+	}
+
+	/**
+	 * Adds given value sequence, associated validity flags and sets the
+	 * corresponding {@link ScalarType} as the raw {@code ScalarType}.
+	 *
+	 * @param scalarType The {@code ScalarType}.
+	 * @param values     The array value sequence must be assignment compatible with
+	 *                   the type represented by the given {@code ScalarType}.
+	 * @param flags      The validity flags for each value in the values sequence.
+	 */
+	protected final void createValues(ScalarType scalarType, Object values, boolean[] flags) {
+		if (values == null || flags == null) {
+			throw new IllegalArgumentException("Neither values nor flags are allowed to be null.");
+		} else if (Array.getLength(values) != flags.length) {
+			throw new IllegalArgumentException("Length of values and flags must be equal.");
+		}
+
+		getWriteRequest().setRawScalarType(scalarType);
+		getWriteRequest().setValues(values, flags);
+	}
+
+	/**
+	 * Returns the {@link WriteRequest}.
+	 *
+	 * @return The {@code WriteRequest} is returned.
+	 */
+	protected final WriteRequest getWriteRequest() {
+		return writeRequest;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ComplexNumericalValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ComplexNumericalValuesBuilder.java
new file mode 100644
index 0000000..f5b37ea
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ComplexNumericalValuesBuilder.java
@@ -0,0 +1,115 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.DoubleComplex;
+import org.eclipse.mdm.api.base.model.FloatComplex;
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder adds values to the {@link WriteRequest} of types listed below.
+ * It is possible to add a sequence where all of its values are valid.
+ * Additionally it is possible to provide a validity flag for each single value.
+ * In either case neither values nor flags are allowed to be {@code
+ * null}. Furthermore if values and flags are given, then their length must be
+ * equal.
+ *
+ * <ul>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * <li>{@link ScalarType#FLOAT_COMPLEX}</li>
+ * <li>{@link ScalarType#DOUBLE_COMPLEX}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ComplexNumericalValuesBuilder extends NumericalValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values will be added to.
+	 */
+	ComplexNumericalValuesBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@link FloatComplex} values to the {@link WriteRequest} with a
+	 * global validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code FloatComplex} array sequence.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder floatComplexValues(FloatComplex[] values) {
+		createValues(ScalarType.FLOAT_COMPLEX, values);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link FloatComplex} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code FloatComplex} array sequence.
+	 * @param flags  The validity flags for each {@code FloatComplex} value.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder floatComplexValues(FloatComplex[] values, boolean[] flags) {
+		createValues(ScalarType.FLOAT_COMPLEX, values, flags);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link DoubleComplex} values to the {@link WriteRequest} with a
+	 * global validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code DoubleComplex} array sequence.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder doubleComplexValues(DoubleComplex[] values) {
+		createValues(ScalarType.DOUBLE_COMPLEX, values);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link DoubleComplex} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code DoubleComplex} array sequence.
+	 * @param flags  The validity flags for each {@code DoubleComplex} value.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder doubleComplexValues(DoubleComplex[] values, boolean[] flags) {
+		createValues(ScalarType.DOUBLE_COMPLEX, values, flags);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ExternalComponent.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ExternalComponent.java
new file mode 100644
index 0000000..822e26a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ExternalComponent.java
@@ -0,0 +1,20 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+public final class ExternalComponent {
+
+	// TODO
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/IndependentBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/IndependentBuilder.java
new file mode 100644
index 0000000..90942cd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/IndependentBuilder.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder allows to configure numerically sortable measured values to be
+ * independent, which means the measured values do not depend on those of other
+ * {@link Channel}s within their common {@link ChannelGroup}. The numerically
+ * sortable types are listed below:
+ *
+ * <ul>
+ * <li>{@link ScalarType#DATE}</li>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class IndependentBuilder extends WriteRequestFinalizer {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest}, whose measured values of the
+	 *                     underlying {@link Channel} may be marked as independent.
+	 */
+	IndependentBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Triggers the measured values of the underlying {@link Channel} to be
+	 * independent.
+	 *
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public final WriteRequestFinalizer independent() {
+		getWriteRequest().setIndependent();
+		return this;
+	}
+
+	/**
+	 * Triggers the measured values of the underlying {@link Channel} to be
+	 * independent or not, depending on the value specified.
+	 *
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public final WriteRequestFinalizer independent(boolean independent) {
+		getWriteRequest().setIndependent(independent);
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/NumericalValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/NumericalValuesBuilder.java
new file mode 100644
index 0000000..45baeb0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/NumericalValuesBuilder.java
@@ -0,0 +1,209 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder adds values to the {@link WriteRequest} of types listed below.
+ * It is possible to add a sequence where all of its values are valid.
+ * Additionally it is possible to provide a validity flag for each single value.
+ * In either case neither values nor flags are allowed to be {@code
+ * null}. Furthermore if values and flags are given, then their length must be
+ * equal.
+ *
+ * <ul>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class NumericalValuesBuilder extends BaseValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values will be added to.
+	 */
+	NumericalValuesBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@code byte} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code byte} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder byteValues(byte[] values) {
+		createValues(ScalarType.BYTE, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code byte} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code byte} array sequence.
+	 * @param flags  The validity flags for each {@code byte} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder byteValues(byte[] values, boolean[] flags) {
+		createValues(ScalarType.BYTE, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code short} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code short} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder shortValues(short[] values) {
+		createValues(ScalarType.SHORT, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code short} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code short} array sequence.
+	 * @param flags  The validity flags for each {@code short} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder shortValues(short[] values, boolean[] flags) {
+		createValues(ScalarType.SHORT, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code int} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code int} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder integerValues(int[] values) {
+		createValues(ScalarType.INTEGER, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code int} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code int} array sequence.
+	 * @param flags  The validity flags for each {@code int} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder integerValues(int[] values, boolean[] flags) {
+		createValues(ScalarType.INTEGER, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code long} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code long} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder longValues(long[] values) {
+		createValues(ScalarType.LONG, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code long} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code long} array sequence.
+	 * @param flags  The validity flags for each {@code long} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder longValues(long[] values, boolean[] flags) {
+		createValues(ScalarType.LONG, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code float} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code float} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder floatValues(float[] values) {
+		createValues(ScalarType.FLOAT, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code float} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code float} array sequence.
+	 * @param flags  The validity flags for each {@code float} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder floatValues(float[] values, boolean[] flags) {
+		createValues(ScalarType.FLOAT, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code double} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code double} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder doubleValues(double[] values) {
+		createValues(ScalarType.DOUBLE, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code double} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code double} array sequence.
+	 * @param flags  The validity flags for each {@code double} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder doubleValues(double[] values, boolean[] flags) {
+		createValues(ScalarType.DOUBLE, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequest.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequest.java
new file mode 100644
index 0000000..26fb806
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequest.java
@@ -0,0 +1,268 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * This class provides all required informations to load measured values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class ReadRequest {
+	public enum ValuesMode {
+		/**
+		 * MeasuredValues will contain the final values, calculated for non-explicit
+		 * sequence representations using generation parameters and, if applicable, the
+		 * raw values. No generation parameters are returned in the resulting
+		 * MeasuredValues, {@link SequenceRepresentation} will be EXPLICIT.
+		 */
+		CALCULATED,
+		/**
+		 * MeasuredValues will contain the (raw) values and generation parameters as
+		 * present in the storage.
+		 */
+		STORAGE
+	}
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<Channel, Unit> channels = new HashMap<>();
+	private final ChannelGroup channelGroup;
+
+	private boolean loadAllChannels;
+
+	private int requestSize = 100_000;
+	private int startIndex;
+
+	private ValuesMode valuesMode = ValuesMode.CALCULATED;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param readRequest The previous {@link ReadRequest}.
+	 */
+	ReadRequest(ReadRequest readRequest) {
+		this(readRequest.getChannelGroup());
+		channels.putAll(readRequest.getChannels());
+		loadAllChannels = readRequest.loadAllChannels;
+		requestSize = readRequest.getRequestSize();
+		startIndex = readRequest.getStartIndex() + readRequest.getRequestSize();
+		valuesMode = readRequest.getValuesMode();
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param channelGroup The {@link ChannelGroup} is the source entity to access
+	 *                     measured values.
+	 */
+	private ReadRequest(ChannelGroup channelGroup) {
+		this.channelGroup = channelGroup;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link ReadRequestBuilder} with the given {@link ChannelGroup}
+	 * as the source entity for the requested measured values.
+	 *
+	 * <pre>
+	 * ReadRequest readRequest1 = ReadRequest.create(ChannelGroup).allChannels() // load
+	 * 																			// values
+	 * 																			// of
+	 * 																			// all
+	 * 																			// related
+	 * 																			// channels
+	 * 		.allValues() // load all values of each channel
+	 * 		.get();
+	 *
+	 * ReadRequest readRequest2 = ReadRequest.create(ChannelGroup).channels(channel1, channel2) // load
+	 * 																							// measured
+	 * 																							// values
+	 * 																							// of
+	 * 																							// these
+	 * 																							// channels
+	 * 		.requestSize(1_000) // load 1000 values of each channel (default
+	 * 							// is 100_000)
+	 * 		.get();
+	 * </pre>
+	 *
+	 * @param channelGroup Used to access measured values.
+	 * @return Returns the {@link ReadRequestBuilder}.
+	 */
+	public static ReadRequestBuilder create(ChannelGroup channelGroup) {
+		return new ReadRequestBuilder(new ReadRequest(channelGroup));
+	}
+
+	/**
+	 * Returns the selected {@link Channel}s whose values will be loaded and the
+	 * corresponding {@link Unit} configuration.
+	 *
+	 * @return The returned {@code Map} is empty, if this request is configured to
+	 *         load values of all related {@code Channel}s.
+	 */
+	public Map<Channel, Unit> getChannels() {
+		return Collections.unmodifiableMap(channels);
+	}
+
+	/**
+	 * Returns the {@link ChannelGroup} which will be used as the source entity to
+	 * access measured values.
+	 *
+	 * @return The measured values source, the {@code ChannelGroup} is returned.
+	 */
+	public ChannelGroup getChannelGroup() {
+		return channelGroup;
+	}
+
+	/**
+	 * Checks whether to load measured values of all related {@link Channel}s.
+	 *
+	 * @return True if this request is configured to load values of all {@code
+	 * 		Channel}s.
+	 */
+	public boolean isLoadAllChannels() {
+		return loadAllChannels;
+	}
+
+	/**
+	 * Returns the number of values that are loaded per {@link Channel} .
+	 *
+	 * @return The number of values per {@code Channel} per is returned.
+	 */
+	public int getRequestSize() {
+		return requestSize;
+	}
+
+	/**
+	 * Returns the overall index of the measured values within the underlying
+	 * {@link ChannelGroup}. This index is used while processing this request and
+	 * means how many values of the values sequences will be skipped.
+	 *
+	 * @return The overall start index is returned.
+	 */
+	public int getStartIndex() {
+		return startIndex;
+	}
+
+	/**
+	 * Returns the {link ValuesMode} for measured values retrieval.
+	 *
+	 * @return The valuesMode is returned.
+	 */
+	public ValuesMode getValuesMode() {
+		return valuesMode;
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Adds a new {@link Channel} whose measured values have to be loaded. The
+	 * measured values will be retrieved in the unit they were stored.
+	 *
+	 * @param channel This {@code Channel} has to related to the underlying
+	 *                {@link ChannelGroup}.
+	 */
+	void addChannel(Channel channel) {
+		addChannel(channel, channel.getUnit());
+	}
+
+	/**
+	 * Adds a new {@link Channel} whose measured values have to be loaded. The
+	 * measured values will be retrieved in the given unit.
+	 *
+	 * <p>
+	 * <b>Note:</b> The processing of this request may fail if it is not possible to
+	 * convert the values.
+	 *
+	 * @param channel This {@code Channel} has to related to the underlying
+	 *                {@link ChannelGroup}.
+	 * @param unit    {@code Unit} the measured values have to be loaded in.
+	 */
+	void addChannel(Channel channel, Unit unit) {
+		channels.put(channel, unit);
+	}
+
+	/**
+	 * Configures this request to retrieve measured values of all related
+	 * {@link Channel}s.
+	 */
+	void setLoadAllChannels() {
+		loadAllChannels = true;
+		channels.clear();
+	}
+
+	/**
+	 * Sets the number of values that will be loaded per {@link Channel} while
+	 * processing this request.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the request size is zero, then all available measured values
+	 * will be loaded for each configured {@link Channel}.
+	 *
+	 * @param requestSize The number of values loaded per {@code Channel}.
+	 */
+	void setRequestSize(int requestSize) {
+		this.requestSize = requestSize;
+	}
+
+	/**
+	 * Sets the number of values that will be skipped.
+	 *
+	 * @param startIndex The number of values that will be skipped.
+	 */
+	void setStartIndex(int startIndex) {
+		this.startIndex = startIndex;
+	}
+
+	/**
+	 * Sets the {@link ValuesMode} for measured values retrieval.
+	 * 
+	 * @param valuesMode The {@link VAluesMode} to set.
+	 */
+	void setValuesMode(ValuesMode valuesMode) {
+		this.valuesMode = valuesMode;
+	}
+
+	/**
+	 * Checks whether there are still more values to retrieve.
+	 *
+	 * @return Returns true if there are more values to retrieve.
+	 */
+	boolean hasNext() {
+		return getStartIndex() + getRequestSize() < getChannelGroup().getNumberOfValues().intValue();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestBuilder.java
new file mode 100644
index 0000000..f25c615
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestBuilder.java
@@ -0,0 +1,192 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.mdm.api.base.massdata.ReadRequest.ValuesMode;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * Builds measured values read request configurations.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class ReadRequestBuilder {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ReadRequest readRequest;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param readRequest The {@link ReadRequest} that will be configured.
+	 */
+	ReadRequestBuilder(ReadRequest readRequest) {
+		this.readRequest = readRequest;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Configures the {@link ReadRequest} to retrieve measured values of all related
+	 * {@link Channel}s.
+	 *
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder allChannels() {
+		readRequest.setLoadAllChannels();
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Channel}s to the underlying {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> {@code Channel}s added with this method will be ignored, once
+	 * {@link #allChannels()} was called.
+	 *
+	 * @param channels The {@code Channel}s whose measured values will be loaded.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder channels(List<Channel> channels) {
+		channels.forEach(readRequest::addChannel);
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Channel}s to the underlying {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> {@code Channel}s added with this method will be ignored, once
+	 * {@link #allChannels()} was called.
+	 *
+	 * @param channels The {@code Channel}s whose measured values will be loaded.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder channels(Channel... channels) {
+		Arrays.stream(channels).forEach(readRequest::addChannel);
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Channel} to the underlying {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> {@code Channel} added with this method will be ignored, once
+	 * {@link #allChannels()} was called.
+	 *
+	 * @param channel The {@code Channel} whose measured values will be loaded.
+	 * @param unit    The unit of the loaded measured values.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder channel(Channel channel, Unit unit) {
+		readRequest.addChannel(channel, unit);
+		return this;
+	}
+
+	/**
+	 * Configures the valuesMode.
+	 * 
+	 * @param valuesMode {@link ValuesMode} to use for the read request.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder valuesMode(ReadRequest.ValuesMode valuesMode) {
+		readRequest.setValuesMode(valuesMode);
+		return this;
+	}
+
+	/**
+	 * Configures the {@link ReadRequest} to load all measured values of each
+	 * configured {@link Channel} and returns the configured {@code
+	 * ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> Before calling this the {@code Channel}s whose measured values
+	 * have to be loaded must be configured.
+	 *
+	 * @return This builder is returned.
+	 */
+	public ReadRequest allValues() {
+		readRequest.setStartIndex(0);
+		readRequest.setRequestSize(0);
+		return readRequest;
+	}
+
+	/**
+	 * Configures the {@link ReadRequest} to load the specified number of values for
+	 * each {@link Channel}. this is a terminal operation returning the built
+	 * {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the request size is zero, then all available measured values
+	 * will be loaded for each configured {@link Channel}.
+	 *
+	 * @param requestSize The request size.
+	 * @return the {@link ReadRequest}
+	 * @throws IllegalArgumentException Thrown if the request size is smaller than
+	 *                                  0.
+	 */
+	public ReadRequest values(int requestSize) {
+		readRequest.setStartIndex(0);
+		readRequest.setRequestSize(requestSize);
+		return readRequest;
+	}
+
+	/**
+	 * Configures the {@link ReadRequest} to load the specified number of values
+	 * from a specified start index for each {@link Channel}. this is a terminal
+	 * operation returning the built {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the request size is zero, then all available measured values
+	 * will be loaded for each configured {@link Channel}.
+	 *
+	 * @param startIndex  The start index.
+	 * @param requestSize The request size.
+	 * @return the {@link ReadRequest}
+	 * @throws IllegalArgumentException Thrown if the request size is smaller than 0
+	 *                                  or if the start index is smaller than 0.
+	 */
+	public ReadRequest values(int startIndex, int requestSize) {
+		readRequest.setStartIndex(startIndex);
+		readRequest.setRequestSize(requestSize);
+		return readRequest;
+	}
+
+	/**
+	 * Returns an {@link ReadRequestIterable} to iterate over all available
+	 * {@link ReadRequest}s.
+	 *
+	 * @return The {@code ReadRequestIterable} is returned.
+	 */
+	public ReadRequestIterable createIterable() {
+		return new ReadRequestIterable(readRequest);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestIterable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestIterable.java
new file mode 100644
index 0000000..5e627b4
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestIterable.java
@@ -0,0 +1,84 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * This is an read request iterable for comfortable processing of subsequent
+ * {@link ReadRequest}s
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class ReadRequestIterable implements Iterable<ReadRequest>, Iterator<ReadRequest> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private ReadRequest readRequest;
+	private int count;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param readRequest The {@link ReadRequest}.
+	 */
+	ReadRequestIterable(ReadRequest readRequest) {
+		this.readRequest = readRequest;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean hasNext() {
+		return count == 0 || readRequest.hasNext();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public ReadRequest next() {
+		if (hasNext()) {
+			readRequest = count == 0 ? readRequest : new ReadRequest(readRequest);
+			count++;
+			return readRequest;
+		}
+
+		throw new NoSuchElementException("Subsequent read request is not available.");
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Iterator<ReadRequest> iterator() {
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitBuilder.java
new file mode 100644
index 0000000..4335172
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitBuilder.java
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * This builder allows to specify a source {@link Unit} which is different to
+ * the origin {@code Unit} of the underlying {@link Channel}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class UnitBuilder extends WriteRequestFinalizer {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest}, whose measured value's source
+	 *                     {@link Unit} may be defined.
+	 */
+	UnitBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Sets a source {@link Unit} for the previously defined measured values.
+	 *
+	 * @param sourceUnit The source {@code Unit}.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer sourceUnit(Unit sourceUnit) {
+		getWriteRequest().setSourceUnit(sourceUnit);
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitIndependentBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitIndependentBuilder.java
new file mode 100644
index 0000000..f0f15db
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitIndependentBuilder.java
@@ -0,0 +1,75 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * This builder allows to specify a source {@link Unit} which is different to
+ * the origin {@code Unit} of the underlying {@link Channel}. In Addition to
+ * that this builder allows to configure numerically sortable measured values to
+ * be independent, which means the measured values do not depend on those of
+ * other {@link Channel}s within their common {@link ChannelGroup}. The
+ * numerically sortable types are listed below:
+ *
+ * <ul>
+ * <li>{@link ScalarType#DATE}</li>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class UnitIndependentBuilder extends IndependentBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} whose measured values source
+	 *                     {@link Unit} may be changed or marked as independent.
+	 */
+	UnitIndependentBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Sets a source {@link Unit} for the previously defined measured values.
+	 *
+	 * @param sourceUnit The source {@code Unit}.
+	 * @return The {@link IndependentBuilder} is returned.
+	 */
+	public IndependentBuilder sourceUnit(Unit sourceUnit) {
+		getWriteRequest().setSourceUnit(sourceUnit);
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequest.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequest.java
new file mode 100644
index 0000000..a08bd99
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequest.java
@@ -0,0 +1,370 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * Holds required data to write mass data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class WriteRequest {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final List<ExternalComponent> externalComponents = new ArrayList<>();
+	private final ChannelGroup channelGroup;
+	private final Channel channel;
+	private final AxisType axisType;
+
+	private SequenceRepresentation sequenceRepresentation;
+	private double[] generationParameters;
+	private boolean independent;
+
+	private ScalarType rawScalarType;
+	private Object values;
+	private boolean allValid;
+	private boolean[] flags;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param channelGroup The {@link ChannelGroup} for this request.
+	 * @param channel      The {@link Channel} specified mass data will be dedicated
+	 *                     to.
+	 * @param axisType     The {@link AxisType} of the written mass data.
+	 */
+	private WriteRequest(ChannelGroup channelGroup, Channel channel, AxisType axisType) {
+		this.channelGroup = channelGroup;
+		this.channel = channel;
+		this.axisType = axisType;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Starts a new {@link WriteRequest} by returning a {@link WriteRequestBuilder}.
+	 *
+	 * @param channelGroup The {@link ChannelGroup} for this request.
+	 * @param channel      The {@link Channel} specified mass data will be dedicated
+	 *                     to.
+	 * @param axisType     The {@link AxisType} of the written mass data.
+	 * @return A {@code WriteRequestBuilder} is returned.
+	 */
+	public static WriteRequestBuilder create(ChannelGroup channelGroup, Channel channel, AxisType axisType) {
+		return new WriteRequestBuilder(new WriteRequest(channelGroup, channel, axisType));
+	}
+
+	/**
+	 * Returns the {@link ChannelGroup} of this request.
+	 *
+	 * @return The {@code ChannelGroup} is returned.
+	 */
+	public ChannelGroup getChannelGroup() {
+		return channelGroup;
+	}
+
+	/**
+	 * Returns the {@link Channel} of this request.
+	 *
+	 * @return The {@code Channel} is returned.
+	 */
+	public Channel getChannel() {
+		return channel;
+	}
+
+	/**
+	 * Returns the {@link AxisType} of this request.
+	 *
+	 * @return The {@code AxisType} is returned.
+	 */
+	public AxisType getAxisType() {
+		return axisType;
+	}
+
+	/**
+	 * Returns the {@link SequenceRepresentation} of this request.
+	 *
+	 * @return The {@code SequenceRepresentation} is returned.
+	 */
+	public SequenceRepresentation getSequenceRepresentation() {
+		return sequenceRepresentation;
+	}
+
+	/**
+	 * Returns the generation parameters of this request. The length of the returned
+	 * array depends on the {@link SequenceRepresentation} of this request.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> In case of an implicit sequence representation this method will
+	 * always return an empty array since these generation parameters are correctly
+	 * typed and stored as measured values.
+	 *
+	 * @return If none available, then an empty array is returned.
+	 */
+	public double[] getGenerationParameters() {
+		return generationParameters == null ? new double[0] : generationParameters.clone();
+	}
+
+	/**
+	 * Returns the independent flag of this request.
+	 *
+	 * @return Returns {@code true} if the measured values do not depend on those of
+	 *         other {@link Channel}s within their common {@link ChannelGroup}.
+	 */
+	public boolean isIndependent() {
+		return independent;
+	}
+
+	/**
+	 * Checks whether this request has measured values.
+	 *
+	 * @return Returns {@code true} if {@link SequenceRepresentation#isExternal()}
+	 *         returns {@code false}.
+	 * @see #hasExternalComponents()
+	 */
+	public boolean hasValues() {
+		return !getSequenceRepresentation().isExternal();
+	}
+
+	/**
+	 * Returns the stored measured values.
+	 *
+	 * @return The measured values are returned.
+	 * @throws IllegalStateException Thrown if values are not available.
+	 */
+	public Object getValues() {
+		if (hasValues()) {
+			return values;
+		}
+
+		throw new IllegalStateException("Values are not available.");
+	}
+
+	/**
+	 * Checks whether this request has measured values, stored in externally linked
+	 * files.
+	 *
+	 * @return Returns {@code true} if {@link SequenceRepresentation#isExternal()}
+	 *         returns {@code true}.
+	 * @see #hasValues()
+	 */
+	public boolean hasExternalComponents() {
+		return getSequenceRepresentation().isExternal();
+	}
+
+	/**
+	 * Returns the configurations for measured values stored in externally
+	 * referenced files.
+	 * 
+	 * @return Returned {@code List} is unmodifiable.
+	 * @throws IllegalStateException Thrown if configurations are not available.
+	 */
+	public List<ExternalComponent> getExternalComponents() {
+		if (!hasExternalComponents()) {
+			throw new IllegalStateException("External components are not available.");
+		}
+
+		return Collections.unmodifiableList(externalComponents);
+	}
+
+	/**
+	 * Returns the {@link ScalarType} of the stored measured value sequence.
+	 *
+	 * @return The raw {@code ScalarType} is returned.
+	 */
+	public ScalarType getRawScalarType() {
+		return rawScalarType;
+	}
+
+	/**
+	 * Returns the calculated {@link ScalarType} which reflects the final
+	 * {@code ScalarType} of the generated measured value sequence. If
+	 * {@link #getGenerationParameters()} returns a not empty array and
+	 * {@link #getRawScalarType()} is an integer type (byte, short, int, long), then
+	 * the returned {@code ScalarType} is bumped to the next suitable floating point
+	 * type as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE} -&gt; {@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#SHORT} -&gt; {@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#INTEGER} -&gt; {@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#LONG} -&gt; {@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * @return The calculated {@code ScalarType} is returned.
+	 */
+	public ScalarType getCalculatedScalarType() {
+		if (getGenerationParameters().length > 0 && getRawScalarType().isIntegerType()) {
+			return getRawScalarType().isLong() ? ScalarType.DOUBLE : ScalarType.FLOAT;
+		}
+
+		return getRawScalarType();
+	}
+
+	/**
+	 * Checks whether all measured values within the whole sequence are valid. If
+	 * this method returns {@code true}, then {@link #getFlags()} will return an
+	 * empty array.
+	 *
+	 * @return Returns {@code true} if all measured values are valid.
+	 * @see #getFlags()
+	 */
+	public boolean areAllValid() {
+		return allValid;
+	}
+
+	/**
+	 * Returns the validity flags sequence for the stored measured values. If
+	 * {@link #areAllValid()} returns {@code false} this method will return an array
+	 * with the same length as the measured values sequence, where each flag
+	 * indicates whether the corresponding measured value is valid or not.
+	 *
+	 * @return The validity flags sequence is returned.
+	 * @see #allValid
+	 */
+	public boolean[] getFlags() {
+		return flags.clone();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Sets the {@link SequenceRepresentation} for this request.
+	 *
+	 * @param sequenceRepresentation The {@link SequenceRepresentation}.
+	 */
+	void setSequenceRepresentation(SequenceRepresentation sequenceRepresentation) {
+		this.sequenceRepresentation = sequenceRepresentation;
+	}
+
+	/**
+	 * Sets generation parameters for this request.
+	 *
+	 * @param generationParameters The generation parameters.
+	 */
+	void setGenerationParameters(double[] generationParameters) {
+		this.generationParameters = generationParameters.clone();
+	}
+
+	/**
+	 * Sets the independent flag for this request.
+	 */
+	void setIndependent() {
+		independent = true;
+	}
+
+	/**
+	 * Sets the independent flag for this request to the value specified.
+	 * 
+	 * @param independent The independent flag.
+	 */
+	void setIndependent(boolean independent) {
+		this.independent = independent;
+	}
+
+	/**
+	 * Triggers an adjustment of the generation parameters and modification of the
+	 * {@link SequenceRepresentation} of this request to match the {@link Channel}s
+	 * default {@link Unit}.
+	 *
+	 * @param sourceUnit The {@link Unit} of the measured values.
+	 */
+	void setSourceUnit(Unit sourceUnit) {
+		throw new UnsupportedOperationException("Conversion between units is not implemented yet.");
+	}
+
+	/**
+	 * Sets the raw {@link ScalarType} for this request.
+	 *
+	 * @param rawScalarType The {@link ScalarType}.
+	 */
+	void setRawScalarType(ScalarType rawScalarType) {
+		this.rawScalarType = rawScalarType;
+	}
+
+	/**
+	 * Sets the measured values sequence where each value in the sequence is
+	 * expected to be valid.
+	 *
+	 * @param values The measured value sequence.
+	 * @throws IllegalStateException Thrown if {@link #hasValues()} returns
+	 *                               {@code false}.
+	 */
+	void setValues(Object values) {
+		if (hasValues()) {
+			this.values = values;
+			allValid = true;
+		} else {
+			throw new IllegalStateException("Measured values stored in externally linked files expected.");
+		}
+	}
+
+	/**
+	 * Sets the measured values sequence where each value's validity is specified in
+	 * the given flags array.
+	 *
+	 * @param values The measured value sequence.
+	 * @param flags  The validity flag sequence.
+	 * @throws IllegalStateException Thrown if {@link #hasValues()} returns
+	 *                               {@code false}.
+	 */
+	void setValues(Object values, boolean[] flags) {
+		if (hasValues()) {
+			this.values = values;
+			this.flags = flags.clone();
+		} else {
+			throw new IllegalStateException("Measured values stored in externally linked files expected.");
+		}
+	}
+
+	/**
+	 * Adds a configuration for measured values stored in externally linked files.
+	 *
+	 * @param externalComponent The new configuration.
+	 * @throws IllegalStateException Thrown if {@link #hasExternalComponents()}
+	 *                               returns {@code false}.
+	 */
+	void addExternalComponent(ExternalComponent externalComponent) {
+		if (hasExternalComponents()) {
+			externalComponents.add(externalComponent);
+		} else {
+			throw new IllegalStateException("Measured values expected");
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestBuilder.java
new file mode 100644
index 0000000..63aebc6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestBuilder.java
@@ -0,0 +1,271 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+
+/**
+ * Builds measured values write request configurations.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class WriteRequestBuilder extends BaseValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} which will be configured.
+	 */
+	WriteRequestBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Configures the {@link WriteRequest} to create an explicit sequence of
+	 * measured values.
+	 *
+	 * @return An {@link AnyTypeValuesBuilder} is returned.
+	 * @see SequenceRepresentation#EXPLICIT
+	 */
+	public AnyTypeValuesBuilder explicit() {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.EXPLICIT);
+		return new AnyTypeValuesBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create an implicit constant sequence
+	 * of measured values. An implicit sequence allows only numerical
+	 * {@link ScalarType}s as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE}</li>
+	 * <li>{@link ScalarType#SHORT}</li>
+	 * <li>{@link ScalarType#INTEGER}</li>
+	 * <li>{@link ScalarType#LONG}</li>
+	 * <li>{@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> Given offset will be cast to an assignment compatible type.
+	 *
+	 * @param scalarType The {@code ScalarType} of each single measured value in the
+	 *                   sequence.
+	 * @param offset     The constant value.
+	 * @return An {@link UnitBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is not
+	 *                                  supported.
+	 * @see SequenceRepresentation#IMPLICIT_CONSTANT
+	 */
+	public UnitBuilder implicitConstant(ScalarType scalarType, double offset) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.IMPLICIT_CONSTANT);
+
+		Object values;
+		if (scalarType.isByte()) {
+			values = new byte[] { (byte) offset };
+		} else if (scalarType.isShort()) {
+			values = new short[] { (short) offset };
+		} else if (scalarType.isInteger()) {
+			values = new int[] { (int) offset };
+		} else if (scalarType.isLong()) {
+			values = new long[] { (long) offset };
+		} else if (scalarType.isFloat()) {
+			values = new float[] { (float) offset };
+		} else if (scalarType.isDouble()) {
+			values = new double[] { offset };
+		} else {
+			throw new IllegalArgumentException("Scalar type '" + scalarType + "' is not supported.");
+		}
+		createValues(scalarType, values);
+
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create an implicit linear sequence of
+	 * measured values. An implicit sequence allows only numerical
+	 * {@link ScalarType}s as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE}</li>
+	 * <li>{@link ScalarType#SHORT}</li>
+	 * <li>{@link ScalarType#INTEGER}</li>
+	 * <li>{@link ScalarType#LONG}</li>
+	 * <li>{@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> Given start and increment will be cast to an assignment
+	 * compatible type.
+	 *
+	 * @param scalarType The {@code ScalarType} of each single measured value in the
+	 *                   sequence.
+	 * @param start      The start value of the line.
+	 * @param increment  The gradient of the line.
+	 * @return An {@link UnitIndependentBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is not
+	 *                                  supported.
+	 * @see SequenceRepresentation#IMPLICIT_LINEAR
+	 */
+	public UnitIndependentBuilder implicitLinear(ScalarType scalarType, double start, double increment) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.IMPLICIT_LINEAR);
+
+		Object values;
+		if (scalarType.isByte()) {
+			values = new byte[] { (byte) start, (byte) increment };
+		} else if (scalarType.isShort()) {
+			values = new short[] { (short) start, (short) increment };
+		} else if (scalarType.isInteger()) {
+			values = new int[] { (int) start, (int) increment };
+		} else if (scalarType.isLong()) {
+			values = new long[] { (long) start, (long) increment };
+		} else if (scalarType.isFloat()) {
+			values = new float[] { (float) start, (float) increment };
+		} else if (scalarType.isDouble()) {
+			values = new double[] { start, increment };
+		} else {
+			throw new IllegalArgumentException("Scalar type '" + scalarType + "' is not supported.");
+		}
+		createValues(scalarType, values);
+
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create an implicit saw sequence of
+	 * measured values. An implicit sequence allows only numerical
+	 * {@link ScalarType}s as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE}</li>
+	 * <li>{@link ScalarType#SHORT}</li>
+	 * <li>{@link ScalarType#INTEGER}</li>
+	 * <li>{@link ScalarType#LONG}</li>
+	 * <li>{@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> Given start, increment and valuesPerSaw will be cast to an
+	 * assignment compatible type.
+	 *
+	 * @param scalarType   The {@code ScalarType} of each single measured value in
+	 *                     the sequence.
+	 * @param start        The start value of each saw cycle.
+	 * @param increment    The increment.
+	 * @param valuesPerSaw The number of values per saw.
+	 * @return An {@link UnitBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is not
+	 *                                  supported.
+	 * @see SequenceRepresentation#IMPLICIT_SAW
+	 */
+	public UnitBuilder implicitSaw(ScalarType scalarType, double start, double increment, double valuesPerSaw) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.IMPLICIT_SAW);
+
+		Object values;
+		if (scalarType.isByte()) {
+			values = new byte[] { (byte) start, (byte) increment, (byte) valuesPerSaw };
+		} else if (scalarType.isShort()) {
+			values = new short[] { (short) start, (short) increment, (short) valuesPerSaw };
+		} else if (scalarType.isInteger()) {
+			values = new int[] { (int) start, (int) increment, (int) valuesPerSaw };
+		} else if (scalarType.isLong()) {
+			values = new long[] { (long) start, (long) increment, (long) valuesPerSaw };
+		} else if (scalarType.isFloat()) {
+			values = new float[] { (float) start, (float) increment, (float) valuesPerSaw };
+		} else if (scalarType.isDouble()) {
+			values = new double[] { start, increment, valuesPerSaw };
+		} else {
+			throw new IllegalArgumentException("Scalar type '" + scalarType + "' is not supported.");
+		}
+		createValues(scalarType, values);
+
+		// NOTE: if it ever should be required to make a channel of this type
+		// an independent one, then return an UnitIndependentBuilder instead!
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create a raw linear sequence of
+	 * measured values.
+	 *
+	 * @param offset The offset for each value.
+	 * @param factor The factor for each value.
+	 * @return A {@link ComplexNumericalValuesBuilder} is returned.
+	 * @see SequenceRepresentation#RAW_LINEAR
+	 */
+	public ComplexNumericalValuesBuilder rawLinear(double offset, double factor) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.RAW_LINEAR);
+		getWriteRequest().setGenerationParameters(new double[] { offset, factor });
+		return new ComplexNumericalValuesBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create a raw polynomial sequence of
+	 * measured values.
+	 *
+	 * @param coefficients At least 2 coefficients must be provided.
+	 * @return A {@link ComplexNumericalValuesBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if coefficients are missing or their
+	 *                                  length is less than 2.
+	 * @see SequenceRepresentation#RAW_POLYNOMIAL
+	 */
+	public ComplexNumericalValuesBuilder rawPolynomial(double... coefficients) {
+		if (coefficients == null || coefficients.length < 2) {
+			throw new IllegalArgumentException(
+					"Coefficients either missing or their length is " + "inconsitent with given grade");
+		}
+
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.RAW_POLYNOMIAL);
+
+		double[] generationParameters = new double[coefficients.length + 1];
+		generationParameters[0] = coefficients.length - 1;
+		System.arraycopy(coefficients, 0, generationParameters, 1, coefficients.length);
+		getWriteRequest().setGenerationParameters(generationParameters);
+
+		// TODO: currently it is possible to define such a channel as
+		// independent
+		// should we prevent this?!
+		return new ComplexNumericalValuesBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create a raw linear calibrated
+	 * sequence of measured values.
+	 *
+	 * @param offset      The offset for each value.
+	 * @param factor      The factor for each value.
+	 * @param calibration The calibration factor.
+	 * @return A {@link ComplexNumericalValuesBuilder} is returned.
+	 * @see SequenceRepresentation#RAW_LINEAR_CALIBRATED
+	 */
+	public ComplexNumericalValuesBuilder rawLinearCalibrated(double offset, double factor, double calibration) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.RAW_LINEAR_CALIBRATED);
+		getWriteRequest().setGenerationParameters(new double[] { offset, factor, calibration });
+		return new ComplexNumericalValuesBuilder(getWriteRequest());
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestFinalizer.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestFinalizer.java
new file mode 100644
index 0000000..0e57e9f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestFinalizer.java
@@ -0,0 +1,72 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+/**
+ * This class provides a terminal {@link WriteRequest} build operation to
+ * retrieve the configured {@code WriteRequest}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class WriteRequestFinalizer {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final WriteRequest writeRequest;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The configured {@link WriteRequest}.
+	 */
+	WriteRequestFinalizer(WriteRequest writeRequest) {
+		this.writeRequest = writeRequest;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the configured {@link WriteRequest}.
+	 *
+	 * @return The configured {@code WriteRequest} is returned.
+	 */
+	public final WriteRequest build() {
+		return getWriteRequest();
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link WriteRequest}.
+	 *
+	 * @return The {@code WriteRequest} is returned.
+	 */
+	protected final WriteRequest getWriteRequest() {
+		return writeRequest;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/AxisType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/AxisType.java
new file mode 100644
index 0000000..913590d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/AxisType.java
@@ -0,0 +1,80 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This is the axis type enumeration as defined in the ASAM ODS NVH model.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Channel
+ */
+public class AxisType extends EnumerationValue {
+
+	/**
+	 * A {@link Channel} of this type may be displayed as the x-axis.
+	 */
+	public static final AxisType X_AXIS = new AxisType("X_AXIS", 0);
+
+	/**
+	 * A {@link Channel} of this type may be displayed as the y-axis.
+	 */
+	public static final AxisType Y_AXIS = new AxisType("Y_AXIS", 1);
+
+	/**
+	 * A {@link Channel} of this type may be displayed as the x- or y-axis.
+	 */
+	public static final AxisType XY_AXIS = new AxisType("XY_AXIS", 2);
+
+	private AxisType(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns true if this axis type is {@link #X_AXIS}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isXAxis() {
+		return X_AXIS == this;
+	}
+
+	/**
+	 * Returns true if this axis type is {@link #Y_AXIS}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isYAxis() {
+		return Y_AXIS == this;
+	}
+
+	/**
+	 * Returns true if this axis type is {@link #XY_AXIS}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isXYAxis() {
+		return XY_AXIS == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntity.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntity.java
new file mode 100644
index 0000000..7211a23
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntity.java
@@ -0,0 +1,134 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * This is a base implementation for modeled entities. API consumers should
+ * never use this class in any way, instead the most common interface should be
+ * used (e.g.: {@link Entity}, {@link ContextDescribable}, etc.). API producers
+ * must let their {@code Entity} implementations extend this class.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public abstract class BaseEntity implements Entity {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Core core;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	protected BaseEntity(Core core) {
+		this.core = core;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getSourceName() {
+		return getCore().getSourceName();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getTypeName() {
+		return getCore().getTypeName();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getID() {
+		return getCore().getID();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final Value getValue(String name) {
+		Value value = getCore().getValues().get(name);
+		if (value == null) {
+			throw new IllegalStateException("Value with name '" + name + "' does not exist");
+		}
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final Map<String, Value> getValues() {
+		return Collections.unmodifiableMap(getCore().getValues());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		String prefix = new StringBuilder(getClass().getSimpleName()).append('(').toString();
+		return getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ", prefix, ")"));
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Returns the internally stored {@link Core}.
+	 *
+	 * @return The {@link Core} is returned.
+	 */
+	protected Core getCore() {
+		return core;
+	}
+
+	/**
+	 * Convenience method to extract {@link Core} of given {@link Entity}.
+	 *
+	 * @param entity The {@code Entity} whose {@code Core} is required.
+	 * @return The {@code Core} is returned.
+	 */
+	protected static Core getCore(Entity entity) {
+		return ((BaseEntity) entity).getCore();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java
new file mode 100644
index 0000000..fbf75a2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java
@@ -0,0 +1,564 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+
+/**
+ * Implementation of an abstract entity factory which creates new entities.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public abstract class BaseEntityFactory {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link Channel}. The name of the returned {@code Channel} is
+	 * retrieved from given {@link Quantity}.
+	 *
+	 * @param measurement The parent {@link Measurement}.
+	 * @param quantity    The {@code Quantity} is used for default initialization.
+	 * @return The created {@code Channel} is returned.
+	 */
+	public Channel createChannel(Measurement measurement, Quantity quantity) {
+		return createChannel(quantity.getDefaultChannelName(), measurement, quantity);
+	}
+
+	/**
+	 * Creates a new {@link Channel}.
+	 *
+	 * @param name        Name of the created {@code Channel}.
+	 * @param measurement The parent {@link Measurement}.
+	 * @param quantity    The {@code Quantity} is used for default initialization.
+	 * @return The created {@code Channel} is returned.
+	 */
+	public Channel createChannel(String name, Measurement measurement, Quantity quantity) {
+		Channel channel = new Channel(createCore(Channel.class));
+
+		// relations
+		getCore(channel).getPermanentStore().set(measurement);
+		getCore(measurement).getChildrenStore().add(channel);
+		getCore(channel).getMutableStore().set(quantity.getDefaultUnit());
+		getCore(channel).getMutableStore().set(quantity);
+
+		// properties
+		channel.setName(name);
+		channel.setDescription(quantity.getDescription());
+		channel.setInterpolation(Interpolation.NONE);
+		channel.setScalarType(quantity.getDefaultScalarType());
+		channel.setRank(quantity.getDefaultRank());
+		channel.setTypeSize(quantity.getDefaultTypeSize());
+
+		return channel;
+	}
+
+	/**
+	 * Creates a new {@link ChannelGroup}.
+	 *
+	 * @param name           Name of the created {@code ChannelGroup}.
+	 * @param numberOfValues The number of values per each related {@link Channel}.
+	 * @param measurement    The parent {@link Measurement}.
+	 * @return The created {@code ChannelGroup} is returned.
+	 * @throws IllegalArgumentException Thrown if numberOfValues is negative.
+	 */
+	public ChannelGroup createChannelGroup(String name, int numberOfValues, Measurement measurement) {
+		if (numberOfValues < 0) {
+			throw new IllegalArgumentException("Number of values must be equal or greater than 0.");
+		}
+
+		ChannelGroup channelGroup = new ChannelGroup(createCore(ChannelGroup.class));
+
+		// relations
+		getCore(channelGroup).getPermanentStore().set(measurement);
+		getCore(measurement).getChildrenStore().add(channelGroup);
+
+		// properties
+		channelGroup.setName(name);
+		channelGroup.setNumberOfValues(Integer.valueOf(numberOfValues));
+
+		return channelGroup;
+	}
+
+	/**
+	 * Creates a new {@link Measurement}.
+	 *
+	 * @param name         Name of the created {@code Measurement}.
+	 * @param testStep     The parent {@link TestStep}.
+	 * @param contextRoots {@link ContextRoot}s containing the descriptive data.
+	 * @return The created {@code Measurement} is returned.
+	 */
+	public Measurement createMeasurement(String name, TestStep testStep, ContextRoot... contextRoots) {
+		Measurement measurement = new Measurement(createCore(Measurement.class));
+
+		// relations
+		getCore(measurement).getPermanentStore().set(testStep);
+		getCore(testStep).getChildrenStore().add(measurement);
+		for (ContextRoot contextRoot : contextRoots) {
+			getCore(measurement).getMutableStore().set(contextRoot, contextRoot.getContextType());
+		}
+
+		// properties
+		measurement.setName(name);
+		measurement.setDateCreated(LocalDateTime.now());
+
+		return measurement;
+	}
+
+	/**
+	 * Creates a new {@link Parameter} with initialized with given value.
+	 *
+	 * @param name         Name of the created {@code Parameter}.
+	 * @param value        The value of the created {@code Parameter}.
+	 * @param unit         An optionally related {@link Unit}.
+	 * @param parameterSet The parent {@link ParameterSet}.
+	 * @return The created {@code Parameter} is returned.
+	 * @throws IllegalArgumentException Thrown if the {@code ParameterSet} already
+	 *                                  contains a {@code Parameter} with given
+	 *                                  name.
+	 * @see Parameter#setObjectValue(Object, Unit)
+	 */
+	public Parameter createParameter(String name, Object value, Unit unit, ParameterSet parameterSet) {
+		if (parameterSet.getParameter(name).isPresent()) {
+			throw new IllegalArgumentException("Parameter with name '" + name + "' already exists.");
+		}
+
+		Parameter parameter = new Parameter(createCore(Parameter.class));
+
+		// relations
+		getCore(parameter).getPermanentStore().set(parameterSet);
+		getCore(parameterSet).getChildrenStore().add(parameter);
+
+		// properties
+		parameter.setName(name);
+		parameter.setObjectValue(value, unit);
+
+		return parameter;
+	}
+
+	/**
+	 * Creates a new {@link ParameterSet} for given {@link Measurement}.
+	 *
+	 * @param name        Name of the created {@code ParameterSet}.
+	 * @param version     Version of the created {@code ParameterSet}.
+	 * @param measurement The owning {@code Measurement}.
+	 * @return The created {@code ParameterSet} is returned.
+	 */
+	public ParameterSet createParameterSet(String name, String version, Measurement measurement) {
+		ParameterSet parameterSet = new ParameterSet(createCore(ParameterSet.class));
+
+		// relations
+		getCore(parameterSet).getPermanentStore().set(measurement);
+		getCore(measurement).getChildrenStore().add(parameterSet);
+
+		// properties
+		parameterSet.setName(name);
+		parameterSet.setVersion(version);
+
+		return parameterSet;
+	}
+
+	/**
+	 * Creates a new {@link ParameterSet} for given {@link Channel}.
+	 *
+	 * @param name    Name of the created {@code ParameterSet}.
+	 * @param version Version of the created {@code ParameterSet}.
+	 * @param channel The owning {@code Channel}.
+	 * @return The created {@code ParameterSet} is returned.
+	 */
+	public ParameterSet createParameterSet(String name, String version, Channel channel) {
+		ParameterSet parameterSet = new ParameterSet(createCore(ParameterSet.class));
+
+		// relations
+		getCore(parameterSet).getPermanentStore().set(channel);
+		getCore(channel).getChildrenStore().add(parameterSet);
+
+		// properties
+		parameterSet.setName(name);
+		parameterSet.setVersion(version);
+
+		return parameterSet;
+	}
+
+	/**
+	 * Creates a new {@link PhysicalDimension}.
+	 *
+	 * @param name Name of the created {@code PhysicalDimension}.
+	 * @return The created {@code PhysicalDimension} is returned.
+	 */
+	public PhysicalDimension createPhysicalDimension(String name) {
+		PhysicalDimension physicalDimension = new PhysicalDimension(createCore(PhysicalDimension.class));
+
+		// properties
+		physicalDimension.setName(name);
+		physicalDimension.setLength(Integer.valueOf(0));
+		physicalDimension.setMass(Integer.valueOf(0));
+		physicalDimension.setTime(Integer.valueOf(0));
+		physicalDimension.setTemperature(Integer.valueOf(0));
+		physicalDimension.setCurrent(Integer.valueOf(0));
+		physicalDimension.setMolarAmount(Integer.valueOf(0));
+		physicalDimension.setLuminousIntensity(Integer.valueOf(0));
+		physicalDimension.setAngle(Integer.valueOf(0));
+
+		return physicalDimension;
+	}
+
+	/**
+	 * Creates a new {@link Quantity}.
+	 *
+	 * @param name        Name of the created {@code Quantity}.
+	 * @param defaultUnit The default {@link Unit}.
+	 * @return The created {@code Quantity} is returned.
+	 */
+	public Quantity createQuantity(String name, Unit defaultUnit) {
+		Quantity quantity = new Quantity(createCore(Quantity.class));
+
+		// relations
+		getCore(quantity).getMutableStore().set(defaultUnit);
+
+		// properties
+		quantity.setName(name);
+		quantity.setDateCreated(LocalDateTime.now());
+		quantity.setDefaultRank(Integer.valueOf(1));
+		quantity.setDefaultDimension(new int[] { 0 });
+		quantity.setDefaultTypeSize(Integer.valueOf(1));
+		quantity.setDefaultChannelName(name);
+		quantity.setDefaultScalarType(ScalarType.FLOAT);
+
+		quantity.getValue("Version").set("1");
+		quantity.getValue("ValidFlag").set(VersionState.VALID);
+
+		return quantity;
+	}
+
+	/**
+	 * Creates a new {@link Test} with a reference to the logged in {@link User}, if
+	 * there is one.
+	 *
+	 * @param name Name of the created {@code Test}.
+	 * @return The created {@code Test} is returned.
+	 */
+	public Test createTest(String name) {
+		Test test = new Test(createCore(Test.class));
+
+		// relations
+		Optional<User> responsiblePerson = getLoggedInUser();
+		if (responsiblePerson.isPresent()) {
+			// may be null if user entities are not available
+			getCore(test).getMutableStore().set(responsiblePerson.get());
+		}
+
+		// properties
+		test.setName(name);
+		test.setDateCreated(LocalDateTime.now());
+
+		return test;
+	}
+
+	/**
+	 * Creates a new {@link TestStep}.
+	 *
+	 * @param name Name of the created {@code TestStep}.
+	 * @param test The parent {@link Test}.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStep(String name, Test test) {
+		TestStep testStep = new TestStep(createCore(TestStep.class));
+
+		// relations
+		getCore(testStep).getPermanentStore().set(test);
+		getCore(test).getChildrenStore().add(testStep);
+
+		// properties
+		testStep.setName(name);
+		testStep.setDateCreated(LocalDateTime.now());
+		testStep.setOptional(Boolean.TRUE);
+
+		if (test.getID() != null && test.getID().length() > 0) {
+			// highest sort index in use will be queried before written
+			testStep.setSortIndex(Integer.valueOf(-1));
+		} else {
+			testStep.setSortIndex(nextIndex(getCore(test).getChildrenStore().get(TestStep.class)));
+		}
+
+		return testStep;
+	}
+
+	/**
+	 * Creates a new {@link Unit}.
+	 *
+	 * @param name              Name of the created {@code Unit}.
+	 * @param physicalDimension The {@link PhysicalDimension}.
+	 * @return The created {@code Unit} is returned.
+	 */
+	public Unit createUnit(String name, PhysicalDimension physicalDimension) {
+		Unit unit = new Unit(createCore(Unit.class));
+
+		// relations
+		getCore(unit).getMutableStore().set(physicalDimension);
+
+		// properties
+		unit.setName(name);
+		unit.setOffset(Double.valueOf(0D));
+		unit.setFactor(Double.valueOf(1D));
+
+		return unit;
+	}
+
+	/**
+	 * Creates a new {@link User}.
+	 *
+	 * @param name      Name of the created {@code User}.
+	 * @param givenName Given name of the created {@code User}.
+	 * @param surname   Surname of the created {@code User}.
+	 * @return The created {@code User} is returned.
+	 */
+	public User createUser(String name, String givenName, String surname) {
+		User user = new User(createCore(User.class));
+
+		// properties
+		user.setName(name);
+		user.setGivenName(givenName);
+		user.setSurname(surname);
+
+		return user;
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link ContextRoot}.
+	 *
+	 * @param name        Name of the created {@code ContextRoot}.
+	 * @param contextType {@link ContextType} of the created {@code ContextRoot}.
+	 * @return The created {@code ContextRoot} is returned.
+	 */
+	protected ContextRoot createContextRoot(String name, ContextType contextType) {
+		ContextRoot contextRoot = new ContextRoot(createCore(ContextRoot.class, contextType));
+
+		// properties
+		contextRoot.setName(name);
+		contextRoot.setVersion(String.valueOf(0));
+
+		return contextRoot;
+	}
+
+	/**
+	 * Creates a new {@link ContextComponent}.
+	 *
+	 * @param name        Name of the created {@code ContextComponent}.
+	 * @param contextRoot The parent {@link ContextRoot}.
+	 * @return The created {@code ContextComponent} is returned.
+	 */
+	protected ContextComponent createContextComponent(String name, ContextRoot contextRoot) {
+		ContextComponent contextComponent = new ContextComponent(createCore(name, ContextComponent.class));
+
+		// relations
+		getCore(contextComponent).getPermanentStore().set(contextRoot);
+		getCore(contextRoot).getChildrenStore().add(contextComponent);
+
+		// properties
+		contextComponent.setName(name);
+
+		return contextComponent;
+	}
+
+	/**
+	 * Creates a new {@link ContextSensor}.
+	 *
+	 * @param name             Name of the created {@code ContextSensor}.
+	 * @param contextComponent The parent {@link ContextComponent}.
+	 * @return The created {@code ContextSensor} is returned.
+	 */
+	protected ContextSensor createContextSensor(String name, ContextComponent contextComponent) {
+		ContextSensor contextSensor = new ContextSensor(createCore(name, ContextSensor.class));
+		// relations
+		getCore(contextSensor).getPermanentStore().set(contextComponent);
+		getCore(contextComponent).getChildrenStore().add(contextSensor);
+
+		// properties
+		contextSensor.setName(name);
+
+		return contextSensor;
+	}
+
+	/**
+	 * Returns the next usable sort index for given {@code List} of
+	 * {@link Sortable}s.
+	 *
+	 * @param sortables The {@code Sortable} whose max sort index will be searched.
+	 * @return {@code 1} is returned if given {@code List} is empty, otherwise the
+	 *         max sort index increased by 1 is returned.
+	 */
+	protected static final Integer nextIndex(List<? extends Sortable> sortables) {
+		Optional<Integer> maxIndex = sortables.stream().max(Sortable.COMPARATOR).map(Sortable::getSortIndex);
+		return Integer.valueOf(maxIndex.isPresent() ? maxIndex.get().intValue() + 1 : 1);
+	}
+
+	/**
+	 * Returns the {@link ChildrenStore} for given {@link BaseEntity}. Please be
+	 * aware that the contents of this store is subject to the adapter creating it.
+	 * It is up to the adapter to decide which related entities are included. As
+	 * there are adapter specific details to the contents of the store it should be
+	 * protected from external access. Therefore by declaring this method protected,
+	 * the related functionality is hidden from other classes since the only classes
+	 * which can access them (outside this package) are derivatives of
+	 * BaseEntityFactory, and it is through such derivatives that BaseEntity's
+	 * Stores should be accessed elsewhere if needed.
+	 *
+	 * @param entity The {@code BaseEntity} whose {@code ChildrenStore} will be
+	 *               returned.
+	 * @return The {@code ChildrenStore} is returned.
+	 */
+	protected static ChildrenStore getChildrenStore(BaseEntity entity) {
+		return getCore(entity).getChildrenStore();
+	}
+
+	/**
+	 * Returns the mutable {@link EntityStore} for given {@link BaseEntity}. Please
+	 * be aware that the contents of this store is subject to the adapter creating
+	 * it. It is up to the adapter to decide which related entities are included. As
+	 * there are adapter specific details to the contents of the store it should be
+	 * protected from external access. Therefore by declaring this method protected,
+	 * the related functionality is hidden from other classes since the only classes
+	 * which can access them (outside this package) are derivatives of
+	 * BaseEntityFactory, and it is through such derivatives that BaseEntity's
+	 * Stores should be accessed elsewhere if needed.
+	 * 
+	 *
+	 * @param entity The {@code BaseEntity} whose {@code ChildrenStore} will be
+	 *               returned.
+	 * @return The mutable {@code EntityStore} is returned.
+	 */
+	protected static EntityStore getMutableStore(BaseEntity entity) {
+		return getCore(entity).getMutableStore();
+	}
+
+	/**
+	 * Returns the permanent {@link EntityStore} for given {@link BaseEntity}.
+	 * Please be aware that the contents of this store is subject to the adapter
+	 * creating it. It is up to the adapter to decide which related entities are
+	 * included. As there are adapter specific details to the contents of the store
+	 * it should be protected from external access. Therefore by declaring this
+	 * method protected, the related functionality is hidden from other classes
+	 * since the only classes which can access them (outside this package) are
+	 * derivatives of BaseEntityFactory, and it is through such derivatives that
+	 * BaseEntity's Stores should be accessed elsewhere if needed.
+	 * 
+	 * @param entity The {@code BaseEntity} whose {@code ChildrenStore} will be
+	 *               returned.
+	 * @return The permanent {@code EntityStore} is returned.
+	 */
+	protected static EntityStore getPermanentStore(BaseEntity entity) {
+		return getCore(entity).getPermanentStore();
+	}
+
+	/**
+	 * Returns {@link Core} of given {@link Entity}. Uses protected method from
+	 * BaseEntity, which is accessible here as BaseEntity resides in the same
+	 * package as BaseEntityFactory. By declaring this method protected, the
+	 * Core-related functionality is hidden from other classes since the only
+	 * classes which can access them (outside this package) are derivatives of
+	 * BaseEntityFactory, and it is through such derivatives that a BaseEntity's
+	 * Core should be accessed elsewhere if needed.
+	 *
+	 * @param entity The {@code BaseEntity} whose {@code Core} is required.
+	 * @return The {@code Core} is returned.
+	 */
+	protected static final Core getCore(BaseEntity entity) {
+		return entity.getCore();
+	}
+
+	/**
+	 * Create an instance of {@link BaseEntity} (or derivative) with core as the
+	 * instance's {@link Core}. By declaring this method protected, the Core-related
+	 * functionality is hidden from other classes since the only classes which can
+	 * access them (outside this package) are derivatives of BaseEntityFactory, and
+	 * it is through such derivatives that a BaseEntity's Core should be accessed
+	 * elsewhere if needed. <br>
+	 * <br>
+	 * This method accesses the (usually protected) Constructor(Core) of clazz, so
+	 * this method should be overridden in a derived class and call
+	 * super.createBaseEntity() if that constructor is invisible from the derived
+	 * class.
+	 * 
+	 * @param clazz The class to instantiate, must extend {@link BaseEntity}.
+	 * @param core  The {@link Core} to use for the newly created instance.
+	 * @return The newly created instance.
+	 */
+	protected <T extends BaseEntity> T createBaseEntity(Class<T> clazz, Core core) {
+		try {
+			Constructor<T> constructor = clazz.getDeclaredConstructor(Core.class);
+			try {
+				return constructor.newInstance(core);
+			} catch (IllegalAccessException exc) {
+				throw new IllegalStateException("Cannot access Constructor(Core) of class '" + clazz.getName() + "'!");
+			}
+		} catch (NoSuchMethodException | InvocationTargetException | InstantiationException exc) {
+			throw new IllegalStateException(exc.getMessage(), exc);
+		}
+	}
+
+	/**
+	 * Returns the {@link User} which is bound to the current session.
+	 *
+	 * @return {@code Optional} is empty if {@code User} entities do not exist.
+	 */
+	protected abstract Optional<User> getLoggedInUser();
+
+	/**
+	 * Returns a new {@link Core} for given entity class.
+	 *
+	 * @param <T>         The entity class type.
+	 * @param entityClass The entity class.
+	 * @return A new {@code Core} instance is returned.
+	 */
+	protected abstract <T extends Entity> Core createCore(Class<T> entityClass);
+
+	/**
+	 * Returns a new {@link Core} for given entity class and {@link ContextType}.
+	 *
+	 * @param <T>         The entity class type.
+	 * @param entityClass The entity class.
+	 * @param contextType The {@code ContextType}.
+	 * @return A new {@code Core} instance is returned.
+	 */
+	protected abstract <T extends Entity> Core createCore(Class<T> entityClass, ContextType contextType);
+
+	/**
+	 * Returns a new {@link Core} for given entity class and type name.
+	 *
+	 * @param <T>         The entity class type.
+	 * @param name        Name of the entity type.
+	 * @param entityClass The entity class.
+	 * @return A new {@code Core} instance is returned.
+	 */
+	protected abstract <T extends Entity> Core createCore(String name, Class<T> entityClass);
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseParameter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseParameter.java
new file mode 100644
index 0000000..21ab70f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseParameter.java
@@ -0,0 +1,443 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of an abstract parameter which holds a value with one of the
+ * supported {@link ValueType}s listed below. The value is internally stored in
+ * its {@code String} representation. Any modeled entity with such a use case
+ * should extends this class. API consumers should never use this class in any
+ * way, instead the implementations of this class have to be used.
+ *
+ * <ul>
+ * <li>{@link ValueType#STRING}</li>
+ * <li>{@link ValueType#DATE}</li>
+ * <li>{@link ValueType#BOOLEAN}</li>
+ * <li>{@link ValueType#BYTE}</li>
+ * <li>{@link ValueType#SHORT}</li>
+ * <li>{@link ValueType#INTEGER}</li>
+ * <li>{@link ValueType#LONG}</li>
+ * <li>{@link ValueType#FLOAT}</li>
+ * <li>{@link ValueType#DOUBLE}</li>
+ * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+ * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see #getVirtualValue()
+ * @see #setObjectValue(Object, Unit)
+ * @see #setStringValue(String)
+ * @see #setDateValue(LocalDateTime)
+ * @see #setBooleanValue(Boolean)
+ * @see #setByteValue(Byte, Unit)
+ * @see #setShortValue(Short, Unit)
+ * @see #setIntegerValue(Integer, Unit)
+ * @see #setLongValue(Long, Unit)
+ * @see #setFloatValue(Float, Unit)
+ * @see #setDoubleValue(Double, Unit)
+ * @see #setFloatComplexValue(FloatComplex, Unit)
+ * @see #setDoubleComplexValue(DoubleComplex, Unit)
+ */
+public abstract class BaseParameter extends BaseEntity implements Deletable {
+
+	private static final Map<ScalarType, Function<String, Object>> SCALARTYPE_FUNCTION_MAP = new HashMap<>();
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final String attrScalarType;
+	private final String attrValue;
+
+	static {
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.STRING, v -> v);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.DATE, v -> LocalDateTime.parse(v, Value.LOCAL_DATE_TIME_FORMATTER));
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.BOOLEAN, Boolean::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.BYTE, Byte::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.SHORT, Short::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.INTEGER, Integer::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.LONG, Long::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.FLOAT, Float::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.DOUBLE, Double::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.FLOAT_COMPLEX, FloatComplex::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.DOUBLE_COMPLEX, DoubleComplex::valueOf);
+	}
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param attrScalarType Name of the {@link ScalarType} attribute.
+	 * @param attrValue      Name of the {@code String} value attribute.
+	 * @param core           The {@link Core}.
+	 */
+	protected BaseParameter(String attrScalarType, String attrValue, Core core) {
+		super(core);
+		this.attrScalarType = attrScalarType;
+		this.attrValue = attrValue;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a virtual representation of this parameter's value. This is done by
+	 * converting the internally stored {@code String} value to type specified by
+	 * this parameter's {@link ValueType} (the allowed types are listed below). The
+	 * name of the returned virtual {@link Value} is the name of this parameter.
+	 *
+	 * <ul>
+	 * <li>{@link ValueType#STRING}</li>
+	 * <li>{@link ValueType#DATE}</li>
+	 * <li>{@link ValueType#BOOLEAN}</li>
+	 * <li>{@link ValueType#BYTE}</li>
+	 * <li>{@link ValueType#SHORT}</li>
+	 * <li>{@link ValueType#INTEGER}</li>
+	 * <li>{@link ValueType#LONG}</li>
+	 * <li>{@link ValueType#FLOAT}</li>
+	 * <li>{@link ValueType#DOUBLE}</li>
+	 * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+	 * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> The returned value is a virtual one and hence intended for
+	 * displaying purposes only. To change this parameter's value one of its
+	 * {@code setXYValue} methods has to be used.
+	 *
+	 * @return The created {@code Value} with the converted value is returned.
+	 */
+	public Value getVirtualValue() {
+		ScalarType scalarType = getScalarType();
+		Function<String, Object> typeConverter = SCALARTYPE_FUNCTION_MAP.get(scalarType);
+
+		if (typeConverter == null) {
+			return ValueType.UNKNOWN.create(getName());
+		}
+
+		Value parameterValue = getParameterValue();
+		Object value = parameterValue.isValid() ? typeConverter.apply(parameterValue.extract()) : null;
+		return scalarType.toSingleValueType().create(getName(), getUnitName(), parameterValue.isValid(), value);
+	}
+
+	/**
+	 * Takes given value and determines its type. Finally value and the optional
+	 * {@code Unit} are passed to the corresponding {@code setXYValue(XY)} method as
+	 * listed below. The value is allowed to be an instance of the following types:
+	 * {@code String}, {@code LocalDateTime}, {@code Boolean}, {@code Byte},
+	 * {@code Short}, {@code Integer}, {@code Long}, {@code Float}, {@code Double},
+	 * {@code FloatComplex} and {@code DoubleComplex}.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the given value is an instance of {@code String}, {@code
+	 * LocalDateTime} or a {@code Boolean}, then the given unit is ignored.
+	 *
+	 * @param value The new value for this parameter is not allowed to be null.
+	 * @param unit  The optionally related {@code Unit}.
+	 * @throws IllegalArgumentException Thrown if the given value is not supported.
+	 * @see #setStringValue(String)
+	 * @see #setDateValue(LocalDateTime)
+	 * @see #setBooleanValue(Boolean)
+	 * @see #setByteValue(Byte, Unit)
+	 * @see #setShortValue(Short, Unit)
+	 * @see #setIntegerValue(Integer, Unit)
+	 * @see #setLongValue(Long, Unit)
+	 * @see #setFloatValue(Float, Unit)
+	 * @see #setDoubleValue(Double, Unit)
+	 * @see #setFloatComplexValue(FloatComplex, Unit)
+	 * @see #setDoubleComplexValue(DoubleComplex, Unit)
+	 */
+	public void setObjectValue(Object value, Unit unit) {
+		if (value instanceof String) {
+			setStringValue((String) value);
+		} else if (value instanceof LocalDateTime) {
+			setDateValue((LocalDateTime) value);
+		} else if (value instanceof Boolean) {
+			setBooleanValue((Boolean) value);
+		} else if (value instanceof Byte) {
+			setByteValue((Byte) value, unit);
+		} else if (value instanceof Short) {
+			setShortValue((Short) value, unit);
+		} else if (value instanceof Integer) {
+			setIntegerValue((Integer) value, unit);
+		} else if (value instanceof Long) {
+			setLongValue((Long) value, unit);
+		} else if (value instanceof Float) {
+			setFloatValue((Float) value, unit);
+		} else if (value instanceof Double) {
+			setDoubleValue((Double) value, unit);
+		} else if (value instanceof FloatComplex) {
+			setFloatComplexValue((FloatComplex) value, unit);
+		} else if (value instanceof DoubleComplex) {
+			setDoubleComplexValue((DoubleComplex) value, unit);
+		} else {
+			throw new IllegalArgumentException(
+					"Value '" + value + "' of type '" + value.getClass().getSimpleName() + "' is not supported.");
+		}
+	}
+
+	/**
+	 * Replaces current value with given {@code String} value. Any existing relation
+	 * to a {@link Unit} will be removed.
+	 *
+	 * @param value The new value for this parameter.
+	 */
+	public void setStringValue(String value) {
+		setScalarType(ScalarType.STRING);
+		getParameterValue().set(value);
+		setUnit(null);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code LocalDateTime}. Any existing relation to a {@link Unit} will be
+	 * removed.
+	 *
+	 * @param value The new value for this parameter.
+	 */
+	public void setDateValue(LocalDateTime value) {
+		setScalarType(ScalarType.DATE);
+		getParameterValue().set(value.format(Value.LOCAL_DATE_TIME_FORMATTER));
+		setUnit(null);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Boolean}. Any existing relation to a {@link Unit} will be removed.
+	 *
+	 * @param value The new value for this parameter.
+	 */
+	public void setBooleanValue(Boolean value) {
+		setScalarType(ScalarType.BOOLEAN);
+		getParameterValue().set(value.toString());
+		setUnit(null);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Byte}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setByteValue(Byte value, Unit unit) {
+		setScalarType(ScalarType.BYTE);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Short}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setShortValue(Short value, Unit unit) {
+		setScalarType(ScalarType.SHORT);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Integer}. Any existing relation to a {@link Unit} will be replaced
+	 * with the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setIntegerValue(Integer value, Unit unit) {
+		setScalarType(ScalarType.INTEGER);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Long}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setLongValue(Long value, Unit unit) {
+		setScalarType(ScalarType.LONG);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Float}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setFloatValue(Float value, Unit unit) {
+		setScalarType(ScalarType.FLOAT);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Double}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setDoubleValue(Double value, Unit unit) {
+		setScalarType(ScalarType.DOUBLE);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code FloatComplex}. Any existing relation to a {@link Unit} will be
+	 * replaced with the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setFloatComplexValue(FloatComplex value, Unit unit) {
+		setScalarType(ScalarType.FLOAT_COMPLEX);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code DoubleComplex}. Any existing relation to a {@link Unit} will be
+	 * replaced with the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setDoubleComplexValue(DoubleComplex value, Unit unit) {
+		setScalarType(ScalarType.DOUBLE_COMPLEX);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append("(Name = ").append(getName());
+
+		sb.append(", Value = ");
+		Value parameterValue = getParameterValue();
+		if (parameterValue.isValid()) {
+			sb.append((String) getParameterValue().extract());
+		}
+
+		Optional<Unit> unit = getUnit();
+		if (unit.isPresent()) {
+			sb.append(" [").append(unit.get().getName()).append(']');
+		}
+
+		return sb.append(')').toString();
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link Value} of this parameter.
+	 *
+	 * @return This parameter's {@code Value} is returned.
+	 */
+	private Value getParameterValue() {
+		return getValue(attrValue);
+	}
+
+	/**
+	 * Returns the scalar value type of this parameter.
+	 *
+	 * @return This parameter's scalar type is returned.
+	 */
+	private ScalarType getScalarType() {
+		return getValue(attrScalarType).extract();
+	}
+
+	/**
+	 * Sets new scalar type for this parameter.
+	 *
+	 * @param scalarType The new {@code ScalarType}.
+	 */
+	private void setScalarType(ScalarType scalarType) {
+		getValue(attrScalarType).set(scalarType);
+	}
+
+	/**
+	 * Returns the name of the related {@link Unit}. If no {@code Unit} is related,
+	 * an empty {@code String} is returned instead.
+	 *
+	 * @return The name of the related {@code Unit} is returned or an empty
+	 *         {@code String}.
+	 */
+	private String getUnitName() {
+		Optional<Unit> unit = getUnit();
+		if (unit.isPresent()) {
+			return unit.get().getName();
+		}
+
+		return "";
+	}
+
+	/**
+	 * Returns an optionally related {@link Unit}.
+	 *
+	 * @return The returned {@code Optional} is empty if no {@code Unit} is related.
+	 */
+	private Optional<Unit> getUnit() {
+		return Optional.ofNullable(getCore().getMutableStore().get(Unit.class));
+	}
+
+	/**
+	 * Replaces current {@link Unit} relation with the given one, if the {@code
+	 * Optional} is not empty. Otherwise any current relations is removed.
+	 *
+	 * @param unit The new {@code Unit} may be {@code null}.
+	 */
+	private void setUnit(Unit unit) {
+		if (unit == null) {
+			getCore().getMutableStore().remove(Unit.class);
+		} else {
+			getCore().getMutableStore().set(unit);
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Channel.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Channel.java
new file mode 100644
index 0000000..8391a79
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Channel.java
@@ -0,0 +1,279 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the channel entity type. Entities of this type are based on
+ * {@link Quantity}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Measurement
+ * @see ChannelGroup
+ * @see ContextSensor
+ * @see ParameterSet
+ */
+public class Channel extends BaseEntity implements Deletable, Describable {
+
+	// TODO Channel may have a relation to a sensor!
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Measurement} parent type.
+	 */
+	public static final Class<Measurement> PARENT_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The {@link ChannelGroup} parent type.
+	 */
+	public static final Class<ChannelGroup> PARENT_TYPE_CHANNELGROUP = ChannelGroup.class;
+
+	/**
+	 * The {@link ParameterSet} child type.
+	 */
+	public static final Class<ParameterSet> CHILD_TYPE_PARAMETERSET = ParameterSet.class;
+
+	/**
+	 * The 'Minimum' attribute name.
+	 */
+	public static final String ATTR_MINIMUM = "Minimum";
+
+	/**
+	 * The 'Maximum' attribute name.
+	 */
+	public static final String ATTR_MAXIMUM = "Maximum";
+
+	/**
+	 * The 'Average' attribute name.
+	 */
+	public static final String ATTR_AVERAGE = "Average";
+
+	/**
+	 * The 'Deviation' attribute name.
+	 */
+	public static final String ATTR_DEVIATION = "Deviation";
+
+	/**
+	 * The 'ScalarType' attribute name.
+	 */
+	public static final String ATTR_SCALAR_TYPE = "DataType";
+
+	/**
+	 * The 'Interpolation' attribute name.
+	 */
+	public static final String ATTR_INTERPOLATION = "Interpolation";
+
+	/**
+	 * The 'Rank' attribute name.
+	 */
+	public static final String ATTR_RANK = "Rank";
+
+	/**
+	 * The 'TypeSize' attribute name.
+	 */
+	public static final String ATTR_TYPE_SIZE = "TypeSize";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Channel(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the minimum value of this channel.
+	 *
+	 * @return The minimum value is returned.
+	 */
+	public Double getMinimum() {
+		return getValue(ATTR_MINIMUM).extract();
+	}
+
+	/**
+	 * Sets new minimum value for this channel.
+	 *
+	 * @param minimum The new minimum value.
+	 */
+	public void setMinimum(Double minimum) {
+		getValue(ATTR_MINIMUM).set(minimum);
+	}
+
+	/**
+	 * Returns the maximum value of this channel.
+	 *
+	 * @return The maximum value is returned.
+	 */
+	public Double getMaximum() {
+		return getValue(ATTR_MAXIMUM).extract();
+	}
+
+	/**
+	 * Sets new maximum value for this channel.
+	 *
+	 * @param maximum The new maximum value.
+	 */
+	public void setMaximum(Double maximum) {
+		getValue(ATTR_MAXIMUM).set(maximum);
+	}
+
+	/**
+	 * Returns the average value of this channel.
+	 *
+	 * @return The average value is returned.
+	 */
+	public Double getAverage() {
+		return getValue(ATTR_AVERAGE).extract();
+	}
+
+	/**
+	 * Sets new average value for this channel.
+	 *
+	 * @param average The new average value.
+	 */
+	public void setAverage(Double average) {
+		getValue(ATTR_AVERAGE).set(average);
+	}
+
+	/**
+	 * Returns the deviation value of this channel.
+	 *
+	 * @return The deviation value is returned.
+	 */
+	public Double getDeviation() {
+		return getValue(ATTR_DEVIATION).extract();
+	}
+
+	/**
+	 * Sets new deviation value for this channel.
+	 *
+	 * @param deviation The new deviation value.
+	 */
+	public void setDeviation(Double deviation) {
+		getValue(ATTR_DEVIATION).set(deviation);
+	}
+
+	/**
+	 * Returns the {@link ScalarType} of this channel.
+	 *
+	 * @return The {@code ScalarType} is returned.
+	 */
+	public ScalarType getScalarType() {
+		return getValue(ATTR_SCALAR_TYPE).extract();
+	}
+
+	/**
+	 * Sets new {@link ScalarType} for this channel.
+	 *
+	 * @param scalarType The new {@code ScalarType}.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is
+	 *                                  {@link ScalarType#UNKNOWN}.
+	 */
+	public void setScalarType(ScalarType scalarType) {
+		if (scalarType.isUnknown()) {
+			throw new IllegalArgumentException("Scalar type constant is not allowed to be '" + scalarType + "'.");
+		}
+
+		getValue(ATTR_SCALAR_TYPE).set(scalarType);
+	}
+
+	/**
+	 * Returns the {@link Interpolation} of this channel.
+	 *
+	 * @return The {@code Interpolation} is returned.
+	 */
+	public Interpolation getInterpolation() {
+		return getValue(ATTR_INTERPOLATION).extract();
+	}
+
+	/**
+	 * Sets new interpolation for this channel.
+	 *
+	 * @param interpolation The new {@code Interpolation}.
+	 */
+	public void setInterpolation(Interpolation interpolation) {
+		getValue(ATTR_INTERPOLATION).set(interpolation);
+	}
+
+	/**
+	 * Returns the rank of this channel.
+	 *
+	 * @return The rank is returned.
+	 */
+	public Integer getRank() {
+		return getValue(ATTR_RANK).extract();
+	}
+
+	/**
+	 * Sets new rank for this channel.
+	 *
+	 * @param rank The new rank.
+	 */
+	public void setRank(Integer rank) {
+		getValue(ATTR_RANK).set(rank);
+	}
+
+	/**
+	 * Returns the type size of this channel.
+	 *
+	 * @return The type size is returned.
+	 */
+	public Integer getTypeSize() {
+		return getValue(ATTR_TYPE_SIZE).extract();
+	}
+
+	/**
+	 * Sets new type size for this channel.
+	 *
+	 * @param typeSize The new type size.
+	 */
+	public void setTypeSize(Integer typeSize) {
+		getValue(ATTR_TYPE_SIZE).set(typeSize);
+	}
+
+	/**
+	 * Returns the related {@link Unit}.
+	 *
+	 * @return Related {@code Unit} is returned.
+	 */
+	public Unit getUnit() {
+		return getCore().getMutableStore().get(Unit.class);
+	}
+
+	/**
+	 * Returns the related {@link Quantity}.
+	 *
+	 * @return Related {@code Quantity} is returned.
+	 */
+	public Quantity getQuantity() {
+		return getCore().getMutableStore().get(Quantity.class);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ChannelGroup.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ChannelGroup.java
new file mode 100644
index 0000000..e906bdd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ChannelGroup.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the channel group entity type. It belongs to exactly one
+ * {@link Measurement} and groups a set of its {@link Channel}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ChannelGroup extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Measurement} parent type.
+	 */
+	public static final Class<Measurement> PARENT_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The {@link Channel} child type.
+	 */
+	public static final Class<Channel> CHILD_TYPE_CHANNEL = Channel.class;
+
+	/**
+	 * The 'NumberOfValues' attribute name.
+	 */
+	public static final String ATTR_NUMBER_OF_VALUES = "SubMatrixNoRows";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ChannelGroup(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the number of measured values of each related {@link Channel}.
+	 *
+	 * @return The number of measured values per {@code Channel} is returned.
+	 */
+	public Integer getNumberOfValues() {
+		return getValue(ATTR_NUMBER_OF_VALUES).extract();
+	}
+
+	/**
+	 * Sets new number of values for this channel group.
+	 *
+	 * @param numberOfValues The new number of values.
+	 */
+	public void setNumberOfValues(Integer numberOfValues) {
+		getValue(ATTR_NUMBER_OF_VALUES).set(numberOfValues);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextComponent.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextComponent.java
new file mode 100644
index 0000000..bbd3bec
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextComponent.java
@@ -0,0 +1,116 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the context component entity types. Instances of this class
+ * are only provided / managed via the owning descriptive {@link ContextRoot}.
+ * Additionally if the owning {@code ContextRoot} is of type
+ * {@link ContextType#TESTEQUIPMENT} this context component may have relations
+ * to {@link ContextSensor}s whose names have to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ContextComponent extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ContextComponent(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextSensor} identified by given name.
+	 *
+	 * @param name The name of the {@code ContextSensor}.
+	 * @return The {@code Optional} is empty if a {@code ContextSensor} with given
+	 *         name does not exist.
+	 */
+	public Optional<ContextSensor> getContextSensor(String name) {
+		return getContextSensors().stream().filter(cs -> cs.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link ContextSensor}s related to this context
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<ContextSensor> getContextSensors() {
+		return getCore().getChildrenStore().get(ContextSensor.class);
+	}
+
+	/**
+	 * Returns the {@link ContextRoot} this context component belongs to.
+	 *
+	 * @return The parent {@link ContextRoot}.
+	 */
+	public ContextRoot getContextRoot() {
+		return getCore().getPermanentStore().get(ContextRoot.class);
+	}
+
+	/**
+	 * Removes the {@link ContextSensor} identified by given name.
+	 *
+	 * @param name Name of the {@code ContextSensor} that has to be removed.
+	 * @return Returns {@code true} if the {@code ContextSensor} with given name has
+	 *         been removed.
+	 */
+	public boolean removeContextSensor(String name) {
+		Optional<ContextSensor> catalogSensor = getContextSensor(name);
+		if (catalogSensor.isPresent()) {
+			getCore().getChildrenStore().remove(catalogSensor.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<ContextSensor> contextSensors = getContextSensors();
+		if (!contextSensors.isEmpty()) {
+			sb.append(", ContextSensors = ").append(contextSensors);
+		}
+
+		return sb.append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextDescribable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextDescribable.java
new file mode 100644
index 0000000..9fea69a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextDescribable.java
@@ -0,0 +1,62 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * {@link TestStep} and {@link Measurement} entity types implement this
+ * interface to indicate the availability of descriptive context data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ContextRoot
+ * @see ContextComponent
+ * @see ContextSensor
+ */
+public interface ContextDescribable extends Entity {
+	/**
+	 * Queries available {@link ContextType} for given {@link ContextDescribable}.
+	 *
+	 * @param manager An object implementing BaseEntityManager.
+	 * @return {@code List} contains the {@code ContextType} of each referenced
+	 *         {@link ContextRoot}.
+	 * @throws DataAccessException Thrown if unable to query the available
+	 *                             {@code ContextType}s.
+	 */
+	List<ContextType> loadContextTypes(BaseEntityManager manager) throws DataAccessException;
+
+	/**
+	 * Loads the requested {@link ContextRoot}s for given
+	 * {@link ContextDescribable}.
+	 *
+	 * @param manager      An object implementing BaseEntityManager.
+	 * @param contextTypes The requested context types. If omitted, all types are be
+	 *                     loaded.
+	 * @return The ordered contexts for given {@code TestStep} or the measured ones
+	 *         for {@code Measurement} are returned in a {@code Map}.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code
+	 * 		ContextRoot}        s.
+	 * @see ContextType
+	 */
+	Map<ContextType, ContextRoot> loadContexts(BaseEntityManager manager, ContextType... contextTypes)
+			throws DataAccessException;
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextRoot.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextRoot.java
new file mode 100644
index 0000000..369e1fd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextRoot.java
@@ -0,0 +1,208 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the context root entity types. This is the root node of the
+ * descriptive component structure for a {@link ContextType}. This element is
+ * used for both, order and measured result description data. If it belongs to
+ * an order description, then a relation to a {@link TestStep} exists. Otherwise
+ * it represents the description of a measurement and therefore has one ore more
+ * relations to {@link Measurement}s. In the base application model the
+ * component structure is provided as is. An extension of the base application
+ * model may define a template, the structure of contained
+ * {@link ContextComponent}s and {@link ContextSensor}s will be restricted to.
+ * Additionally the <b>names</b> of all related {@code ContextComponent}s have
+ * to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ContextRoot extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Version' attribute name.
+	 */
+	public static final String ATTR_VERSION = "Version";
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ContextType contextType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ContextRoot(Core core) {
+		super(core);
+		contextType = ContextType.valueOf(core.getTypeName().toUpperCase(Locale.ROOT));
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextType} of this context root.
+	 *
+	 * @return The {@code ContextType} is returned.
+	 */
+	public ContextType getContextType() {
+		return contextType;
+	}
+
+	/**
+	 * Returns the {@link ContextComponent} identified by given name.
+	 *
+	 * @param name The name of the {@code ContextComponent}.
+	 * @return The {@code Optional} is empty if a {@code ContextComponent} with
+	 *         given name does not exist.
+	 */
+	public Optional<ContextComponent> getContextComponent(String name) {
+		return getContextComponents().stream().filter(cc -> cc.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link ContextComponent}s related to this context root.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<ContextComponent> getContextComponents() {
+		return getCore().getChildrenStore().get(ContextComponent.class);
+	}
+
+	/**
+	 * Removes the {@link ContextComponent} identified by given name.
+	 *
+	 * @param name Name of the {@code ContextComponent} that have to be removed.
+	 * @return Returns {@code true} if the {@code ContextComponent} with given name
+	 *         has been removed.
+	 */
+	public boolean removeContextComponent(String name) {
+		Optional<ContextComponent> contextComponent = getContextComponent(name);
+		if (contextComponent.isPresent()) {
+			getCore().getChildrenStore().remove(contextComponent.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns all available {@link ContextSensor}s related to the
+	 * {@link ContextComponent}s, which are held by this context root.
+	 *
+	 * @return The returned {@code List} will always be empty if this context root
+	 *         is of type {@link ContextType#UNITUNDERTEST} or
+	 *         {@link ContextType#TESTSEQUENCE}.
+	 */
+	public List<ContextSensor> getContextSensors() {
+		if (!getContextType().isTestEquipment()) {
+			return Collections.emptyList();
+		}
+
+		return getContextComponents().stream().map(ContextComponent::getContextSensors).collect(ArrayList::new,
+				List::addAll, List::addAll);
+	}
+
+	/**
+	 * Returns the version of this context root.
+	 *
+	 * @return The version is returned.
+	 */
+	public String getVersion() {
+		return getValue(ATTR_VERSION).extract();
+	}
+
+	/**
+	 * Sets new version for this context root.
+	 *
+	 * @param version The new version.
+	 */
+	public void setVersion(String version) {
+		getValue(ATTR_VERSION).set(version);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append("ContextType = ").append(getContextType()).append(", ");
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<ContextComponent> contextComponents = getContextComponents();
+		if (!contextComponents.isEmpty()) {
+			sb.append(", ContextComponents = ").append(contextComponents);
+		}
+
+		return sb.append(')').toString();
+	}
+
+	/**
+	 * Convenience method to access the {@link ContextRoot}s of newly created
+	 * {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or a {@link Measurement}.
+	 * @return The {@code ContextRoot}s are returned.
+	 */
+	public static List<ContextRoot> of(ContextDescribable contextDescribable) {
+		List<ContextRoot> contextRoots = new ArrayList<>();
+		of(contextDescribable, ContextType.UNITUNDERTEST).ifPresent(contextRoots::add);
+		of(contextDescribable, ContextType.TESTSEQUENCE).ifPresent(contextRoots::add);
+		of(contextDescribable, ContextType.TESTEQUIPMENT).ifPresent(contextRoots::add);
+		return contextRoots;
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextRoot} with given {@link ContextType} from given
+	 * {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or a {@link Measurement}.
+	 * @param contextType        The requested {@code ContextType}.
+	 * @return {@code Optional} is empty if a {@code ContextRoot} with given
+	 *         {@code ContextType} does not exist.
+	 */
+	private static Optional<ContextRoot> of(ContextDescribable contextDescribable, ContextType contextType) {
+		return Optional.ofNullable(getCore(contextDescribable).getMutableStore().get(ContextRoot.class, contextType));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextSensor.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextSensor.java
new file mode 100644
index 0000000..7579c12
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextSensor.java
@@ -0,0 +1,51 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the context sensor entity types. Instances of this class
+ * are only provided / managed via the owning {@link ContextComponent}. A
+ * context sensor may be related to a {@link Channel}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ContextSensor extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ContextSensor(Core core) {
+		super(core);
+	}
+
+	/**
+	 * Returns the {@link ContextComponent} this context sensor belongs to.
+	 *
+	 * @return The parent {@link ContextComponent}
+	 */
+	public ContextComponent getContextComponent() {
+		return getCore().getPermanentStore().get(ContextComponent.class);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextType.java
new file mode 100644
index 0000000..98a3541
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextType.java
@@ -0,0 +1,81 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Context type enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ContextRoot
+ */
+public enum ContextType {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * A {@link ContextRoot} of this type unites meta data of the unit under test.
+	 */
+	UNITUNDERTEST,
+
+	/**
+	 * A {@link ContextRoot} of this type unites meta data of the test conditions.
+	 */
+	TESTSEQUENCE,
+
+	/**
+	 * A {@link ContextRoot} of this type unites meta data of the used equipment
+	 * (hardware and sensors).
+	 */
+	TESTEQUIPMENT;
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns true if this context type is {@link #UNITUNDERTEST}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isUnitUnderTest() {
+		return UNITUNDERTEST == this;
+	}
+
+	/**
+	 * Returns true if this context type is {@link #TESTSEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isTestSequence() {
+		return TESTSEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this context type is {@link #TESTEQUIPMENT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isTestEquipment() {
+		return TESTEQUIPMENT == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Datable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Datable.java
new file mode 100644
index 0000000..714dc74
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Datable.java
@@ -0,0 +1,60 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'DateCreated' field of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Datable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'DateCreated' attribute name.
+	 */
+	String ATTR_DATE_CREATED = "DateCreated";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the creation time stamp of this entity.
+	 *
+	 * @return The creation time stamp is returned.
+	 */
+	default LocalDateTime getDateCreated() {
+		return getValue(ATTR_DATE_CREATED).extract();
+	}
+
+	/**
+	 * Set new creation time stamp for this entity.
+	 *
+	 * @param dateCreated The new creation time stamp.
+	 */
+	default void setDateCreated(LocalDateTime dateCreated) {
+		getValue(ATTR_DATE_CREATED).set(dateCreated);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Deletable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Deletable.java
new file mode 100644
index 0000000..156d949
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Deletable.java
@@ -0,0 +1,27 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This interface is used to indicate that implementing entity types are allowed
+ * to be deleted.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Deletable extends Entity {
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Describable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Describable.java
new file mode 100644
index 0000000..0ea31f8
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Describable.java
@@ -0,0 +1,58 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'Description' field of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Describable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Description' attribute name.
+	 */
+	String ATTR_DESCRIPTION = "Description";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the description of this entity.
+	 *
+	 * @return The description is returned.
+	 */
+	default String getDescription() {
+		return getValue(ATTR_DESCRIPTION).extract();
+	}
+
+	/**
+	 * Sets new description for this entity.
+	 *
+	 * @param description The new description.
+	 */
+	default void setDescription(String description) {
+		getValue(ATTR_DESCRIPTION).set(description);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/DoubleComplex.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/DoubleComplex.java
new file mode 100644
index 0000000..c870ee2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/DoubleComplex.java
@@ -0,0 +1,100 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This class represents a complex value with real and imaginary parts of type
+ * {@code double}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class DoubleComplex {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final double re;
+	private final double im;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param real      The real part.
+	 * @param imaginary The imaginary part.
+	 */
+	public DoubleComplex(double real, double imaginary) {
+		re = real;
+		im = imaginary;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Parses given {@code String} where real and imaginary parts are separated by
+	 * one or more blanks. Furthermore both must be floating point numbers that can
+	 * be parsed by calling {@link Double#valueOf(String)}.
+	 *
+	 * @param s The {@code String} to be parsed.
+	 * @return The parsed {@link DoubleComplex} value is returned.
+	 * @throws NumberFormatException Thrown if unable to parse the complex value.
+	 */
+	public static DoubleComplex valueOf(String s) {
+		String[] values = s.split(" +");
+		if (values.length != 2) {
+			throw new NumberFormatException("Unable to parse complex value.");
+		}
+
+		return new DoubleComplex(Double.parseDouble(values[0]), Double.parseDouble(values[1]));
+	}
+
+	/**
+	 * Returns the real part of this complex value.
+	 *
+	 * @return The real part is returned.
+	 */
+	public double real() {
+		return re;
+	}
+
+	/**
+	 * Returns the imaginary part of this complex value.
+	 *
+	 * @return The imaginary part is returned.
+	 */
+	public double imaginary() {
+		return im;
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this complex value.
+	 * The real and imaginary parts are separated with a blank.
+	 *
+	 * @return The {@code String} representation of this complex value.
+	 */
+	@Override
+	public String toString() {
+		return new StringBuilder().append(real()).append(' ').append(imaginary()).toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Entity.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Entity.java
new file mode 100644
index 0000000..bd48e4f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Entity.java
@@ -0,0 +1,148 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * This is the base interface for any modeled entity type.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * This {@code Comparator} compares entities by their name in ascending order.
+	 */
+	Comparator<Entity> COMPARATOR = Comparator.comparing(Entity::getName);
+
+	/**
+	 * The 'MimeType' attribute name.
+	 */
+	String ATTR_MIMETYPE = "MimeType";
+
+	/**
+	 * The 'Name' attribute name.
+	 */
+	String ATTR_NAME = "Name";
+
+	/**
+	 * The 'Id' attribute name.
+	 */
+	String ATTR_ID = "Id";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of the data source this entity was retrieved from.
+	 *
+	 * @return Name of the data source.
+	 */
+	String getSourceName();
+
+	/**
+	 * Returns the name of the entity type.
+	 *
+	 * @return Name of the entity type is returned.
+	 */
+	String getTypeName();
+
+	/**
+	 * Returns the instance ID or {@code 0} if this instance is not yet persisted.
+	 *
+	 * @return The instance ID is returned.
+	 */
+	String getID();
+
+	/**
+	 * Returns the name of this entity.
+	 *
+	 * @return The name is returned.
+	 */
+	default String getName() {
+		return getValue(ATTR_NAME).extract();
+	}
+
+	/**
+	 * Sets new name for this entity.
+	 *
+	 * @param name The new name.
+	 */
+	default void setName(String name) {
+		getValue(ATTR_NAME).set(name);
+	}
+
+	/**
+	 * Returns the {@link MimeType} of this entity.
+	 *
+	 * @return The {@code MimeType} is returned.
+	 */
+	default MimeType getMimeType() {
+		return new MimeType(getValue(ATTR_MIMETYPE).extract());
+	}
+
+	/**
+	 * Sets new {@link MimeType} for this entity.
+	 *
+	 * @param mimeType The new {@code MimeType}.
+	 */
+	default void setMimeType(MimeType mimeType) {
+		getValue(ATTR_MIMETYPE).set(mimeType.toString());
+	}
+
+	/**
+	 * Returns the {@link Value} container associated with given name.
+	 *
+	 * @param name Name of the attribute.
+	 * @return The {@code Value} container is returned.
+	 */
+	Value getValue(String name);
+
+	/**
+	 * Returns <i>all</i> {@link Value} containers of this entity mapped by their
+	 * name (no matter a value is valid or not).
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	Map<String, Value> getValues();
+
+	/**
+	 * Returns a human readable {@code String} representation of this entity.
+	 *
+	 * @return The {@code String} representation of this entity.
+	 */
+	@Override
+	String toString();
+
+	/**
+	 * Checks whether given name equals the name of this entity.
+	 *
+	 * @param name The checked name.
+	 * @return Returns {@code true} if given name equals the name of this entity.
+	 */
+	default boolean nameEquals(String name) {
+		return getName().equals(name);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumRegistry.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumRegistry.java
new file mode 100644
index 0000000..1d5d56f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumRegistry.java
@@ -0,0 +1,78 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This singleton class registers globally available enumerations.
+ *
+ */
+public final class EnumRegistry {
+
+	// singleton instance
+	private static final EnumRegistry instance = new EnumRegistry();
+
+	public static final String SCALAR_TYPE = "ScalarType";
+	public static final String INTERPOLATION = "Interpolation";
+	public static final String SEQUENCE_REPRESENTATION = "SequenceRepresentation";
+	public static final String TYPE_SPECIFICATION = "TypeSpecification";
+	public static final String VALUE_TYPE = "ValueType";
+	public static final String VERSION_STATE = "VersionState";
+	public static final String AXIS_TYPE = "AxisType";
+
+	private Map<String, Enumeration<? extends EnumerationValue>> enumerations;
+
+	/**
+	 * Constructor. Not called directly. Use getInstance() instead.
+	 */
+	private EnumRegistry() {
+		enumerations = new HashMap<>();
+		add(INTERPOLATION, new Enumeration<Interpolation>(Interpolation.class, INTERPOLATION));
+		add(SCALAR_TYPE, new Enumeration<ScalarType>(ScalarType.class, SCALAR_TYPE));
+		add(SEQUENCE_REPRESENTATION,
+				new Enumeration<SequenceRepresentation>(SequenceRepresentation.class, SEQUENCE_REPRESENTATION));
+		add(TYPE_SPECIFICATION, new Enumeration<TypeSpecification>(TypeSpecification.class, TYPE_SPECIFICATION));
+		add(VALUE_TYPE, new Enumeration<ValueType>(ValueType.class, VALUE_TYPE));
+		add(VERSION_STATE, new Enumeration<VersionState>(VersionState.class, VERSION_STATE));
+		add(AXIS_TYPE, new Enumeration<AxisType>(AxisType.class, AXIS_TYPE));
+	}
+
+	/**
+	 * adds a new enumeration to the registry
+	 * 
+	 * @param name        the name under which the enumeration can be accessed
+	 * @param enumeration the dynamic enumeration object
+	 */
+	public void add(String name, Enumeration<? extends EnumerationValue> enumeration) {
+		enumerations.put(name, enumeration);
+	}
+
+	/**
+	 * @param name the name of the registered enumeration
+	 * @return the dynamic enumeration object
+	 */
+	public Enumeration<?> get(String name) {
+		return enumerations.get(name);
+	}
+
+	/**
+	 * @return the instance of this singleton
+	 */
+	public static EnumRegistry getInstance() {
+		return instance;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Enumeration.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Enumeration.java
new file mode 100644
index 0000000..79bd4ad
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Enumeration.java
@@ -0,0 +1,151 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class which dynamically bundles enumeration values
+ *
+ * @param <E>
+ */
+public class Enumeration<E extends EnumerationValue> {
+
+	private Map<String, E> values;
+
+	private Map<E, String> revvalues;
+
+	private Map<Integer, String> ordinals;
+
+	private Map<String, Integer> revordinals;
+
+	private int maxordinal;
+
+	private String name;
+
+	private Class<E> enumclass;
+
+	/**
+	 * Constructor. Static fields in the given enumclass of the same type are added
+	 * automatically as enum values. This way you can simply prefill the object with
+	 * static values.
+	 * 
+	 * @param enumclass the class of the enumeration values
+	 * @param name      the name of the enumeration bundle
+	 */
+	@SuppressWarnings("unchecked")
+	public Enumeration(Class<E> enumclass, String name) {
+		this.maxordinal = 0;
+		this.values = new HashMap<>();
+		this.revvalues = new HashMap<>();
+		this.ordinals = new HashMap<>();
+		this.revordinals = new HashMap<>();
+		this.name = name;
+		this.enumclass = enumclass;
+		java.lang.reflect.Field[] fields = enumclass.getFields();
+		for (Field field : fields) {
+			if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) // only
+																			// examine
+																			// static
+																			// fields
+			{
+				Object fieldObject;
+				try {
+					fieldObject = field.get(null);
+					if (!(enumclass.isInstance(fieldObject))) {
+						continue;
+					}
+				} catch (Exception e) {
+					throw new RuntimeException(e);
+				}
+				String fname = ((EnumerationValue) fieldObject).name();
+				if (fname == null) {
+					fname = field.getName();
+					((EnumerationValue) fieldObject).setName(fname);
+				}
+				addValue((E) fieldObject);
+			}
+		}
+	}
+
+	/**
+	 * adds a value to the dynamic enumeration
+	 * 
+	 * @param enumeration
+	 */
+	public void addValue(E enumeration) {
+		enumeration.setOwner(this);
+		String enumerationName = enumeration.name();
+		Integer ordinal = enumeration.ordinal();
+		if (ordinal == null) {
+			ordinal = ++maxordinal;
+			enumeration.setOrdinal(ordinal);
+		} else {
+			maxordinal = Math.max(ordinal, maxordinal);
+		}
+		values.put(enumerationName, enumeration);
+		revvalues.put(enumeration, enumerationName);
+		ordinals.put(ordinal, enumerationName);
+		revordinals.put(enumerationName, ordinal);
+	}
+
+	/**
+	 * returns the value represented by the given name
+	 * 
+	 * @param name
+	 * @return
+	 */
+	public E valueOf(String name) {
+		return values.get(name);
+	}
+
+	/**
+	 * returns the value represented by the given number
+	 * 
+	 * @param ordinal
+	 * @return
+	 */
+	public E valueOf(int ordinal) {
+		return values.get(ordinals.get(ordinal));
+	}
+
+	/**
+	 * returns the ordinal represented by the given enumeration value
+	 * 
+	 * @param enumval
+	 * @return
+	 */
+	public int ordinal(EnumerationValue enumval) {
+		return revordinals.get(revvalues.get(enumval));
+	}
+
+	/**
+	 * @return the class of the enumeration values represented by this dynamic
+	 *         enumeration
+	 */
+	public Class<E> getEnumClass() {
+		return enumclass;
+	}
+
+	/**
+	 * @return the name of the dynamic enumeration collection
+	 */
+	public String getName() {
+		return name;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumerationValue.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumerationValue.java
new file mode 100644
index 0000000..679d7c4
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumerationValue.java
@@ -0,0 +1,135 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Objects;
+
+/**
+ * This class emulates the behaviour of a java enum. The reason for its
+ * existence is that classic enums can't be extended by new values. This class
+ * on the other hand can be extended by java's inheritance mechanism.
+ * 
+ * For a basic emulation of java enums, just extend this class and add static
+ * fields whose type is of the derivative class.
+ * 
+ * To be able to add dynamically enum values and for full initialization, you
+ * should set an owner enumeration (either by choosing the right constructor or
+ * by calling the setOwner method)
+ * 
+ * @author Florian Schmitt
+ *
+ */
+public class EnumerationValue {
+
+	private String name;
+	private Integer ordinal;
+
+	private Enumeration<? extends EnumerationValue> owner;
+
+	/**
+	 * explicitly set the name of this element.
+	 *
+	 * @param name
+	 */
+	protected void setName(String name) {
+		this.name = Objects.requireNonNull(name);
+	}
+
+	/**
+	 * explicitly set the ordinal of this element.
+	 */
+	protected void setOrdinal(int ordinal) {
+		this.ordinal = ordinal;
+	}
+
+	/**
+	 * 
+	 * set the owner dynamic enumeration of this object.
+	 * 
+	 * @param er
+	 */
+	protected void setOwner(Enumeration<? extends EnumerationValue> er) {
+		owner = er;
+	}
+
+	/**
+	 * get the owner dynamic enumeration of this object
+	 * 
+	 * @return
+	 */
+	public Enumeration<? extends EnumerationValue> getOwner() {
+		return owner;
+	}
+
+	/**
+	 * This Constructor is protected to avoid accidental misuse.
+	 * 
+	 * be sure to initialize the enumeration fully, by either adding it as a static
+	 * field in an extending class, or setting the ordinal by hand. You'll also have
+	 * to add the resulting object to a DynamicEnumeration for it to be completely
+	 * usable.
+	 * 
+	 * @param name
+	 */
+	protected EnumerationValue(String name) {
+		this(name, null);
+	}
+
+	/**
+	 * This Constructor is protected to avoid accidental misuse.
+	 * 
+	 * You'll have to add the resulting object to a Enumeration for it to be
+	 * completely usable.
+	 * 
+	 * @param name
+	 */
+	protected EnumerationValue(String name, Integer ordinal) {
+		this.name = Objects.requireNonNull(name, "Name of an EnumerationValue can never be null!");
+		this.ordinal = ordinal;
+		this.owner = null;
+	}
+
+	/**
+	 * @return the name of this enumeration value
+	 */
+	public String name() {
+		return name;
+	}
+
+	/**
+	 * @return the enumeration value represented by the given name
+	 */
+	public EnumerationValue valueOf(String name) {
+		return owner.valueOf(name);
+	}
+
+	/**
+	 * @return the ordinal value represented by this enumeration value
+	 */
+	public Integer ordinal() {
+		return ordinal;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return name();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Environment.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Environment.java
new file mode 100644
index 0000000..4b990e1
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Environment.java
@@ -0,0 +1,134 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the environment entity type. The {@link Environment} is a
+ * singleton within a connected data source.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Environment extends BaseEntity implements Datable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'MaxTestLevel' attribute name.
+	 */
+	public static final String ATTR_MAX_TEST_LEVEL = "Max_test_level";
+
+	/**
+	 * The 'BaseModelVersion' attribute name.
+	 */
+	public static final String ATTR_BASE_MODEL_VERSION = "Base_model_version";
+
+	/**
+	 * The 'AppModelVersion' attribute name.
+	 */
+	public static final String ATTR_APP_MODEL_VERSION = "AppModelVersion";
+
+	/**
+	 * The 'AppModelType' attribute name.
+	 */
+	public static final String ATTR_APP_MODEL_TYPE = "AppModelType";
+
+	/**
+	 * The 'Timezone' attribute name.
+	 */
+	public static final String ATTR_TIMEZONE = "Timezone";
+
+	/**
+	 * The 'MeaningOfAliases' attribute name.
+	 */
+	public static final String ATTR_MEANING_OF_ALIASES = "MeaningOfAliases";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Environment(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the max test level of this environment.
+	 *
+	 * @return The max test level is returned.
+	 */
+	public Integer getMaxTestLevel() {
+		return getValue(ATTR_MAX_TEST_LEVEL).extract();
+	}
+
+	/**
+	 * Returns the base model version of this environment.
+	 *
+	 * @return The base model version is returned.
+	 */
+	public String getBaseModelVersion() {
+		return getValue(ATTR_BASE_MODEL_VERSION).extract();
+	}
+
+	/**
+	 * Returns the application model version of this environment.
+	 *
+	 * @return The application model version is returned.
+	 */
+	public String getAppModelVersion() {
+		return getValue(ATTR_APP_MODEL_VERSION).extract();
+	}
+
+	/**
+	 * Returns the application model type of this environment.
+	 *
+	 * @return The application model type is returned.
+	 */
+	public String getAppModelType() {
+		return getValue(ATTR_APP_MODEL_TYPE).extract();
+	}
+
+	/**
+	 * Returns the time zone of this environment.
+	 *
+	 * @return The time zone is returned.
+	 */
+	public String getTimezone() {
+		return getValue(ATTR_TIMEZONE).extract();
+	}
+
+	/**
+	 * Returns the Meaning of aliases of this environment.
+	 *
+	 * @return The meaning of aliases are returned.
+	 */
+	public String[] getMeaningOfAliases() {
+		return getValue(ATTR_MEANING_OF_ALIASES).extract();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FileLink.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FileLink.java
new file mode 100644
index 0000000..f558b54
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FileLink.java
@@ -0,0 +1,506 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Utility class to manage links to externally stored files (local/remote).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class FileLink {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final State state;
+
+	private String remotePath;
+	private MimeType mimeType;
+	private String description;
+
+	private InputStream localStream;
+	private String localFileName;
+
+	private long size = -1;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param fileLink Will be copied.
+	 */
+	FileLink(FileLink fileLink) {
+		remotePath = fileLink.remotePath;
+		mimeType = fileLink.mimeType;
+		description = fileLink.description;
+		localStream = fileLink.localStream;
+		size = fileLink.size;
+		state = fileLink.state;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param remotePath The remote path.
+	 * @param mimeType   The MIME type of the linked file.
+	 */
+	private FileLink(String remotePath, MimeType mimeType) {
+		this.remotePath = remotePath;
+		this.mimeType = mimeType;
+
+		state = State.REMOTE;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param localPath The local {@link Path}.
+	 * @throws IOException Thrown in case of errors.
+	 */
+	private FileLink(InputStream localStream, String name, long size, MimeType mimeType, String description) throws IOException {
+		this.localStream = localStream;
+		this.mimeType = mimeType == null ? new MimeType("application/octet-stream") : mimeType;
+		this.size = size;
+		this.localFileName = name;
+		this.description = description;
+		state = State.LOCAL;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link FileLink} instance which remotely available.
+	 *
+	 * @param remotePath  The remote path.
+	 * @param mimeType    The MIME type.
+	 * @param description Description of the file.
+	 * @return The created {@code FileLink} instance is returned.
+	 */
+	public static FileLink newRemote(String remotePath, MimeType mimeType, String description) {
+		FileLink fileLink = new FileLink(remotePath, mimeType);
+		fileLink.setDescription(description);
+		return fileLink;
+	}
+
+	/**
+	 * Creates a new {@link FileLink} instance which locally available.
+	 *
+	 * @param localPath The local {@link Path} to the file.
+	 * @return The created {@code FileLink} instance is returned.
+	 * @throws IOException Thrown if unable to access file with given {@code
+	 * 		Path}       .
+	 */
+	public static FileLink newLocal(InputStream localStream, String name, long size, MimeType mimeType, String description) throws IOException {
+		return new FileLink(localStream, name, size, mimeType, description);
+	}
+	
+	public static FileLink newLocal(Path localPath) throws IOException {
+		if (Files.isDirectory(localPath)) {
+			throw new IllegalArgumentException("Local path is a directory.");
+		} else if (!Files.exists(localPath)) {
+			throw new IllegalArgumentException("Local path does not exist.");
+		} else if (!Files.isReadable(localPath)) {
+			throw new IllegalArgumentException("Local path is not readable.");
+		}
+		
+		InputStream localStream = Files.newInputStream(localPath);
+		long size = Files.size(localPath);
+		String name = localPath.getFileName().toString();
+		String mimeType = Files.probeContentType(localPath);
+		MimeType mimeT = mimeType == null ? null : new MimeType(mimeType);
+		return new FileLink(localStream, name, size, mimeT, name);
+	}
+
+	/**
+	 * Returns the name of the linked file.
+	 *
+	 * @return Name of the file is returned.
+	 * @throws IllegalStateException Thrown if unable to retrieve the file name.
+	 */
+	public String getFileName() {
+		Path fileNamePath = null;
+		String fileName = null;
+		if (isLocal()) {
+			fileName = this.localFileName;
+		} else if (isRemote()) {
+			try {
+				// on Windows, Paths.get() cannot handle file urls in the form
+				// file://REMOTE_HOST/path/filename
+				String fixedPath = remotePath.replaceFirst("file:", "");
+				fileNamePath = Paths.get(URLDecoder.decode(fixedPath, StandardCharsets.UTF_8.name())).getFileName();
+			} catch (UnsupportedEncodingException e) {
+				throw new IllegalStateException("Unable to decode remote path due to: " + e.getMessage(), e);
+			}
+			
+			if (fileNamePath == null) {
+				throw new IllegalStateException("File name is unknown.");
+			}
+			fileName = fileNamePath.toString();
+		}
+
+		return fileName;
+	}
+
+	/**
+	 * Returns the MIME type of the linked file.
+	 *
+	 * @return The MIME type is returned.
+	 */
+	public MimeType getMimeType() {
+		return mimeType;
+	}
+
+	/**
+	 * Checks whether a local {@link Path} is available for the linked file.
+	 *
+	 * @return Returns {@code true} if a local {@code Path} is available.
+	 */
+	public boolean isLocal() {
+		return localStream != null;
+	}
+
+	/**
+	 * Returns the local {@link InputStream} to the linked file. Calling this method is
+	 * only allowed if calling {@link #isLocal()} returns {@code
+	 * true}.
+	 *
+	 * @return The local {@code Path} to the linked file is returned.
+	 */
+	public InputStream getLocalStream() {
+		if (isLocal()) {
+			return localStream;
+		}
+
+		throw new IllegalStateException("Local path is not available.");
+	}
+
+	/**
+	 * This method is called by API providers to set the local {@link InputStream} once the
+	 * remote file was downloaded.
+	 *
+	 * @param localPath The local {@code InputStream} of the downloaded file.
+	 * @throws IllegalStateException Thrown if this file link is 'LOCAL'.
+	 */
+	public void setLocalStream(InputStream localStream) {
+		if (State.LOCAL == state) {
+			throw new IllegalStateException("It is not allowed to replace an existing local path.");
+		}
+
+		this.localStream = localStream;
+	}
+
+	/**
+	 * Checks whether a remote path is available for for linked file.
+	 *
+	 * @return Returns {@code true} if a remote path is available.
+	 */
+	public boolean isRemote() {
+		return remotePath != null && !remotePath.isEmpty();
+	}
+
+	/**
+	 * Returns the remote path to the linked file. Calling this method is only
+	 * allowed if calling {@link #isRemote()} returns {@code true}.
+	 *
+	 * @return The remote path to the linked file is returned.
+	 */
+	public String getRemotePath() {
+		if (isRemote()) {
+			return remotePath;
+		}
+
+		throw new IllegalStateException("Remote path is not available.");
+	}
+
+	/**
+	 * This method is called by API providers to set the remote path once the local
+	 * file has been uploaded.
+	 *
+	 * @param remotePath The remote path of the uploaded file.
+	 * @throws IllegalStateException Thrown if this file link is 'REMOTE'.
+	 */
+	public void setRemotePath(String remotePath) {
+		if (State.REMOTE == state) {
+			throw new IllegalStateException("It is not allowed to replace an existing remote path.");
+		}
+		this.remotePath = remotePath;
+	}
+
+	/**
+	 * Returns the description of the linked file.
+	 *
+	 * @return The description is returned.
+	 */
+	public String getDescription() {
+		return description == null ? "" : description;
+	}
+
+	/**
+	 * Sets a new description for the linked file.
+	 *
+	 * @param description The new description.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	/**
+	 * Returns the size of the linked file or {@code -1} if unknown.
+	 *
+	 * @return The file size in bytes is returned.
+	 */
+	public long getSize() {
+		return size;
+	}
+
+	/**
+	 * Returns the formatted file size of the linked file.
+	 *
+	 * @param format Used to format the size.
+	 * @return The formatted file size is returned.
+	 */
+	public String getSize(Format format) {
+		return format.getSize(size);
+	}
+
+	/**
+	 * This method is called by API providers to set the file size for the linked
+	 * file.
+	 *
+	 * @param size The size of the file in bytes.
+	 */
+	public void setFileSize(long size) {
+		this.size = size;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		if (State.LOCAL == state) {
+			if (!isLocal()) {
+				return "".hashCode();
+			}
+			return getLocalStream().hashCode();
+		}
+		if (!isRemote()) {
+			return "".hashCode();
+		}
+		return getRemotePath().hashCode();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (object instanceof FileLink) {
+			FileLink other = (FileLink) object;
+			if (state == other.state) {
+				if (State.LOCAL == state) {
+					if (!isLocal()) {
+						return !other.isLocal();
+					}
+					return getLocalStream().equals(other.getLocalStream());
+				}
+				if (!isRemote()) {
+					return !other.isRemote();
+				}
+				return getRemotePath().equals(other.getRemotePath());
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("FileLink(Description = ");
+
+		if (!getDescription().isEmpty()) {
+			sb.append(getDescription());
+		}
+
+		if (isLocal()) {
+			sb.append(", LocalPath = ").append(getLocalStream());
+		}
+
+		if (isRemote()) {
+			sb.append(", RemotePath = ").append(getRemotePath());
+		}
+
+		sb.append(", Size = ");
+		if (getSize() > 0) {
+			sb.append(getSize(Format.DECIMAL)).append(" / ").append(getSize(Format.BINARY));
+		} else {
+			sb.append("UNKNOWN");
+		}
+
+		return sb.append(')').toString();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Checks whether given {@link FileLink} may be treated as equal. This is the
+	 * case if either their local {@link Path}s or remote paths are equal.
+	 *
+	 * @param o1 The first {@code FileLink}.
+	 * @param o2 The second {@code FileLink}.
+	 * @return Returns {@code true} if either their local {@code Path}s or remote
+	 *         paths are equal.
+	 */
+	static boolean areEqual(FileLink o1, FileLink o2) {
+		return isLocalPathEqual(o1, o2) || isRemotePathEqual(o1, o2);
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Checks whether both {@link FileLink}s return {@code true} when
+	 * {@link #isLocal()} is called and their {@link Path}s are equal.
+	 *
+	 * @param o1 The first {@code FileLink}.
+	 * @param o2 The second {@code FileLink}.
+	 * @return Returns {@code true} if both {@code FileLink}s have a local
+	 *         {@code Path} which are equal.
+	 */
+	private static boolean isLocalPathEqual(FileLink o1, FileLink o2) {
+		return o1.isLocal() && o2.isLocal() && o1.getLocalStream().equals(o2.getLocalStream());
+	}
+
+	/**
+	 * Checks whether both {@link FileLink}s return {@code true} when
+	 * {@link #isRemote()} is called and their remote paths are equal.
+	 *
+	 * @param o1 The first {@code FileLink}.
+	 * @param o2 The second {@code FileLink}.
+	 * @return Returns {@code true} if both {@code FileLink}s have a remote path
+	 *         which are equal.
+	 */
+	private static boolean isRemotePathEqual(FileLink o1, FileLink o2) {
+		return o1.isRemote() && o2.isRemote() && o1.getRemotePath().equals(o2.getRemotePath());
+	}
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * Used to format a number of bytes into a human readable size.
+	 */
+	public enum Format {
+
+		// ======================================================================
+		// Enum constants
+		// ======================================================================
+
+		/**
+		 * Counts 1000 bits as 1 byte, so formats 110592 to '110.6 kB'.
+		 */
+		DECIMAL(1000, "kMGTPE"),
+
+		/**
+		 * Counts 1024 bits as 1 byte, so formats 110592 to '108.0 KiB'.
+		 */
+		BINARY(1024, "KMGTPE");
+
+		// ======================================================================
+		// Inner classes
+		// ======================================================================
+
+		private final String prefixChars;
+		private final int unit;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param unit        The unit.
+		 * @param prefixChars The prefix characters.
+		 */
+		private Format(int unit, String prefixChars) {
+			this.prefixChars = prefixChars;
+			this.unit = unit;
+		}
+
+		// ======================================================================
+		// Private methods
+		// ======================================================================
+
+		/**
+		 * Formats given file size in bytes into a human readable one.
+		 *
+		 * @param size The number of bytes.
+		 * @return Formatted file size is returned.
+		 */
+		private String getSize(long size) {
+			if (size < 0) {
+				return "UNKNOWN";
+			} else if (size < unit) {
+				return size + " B";
+			}
+
+			int exponent = (int) (Math.log(size) / Math.log(unit));
+			String prefixChar = prefixChars.charAt(exponent - 1) + (DECIMAL == this ? "" : "i");
+			return String.format("%.1f %sB", size / Math.pow(unit, exponent), prefixChar);
+		}
+	}
+
+	/**
+	 * Used to preserve the initial state of a {@link FileLink}.
+	 */
+	private enum State {
+
+		/**
+		 * {@link FileLink} was initially only remotely available.
+		 */
+		REMOTE,
+
+		/**
+		 * {@link FileLink} was initially only locally available.
+		 */
+		LOCAL
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FilesAttachable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FilesAttachable.java
new file mode 100644
index 0000000..3ccb0a7
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FilesAttachable.java
@@ -0,0 +1,88 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'FileLinks' sequence field of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see FileLink
+ */
+public interface FilesAttachable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'FileLinks' attribute name.
+	 */
+	String ATTR_FILE_LINKS = "MDMLinks";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns current set of linked files of this entity.
+	 *
+	 * @return Current set of linked files are returned.
+	 */
+	default FileLink[] getFileLinks() {
+		return ((FileLink[]) getValue(ATTR_FILE_LINKS).extract()).clone();
+	}
+
+	/**
+	 * Replaces current set of linked files with given {@link FileLink}s.
+	 *
+	 * @param fileLinks The new {@code FileLink}s.
+	 */
+	default void setFileLinks(FileLink[] fileLinks) {
+		getValue(ATTR_FILE_LINKS).set(fileLinks);
+	}
+
+	/**
+	 * Adds given {@link FileLink} to the current set of linked files.
+	 *
+	 * @param fileLink The new {@code FileLink}.
+	 */
+	default void addFileLink(FileLink fileLink) {
+		FileLink[] fileLinks = getFileLinks();
+
+		FileLink[] newFileLinks = new FileLink[fileLinks.length + 1];
+		System.arraycopy(fileLinks, 0, newFileLinks, 0, fileLinks.length);
+		newFileLinks[fileLinks.length] = fileLink;
+		setFileLinks(newFileLinks);
+	}
+
+	/**
+	 * Removes given {@link FileLink} from current set of linked files.
+	 *
+	 * @param fileLink The {@code FileLink} which shall be removed.
+	 */
+	default void removeFileLink(FileLink fileLink) {
+		List<FileLink> fileLinks = new ArrayList<>(Arrays.asList(getFileLinks()));
+		fileLinks.remove(fileLink);
+		setFileLinks(fileLinks.toArray(new FileLink[fileLinks.size()]));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FloatComplex.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FloatComplex.java
new file mode 100644
index 0000000..226f4a6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FloatComplex.java
@@ -0,0 +1,100 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This class represents a complex value with real and imaginary parts of type
+ * {@code float}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class FloatComplex {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final float re;
+	private final float im;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param real      The real part.
+	 * @param imaginary The imaginary part.
+	 */
+	public FloatComplex(float real, float imaginary) {
+		re = real;
+		im = imaginary;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Parses given {@code String} where real and imaginary parts are separated by
+	 * one or more blanks. Furthermore both must be floating point numbers that can
+	 * be parsed by calling {@link Float#valueOf(String)}.
+	 *
+	 * @param s The {@code String} to be parsed.
+	 * @return The parsed {@link FloatComplex} value is returned.
+	 * @throws NumberFormatException Thrown if unable to parse the complex value.
+	 */
+	public static FloatComplex valueOf(String s) {
+		String[] values = s.split(" +");
+		if (values.length != 2) {
+			throw new NumberFormatException("Unable to parse complex value.");
+		}
+
+		return new FloatComplex(Float.parseFloat(values[0]), Float.parseFloat(values[1]));
+	}
+
+	/**
+	 * Returns the real part of this complex value.
+	 *
+	 * @return The real part is returned.
+	 */
+	public float real() {
+		return re;
+	}
+
+	/**
+	 * Returns the imaginary part of this complex value.
+	 *
+	 * @return The imaginary part is returned.
+	 */
+	public float imaginary() {
+		return im;
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this complex value.
+	 * The real and imaginary parts are separated with a blank.
+	 *
+	 * @return The {@code String} representation of this complex value.
+	 */
+	@Override
+	public String toString() {
+		return new StringBuilder().append(real()).append(' ').append(imaginary()).toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Interpolation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Interpolation.java
new file mode 100644
index 0000000..602d4e6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Interpolation.java
@@ -0,0 +1,75 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This is the interpolation enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Interpolation extends EnumerationValue {
+
+	/**
+	 * No interpolation is used.
+	 */
+	public static final Interpolation NONE = new Interpolation("NONE", 0);
+
+	/**
+	 * Interpolation is linear.
+	 */
+	public static final Interpolation LINEAR = new Interpolation("LINEAR", 1);
+
+	/**
+	 * Interpolation is application specific.
+	 */
+	public static final Interpolation SPECIFIC = new Interpolation("SPECIFIC", 2);
+
+	private Interpolation(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	/**
+	 * Returns true if this interpolation is {@link #NONE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isNone() {
+		return NONE == this;
+	}
+
+	/**
+	 * Returns true if this interpolation is {@link #LINEAR}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLinear() {
+		return LINEAR == this;
+	}
+
+	/**
+	 * Returns true if this interpolation is {@link #SPECIFIC}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isSpecific() {
+		return SPECIFIC == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MeasuredValues.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MeasuredValues.java
new file mode 100644
index 0000000..1935ea0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MeasuredValues.java
@@ -0,0 +1,278 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static java.util.stream.IntStream.range;
+import static org.eclipse.mdm.api.base.model.Value.readAt;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.stream.Collectors;
+
+/**
+ * Class represents a sequence of measured values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class MeasuredValues {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ScalarType scalarType;
+	private final Object values;
+	private final boolean[] flags;
+
+	/*
+	 * TODO: - replace name and unit with the corresponding Channel & Unit entities
+	 * - provide further information if required - provide an overall offset for
+	 * this value sequence
+	 */
+
+	private final String name;
+	private final String unit;
+
+	private final int length;
+
+	private final SequenceRepresentation sequenceRepresentation;
+	private final double[] generationParameters;
+	private final boolean independent;
+	private final AxisType axisType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param scalarType             The {@link ScalarType} of this measured values.
+	 * @param name                   This is the name of the corresponding
+	 *                               {@link Channel}.
+	 * @param unit                   Name of the unit the contained values are of.
+	 * @param sequenceRepresentation The {@link SequenceRepresentation} of the
+	 *                               measured values.
+	 * @param generationParameters   The generation parameters for the measured
+	 *                               values.
+	 * @param independent            The independent flag of the measured values.
+	 * @param axisType               The {@link AxisType} of the measured values.
+	 * @param values                 The measured values.
+	 * @param flags                  The validity flags of the measured values.
+	 * @throws IllegalArgumentException Thrown if values or flags is null or length
+	 *                                  of values and flags is not equal.
+	 */
+	MeasuredValues(ScalarType scalarType, String name, String unit, SequenceRepresentation sequenceRepresentation,
+			double[] generationParameters, boolean independent, AxisType axisType, Object values, boolean[] flags) {
+		this.name = name;
+		this.unit = (unit == null ? "" : unit);
+		this.scalarType = scalarType;
+		this.sequenceRepresentation = sequenceRepresentation;
+		this.generationParameters = generationParameters;
+		this.independent = independent;
+		this.axisType = axisType;
+		this.values = values;
+
+		if (values == null || flags == null) {
+			throw new IllegalArgumentException("Neither values nor flags is allowed to be null.");
+		} else if (Array.getLength(values) != flags.length) {
+			throw new IllegalArgumentException("Length of values and flags is not equal.");
+		}
+
+		this.flags = Arrays.copyOf(flags, flags.length);
+		length = flags.length;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of this measured values sequence.
+	 *
+	 * @return The name is returned.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the unit name for this measured values sequence.
+	 *
+	 * @return The unit name is returned.
+	 */
+	public String getUnit() {
+		return unit;
+	}
+
+	/**
+	 * Returns the {@link ScalarType} of this measured values sequence.
+	 *
+	 * @return The {@code ScalarType} is returned.
+	 */
+	public ScalarType getScalarType() {
+		return scalarType;
+	}
+
+	/**
+	 * Returns the number of values of this measured values sequence.
+	 *
+	 * @return The number of values is returned.
+	 */
+	public int getLength() {
+		return length;
+	}
+
+	/**
+	 * Returns the {@link SequenceRepresentation} of this measured values sequence.
+	 *
+	 * @return The {@code SequenceRepresentation} is returned.
+	 */
+	public SequenceRepresentation getSequenceRepresentation() {
+		return sequenceRepresentation;
+	}
+
+	/**
+	 * Returns the generation parameters for this measured values sequence.
+	 *
+	 * @return The generation parameters are returned.
+	 */
+	public double[] getGenerationParameters() {
+		return generationParameters;
+	}
+
+	/**
+	 * Returns the independent flag of this measured values sequence.
+	 *
+	 * @return The independent flag is returned.
+	 */
+	public boolean isIndependent() {
+		return independent;
+	}
+
+	/**
+	 * Returns the {@link AxisType} of this measured values sequence.
+	 *
+	 * @return The {@code AxisType} is returned.
+	 */
+	public AxisType getAxisType() {
+		return axisType;
+	}
+
+	/**
+	 * Returns a typed {@link ValueIterator}. Its usage is described below:
+	 *
+	 * <pre>
+	 * // assume the measuredValues().getScalarType() == ScalarType.BYTE
+	 * ValueIterator&lt;Byte&gt; valueIterator = measuredValues().iterator();
+	 * while (valueIterator.hasNext()) {
+	 * 	boolean isCurrentValid = valueIterator.isValid();
+	 * 	Byte currentValue = valueIterator.next();
+	 * }
+	 * </pre>
+	 *
+	 * @param <E> This type has to be derived from the {@link ScalarType} of this
+	 *            measured values.
+	 * @return A typed {@code ValueIterator} is returned.
+	 */
+	public <E> ValueIterator<E> iterator() {
+		// TODO provide custom implementations for each type and typed
+		// nextType() methods
+		// idea: getScalarType().createIterator(values, flags); // <- package
+		// private
+		return new ValueIterator<E>() {
+			private int index = 0;
+
+			@Override
+			public boolean hasNext() {
+				return index < length;
+			}
+
+			@Override
+			public boolean isValid() {
+				return flags[index];
+			}
+
+			@Override
+			@SuppressWarnings("unchecked")
+			public E next() {
+				if (hasNext()) {
+					return (E) Array.get(values, index++);
+				}
+				throw new NoSuchElementException("Subsequent value is not available.");
+			}
+		};
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this measured
+	 * values. If this sequence contains more than 10 values, only the first and
+	 * last 5 values are written. If a value is marked as not valid, then 'XX' is
+	 * written instead of its value.
+	 *
+	 * @return The {@code String} representation of this entity.
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("MeasuredValues(ChannelName = ").append(getName());
+		sb.append(", ScalarType = ").append(getScalarType());
+
+		if (!getUnit().isEmpty()) {
+			sb.append(", Unit = ").append(getUnit());
+		}
+
+		sb.append(", Values = [");
+		String notValidMarker = "XX";
+		if (getLength() > 10) {
+			sb.append(range(0, 5).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
+					.collect(Collectors.joining(", ")));
+			sb.append(", ..., ");
+			sb.append(range(length - 5, length).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
+					.collect(Collectors.joining(", ")));
+		} else if (getLength() > 0) {
+			sb.append(range(0, length).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
+					.collect(Collectors.joining(", ")));
+		}
+
+		return sb.append("])").toString();
+	}
+
+	// ======================================================================
+	// Inner Types
+	// ======================================================================
+
+	/**
+	 * The measured values iterator.
+	 *
+	 * @param <E> Type of the returned values.
+	 * @since 1.0.0
+	 * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+	 */
+	public interface ValueIterator<E> extends Iterator<E> {
+
+		/**
+		 * Returns true if the current value is marked as valid.
+		 *
+		 * @return True if current value is valid.
+		 */
+		boolean isValid();
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Measurement.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Measurement.java
new file mode 100644
index 0000000..d7ee766
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Measurement.java
@@ -0,0 +1,170 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Implementation of the measurement entity type. The measurement entity holds
+ * data of a measurement or an analysis. It is the linking point to the
+ * following related data:
+ *
+ * <ul>
+ * <li>To ensure any persisted measurement can always be reinterpreted it,
+ * always should have relations to {@link ContextRoot}s that contain the
+ * description of the test run. All measurement entities under the same parent
+ * {@link TestStep} must reference the same {@code
+ * 		ContextRoot}.</li>
+ * <li>The results of a test run are accessible via the children of type
+ * {@link ChannelGroup} and {@link Channel}.</li>
+ * </ul>
+ *
+ * The name of a measurement should be chosen in a speaking way. It has to be
+ * unique under the parent {@code TestStep}.
+ * <p>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ParameterSet
+ */
+public class Measurement extends BaseEntity
+		implements ContextDescribable, Datable, Deletable, Describable, FilesAttachable, Tagable, StatusAttachable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link TestStep} parent type.
+	 */
+	public static final Class<TestStep> PARENT_TYPE_TESTSTEP = TestStep.class;
+
+	/**
+	 * The {@link ChannelGroup} child type.
+	 */
+	public static final Class<ChannelGroup> CHILD_TYPE_CHANNELGROUP = ChannelGroup.class;
+
+	/**
+	 * The {@link ParameterSet} child type.
+	 */
+	public static final Class<ParameterSet> CHILD_TYPE_PARAMETERSET = ParameterSet.class;
+
+	/**
+	 * The {@link Channel} child type.
+	 */
+	public static final Class<Channel> CHILD_TYPE_CHANNEL = Channel.class;
+
+	/**
+	 * The 'MeasurementBegin' attribute name.
+	 */
+	public static final String ATTR_MEASUREMENT_BEGIN = "MeasurementBegin";
+
+	/**
+	 * The 'MeasurementEnd' attribute name.
+	 */
+	public static final String ATTR_MEASUREMENT_END = "MeasurementEnd";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Measurement(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the time stamp of the date when this measurement was started.
+	 *
+	 * @return Measurement execution start time stamp is returned.
+	 */
+	public LocalDateTime getMeasurementBegin() {
+		return getValue(ATTR_MEASUREMENT_BEGIN).extract();
+	}
+
+	/**
+	 * Sets new time stamp for the date when this measurement was started.
+	 *
+	 * @param measurementBegin The new measurement start time stamp.
+	 */
+	public void setMeasurementBegin(LocalDateTime measurementBegin) {
+		getValue(ATTR_MEASUREMENT_BEGIN).set(measurementBegin);
+	}
+
+	/**
+	 * Returns the time stamp of the date when this measurement was finished.
+	 *
+	 * @return Measurement execution end time stamp is returned.
+	 */
+	public LocalDateTime getMeasurementEnd() {
+		return getValue(ATTR_MEASUREMENT_END).extract();
+	}
+
+	/**
+	 * Sets new time stamp for the date when this measurement was finished.
+	 *
+	 * @param measurementEnd The new measurement execution end time stamp.
+	 */
+	public void setMeasurementEnd(LocalDateTime measurementEnd) {
+		getValue(ATTR_MEASUREMENT_END).set(measurementEnd);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<ContextType> loadContextTypes(BaseEntityManager manager) throws DataAccessException {
+		return manager.loadContextTypes(this);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<ContextType, ContextRoot> loadContexts(BaseEntityManager manager, ContextType... contextTypes)
+			throws DataAccessException {
+
+		Map<ContextType, ContextRoot> map = new HashMap<>();
+
+		for (ContextType contextType : contextTypes) {
+			ContextRoot c = getCore().getMutableStore().get(ContextRoot.class, contextType);
+			if (c != null) {
+				map.put(contextType, c);
+			}
+		}
+		if (map.isEmpty()) {
+			return manager.loadContexts(this, contextTypes);
+		} else {
+			return map;
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MimeType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MimeType.java
new file mode 100644
index 0000000..8abbc4c
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MimeType.java
@@ -0,0 +1,136 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Locale;
+
+/**
+ * Class provides easy to use MIME type comparison methods.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Entity
+ */
+public final class MimeType {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final String internal;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param mimeType The MIME type will be changed to lower case.
+	 */
+	public MimeType(String mimeType) {
+		internal = mimeType.toLowerCase(Locale.ROOT);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	public MimeType addSubType(String name) {
+		return new MimeType(internal + '.' + name);
+	}
+
+	/**
+	 * Checks whether given {@code MimeType} is either the same as or a sub type of
+	 * this MIME type. See the following examples:
+	 *
+	 * <pre>
+	 * MimeType type = new MimeType("application/x-asam.aomeasurement");
+	 * MimeType subType = new MimeType("application/x-asam.aomeasurement.subtype");
+	 *
+	 * type.isParentOf(subType); // true
+	 * subType.isParentOf(type); // false
+	 * type.isParentOf(type); // true
+	 * </pre>
+	 *
+	 * @param mimeType The checked type.
+	 * @return Returns true if either this MIME type and given one are the same or
+	 *         the given one is a sub type of this MIME type.
+	 */
+	public boolean isParentOf(MimeType mimeType) {
+		return mimeType != null && mimeType.compareString().startsWith(compareString());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		return internal.hashCode();
+	}
+
+	/**
+	 * Checks whether given {@code Object} represents the same type as this MIME
+	 * type.
+	 *
+	 * <pre>
+	 * MimeType type = new MimeType("application/x-asam.aomeasurement");
+	 * MimeType equalType = new MimeType("application/x-asam.aomeasurement");
+	 * MimeType subType = new MimeType("application/x-asam.aomeasurement.subtype");
+	 * MimeType anotherType = new MimeType("application/x-asam.aounit");
+	 *
+	 * type.equals(equalType); // true
+	 * subType.equals(type); // false
+	 * type.equals(anotherType); // false
+	 * </pre>
+	 *
+	 * @param object The checked object.
+	 * @return True if given object is of type {@code MimeType} and represents
+	 *         exactly the same type as this MIME type.
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (object instanceof MimeType) {
+			return internal.equals(((MimeType) object).internal);
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns the MIME type.
+	 *
+	 * @return The MIME type is returned in lower case.
+	 */
+	@Override
+	public String toString() {
+		return internal;
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Adds a termination character to the internally stored string representation.
+	 *
+	 * @return A closed comparison string is returned.
+	 */
+	private String compareString() {
+		return internal + '.';
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Parameter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Parameter.java
new file mode 100644
index 0000000..2d38d22
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Parameter.java
@@ -0,0 +1,90 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the parameter entity type. Instances of this class hold a
+ * value in its {@code String} representation, which is converted upon request
+ * and provided as a virtual {@link Value}. The returned {@code Value} is for
+ * displaying purposes only. To change the value, held by this parameter, one of
+ * its {@code setXYValue(XY)} methods has to be used. {@link ValueType}s
+ * supported by this parameter are listed below:
+ *
+ * <ul>
+ * <li>{@link ValueType#STRING}</li>
+ * <li>{@link ValueType#DATE}</li>
+ * <li>{@link ValueType#BOOLEAN}</li>
+ * <li>{@link ValueType#BYTE}</li>
+ * <li>{@link ValueType#SHORT}</li>
+ * <li>{@link ValueType#INTEGER}</li>
+ * <li>{@link ValueType#LONG}</li>
+ * <li>{@link ValueType#FLOAT}</li>
+ * <li>{@link ValueType#DOUBLE}</li>
+ * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+ * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ParameterSet
+ * @see #getVirtualValue()
+ * @see #setObjectValue(Object, Unit)
+ * @see #setStringValue(String)
+ * @see #setDateValue(LocalDateTime)
+ * @see #setBooleanValue(Boolean)
+ * @see #setByteValue(Byte, Unit)
+ * @see #setShortValue(Short, Unit)
+ * @see #setIntegerValue(Integer, Unit)
+ * @see #setLongValue(Long, Unit)
+ * @see #setFloatValue(Float, Unit)
+ * @see #setDoubleValue(Double, Unit)
+ * @see #setFloatComplexValue(FloatComplex, Unit)
+ * @see #setDoubleComplexValue(DoubleComplex, Unit)
+ */
+public final class Parameter extends BaseParameter {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'ScalarType' attribute name.
+	 */
+	public static final String ATTR_SCALAR_TYPE = "DataType";
+
+	/**
+	 * The 'Value' attribute name.
+	 */
+	public static final String ATTR_VALUE = "Value";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Parameter(Core core) {
+		super(ATTR_SCALAR_TYPE, ATTR_VALUE, core);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ParameterSet.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ParameterSet.java
new file mode 100644
index 0000000..a774cd1
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ParameterSet.java
@@ -0,0 +1,136 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the parameter set entity type. Instances of this class
+ * group a set of further describing data stored in {@link Parameter}s.
+ * Parameter sets are attached either to a {@link Measurement} or
+ * {@link Channel}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ParameterSet extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Measurement} parent type.
+	 */
+	public static final Class<Measurement> PARENT_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The {@link ChannelGroup} parent type.
+	 */
+	public static final Class<Channel> PARENT_TYPE_CHANNEL = Channel.class;
+
+	/**
+	 * The 'Version' attribute name.
+	 */
+	public static final String ATTR_VERSION = "Version";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ParameterSet(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link Parameter} identified by given name.
+	 *
+	 * @param name The name of the {@code Parameter}.
+	 * @return The {@code Optional} is empty if a {@code Parameter} with given name
+	 *         does not exist.
+	 */
+	public Optional<Parameter> getParameter(String name) {
+		return getParameters().stream().filter(p -> p.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link Parameter}s related to this parameter set.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<Parameter> getParameters() {
+		return getCore().getChildrenStore().get(Parameter.class);
+	}
+
+	/**
+	 * Removes the {@link Parameter} identified by given name.
+	 *
+	 * @param name Name of the {@code Parameter} that have to be removed.
+	 * @return Returns {@code true} if the {@code Parameter} with given name has
+	 *         been removed.
+	 */
+	public boolean removeParameter(String name) {
+		Optional<Parameter> parameter = getParameter(name);
+		if (parameter.isPresent()) {
+			getCore().getChildrenStore().remove(parameter.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns the version of this parameter set.
+	 *
+	 * @return The version is returned.
+	 */
+	public String getVersion() {
+		return getValue(ATTR_VERSION).extract();
+	}
+
+	/**
+	 * Sets new version for this parameter set.
+	 *
+	 * @param version The new version.
+	 */
+	public void setVersion(String version) {
+		getValue(ATTR_VERSION).set(version);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+		return sb.append(", Parameters = ").append(getParameters()).append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/PhysicalDimension.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/PhysicalDimension.java
new file mode 100644
index 0000000..aa67bcc
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/PhysicalDimension.java
@@ -0,0 +1,238 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the physical dimension entity type. Each {@link Unit} must
+ * have a relation to an instance of this type. The attributes represent the
+ * exponents of the seven SI base units and additionally the angle exponent as
+ * defined in the ASAM NVH model. A {@code Unit} with a certain physical
+ * dimension can be converted to all units having the same relation. Names of
+ * the physical dimensions have to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class PhysicalDimension extends BaseEntity implements Describable, Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Length' attribute name.
+	 */
+	public static final String ATTR_LENGTH = "Length";
+
+	/**
+	 * The 'Mass' attribute name.
+	 */
+	public static final String ATTR_MASS = "Mass";
+
+	/**
+	 * The 'Time' attribute name.
+	 */
+	public static final String ATTR_TIME = "Time";
+
+	/**
+	 * The 'Current' attribute name.
+	 */
+	public static final String ATTR_CURRENT = "Current";
+
+	/**
+	 * The 'Temperature' attribute name.
+	 */
+	public static final String ATTR_TEMPERATURE = "Temperature";
+
+	/**
+	 * The 'MolarAmount' attribute name.
+	 */
+	public static final String ATTR_MOLAR_AMOUNT = "MolarAmount";
+
+	/**
+	 * The 'LuminousIntensity' attribute name.
+	 */
+	public static final String ATTR_LUMINOUS_INTENSITY = "LuminousIntensity";
+
+	/**
+	 * The 'Angle' attribute name.
+	 */
+	public static final String ATTR_ANGLE = "angle";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	PhysicalDimension(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the length exponent of this physical dimension.
+	 *
+	 * @return The length exponent is returned.
+	 */
+	public Integer getLength() {
+		return getValue(ATTR_LENGTH).extract();
+	}
+
+	/**
+	 * Sets new length exponent for this physical dimension.
+	 *
+	 * @param exponent The new length exponent.
+	 */
+	public void setLength(Integer exponent) {
+		getValue(ATTR_LENGTH).set(exponent);
+	}
+
+	/**
+	 * Returns the mass exponent of this physical dimension.
+	 *
+	 * @return The mass exponent is returned.
+	 */
+	public Integer getMass() {
+		return getValue(ATTR_MASS).extract();
+	}
+
+	/**
+	 * Sets new mass exponent for this physical dimension.
+	 *
+	 * @param exponent The new mass exponent.
+	 */
+	public void setMass(Integer exponent) {
+		getValue(ATTR_MASS).set(exponent);
+	}
+
+	/**
+	 * Returns the time exponent of this physical dimension.
+	 *
+	 * @return The time exponent is returned.
+	 */
+	public Integer getTime() {
+		return getValue(ATTR_TIME).extract();
+	}
+
+	/**
+	 * Sets new time exponent for this physical dimension.
+	 *
+	 * @param exponent The new time exponent.
+	 */
+	public void setTime(Integer exponent) {
+		getValue(ATTR_TIME).set(exponent);
+	}
+
+	/**
+	 * Returns the current exponent of this physical dimension.
+	 *
+	 * @return The current exponent is returned.
+	 */
+	public Integer getCurrent() {
+		return getValue(ATTR_CURRENT).extract();
+	}
+
+	/**
+	 * Sets new current exponent for this physical dimension.
+	 *
+	 * @param exponent The new current exponent.
+	 */
+	public void setCurrent(Integer exponent) {
+		getValue(ATTR_CURRENT).set(exponent);
+	}
+
+	/**
+	 * Returns the temperature exponent of this physical dimension.
+	 *
+	 * @return The temperature exponent is returned.
+	 */
+	public Integer getTemperature() {
+		return getValue(ATTR_TEMPERATURE).extract();
+	}
+
+	/**
+	 * Sets new temperature exponent for this physical dimension.
+	 *
+	 * @param exponent The new temperature exponent.
+	 */
+	public void setTemperature(Integer exponent) {
+		getValue(ATTR_TEMPERATURE).set(exponent);
+	}
+
+	/**
+	 * Returns the molar amount exponent of this physical dimension.
+	 *
+	 * @return The molar amount exponent is returned.
+	 */
+	public Integer getMolarAmount() {
+		return getValue(ATTR_MOLAR_AMOUNT).extract();
+	}
+
+	/**
+	 * Sets new molar amount exponent for this physical dimension.
+	 *
+	 * @param exponent The new molar amount exponent.
+	 */
+	public void setMolarAmount(Integer exponent) {
+		getValue(ATTR_MOLAR_AMOUNT).set(exponent);
+	}
+
+	/**
+	 * Returns the luminous intensity exponent of this physical dimension.
+	 *
+	 * @return The luminous intensity exponent is returned.
+	 */
+	public Integer getLuminousIntensity() {
+		return getValue(ATTR_LUMINOUS_INTENSITY).extract();
+	}
+
+	/**
+	 * Sets new luminous intensity exponent for this physical dimension.
+	 *
+	 * @param exponent The new luminous intensity exponent.
+	 */
+	public void setLuminousIntensity(Integer exponent) {
+		getValue(ATTR_LUMINOUS_INTENSITY).set(exponent);
+	}
+
+	/**
+	 * Returns the angle exponent of this physical dimension.
+	 *
+	 * @return The angle exponent is returned.
+	 */
+	public Integer getAngle() {
+		return getValue(ATTR_ANGLE).extract();
+	}
+
+	/**
+	 * Sets new angle exponent for this physical dimension.
+	 *
+	 * @param exponent The new angle exponent.
+	 */
+	public void setAngle(Integer exponent) {
+		getValue(ATTR_ANGLE).set(exponent);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Quantity.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Quantity.java
new file mode 100644
index 0000000..a0e9cb8
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Quantity.java
@@ -0,0 +1,191 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the quantity entity type. {@link Channel}s are based on
+ * entities of this type. Each quantity has a relation to a default
+ * {@link Unit}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Quantity extends BaseEntity implements Datable, Deletable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'DefaultRank' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_RANK = "DefaultRank";
+
+	/**
+	 * The 'DefaultDimension' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_DIMENSION = "DefDimension";
+
+	/**
+	 * The 'DefaultTypeSize' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_TYPE_SIZE = "DefTypeSize";
+
+	/**
+	 * The 'DefaultChannelName' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_CHANNEL_NAME = "DefMQName";
+
+	/**
+	 * The 'DefaultScalarType' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_SCALAR_TYPE = "DefDataType";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Quantity(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the default rank of this quantity.
+	 *
+	 * @return The default rank is returned.
+	 */
+	public Integer getDefaultRank() {
+		return getValue(ATTR_DEFAULT_RANK).extract();
+	}
+
+	/**
+	 * Sets new default rank for this quantity.
+	 *
+	 * @param defaultRank The new default rank.
+	 */
+	public void setDefaultRank(Integer defaultRank) {
+		getValue(ATTR_DEFAULT_RANK).set(defaultRank);
+	}
+
+	/**
+	 * Returns the default dimension of this quantity.
+	 *
+	 * @return The default dimension is returned.
+	 */
+	public int[] getDefaultDimension() {
+		return getValue(ATTR_DEFAULT_DIMENSION).extract();
+	}
+
+	/**
+	 * Sets new default dimension for this quantity.
+	 *
+	 * @param defaultDimension The new default dimension.
+	 */
+	public void setDefaultDimension(int[] defaultDimension) {
+		getValue(ATTR_DEFAULT_DIMENSION).set(defaultDimension);
+	}
+
+	/**
+	 * Returns the default type size of this quantity.
+	 *
+	 * @return The default type size is returned.
+	 */
+	public Integer getDefaultTypeSize() {
+		return getValue(ATTR_DEFAULT_TYPE_SIZE).extract();
+	}
+
+	/**
+	 * Sets new default type size for this quantity.
+	 *
+	 * @param defaultTypeSize The new default type size.
+	 */
+	public void setDefaultTypeSize(Integer defaultTypeSize) {
+		getValue(ATTR_DEFAULT_TYPE_SIZE).set(defaultTypeSize);
+	}
+
+	/**
+	 * Returns the default {@link Channel} name of this quantity.
+	 *
+	 * @return The default {@code Channel} name is returned.
+	 */
+	public String getDefaultChannelName() {
+		return getValue(ATTR_DEFAULT_CHANNEL_NAME).extract();
+	}
+
+	/**
+	 * Sets new default {@link Channel} name for this quantity.
+	 *
+	 * @param defaultChannelName The new default {@code Channel} name.
+	 */
+	public void setDefaultChannelName(String defaultChannelName) {
+		getValue(ATTR_DEFAULT_CHANNEL_NAME).set(defaultChannelName);
+	}
+
+	/**
+	 * Returns the default {@link ScalarType} of this quantity.
+	 *
+	 * @return The default {@code ScalarType} is returned.
+	 */
+	public ScalarType getDefaultScalarType() {
+		return getValue(ATTR_DEFAULT_SCALAR_TYPE).extract();
+	}
+
+	/**
+	 * Sets new default {@link ScalarType} for this quantity.
+	 *
+	 * @param defaultScalarType The new default {@code ScalarType}.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is
+	 *                                  {@link ScalarType#UNKNOWN}.
+	 */
+	public void setDefaultScalarType(ScalarType defaultScalarType) {
+		if (defaultScalarType.isUnknown()) {
+			throw new IllegalArgumentException(
+					"Default scalar type constant is not allowed to be '" + defaultScalarType + "'.");
+		}
+
+		getValue(ATTR_DEFAULT_SCALAR_TYPE).set(defaultScalarType);
+	}
+
+	/**
+	 * Returns the default {@link Unit} of this quantity.
+	 *
+	 * @return The default {@code Unit} is returned.
+	 */
+	public Unit getDefaultUnit() {
+		return getCore().getMutableStore().get(Unit.class);
+	}
+
+	/**
+	 * Sets new default {@link Unit} for this quantity.
+	 *
+	 * @param defaultUnit The new default {@code Unit}.
+	 */
+	public void setDefaultUnit(Unit defaultUnit) {
+		getCore().getMutableStore().set(defaultUnit);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ScalarType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ScalarType.java
new file mode 100644
index 0000000..cf8ece3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ScalarType.java
@@ -0,0 +1,434 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Array;
+import java.time.LocalDateTime;
+
+/**
+ * Scalar type enumeration is a {@link MeasuredValues} factory. Another context
+ * where this enumeration is used is the storage of values, represented by the
+ * constants of this enumeration, in their {@code String} representation (see:
+ * {@link BaseParameter}).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+
+public final class ScalarType extends EnumerationValue {
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code String} values.
+	 */
+	public static final ScalarType STRING = new ScalarType(0, "STRING", ValueType.STRING_SEQUENCE, String.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code LocalDateTime} values.
+	 */
+	public static final ScalarType DATE = new ScalarType(1, "DATE", ValueType.DATE_SEQUENCE, LocalDateTime.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code boolean} values.
+	 */
+	public static final ScalarType BOOLEAN = new ScalarType(2, "BOOLEAN", ValueType.BOOLEAN_SEQUENCE, boolean.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code byte} values.
+	 */
+	public static final ScalarType BYTE = new ScalarType(3, "BYTE", ValueType.BYTE_SEQUENCE, byte.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code short} values.
+	 */
+	public static final ScalarType SHORT = new ScalarType(4, "SHORT", ValueType.SHORT_SEQUENCE, short.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code int} values.
+	 */
+	public static final ScalarType INTEGER = new ScalarType(5, "INTEGER", ValueType.INTEGER_SEQUENCE, int.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code long} values.
+	 */
+	public static final ScalarType LONG = new ScalarType(6, "LONG", ValueType.LONG_SEQUENCE, long.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code float} values.
+	 */
+	public static final ScalarType FLOAT = new ScalarType(7, "FLOAT", ValueType.FLOAT_SEQUENCE, float.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code double} values.
+	 */
+	public static final ScalarType DOUBLE = new ScalarType(8, "DOUBLE", ValueType.DOUBLE_SEQUENCE, double.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code byte[]} values.
+	 */
+	public static final ScalarType BYTE_STREAM = new ScalarType(9, "BYTE_STREAM", ValueType.BYTE_STREAM_SEQUENCE,
+			byte[].class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code FloatComplex} values.
+	 */
+	public static final ScalarType FLOAT_COMPLEX = new ScalarType(10, "FLOAT_COMPLEX", ValueType.FLOAT_COMPLEX_SEQUENCE,
+			FloatComplex.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code DoubleComplex} values.
+	 */
+	public static final ScalarType DOUBLE_COMPLEX = new ScalarType(11, "DOUBLE_COMPLEX",
+			ValueType.DOUBLE_COMPLEX_SEQUENCE, DoubleComplex.class);
+
+	/**
+	 * {@link MeasuredValues} are not allowed to be of this type. This constant may
+	 * be used in other contexts.
+	 */
+	public static final ScalarType ENUMERATION = new ScalarType(12, "ENUMERATION", ValueType.ENUMERATION_SEQUENCE);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code FileLink} values.
+	 */
+	public static final ScalarType FILE_LINK = new ScalarType(13, "FILE_LINK", ValueType.FILE_LINK_SEQUENCE,
+			FileLink.class);
+
+	/**
+	 * TODO ...
+	 */
+	public static final ScalarType BLOB = new ScalarType(14, "BLOB", ValueType.BLOB, Object.class);
+
+	/**
+	 * {@link MeasuredValues} are not allowed to be of this type. This constant may
+	 * be used in other contexts.
+	 */
+	public static final ScalarType UNKNOWN = new ScalarType(15, "UNKNOWN", ValueType.UNKNOWN);
+
+	private final ValueType valueType;
+	private final Class<?> arrayType;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param ord       ordinal number of the enum value
+	 * @param name      name of the enum value
+	 * @param valueType The associated {@link ValueType}.
+	 */
+	private ScalarType(int ord, String name, ValueType valueType) {
+		super(name, ord);
+		this.valueType = valueType;
+		arrayType = null;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param ord           ordinal number of the enum value
+	 * @param name          name of the enum value
+	 * @param valueType     The associated {@link ValueType}.
+	 * @param componentType The component type of the array held by instances of
+	 *                      {@link MeasuredValues}.
+	 */
+	private ScalarType(int ord, String name, ValueType valueType, Class<?> componentType) {
+		super(name, ord);
+		this.valueType = valueType;
+		arrayType = Array.newInstance(componentType, 0).getClass();
+	}
+
+	/**
+	 * Creates a new {@link MeasuredValues} initialized with given name, unit and
+	 * values including the related validity flags.
+	 *
+	 * @param name                   This is the name of the corresponding
+	 *                               {@link Channel}.
+	 * @param unit                   Name of the unit the contained values are of.
+	 * @param sequenceRepresentation The {@link SequenceRepresentation} of the
+	 *                               measured values.
+	 * @param independent            The independent flag of the measured values.
+	 * @param axisType               The {@link AxisType} of the measured values.
+	 * @param input                  The measured values.
+	 * @param flags                  The validity flags of the measured values.
+	 * @return The created {@code MeasuredValues} is returned.
+	 * @throws IllegalStateException    Thrown if {@link #isEnumeration()} or
+	 *                                  {@link #isUnknown()} returns {@code true}.
+	 * @throws IllegalArgumentException Thrown if given values are not assignment
+	 *                                  compatible.
+	 */
+	public MeasuredValues createMeasuredValues(String name, String unit, SequenceRepresentation sequenceRepresentation,
+			double[] generationParameters, boolean independent, AxisType axisType, Object input, boolean[] flags) {
+		if (isEnumeration() || isUnknown()) {
+			throw new IllegalStateException("It is not allowed to create measured values of type '" + this + "'.");
+		} else if (!arrayType.isInstance(input)) {
+			throw new IllegalArgumentException("Given values of type '" + input.getClass() + "'.");
+		}
+
+		return new MeasuredValues(this, name, unit, sequenceRepresentation, generationParameters, independent, axisType,
+				input, flags);
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #STRING}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isString() {
+		return STRING == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #DATE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDate() {
+		return DATE == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BOOLEAN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBoolean() {
+		return BOOLEAN == this;
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isNumericalType() {
+		return isIntegerType() || isFloatType();
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #LONG}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isIntegerType() {
+		return isByte() || isShort() || isInteger() || isLong();
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BYTE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByte() {
+		return BYTE == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #SHORT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isShort() {
+		return SHORT == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #INTEGER}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isInteger() {
+		return INTEGER == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #LONG}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLong() {
+		return LONG == this;
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFloatType() {
+		return isFloat() || isDouble();
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #FLOAT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloat() {
+		return FLOAT == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #DOUBLE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDouble() {
+		return DOUBLE == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BYTE_STREAM}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteStream() {
+		return BYTE_STREAM == this;
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT_COMPLEX}</li>
+	 * <li>{@link #DOUBLE_COMPLEX}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isComplexType() {
+		return isFloatComplex() || isDoubleComplex();
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #FLOAT_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatComplex() {
+		return FLOAT_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #DOUBLE_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleComplex() {
+		return DOUBLE_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #ENUMERATION}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEnumeration() {
+		return ENUMERATION == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #FILE_LINK}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFileLink() {
+		return FILE_LINK == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BLOB}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBlob() {
+		return BLOB == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #UNKNOWN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isUnknown() {
+		return UNKNOWN == this;
+	}
+
+	/**
+	 * Returns the associated {@link ValueType}.
+	 *
+	 * @return The associated {@code ValueType} is returned.
+	 */
+	public ValueType toValueType() {
+		return valueType;
+	}
+
+	/**
+	 * Returns the non sequence {@link ValueType} of the associated {@code
+	 * ValueType}.
+	 *
+	 * @return The non sequence {@code ValueType} is returned.
+	 */
+	public ValueType toSingleValueType() {
+		return valueType.toSingleType();
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/SequenceRepresentation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/SequenceRepresentation.java
new file mode 100644
index 0000000..51ab0d1
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/SequenceRepresentation.java
@@ -0,0 +1,262 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * The sequence representation to describe the storage type of measured values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Channel
+ */
+public class SequenceRepresentation extends EnumerationValue {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Measured values are stored as is and values are therefore immediately
+	 * available.
+	 */
+	public static final SequenceRepresentation EXPLICIT = new SequenceRepresentation("EXPLICIT", 0);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> = p for i
+	 * &isin; [1, n], n is the total number of values and generation parameter p
+	 * (offset).
+	 */
+	public static final SequenceRepresentation IMPLICIT_CONSTANT = new SequenceRepresentation("IMPLICIT_CONSTANT", 1);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+(i-1)*p<sub>2</sub> for i &isin; [1, n], n is the total number
+	 * of values and generation parameters p<sub>1</sub> (start value) and
+	 * p<sub>2</sub> (increment).
+	 */
+	public static final SequenceRepresentation IMPLICIT_LINEAR = new SequenceRepresentation("IMPLICIT_LINEAR", 2);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+((i-1)mod(p<sub>3</sub>-p<sub>1</sub>)/p<sub>2</sub>)*
+	 * p<sub>2</sub> for i &isin; [1, n], n is the total number of values and
+	 * generation parameters p<sub>1</sub> (start value), p<sub>2</sub> (increment)
+	 * and p<sub>3</sub> (number of values per saw). The expression
+	 * (p<sub>3</sub>-p<sub>1</sub>)/p<sub>2</sub> must be truncated to integer to
+	 * start each saw curve cycle at p<sub>1</sub>.
+	 */
+	public static final SequenceRepresentation IMPLICIT_SAW = new SequenceRepresentation("IMPLICIT_SAW", 3);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub> for i &isin; [1, n], n is the total
+	 * number of values and generation parameters p<sub>1</sub> (offset),
+	 * p<sub>2</sub> (factor) and the raw value r at position i.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR = new SequenceRepresentation("RAW_LINEAR", 4);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> = &sum;
+	 * p<sub>j</sub>*r<sub>i</sub><sup>j-1</sup> = p<sub>2</sub>+p<sub>3
+	 * </sub>*r<sub>i</sub>+p<sub>4</sub>*r<sub>i</sub><sup>2</sup>+... for i &isin;
+	 * [1, n], n is the total number of values and generation parameters
+	 * p<sub>j</sub> for j &isin; [1, p<sub>1</sub>] and the raw value r at position
+	 * i.
+	 */
+	public static final SequenceRepresentation RAW_POLYNOMIAL = new SequenceRepresentation("RAW_POLYNOMIAL", 5);
+
+	/*
+	 * Not used. But keep here to show ordinal sequence.
+	 */
+	public static final SequenceRepresentation FORMULA = new SequenceRepresentation("FORMULA", 6);
+
+	/**
+	 * Measured values are stored as is in an external file and values are therefore
+	 * immediately available.
+	 */
+	public static final SequenceRepresentation EXPLICIT_EXTERNAL = new SequenceRepresentation("EXPLICIT_EXTERNAL", 7);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub> for i &isin; [1, n], n is the total
+	 * number of values and generation parameters p<sub>1</sub> (offset),
+	 * p<sub>2</sub> (factor) and the raw value r at position i read from an
+	 * external file.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR_EXTERNAL = new SequenceRepresentation("RAW_LINEAR_EXTERNAL",
+			8);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> = &sum;
+	 * p<sub>j</sub>*r<sub>i</sub><sup>j-1</sup> = p<sub>2</sub>+p<sub>3
+	 * </sub>*r<sub>i</sub>+p<sub>4</sub>*r<sub>i</sub><sup>2</sup>+... for i &isin;
+	 * [1, n], n is the total number of values and generation parameters
+	 * p<sub>j</sub> for j &isin; [1, p<sub>1</sub>] and the raw value r at position
+	 * i read from an external file.
+	 */
+	public static final SequenceRepresentation RAW_POLYNOMIAL_EXTERNAL = new SequenceRepresentation(
+			"RAW_POLYNOMIAL_EXTERNAL", 9);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * (p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub>)*p<sub>3</sub> for i &isin; [1,
+	 * n], n is the total number of values and generation parameters p<sub>1</sub>
+	 * (offset), p<sub>2</sub> (factor), p<sub>2</sub> (calibration) and the raw
+	 * value r at position i.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR_CALIBRATED = new SequenceRepresentation(
+			"RAW_LINEAR_CALIBRATED", 10);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * (p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub>)*p<sub>3</sub> for i &isin; [1,
+	 * n], n is the total number of values and generation parameters p<sub>1</sub>
+	 * (offset), p<sub>2</sub> (factor), p<sub>2</sub> (calibration) and the raw
+	 * value r at position i read from an external file.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR_CALIBRATED_EXTERNAL = new SequenceRepresentation(
+			"RAW_LINEAR_CALIBRATED_EXTERNAL", 11);
+
+	private SequenceRepresentation(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #EXPLICIT}</li>
+	 * <li>{@link #EXPLICIT_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isExplicit() {
+		return name().startsWith("EXPLICIT");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #IMPLICIT_CONSTANT}</li>
+	 * <li>{@link #IMPLICIT_LINEAR}</li>
+	 * <li>{@link #IMPLICIT_SAW}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isImplicit() {
+		return name().startsWith("IMPLICIT");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #IMPLICIT_CONSTANT}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isConstant() {
+		return name().contains("CONSTANT");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #IMPLICIT_LINEAR}</li>
+	 * <li>{@link #RAW_LINEAR}</li>
+	 * <li>{@link #RAW_LINEAR_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isLinear() {
+		return name().contains("LINEAR");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #RAW_POLYNOMIAL}</li>
+	 * <li>{@link #RAW_POLYNOMIAL_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isPolynomial() {
+		return name().contains("POLYNOMIAL");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isCalibrated() {
+		return name().contains("CALIBRATED");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #EXPLICIT_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_EXTERNAL}</li>
+	 * <li>{@link #RAW_POLYNOMIAL_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isExternal() {
+		return name().endsWith("EXTERNAL");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #RAW_LINEAR}</li>
+	 * <li>{@link #RAW_POLYNOMIAL}</li>
+	 * <li>{@link #RAW_LINEAR_EXTERNAL}</li>
+	 * <li>{@link #RAW_POLYNOMIAL_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isRaw() {
+		return name().startsWith("RAW");
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Sortable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Sortable.java
new file mode 100644
index 0000000..f445a90
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Sortable.java
@@ -0,0 +1,69 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Comparator;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'SortIndex' field of an entity. The value in this
+ * field is the index of an entity relative to all other entities of the same
+ * type beneath their shared parent.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Sortable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * This {@code Comparator} compares entities implementing the {@link Sortable}
+	 * interface by the mandatory {@link #ATTR_SORT_INDEX} property in ascending
+	 * order.
+	 */
+	Comparator<Sortable> COMPARATOR = Comparator.comparing(Sortable::getSortIndex);
+
+	/**
+	 * The 'SortIndex' attribute name.
+	 */
+	String ATTR_SORT_INDEX = "Sortindex";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the sort index of this entity.
+	 *
+	 * @return The sort index is returned.
+	 */
+	default Integer getSortIndex() {
+		return getValue(ATTR_SORT_INDEX).extract();
+	}
+
+	/**
+	 * Sets new sort index for this entity.
+	 *
+	 * @param sortIndex The new sort index.
+	 */
+	default void setSortIndex(Integer sortIndex) {
+		getValue(ATTR_SORT_INDEX).set(sortIndex);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/StatusAttachable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/StatusAttachable.java
new file mode 100644
index 0000000..10a612b
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/StatusAttachable.java
@@ -0,0 +1,30 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Each modeled {@link Entity} implements this interface to indicate that it has
+ * a status.
+ *
+ * <p>
+ * <b>Note:</b> State management is not part of the base application model.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface StatusAttachable extends Entity {
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Tagable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Tagable.java
new file mode 100644
index 0000000..57cabe3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Tagable.java
@@ -0,0 +1,27 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Each modeled {@link Entity} implements this interface to indicate that tags
+ * can be attached to it.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Tagable extends Entity {
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Test.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Test.java
new file mode 100644
index 0000000..59641d2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Test.java
@@ -0,0 +1,122 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the test entity type. The test groups a number of single
+ * {@link TestStep}s. A measurement order always corresponds with exactly one
+ * test entity. The name of a test should be chosen in a speaking way, because
+ * it is often used in different contexts, e.g. as a link between the
+ * measurement data from the device and the order in the database. This type is
+ * a root node for persisted tests within a base application model. Extensions
+ * are free to introduce new entity types that may act as an immediate parent
+ * for entities of this type. In such cases tests have to be unique under the
+ * corresponding parent. Children of a test are {@code TestStep}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Test extends BaseEntity
+		implements Datable, Deletable, Describable, FilesAttachable, Tagable, StatusAttachable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link TestStep} child type.
+	 */
+	public static final Class<TestStep> CHILD_TYPE_TESTSTEP = TestStep.class;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Test(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link User} who is responsible for this test.
+	 *
+	 * @return {@code Optional} is empty if the data source does not provide any
+	 *         {@code User} entities at all, which is implementation specific!
+	 */
+	public Optional<User> getResponsiblePerson() {
+		return Optional.ofNullable(getCore().getMutableStore().get(User.class));
+	}
+
+	/**
+	 * Sets new {@link User} as the responsible person for this test.
+	 *
+	 * @param responsiblePerson The new responsible person.
+	 */
+	public void setResponsiblePerson(User responsiblePerson) {
+		getCore().getMutableStore().set(responsiblePerson);
+	}
+
+	/**
+	 * Returns the commissioned {@link TestStep} identified by given name.
+	 *
+	 * @param name The name of the {@code TestStep}.
+	 * @return The {@code Optional} is empty if a {@code TestStep} with given name
+	 *         does not exist.
+	 */
+	public Optional<TestStep> getCommissionedTestStep(String name) {
+		return getCommissionedTestSteps().stream().filter(ts -> ts.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all commissioned {@link TestStep}s related to this test.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TestStep> getCommissionedTestSteps() {
+		return getCore().getChildrenStore().get(TestStep.class);
+	}
+
+	/**
+	 * Removes the commissioned {@link TestStep} identified by given name.
+	 *
+	 * @param name Name of the {@code TestStep} that has to be removed.
+	 * @return Returns {@code true} if the {@code TestStep} with given name has been
+	 *         removed.
+	 */
+	public boolean removeCommissionedTestStep(String name) {
+		Optional<TestStep> testStep = getCommissionedTestStep(name);
+		if (testStep.isPresent()) {
+			getCore().getChildrenStore().remove(testStep.get());
+			return true;
+		}
+
+		return false;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TestStep.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TestStep.java
new file mode 100644
index 0000000..f1f46a2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TestStep.java
@@ -0,0 +1,129 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Implementation of the test step entity type. A test step is an atomic
+ * measurement task as part of a {@link Test}. The boundary conditions do not
+ * change within a single test step, therefore every ordered test step has to be
+ * fully described. It may have relations to {@link ContextRoot}s, which contain
+ * the describing order data. Test steps may have a sort order in the context of
+ * their parent {@code Test}, indicating the desired execution order. The name
+ * of a test step should be chosen in a speaking way, because it is often used
+ * in different contexts, e.g. as a link between the measurement data from the
+ * device and the order in the database. Furthermore the name has to be unique
+ * under the parent {@code Test}. Children of a test step are
+ * {@link Measurement}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class TestStep extends BaseEntity implements ContextDescribable, Datable, Deletable, Describable,
+		FilesAttachable, Sortable, StatusAttachable, Tagable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Test} parent type.
+	 */
+	public static final Class<Test> PARENT_TYPE_TEST = Test.class;
+
+	/**
+	 * The {@link Measurement} child type.
+	 */
+	public static final Class<Measurement> CHILD_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The 'Optional' attribute name.
+	 */
+	public static final String ATTR_OPTIONAL = "Optional";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TestStep(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the optional flag of this test step.
+	 *
+	 * @return Returns the optional flag.
+	 */
+	public Boolean isOptional() {
+		return getValue(ATTR_OPTIONAL).extract();
+	}
+
+	/**
+	 * Sets new optional flag for this test step.
+	 *
+	 * @param optional The new optional flag.
+	 */
+	public void setOptional(Boolean optional) {
+		getValue(ATTR_OPTIONAL).set(optional);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<ContextType> loadContextTypes(BaseEntityManager manager) throws DataAccessException {
+		return manager.loadContextTypes(this);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<ContextType, ContextRoot> loadContexts(BaseEntityManager manager, ContextType... contextTypes)
+			throws DataAccessException {
+
+		Map<ContextType, ContextRoot> map = new HashMap<>();
+
+		for (ContextType contextType : contextTypes) {
+			ContextRoot c = getCore().getMutableStore().get(ContextRoot.class, contextType);
+			if (c != null) {
+				map.put(contextType, c);
+			}
+		}
+		if (map.isEmpty()) {
+			return manager.loadContexts(this, contextTypes);
+		} else {
+			return map;
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TypeSpecification.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TypeSpecification.java
new file mode 100644
index 0000000..3b9c70d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TypeSpecification.java
@@ -0,0 +1,107 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * The type specification of mass data stored in external files.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Channel
+ */
+public class TypeSpecification extends EnumerationValue {
+
+	public static final TypeSpecification BOOLEAN = new TypeSpecification("BOOLEAN", 0);
+
+	public static final TypeSpecification BYTE = new TypeSpecification("BYTE", 1);
+
+	public static final TypeSpecification SHORT = new TypeSpecification("SHORT", 2);
+
+	public static final TypeSpecification INTEGER = new TypeSpecification("INTEGER", 3);
+
+	public static final TypeSpecification LONG = new TypeSpecification("LONG", 4);
+
+	public static final TypeSpecification FLOAT = new TypeSpecification("FLOAT", 5);
+
+	public static final TypeSpecification DOUBLE = new TypeSpecification("DOUBLE", 6);
+
+	public static final TypeSpecification SHORT_BEO = new TypeSpecification("SHORT_BEO", 7);
+
+	public static final TypeSpecification INTEGER_BEO = new TypeSpecification("INTEGER_BEO", 8);
+
+	public static final TypeSpecification LONG_BEO = new TypeSpecification("LONG_BEO", 9);
+
+	public static final TypeSpecification FLOAT_BEO = new TypeSpecification("FLOAT_BEO", 10);
+
+	public static final TypeSpecification DOUBLE_BEO = new TypeSpecification("DOUBLE_BEO", 11);
+
+	public static final TypeSpecification STRING = new TypeSpecification("STRING", 12);
+
+	public static final TypeSpecification BYTE_STREAM = new TypeSpecification("BYTE_STREAM", 13);
+
+	public static final TypeSpecification BLOB = new TypeSpecification("BLOB", 14);
+
+	public static final TypeSpecification BOOLEAN_FLAGS_BEO = new TypeSpecification("BOOLEAN_FLAGS_BEO", 15);
+
+	public static final TypeSpecification BYTE_FLAGS_BEO = new TypeSpecification("BYTE_FLAGS_BEO", 16);
+
+	public static final TypeSpecification STRING_FLAGS_BEO = new TypeSpecification("STRING_FLAGS_BEO", 17);
+
+	public static final TypeSpecification BYTE_STREAM_BEO = new TypeSpecification("BYTE_STREAM_BEO", 18);
+
+	// SBYTE,
+	public static final TypeSpecification SIGNED_BYTE = new TypeSpecification("SIGNED_BYTE", 19);
+
+	// SBYTE_FLAGS_BEO,
+	public static final TypeSpecification SIGNED_BYTE_FLAGS_BEO = new TypeSpecification("SIGNED_BYTE_FLAGS_BEO", 20);
+
+	// USHORT,
+	public static final TypeSpecification UNSIGNED_SHORT = new TypeSpecification("UNSIGNED_SHORT", 21);
+
+	// USHORT_BEO,
+	public static final TypeSpecification UNSIGNED_SHORT_BEO = new TypeSpecification("UNSIGNED_SHORT_BEO", 22);
+
+	// UINTEGER,
+	public static final TypeSpecification UNSIGNED_INTEGER = new TypeSpecification("UNSIGNED_INTEGER", 23);
+
+	// UINTEGER_BEO,
+	public static final TypeSpecification UNSIGNED_INTEGER_BEO = new TypeSpecification("UNSIGNED_INTEGER_BEO", 24);
+
+	public static final TypeSpecification STRING_UTF8 = new TypeSpecification("STRING_UTF8", 25);
+
+	public static final TypeSpecification STRING_UTF8_FLAGS_BEO = new TypeSpecification("STRING_UTF8_FLAGS_BEO", 26);
+
+	// BIT_INT,
+	public static final TypeSpecification BIT_INTEGER = new TypeSpecification("BIT_INTEGER", 27);
+
+	// BIT_INT_BEO,
+	public static final TypeSpecification BIT_INTEGER_BEO = new TypeSpecification("BIT_INTEGER_BEO", 28);
+
+	// BIT_UINT,
+	public static final TypeSpecification BIT_UNSIGNED_INTEGER = new TypeSpecification("BIT_UNSIGNED_INTEGER", 29);
+
+	// BIT_UINT_BEO,
+	public static final TypeSpecification BIT_UNSIGNED_INTEGER_BEO = new TypeSpecification("BIT_UNSIGNED_INTEGER_BEO",
+			30);
+
+	public static final TypeSpecification BIT_FLOAT = new TypeSpecification("BIT_FLOAT", 31);
+
+	public static final TypeSpecification BIT_FLOAT_BEO = new TypeSpecification("BIT_FLOAT_BEO", 32);
+
+	private TypeSpecification(String name, int ordinal) {
+		super(name, ordinal);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Unit.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Unit.java
new file mode 100644
index 0000000..ccf3bf3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Unit.java
@@ -0,0 +1,170 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the unit entity type. Units referring to the same
+ * {@link PhysicalDimension} can be converted to each other by means of their
+ * attribute values "Offset" and "Factor". The names of the units have to be
+ * unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Unit extends BaseEntity implements Datable, Deletable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Factor' attribute name.
+	 */
+	public static final String ATTR_FACTOR = "Factor";
+
+	/**
+	 * The 'Offset' attribute name.
+	 */
+	public static final String ATTR_OFFSET = "Offset";
+
+	/**
+	 * The 'DB' attribute name.
+	 */
+	public static final String ATTR_DB = "dB";
+
+	/**
+	 * The 'DBRreferenceFactor' attribute name.
+	 */
+	public static final String ATTR_DB_REFERENCE_FACTOR = "dB_reference_factor";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Unit(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the factor of this unit.
+	 *
+	 * @return The factor is returned.
+	 */
+	public Double getFactor() {
+		return getValue(ATTR_FACTOR).extract();
+	}
+
+	/**
+	 * Sets new factor for this unit.
+	 *
+	 * @param factor The new factor.
+	 */
+	public void setFactor(Double factor) {
+		getValue(ATTR_FACTOR).set(factor);
+	}
+
+	/**
+	 * Returns the offset of this unit.
+	 *
+	 * @return The offset is returned.
+	 */
+	public Double getOffset() {
+		return getValue(ATTR_OFFSET).extract();
+	}
+
+	/**
+	 * Sets new offset for this unit.
+	 *
+	 * @param offset The new offset.
+	 */
+	public void setOffset(Double offset) {
+		getValue(ATTR_OFFSET).set(offset);
+	}
+
+	/**
+	 * Returns the decibel flag of this unit. If the flag is true, then
+	 * {@link #getDBRefFactor()} should return a finite value as returned by
+	 * {@link Float#isFinite(float)} that is not 0.
+	 *
+	 * @return True if this unit is a decibel unit.
+	 * @see #getDBRefFactor()
+	 */
+	public Boolean isDB() {
+		return getValue(ATTR_DB).extract();
+	}
+
+	/**
+	 * Returns the factor, which allows to convert the decibel values back into
+	 * linear values. If the decibel flag is set to false, this method should return
+	 * 0, which is described in the ASAM NVH specification (Chapter 11, 10.3).
+	 *
+	 * @return The decibel reference factor is returned.
+	 * @see #isDB()
+	 */
+	public Float getDBRefFactor() {
+		return getValue(ATTR_DB_REFERENCE_FACTOR).extract();
+	}
+
+	/**
+	 * Changes the decibel status of this unit. The decibel flag is deduced from
+	 * given reference factor. If the reference factor is finite, as returned by
+	 * {@link Float#isFinite(float)}, and not 0, then the decibel flag is set to
+	 * true and given reference factor is taken. In any other case both, the decibel
+	 * flag and the reference factor, will be reset.
+	 *
+	 * @param dbReferenceFactor The new decibel reference factor.
+	 */
+	public void setDB(Float dbReferenceFactor) {
+		boolean isValid = Float.isFinite(dbReferenceFactor) && Float.compare(Math.abs(dbReferenceFactor), 0F) != 0;
+		getValue(ATTR_DB).set(isValid);
+
+		if (isValid) {
+			getValue(ATTR_DB_REFERENCE_FACTOR).set(dbReferenceFactor);
+		} else {
+			getValue(ATTR_DB_REFERENCE_FACTOR).setValid(false);
+		}
+	}
+
+	/**
+	 * Returns the {@link PhysicalDimension} of this unit.
+	 *
+	 * @return The {@code PhysicalDimension} is returned.
+	 */
+	public PhysicalDimension getPhysicalDimension() {
+		return getCore().getMutableStore().get(PhysicalDimension.class);
+	}
+
+	/**
+	 * Sets new {@link PhysicalDimension} for this unit.
+	 *
+	 * @param physicalDimension The new {@code PhysicalDimension}.
+	 */
+	public void setPhysicalDimension(PhysicalDimension physicalDimension) {
+		getCore().getMutableStore().set(physicalDimension);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/User.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/User.java
new file mode 100644
index 0000000..531a945
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/User.java
@@ -0,0 +1,164 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the user entity type.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class User extends BaseEntity implements Deletable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Surname' attribute name.
+	 */
+	public static final String ATTR_SURNAME = "Surname";
+
+	/**
+	 * The 'GivenName' attribute name.
+	 */
+	public static final String ATTR_GIVEN_NAME = "GivenName";
+
+	/**
+	 * The 'Department' attribute name.
+	 */
+	public static final String ATTR_DEPARTMENT = "Department";
+
+	/**
+	 * The 'Telephone' attribute name.
+	 */
+	public static final String ATTR_PHONE = "Telephone";
+
+	/**
+	 * The 'EMail' attribute name.
+	 */
+	public static final String ATTR_EMAIL = "E-Mail";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	User(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the given name of this user.
+	 *
+	 * @return The given name is returned.
+	 */
+	public String getGivenName() {
+		return getValue(ATTR_GIVEN_NAME).extract();
+	}
+
+	/**
+	 * Sets new given name for this user.
+	 *
+	 * @param givenName The new given name.
+	 */
+	public void setGivenName(String givenName) {
+		getValue(ATTR_GIVEN_NAME).set(givenName);
+	}
+
+	/**
+	 * Returns the surname of this user.
+	 *
+	 * @return The surname is returned.
+	 */
+	public String getSurname() {
+		return getValue(ATTR_SURNAME).extract();
+	}
+
+	/**
+	 * Sets new surname for this user.
+	 *
+	 * @param surname The new surname.
+	 */
+	public void setSurname(String surname) {
+		getValue(ATTR_SURNAME).set(surname);
+	}
+
+	/**
+	 * Returns the department of this user.
+	 *
+	 * @return The department is returned.
+	 */
+	public String getDepartment() {
+		return getValue(ATTR_DEPARTMENT).extract();
+	}
+
+	/**
+	 * Sets new department for this user.
+	 *
+	 * @param department The new department.
+	 */
+	public void setDepartment(String department) {
+		getValue(ATTR_DEPARTMENT).set(department);
+	}
+
+	/**
+	 * Returns the phone number of this user.
+	 *
+	 * @return The phone number is returned.
+	 */
+	public String getPhone() {
+		return getValue(ATTR_PHONE).extract();
+	}
+
+	/**
+	 * Sets new phone number for this user.
+	 *
+	 * @param phone The new phone number.
+	 */
+	public void setPhone(String phone) {
+		getValue(ATTR_PHONE).set(phone);
+	}
+
+	/**
+	 * Returns the e-mail address of this user.
+	 *
+	 * @return The e-mail address is returned.
+	 */
+	public String getMail() {
+		return getValue(ATTR_EMAIL).extract();
+	}
+
+	/**
+	 * Sets new e-mail address for this user.
+	 *
+	 * @param eMail The new e-mail address.
+	 */
+	public void setMail(String eMail) {
+		getValue(ATTR_EMAIL).set(eMail);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Value.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Value.java
new file mode 100644
index 0000000..05c02e5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Value.java
@@ -0,0 +1,448 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static java.util.stream.IntStream.range;
+
+import java.lang.reflect.Array;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Generic value container. This value container is tightly coupled with its
+ * {@link ValueType}. It allows only to store assignment compatible values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class Value {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	public static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
+	// ======================================================================
+	// Instances variables
+	// ======================================================================
+
+	private final ValueType<?> valueType;
+	private final String name;
+	private final String unit;
+
+	private boolean initialValid;
+	private Object initialValue;
+
+	private boolean valid;
+	private Object value;
+
+	private final Class<?> valueClass;
+	private final String valueTypeDescr;
+	private final Object defaultValue;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param valueType    The associated {@link ValueType}.
+	 * @param name         The name of this container.
+	 * @param unit         The name of the unit.
+	 * @param valid        The initial validity flag.
+	 * @param value        The initial value.
+	 * @param valueClass   Used for type checking upon assignment.
+	 * @param defaultValue Used as null replacement.
+	 */
+	Value(ValueType<?> valueType, String name, String unit, boolean valid, Object value, Class<?> valueClass,
+			Object defaultValue, String valueTypeDescr) {
+		this.valueType = valueType;
+		this.valueTypeDescr = valueTypeDescr;
+		this.name = name;
+		this.unit = unit == null ? "" : unit;
+
+		this.valueClass = valueClass;
+		this.defaultValue = defaultValue;
+
+		// set initial value
+		set(value);
+		// overwrite initial validity flag
+		setValid(valid);
+
+		// preserve initial values
+		initialValid = isValid();
+		initialValue = copy(extract());
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param origin The origin {@link Value}.
+	 * @param input  The new value.
+	 */
+	private Value(Value origin, Object input) {
+		this(origin.valueType, origin.name, origin.unit, origin.valid, input, origin.valueClass, origin.defaultValue,
+				origin.valueTypeDescr);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of this value container.
+	 *
+	 * @return This value container's name is returned.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the {@link ValueType} this value container is associated with.
+	 *
+	 * @return The associated {@code ValueType} is returned.
+	 */
+	public ValueType<?> getValueType() {
+		return valueType;
+	}
+
+	/**
+	 * Returns the unit name of this value container.
+	 *
+	 * @return The unit name of this value container is returned.
+	 */
+	public String getUnit() {
+		return unit;
+	}
+
+	/**
+	 * Returns the validity flag of this value container.
+	 *
+	 * @return True, if the stored value is marked to be valid.
+	 */
+	public boolean isValid() {
+		Object v = extract();
+
+		if (v != null) {
+			if (v.getClass().isArray()) {
+				return valid && Array.getLength(v) > 0;
+			} else if (v instanceof String) {
+				return valid && !((String) v).isEmpty();
+			}
+		}
+
+		return valid && v != null;
+	}
+
+	/**
+	 * Overwrites validity flag with given flag.
+	 *
+	 * @param valid The new validity flag.
+	 */
+	public void setValid(boolean valid) {
+		this.valid = valid;
+	}
+
+	/**
+	 * Returns currently stored value of this value container.
+	 *
+	 * @param <T>  The expected value type.
+	 * @param type The {@link ValueType}.
+	 * @return Currently stored value is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T> T extract(ValueType<T> type) {
+		return (T) value;
+	}
+
+	/**
+	 * Returns currently stored value of this value container.
+	 *
+	 * @param <T> The expected value type.
+	 * @return Currently stored value is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T> T extract() {
+		return (T) value;
+	}
+
+	/**
+	 * Replaces currently stored value with the given one. If {@code null} is given,
+	 * then a well defined default value is used instead and the validity flag is
+	 * automatically set to {@code false}.
+	 *
+	 * @param input The new value must be an instance of the type defined in
+	 *              {@link ValueType#type} or in case of an enumeration type an
+	 *              appropriate enumeration constant or array thereof.
+	 * @throws IllegalArgumentException Thrown if an incompatible value is given.
+	 */
+	public void set(Object input) {
+		if (input == null) {
+			value = defaultValue;
+			setValid(false);
+		} else if (valueClass.isInstance(input)) {
+			value = input;
+			setValid(true);
+		} else if (input instanceof EnumerationValue) {
+			setForEnumerationValue(input);
+		} else {
+			throw new IllegalArgumentException("Incompatible value type '" + input.getClass().getSimpleName()
+					+ "' passed, expected '" + valueClass.getSimpleName() + "'.");
+		}
+	}
+
+	/**
+	 * Merges given value container with this instance. To be able to do so, the
+	 * given value container must be compatible with this one. Value containers are
+	 * compatible if the their name, unit and {@link ValueType} is equal. If the
+	 * stored values or the validity flags do not match, then both values are
+	 * discarded and {@code null} is taken as the initial value.
+	 *
+	 * @param value The value container that will be merged with this instance.
+	 * @return A new value container with merged value is returned.
+	 * @throws IllegalArgumentException Thrown if given value container is not
+	 *                                  compatible.
+	 */
+	public Value merge(Value value) {
+		boolean nameMissmatch = !getName().equals(value.getName());
+		boolean unitMissmatch = !getUnit().equals(value.getUnit());
+		boolean typeMissmatch = !getValueType().equals(value.getValueType());
+		if (nameMissmatch || unitMissmatch || typeMissmatch) {
+			throw new IllegalArgumentException("Unable to merge, incompatible value passed.");
+		}
+
+		boolean equalValue = Objects.deepEquals(extract(), value.extract());
+		boolean bothValid = isValid() && value.isValid();
+		return new Value(this, equalValue && bothValid ? extract() : null);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof Value)) {
+			return false;
+		}
+
+		Value val = (Value) other;
+
+		return Objects.equals(this.valueType, val.valueType) && Objects.equals(this.name, val.name)
+				&& Objects.equals(this.unit, val.unit) && Objects.equals(this.initialValid, val.initialValid)
+				&& Objects.deepEquals(this.initialValue, val.initialValue) && Objects.equals(this.valid, val.valid)
+				&& Objects.deepEquals(this.value, val.value) && Objects.equals(this.valueClass, val.valueClass)
+				&& Objects.equals(this.valueTypeDescr, val.valueTypeDescr)
+				&& Objects.equals(this.defaultValue, val.defaultValue);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(valueType, name, unit, initialValid, initialValue, valid, value, valueClass, valueTypeDescr,
+				defaultValue);
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this value. In case
+	 * of a sequence value container with up to 10 values the complete sequence will
+	 * be printed. Otherwise only the 5 first and last values will be printed. If
+	 * the contained value is marked as not valid, then the contained value is
+	 * omitted in the representation.
+	 *
+	 * @return The {@code String} representation of this value.
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(name).append(" = ");
+
+		if (isValid()) {
+			Object v = extract();
+			if (v != null && v.getClass().isArray()) {
+				int length = Array.getLength(v);
+				sb.append('[');
+
+				if (length > 10) {
+					sb.append(range(0, 5).mapToObj(i -> readAt(v, i)).collect(Collectors.joining(", ")));
+					sb.append(", ..., ");
+					sb.append(range(length - 5, length).mapToObj(i -> readAt(v, i)).collect(Collectors.joining(", ")));
+				} else {
+					sb.append(range(0, length).mapToObj(i -> readAt(v, i)).collect(Collectors.joining(", ")));
+				}
+				sb.append(']');
+			} else {
+				sb.append(v);
+			}
+		}
+
+		if (!getUnit().isEmpty()) {
+			sb.append(" [").append(getUnit()).append(']');
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * Checks whether either the validity flag or the value have been modified since
+	 * initialization.
+	 *
+	 * @return Returns {@code true} either if the flag or the value has been
+	 *         modified.
+	 */
+	public boolean isModified() {
+		return wasValid() != isValid() || !Objects.deepEquals(extractInitial(), extract());
+	}
+
+	/**
+	 * Returns the initial validity flag.
+	 *
+	 * @return Returns {@code true} if the value was initially marked as valid.
+	 */
+	public boolean wasValid() {
+		return initialValid;
+	}
+
+	/**
+	 * Returns the initial value.
+	 *
+	 * @return The initial value is returned.
+	 */
+	public Object extractInitial() {
+		return initialValue;
+	}
+
+	/**
+	 * Overwrites the initial validity flag and value with the current ones.
+	 */
+	public void apply() {
+		initialValid = isValid();
+		initialValue = copy(extract());
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@code String} value from given array at given position.
+	 *
+	 * @param array The array {@code Object}.
+	 * @param index The index of the required value.
+	 * @return The {@code String} value of the requested value is returned.
+	 */
+	static String readAt(Object array, int index) {
+		Object value = Array.get(array, index);
+		if (value != null && byte[].class.isInstance(value)) {
+			return Arrays.toString((byte[]) value);
+		}
+
+		return value == null ? "" : String.valueOf(value);
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Returns a copy of given {@code Object}, so modifications in one do not affect
+	 * to other.
+	 *
+	 * @param value The object which will be copied.
+	 * @return The copy is returned.
+	 */
+	private static Object copy(Object value) {
+		if (value == null) {
+			return null;
+		}
+
+		Class<?> valueClass = value.getClass();
+		if (valueClass.isArray() && Array.getLength(value) > 0) {
+			return createDeepCopy(value, valueClass);
+		} else if (value instanceof FileLink) {
+			return new FileLink((FileLink) value);
+		}
+
+		// simple immutable value
+		return value;
+	}
+
+	/**
+	 * Replaces currently stored value with the given one.
+	 *
+	 * @param input The new value must be an instance of the enumeration type an
+	 *              appropriate enumeration constant.
+	 * @throws IllegalArgumentException Thrown if an incompatible value is given.
+	 */
+	private void setForEnumerationValue(Object input) {
+		String inpvalueTypeDescr = ((EnumerationValue) input).getOwner().getName();
+		if (inpvalueTypeDescr == null) {
+			throw new IllegalArgumentException(
+					"EnumerationValue value description of input value not correctly initialized");
+		}
+		if (valueTypeDescr == null) {
+			throw new IllegalArgumentException(
+					"EnumerationValue value description not correctly initialized got null, '" + "' expected '"
+							+ valueClass.getSimpleName() + "'.");
+		}
+
+		if (valueTypeDescr.equals(inpvalueTypeDescr)) {
+			value = input;
+			setValid(true);
+		} else {
+			throw new IllegalArgumentException("Incompatible value type description'" + inpvalueTypeDescr
+					+ "' passed, expected '" + valueTypeDescr + "'.");
+		}
+	}
+
+	/**
+	 * Returns a deep copy of given {@code Object}, so modifications in one do not
+	 * affect to other.
+	 *
+	 * @param value      The object which will be copied.
+	 * @param valueClass The class of the value object.
+	 * @return The copy is returned.
+	 */
+	private static Object createDeepCopy(Object value, Class<?> valueClass) {
+		int length = Array.getLength(value);
+
+		if (valueClass.getComponentType().isPrimitive()) {
+			Object copy = Array.newInstance(valueClass.getComponentType(), length);
+			System.arraycopy(value, 0, copy, 0, length);
+			return copy;
+		} else {
+			if (value instanceof byte[][]) {
+				return Arrays.stream((byte[][]) value).map(v -> v.clone()).toArray(byte[][]::new);
+			} else if (value instanceof FileLink[]) {
+				return Arrays.stream((FileLink[]) value).map(FileLink::new).toArray(FileLink[]::new);
+			} else {
+				return Arrays.copyOf((Object[]) value, length);
+			}
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ValueType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ValueType.java
new file mode 100644
index 0000000..5717b7e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ValueType.java
@@ -0,0 +1,1038 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.time.LocalDateTime;
+
+/**
+ * Value type enumeration is a {@link Value} factory.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ValueType<T> extends EnumerationValue {
+
+	/**
+	 * A {@link Value} with this type contains a {@code String} value and replaces
+	 * {@code null} with an empty {@code String}.
+	 */
+	public static final ValueType<String> STRING = new ValueType<>(String.class, "STRING", "");
+
+	/**
+	 * A {@link Value} with this type contains a {@code String[]} value replaces
+	 * {@code null} with an empty {@code String} array.
+	 */
+	public static final ValueType<String[]> STRING_SEQUENCE = new ValueType<>(String[].class, "STRING_SEQUENCE",
+			new String[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link LocalDateTime} value and
+	 * does not replace {@code null}.
+	 */
+	public static final ValueType<LocalDateTime> DATE = new ValueType<>(LocalDateTime.class, "DATE", null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code LocalDateTime[]} value and
+	 * replaces {@code null} with an empty {@code LocalDateTime} array.
+	 */
+	public static final ValueType<LocalDateTime[]> DATE_SEQUENCE = new ValueType<>(LocalDateTime[].class,
+			"DATE_SEQUENCE", new LocalDateTime[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Boolean} value and replaces
+	 * {@code null} with {@link Boolean#FALSE}.
+	 */
+	public static final ValueType<Boolean> BOOLEAN = new ValueType<>(Boolean.class, "BOOLEAN", Boolean.FALSE);
+
+	/**
+	 * A {@link Value} with this type contains a {@code boolean[]} value and
+	 * replaces {@code null} with an empty {@code boolean} array.
+	 */
+	public static final ValueType<boolean[]> BOOLEAN_SEQUENCE = new ValueType<>(boolean[].class, "BOOLEAN_SEQUENCE",
+			new boolean[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Byte} value and replaces
+	 * {@code null} with a {@code Byte} containing zero.
+	 */
+	public static final ValueType<Byte> BYTE = new ValueType<>(Byte.class, "BYTE", Byte.valueOf((byte) 0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code byte[]} value and replaces
+	 * {@code null} with an empty {@code byte} array.
+	 */
+	public static final ValueType<byte[]> BYTE_SEQUENCE = new ValueType<>(byte[].class, "BYTE_SEQUENCE", new byte[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Short} value and replaces
+	 * {@code null} with a {@code Short} containing zero.
+	 */
+	public static final ValueType<Short> SHORT = new ValueType<>(Short.class, "SHORT", Short.valueOf((short) 0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code short[]} value and replaces
+	 * {@code null} with an empty {@code short} array.
+	 */
+	public static final ValueType<short[]> SHORT_SEQUENCE = new ValueType<>(short[].class, "SHORT_SEQUENCE",
+			new short[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Integer} value and replaces
+	 * {@code null} with a {@code Integer} containing zero.
+	 */
+	public static final ValueType<Integer> INTEGER = new ValueType<>(Integer.class, "INTEGER", Integer.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code int[]} value and replaces
+	 * {@code null} with an empty {@code int} array.
+	 */
+	public static final ValueType<int[]> INTEGER_SEQUENCE = new ValueType<>(int[].class, "INTEGER_SEQUENCE",
+			new int[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Long} value and replaces
+	 * {@code null} with a {@code Long} containing zero.
+	 */
+	public static final ValueType<Long> LONG = new ValueType<>(Long.class, "LONG", Long.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code long[]} value and replaces
+	 * {@code null} with an empty {@code long} array.
+	 */
+	public static final ValueType<long[]> LONG_SEQUENCE = new ValueType<>(long[].class, "LONG_SEQUENCE", new long[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Float} value and replaces
+	 * {@code null} with a {@code Float} containing zero.
+	 */
+	public static final ValueType<Float> FLOAT = new ValueType<>(Float.class, "FLOAT", Float.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code float[]} value and replaces
+	 * {@code null} with an empty {@code float} array.
+	 */
+	public static final ValueType<float[]> FLOAT_SEQUENCE = new ValueType<>(float[].class, "FLOAT_SEQUENCE",
+			new float[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Double} value and replaces
+	 * {@code null} with a {@code Double} containing zero.
+	 */
+	public static final ValueType<Double> DOUBLE = new ValueType<>(Double.class, "DOUBLE", Double.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code double[]} value and replaces
+	 * {@code null} with an empty {@code double} array.
+	 */
+	public static final ValueType<double[]> DOUBLE_SEQUENCE = new ValueType<>(double[].class, "DOUBLE_SEQUENCE",
+			new double[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@code byte[]} value and replaces
+	 * {@code null} with an empty {@code byte} array.
+	 */
+	public static final ValueType<byte[]> BYTE_STREAM = new ValueType<>(byte[].class, "BYTE_STREAM", new byte[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@code byte[][]} value and replaces
+	 * {@code null} with an empty {@code byte[][]} array.
+	 */
+	public static final ValueType<byte[][]> BYTE_STREAM_SEQUENCE = new ValueType<>(byte[][].class,
+			"BYTE_STREAM_SEQUENCE", new byte[0][]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link FloatComplex} value and does
+	 * not replaces {@code null}.
+	 */
+	public static final ValueType<FloatComplex> FLOAT_COMPLEX = new ValueType<>(FloatComplex.class, "FLOAT_COMPLEX",
+			null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code FloatComplex[]} value and
+	 * replaces {@code null} with an empty {@code FloatComplex[]} array.
+	 */
+	public static final ValueType<FloatComplex[]> FLOAT_COMPLEX_SEQUENCE = new ValueType<>(FloatComplex[].class,
+			"FLOAT_COMPLEX_SEQUENCE", new FloatComplex[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link DoubleComplex} value and
+	 * does not replaces {@code null}.
+	 */
+	public static final ValueType<DoubleComplex> DOUBLE_COMPLEX = new ValueType<>(DoubleComplex.class, "DOUBLE_COMPLEX",
+			null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code DoubleComplex[]} value and
+	 * replaces {@code null} with an empty {@code DoubleComplex[]} array.
+	 */
+	public static final ValueType<DoubleComplex[]> DOUBLE_COMPLEX_SEQUENCE = new ValueType<>(DoubleComplex[].class,
+			"DOUBLE_COMPLEX_SEQUENCE", new DoubleComplex[0]);
+
+	/**
+	 * A {@link Value} with this type contains a modeled enumeration constant value
+	 * and does not replace {@code null}.
+	 *
+	 */
+	public static final ValueType<EnumerationValue> ENUMERATION = new ValueType<>("ENUMERATION");
+
+	/**
+	 * A {@link Value} with this type contains a modeled enumeration constant array
+	 * value and replaces {@code null} with an empty array with defined component
+	 * type.
+	 *
+	 */
+	public static final ValueType<EnumerationValue[]> ENUMERATION_SEQUENCE = new ValueType<>("ENUMERATION_SEQUENCE");
+
+	/**
+	 * A {@link Value} with this type contains a {@link FileLink} value and does not
+	 * replace {@code null}.
+	 */
+	public static final ValueType<FileLink> FILE_LINK = new ValueType<>(FileLink.class, "FILE_LINK", null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code FileLink[]} value and
+	 * replaces {@code null} with an empty {@code FileLink} array.
+	 */
+	public static final ValueType<FileLink[]> FILE_LINK_SEQUENCE = new ValueType<>(FileLink[].class,
+			"FILE_LINK_SEQUENCE", new FileLink[0]);
+
+	/**
+	 * TODO ...
+	 */
+	public static final ValueType<Object> BLOB = new ValueType<>(Object.class, "", null);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Object} value and does not
+	 * replace {@code null}. This value type does not have a corresponding sequence
+	 * type.
+	 */
+	public static final ValueType<Object> UNKNOWN = new ValueType<>(Object.class, "UNKNOWN", null);
+
+	/**
+	 * The type is used to check assignment compatibility of non {@code null} values
+	 * passed to {@link Value#set(Object)}.
+	 */
+	private final Class<T> type;
+
+	/**
+	 * The default value will be used in {@link Value#set(Object)} to replace a
+	 * {@code null} input argument.
+	 */
+	private final T defaultValue;
+
+	/**
+	 * Constructor - May only be used to create {@link #ENUMERATION},
+	 * {@link #ENUMERATION_SEQUENCE} or {@link #UNKNOWN} types.
+	 * 
+	 * @param name
+	 */
+	private ValueType(String name) {
+		this(null, name, null);
+	}
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param type         The type of value a {@link Value} with this value type
+	 *                     will accept.
+	 * @param name
+	 * @param defaultValue Will be used as {@code null} replacement in
+	 *                     {@link Value#set(Object)}.
+	 */
+	private ValueType(Class<T> type, String name, T defaultValue) {
+		super(name);
+		this.type = type;
+		this.defaultValue = defaultValue;
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given name. The {@code
+	 * Value}'s initial validity flag will be set to {@code true}, the unit name
+	 * will be omitted.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code false}.
+	 *
+	 * @param name  The name of the attribute.
+	 * @param input The initial value.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Value create(String name, Object input) {
+		return create(name, "", true, input);
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given name. The {@code
+	 * Value}'s initial validity flag will be set to {@code false}, the unit name
+	 * will be omitted. The initial value will be the one defined in
+	 * {@link #defaultValue}.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code false}.
+	 *
+	 * @param name The name of the attribute.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Value create(String name) {
+		return create(name, "", false, defaultValue);
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given arguments.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code false}.
+	 *
+	 * @param name  The name of the attribute.
+	 * @param unit  The unit name of the attribute.
+	 * @param valid The initial validity flag.
+	 * @param input The initial value.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Value create(String name, String unit, boolean valid, Object input) {
+		if (isEnumerationType()) {
+			throw new IllegalStateException("This value type is an enumeration type.");
+		}
+
+		return new Value(this, name, unit, valid, input, type, defaultValue, null);
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given name. The {@code
+	 * Value}'s initial validity flag will be set to {@code false}, the unit name
+	 * will be omitted. The initial value will be {@code null} if
+	 * {@link #isSequence()} returns {@code false} otherwise an empty array with
+	 * given component type in enumClass is used.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code true}.
+	 *
+	 * @param <E>  Modeled enumeration type.
+	 * @param name The name of the attribute.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code false}.
+	 */
+	public <E extends EnumerationValue> Value create(Enumeration<E> enumObj, String name) {
+		return create(name, "", false, null, enumObj.getName());
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given arguments.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code true}.
+	 *
+	 * @param <E>   Modeled enumeration type.
+	 * @param name  The name of the attribute.
+	 * @param unit  The unit name of the attribute.
+	 * @param valid The initial validity flag.
+	 * @param input The initial value.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code false}.
+	 */
+	public <E extends EnumerationValue> Value create(String name, String unit, boolean valid, Object input,
+			String valueTypeDescr) {
+		if (isEnumerationType()) {
+			Object nullReplacement = null;
+			Class<?> valueClass = EnumerationValue.class;
+			if (isSequence()) {
+				nullReplacement = Array.newInstance(valueClass, 0);
+				valueClass = nullReplacement.getClass();
+			}
+
+			return new Value(this, name, unit, valid, input, valueClass, nullReplacement, valueTypeDescr);
+		}
+
+		throw new IllegalStateException("This value type is not an enumeration type.");
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #STRING}</li>
+	 * <li>{@link #STRING_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isStringType() {
+		return isString() || isStringSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #STRING}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isString() {
+		return STRING == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #STRING_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isStringSequence() {
+		return STRING_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #DATE}</li>
+	 * <li>{@link #DATE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isDateType() {
+		return isDate() || isDateSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DATE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDate() {
+		return DATE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DATE_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDateSequence() {
+		return DATE_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BOOLEAN}</li>
+	 * <li>{@link #BOOLEAN_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isBooleanType() {
+		return isBoolean() || isBooleanSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BOOLEAN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBoolean() {
+		return BOOLEAN == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BOOLEAN_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBooleanSequence() {
+		return BOOLEAN_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isNumericalType() {
+		return isAnyIntegerType() || isAnyFloatType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isAnyIntegerType() {
+		return isByteType() || isShortType() || isIntegerType() || isLongType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isByteType() {
+		return isByte() || isByteSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByte() {
+		return BYTE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteSequence() {
+		return BYTE_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isShortType() {
+		return isShort() || isShortSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #SHORT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isShort() {
+		return SHORT == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #SHORT_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isShortSequence() {
+		return SHORT_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isIntegerType() {
+		return isInteger() || isIntegerSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #INTEGER}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isInteger() {
+		return INTEGER == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #INTEGER_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isIntegerSequence() {
+		return INTEGER_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isLongType() {
+		return isLong() || isLongSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #LONG}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLong() {
+		return LONG == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #LONG_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLongSequence() {
+		return LONG_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isAnyFloatType() {
+		return isFloatType() || isDoubleType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFloatType() {
+		return isFloat() || isFloatSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloat() {
+		return FLOAT == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatSequence() {
+		return FLOAT_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #DOUBLE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isDoubleType() {
+		return isDouble() || isDoubleSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDouble() {
+		return DOUBLE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleSequence() {
+		return DOUBLE_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE_STREAM}</li>
+	 * <li>{@link #BYTE_STREAM_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isByteStreamType() {
+		return isByteStream() || isByteStreamSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE_STREAM}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteStream() {
+		return BYTE_STREAM == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE_STREAM_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteStreamSequence() {
+		return BYTE_STREAM_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT_COMPLEX}</li>
+	 * <li>{@link #FLOAT_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE_COMPLEX}</li>
+	 * <li>{@link #DOUBLE_COMPLEX_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isComplexType() {
+		return isFloatComplexType() || isDoubleComplexType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT_COMPLEX}</li>
+	 * <li>{@link #FLOAT_COMPLEX_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFloatComplexType() {
+		return isFloatComplex() || isFloatComplexSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatComplex() {
+		return FLOAT_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT_COMPLEX_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatComplexSequence() {
+		return FLOAT_COMPLEX_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #DOUBLE_COMPLEX}</li>
+	 * <li>{@link #DOUBLE_COMPLEX_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isDoubleComplexType() {
+		return isDoubleComplex() || isDoubleComplexSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleComplex() {
+		return DOUBLE_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE_COMPLEX_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleComplexSequence() {
+		return DOUBLE_COMPLEX_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #ENUMERATION}</li>
+	 * <li>{@link #ENUMERATION_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isEnumerationType() {
+		return isEnumeration() || isEnumerationSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #ENUMERATION}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEnumeration() {
+		return ENUMERATION == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #ENUMERATION_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEnumerationSequence() {
+		return ENUMERATION_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FILE_LINK}</li>
+	 * <li>{@link #FILE_LINK_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFileLinkType() {
+		return isFileLink() || isFileLinkSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FILE_LINK}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFileLink() {
+		return FILE_LINK == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FILE_LINK_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFileLinkSequence() {
+		return FILE_LINK_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BLOB}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBlob() {
+		return BLOB == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #UNKNOWN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isUnknown() {
+		return UNKNOWN == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #STRING_SEQUENCE}</li>
+	 * <li>{@link #DATE_SEQUENCE}</li>
+	 * <li>{@link #BOOLEAN_SEQUENCE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * <li>{@link #BYTE_STREAM_SEQUENCE}</li>
+	 * <li>{@link #FLOAT_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link #ENUMERATION_SEQUENCE}</li>
+	 * <li>{@link #FILE_LINK_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isSequence() {
+		return name() != null && name().endsWith("SEQUENCE");
+	}
+
+	/**
+	 * Returns the sequence version of this value type. This method returns itself,
+	 * if this value type is a sequence type.
+	 * 
+	 * If you extend the class ValueType, you have to ensure that T contains a field
+	 * of the correct name and type, otherwise a runtime error will occur.
+	 *
+	 * @return The sequence version of this value type is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <S extends ValueType<?>> S toSequenceType() {
+		if (isSequence()) {
+			return (S) this;
+		}
+
+		return (S) valueOf(name() + "_SEQUENCE");
+	}
+
+	/**
+	 * Returns the scalar version of this value type. This method returns itself, if
+	 * this value type is a scalar type.
+	 * 
+	 * If you extend the class ValueType, you have to ensure that T contains a field
+	 * of the correct name and type, otherwise a runtime error will occur.
+	 *
+	 * @return The sequence version of this value type is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <S extends ValueType<?>> S toSingleType() {
+
+		if (isEnumerationType()) {
+			if (isSequence()) {
+				return (S) valueOf(name().replace("_SEQUENCE", ""));
+			}
+
+			return (S) this;
+		} else {
+			try {
+				if (isSequence()) {
+					Field field = getClass().getField(name().replace("_SEQUENCE", ""));
+					return (S) field.get(this);
+				}
+				return (S) this;
+			} catch (NoSuchFieldException | ClassCastException | IllegalAccessException e) {
+				throw new RuntimeException("Can't figure out single type for " + name());
+			}
+		}
+	}
+
+	/**
+	 * Returns the value class for this value type.
+	 *
+	 * @return The value class is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Class<?> getValueClass() {
+		if (isEnumerationType()) {
+			throw new IllegalStateException("");
+		}
+		return type;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/VersionState.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/VersionState.java
new file mode 100644
index 0000000..6f2bdb5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/VersionState.java
@@ -0,0 +1,91 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Version state enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see FileLink
+ */
+public class VersionState extends EnumerationValue {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * An entity with this version state is still editable and hence not allowed be
+	 * used when creating new entities.
+	 */
+	public static final VersionState EDITABLE = new VersionState("EDITABLE", 0);
+
+	/**
+	 * An entity with this version state is no longer editable and is allowed to be
+	 * used when creating new entities.
+	 *
+	 * <p>
+	 * <b>Note:</b> If an entity's version state is this state, then its version
+	 * state is only allowed to be changed to {@link #ARCHIVED}.
+	 */
+	public static final VersionState VALID = new VersionState("VALID", 1);
+
+	/**
+	 * An entity with this version state is neither editable nor is it allowed to
+	 * use it when creating new entities
+	 *
+	 * <p>
+	 * <b>Note:</b> If an entity's version state is this state, then its version
+	 * state is no longer allowed to be changed.
+	 */
+	public static final VersionState ARCHIVED = new VersionState("ARCHIVED", 2);
+
+	private VersionState(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	/**
+	 * Returns true if this version state is {@link #EDITABLE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEditable() {
+		return EDITABLE == this;
+	}
+
+	/**
+	 * Returns true if this version state is {@link #VALID}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isValid() {
+		return VALID == this;
+	}
+
+	/**
+	 * Returns true if this version state is {@link #ARCHIVED}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isArchived() {
+		return ARCHIVED == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationException.java
new file mode 100644
index 0000000..de97102
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationException.java
@@ -0,0 +1,46 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+/**
+ * Thrown to indicate a errors concerning notifications.
+ *
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public class NotificationException extends Exception {
+
+	private static final long serialVersionUID = 4011877631559261716L;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The error message.
+	 */
+	public NotificationException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message   The error message.
+	 * @param throwable The origin cause.
+	 */
+	public NotificationException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationFilter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationFilter.java
new file mode 100644
index 0000000..4f6eb9a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationFilter.java
@@ -0,0 +1,81 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+
+/**
+ * Class represents a filter for notifications.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public class NotificationFilter {
+
+	/**
+	 * Modification type enumeration
+	 * 
+	 * @since 1.0.0
+	 * @author Matthias Koller, Peak Solution GmbH
+	 */
+	public static enum ModificationType {
+		INSTANCE_CREATED, INSTANCE_MODIFIED, INSTANCE_DELETED, MODEL_MODIFIED, SECURITY_MODIFIED;
+	}
+
+	private EnumSet<ModificationType> types = EnumSet.allOf(ModificationType.class);
+
+	private Set<EntityType> entityTypes = Collections.emptySet();
+
+	/**
+	 * Returns the {@link ModificationType}s of this filter.
+	 * 
+	 * @return Set with {@link ModificationType} is returned.
+	 */
+	public Set<ModificationType> getTypes() {
+		return types;
+	}
+
+	/**
+	 * Sets the {@link ModificationType}s used to filter the notifications.
+	 * 
+	 * @param types Set with {@link ModificationType}
+	 */
+	public void setTypes(Set<ModificationType> types) {
+		this.types = EnumSet.copyOf(types);
+	}
+
+	/**
+	 * Returns the {@link EntityType}s of this filter.
+	 * 
+	 * @return Set with {@link EntityType} is returned.
+	 */
+	public Set<EntityType> getEntityTypes() {
+		return entityTypes;
+	}
+
+	/**
+	 * Sets the {@link EntityType}s used to filter the notifications.
+	 * 
+	 * @param entityTypes Set with {@link EntityType}.
+	 */
+	public void setEntityTypes(Set<EntityType> entityTypes) {
+		this.entityTypes = new HashSet<>(entityTypes);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationListener.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationListener.java
new file mode 100644
index 0000000..a03a3d8
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationListener.java
@@ -0,0 +1,72 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.User;
+
+/**
+ * Listener interface for notifications.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public interface NotificationListener {
+	/**
+	 * Called when a new instance element was created by the server.
+	 * 
+	 * @param entities A list of newly created entities.
+	 * @param user     The user who created the entities.
+	 */
+	void instanceCreated(List<? extends Entity> entities, User user);
+
+	/**
+	 * Called when a existing instance element was modified by the server.
+	 * 
+	 * @param entities A list of modified entities.
+	 * @param user     The user who modified the entities.
+	 */
+	void instanceModified(List<? extends Entity> entities, User user);
+
+	/**
+	 * Called when a existing instance element was deleted by the server.
+	 * 
+	 * @param entityType EntityType of the deleted entities.
+	 * @param entities   A list with the IDs of deleted entities.
+	 * @param user       The user who deleted the entities.
+	 */
+	void instanceDeleted(EntityType entityType, List<String> ids, User user);
+
+	/**
+	 * Called when the application model is changed by the server
+	 * 
+	 * @param entityType Modified entityType.
+	 * @param user       The user who modified the application model.
+	 */
+	void modelModified(EntityType entityType, User user);
+
+	/**
+	 * Called when security related information is changed by the server
+	 * 
+	 * @param entityType EntityType with changed security
+	 * @param entities   A list with the IDs of entities related to the change.
+	 *                   Empty if change was only relevant for entityType.
+	 * @param user       The user who modified security information.
+	 */
+	void securityModified(EntityType entityType, List<String> ids, User user);
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationService.java
new file mode 100644
index 0000000..3f17478
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationService.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+/**
+ * Manages registrations to a notification service.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public interface NotificationService {
+
+	/**
+	 * Registers a NotificationListener at the underlying notification service.
+	 * 
+	 * @param registrationName An unique name used for the registration.
+	 * @param filter           A notification filter, specifying which events should
+	 *                         be received by the listener.
+	 * @param listener         A notification listener which is informed if new
+	 *                         events are received.
+	 * @throws NotificationException In case the listener cannot be registered at
+	 *                               the notification service.
+	 */
+	void register(String registrationName, NotificationFilter filter, NotificationListener listener)
+			throws NotificationException;
+
+	/**
+	 * Unregisters a NotificationListener from the underlying notification service.
+	 * 
+	 * @param registrationName The unique name previously used for the registration.
+	 * @throws NotificationException In case the listener cannot be deregistered.
+	 */
+	void deregister(String registrationName) throws NotificationException;
+
+	/**
+	 * Closes the NotificationManager and all registered NotificationListeners
+	 * 
+	 * @param deregisterAll if true, all NotificationListeners are also deregistered
+	 *                      before closing.
+	 * @throws NotificationException In case the listeners cannot be deregistered or
+	 *                               the manager cannot be closed.
+	 */
+	void close(boolean deregisterAll) throws NotificationException;
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Aggregation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Aggregation.java
new file mode 100644
index 0000000..cc4d733
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Aggregation.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * Aggregation enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Query
+ */
+public enum Aggregation {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * No aggregate function is used for the selected attribute.
+	 */
+	NONE,
+
+	/**
+	 * Used to count the number of result rows.
+	 */
+	COUNT,
+
+	/**
+	 * Within the result rows for the selected attribute all distinct values are
+	 * counted.
+	 */
+	DISTINCT_COUNT,
+
+	/**
+	 * Within the result rows for the selected attribute the smallest value is
+	 * selected. Only for numerical values.
+	 */
+	MINIMUM,
+
+	/**
+	 * Within the result rows for the selected attribute the highest value is
+	 * selected. Only for numerical values.
+	 */
+	MAXIMUM,
+
+	/**
+	 * Over all result rows for the selected attribute the average value is
+	 * calculated. Only for numerical values.
+	 */
+	AVERAGE,
+
+	/**
+	 * Over all result rows for the selected attribute the standard deviation value
+	 * is calculated. Only for numerical values.
+	 */
+	DEVIATION,
+
+	/**
+	 * All result rows for the selected attribute are summed. Only for numerical
+	 * values.
+	 */
+	SUM,
+
+	/**
+	 * Within the result rows for the selected attribute all distinct values are
+	 * collected.
+	 */
+	DISTINCT
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BooleanOperator.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BooleanOperator.java
new file mode 100644
index 0000000..d92b9df
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BooleanOperator.java
@@ -0,0 +1,47 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * The operator enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Condition
+ * @see Filter
+ */
+public enum BooleanOperator {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Logical conjunction.
+	 */
+	AND,
+
+	/**
+	 * Logical disjunction.
+	 */
+	OR,
+
+	/**
+	 * Logical Negation.
+	 */
+	NOT
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BracketOperator.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BracketOperator.java
new file mode 100644
index 0000000..71070ca
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BracketOperator.java
@@ -0,0 +1,52 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * The bracket operator enumeration.
+ *
+ * @since 1.0.0
+ * @see Condition
+ * @see Filter
+ */
+
+public enum BracketOperator {
+	/**
+	 * Left parenthesis.
+	 */
+	OPEN,
+
+	/**
+	 * Right parenthesis.
+	 */
+	CLOSE;
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Enum#toString()
+	 */
+	@Override
+	public String toString() {
+		switch (this) {
+		case OPEN:
+			return "(";
+		case CLOSE:
+			return ")";
+		default:
+			return this.toString();
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/ComparisonOperator.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/ComparisonOperator.java
new file mode 100644
index 0000000..f21710b
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/ComparisonOperator.java
@@ -0,0 +1,197 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Arrays;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * The selection operations define query instructions like "equal", "greater",
+ * etc. Such operations are case sensitive. If an insensitive instruction is
+ * required, then its counterpart starting with the "CI_" prefix has to be used.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Condition
+ * @see Filter
+ */
+public enum ComparisonOperator {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Exact match
+	 */
+	EQUAL,
+
+	/**
+	 * Not equal (!=)
+	 */
+	NOT_EQUAL,
+
+	/**
+	 * Less than (&lt;)
+	 */
+	LESS_THAN,
+
+	/**
+	 * Less than equal (&lt;=)
+	 */
+	LESS_THAN_OR_EQUAL,
+
+	/**
+	 * Greater than (&gt;)
+	 */
+	GREATER_THAN,
+
+	/**
+	 * Greater than equal (&gt;=)
+	 */
+	GREATER_THAN_OR_EQUAL,
+
+	/**
+	 * In set, value can be a sequence.
+	 */
+	IN_SET,
+
+	/**
+	 * Not in set, value can be a sequence.
+	 */
+	NOT_IN_SET,
+
+	/**
+	 * like, use pattern matching, see Pattern for the wildcard definitions.
+	 */
+	LIKE,
+
+	/**
+	 * Not LIKE
+	 */
+	NOT_LIKE,
+
+	/**
+	 * Equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_EQUAL,
+
+	/**
+	 * Not equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_NOT_EQUAL,
+
+	/**
+	 * Less than. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_LESS_THAN,
+
+	/**
+	 * Less than equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_LESS_THAN_OR_EQUAL,
+
+	/**
+	 * Greater than. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_GREATER_THAN,
+
+	/**
+	 * Greater than equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_GREATER_THAN_OR_EQUAL,
+
+	/**
+	 * In set, value can be a sequence. case insensitive for
+	 * {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_IN_SET,
+
+	/**
+	 * Not in set, value can be a sequence. case insensitive for
+	 * {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_NOT_IN_SET,
+
+	/**
+	 * like, use pattern matching, see Pattern for the wildcard definitions. case
+	 * insensitive for DT_STRING.
+	 */
+	CASE_INSENSITIVE_LIKE,
+
+	/**
+	 * Not LIKE, case insensitive for DT_STRING.
+	 */
+	CASE_INSENSITIVE_NOT_LIKE,
+
+	/**
+	 * Value is NULL
+	 */
+	IS_NULL,
+
+	/**
+	 * Value is not NULL
+	 */
+	IS_NOT_NULL,
+
+	/**
+	 * Between; selects all instances where the value of 'attr' lies between the
+	 * first two values given in 'value' (with 'attr', 'value' being elements of the
+	 * SelValue structure; 'value' must be of data type S_*).
+	 */
+	BETWEEN;
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link Condition} for given {@link Attribute} and value.
+	 *
+	 * @param attribute The {@code Attribute} the condition will be applied to.
+	 * @param value     The value.
+	 * @return The created {@code Condition} is returned.
+	 */
+	public Condition create(Attribute attribute, Object value) {
+		return new Condition(attribute, this, "", value);
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Checks whether this operation requires a sequence value container. This is
+	 * the case for the following types:
+	 *
+	 * <ul>
+	 * <li>{@link ComparisonOperator#IN_SET}</li>
+	 * <li>{@link ComparisonOperator#NOT_IN_SET}</li>
+	 * <li>{@link ComparisonOperator#CASE_INSENSITIVE_IN_SET}</li>
+	 * <li>{@link ComparisonOperator#CASE_INSENSITIVE_NOT_IN_SET}</li>
+	 * <li>{@link ComparisonOperator#BETWEEN}</li>
+	 * </ul>
+	 *
+	 * @return True if this operation is one of those listed above.
+	 */
+	boolean requiresSequence() {
+		return Arrays.asList(IN_SET, NOT_IN_SET, CASE_INSENSITIVE_IN_SET, CASE_INSENSITIVE_NOT_IN_SET, BETWEEN)
+				.contains(this);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Condition.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Condition.java
new file mode 100644
index 0000000..7b6c4f2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Condition.java
@@ -0,0 +1,131 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Objects;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Describes a filter condition.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Attribute
+ * @see ComparisonOperator
+ */
+public final class Condition {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Attribute attribute;
+	private final Value value;
+	private final ComparisonOperator comparisonOperator;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param attribute          The {@link Attribute} this condition will be
+	 *                           applied to.
+	 * @param comparisonOperator The condition {@link ComparisonOperator}.
+	 * @param unit               The unit of the created value.
+	 * @param input              The condition value.
+	 */
+	Condition(Attribute attribute, ComparisonOperator comparisonOperator, String unit, Object input) {
+		this.attribute = attribute;
+		this.comparisonOperator = comparisonOperator;
+		value = comparisonOperator.requiresSequence() ? attribute.createValueSeq(unit, input)
+				: attribute.createValue(unit, input);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the target {@link Attribute}.
+	 *
+	 * @return The target {@code Attribute} is returned.
+	 */
+	public Attribute getAttribute() {
+		return attribute;
+	}
+
+	/**
+	 * Returns the condition {@link Value}.
+	 *
+	 * @return The condition {@code Value} is returned.
+	 */
+	public Value getValue() {
+		return value;
+	}
+
+	/**
+	 * Returns the condition {@link ComparisonOperator}.
+	 *
+	 * @return The condition {@code ComparisonOperator} is returned.
+	 */
+	public ComparisonOperator getComparisonOperator() {
+		return comparisonOperator;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof Condition)) {
+			return false;
+		}
+
+		Condition condition = (Condition) other;
+
+		return Objects.equals(this.attribute, condition.attribute) && Objects.equals(this.value, condition.value)
+				&& Objects.equals(this.comparisonOperator, condition.comparisonOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(attribute, value, comparisonOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return attribute.getEntityType().getName() + "." + attribute.getName() + " " + comparisonOperator + " " + value;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/DataAccessException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/DataAccessException.java
new file mode 100644
index 0000000..6848249
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/DataAccessException.java
@@ -0,0 +1,54 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * Thrown to indicate errors while querying data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class DataAccessException extends RuntimeException {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final long serialVersionUID = 5024184555274518451L;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The error message.
+	 */
+	public DataAccessException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message   The error message.
+	 * @param throwable The origin cause.
+	 */
+	public DataAccessException(String message, Throwable throwable) {
+		super(message, throwable);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Filter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Filter.java
new file mode 100644
index 0000000..010bc86
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Filter.java
@@ -0,0 +1,513 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.SearchService;
+
+/**
+ * A filter is a sequence of {@link FilterItem}s containing
+ * {@link BooleanOperator}s or {@link Condition}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Query
+ * @see SearchQuery
+ * @see SearchService
+ */
+public final class Filter implements Iterable<FilterItem> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Deque<FilterItem> filterItems = new ArrayDeque<>();
+	private final FilterItem operatorItem;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param operatorItem Will be added between {@link Condition}s or merged
+	 *                     filters.
+	 */
+	private Filter(FilterItem operatorItem) {
+		this.operatorItem = operatorItem;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new filter with an instance ID condition for given
+	 * {@link EntityType} and instance ID.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param id         The instance ID.
+	 * @return The created filter is returned.
+	 * @see #id(EntityType, String)
+	 */
+	public static Filter idOnly(EntityType entityType, String id) {
+		return and().id(entityType, id);
+	}
+
+	/**
+	 * Creates a new filter with an foreign ID condition for given {@link Relation}
+	 * and instance ID.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param id       The instance ID.
+	 * @return The created filter is returned.
+	 * @see #id(Relation, String)
+	 */
+	public static Filter idOnly(Relation relation, String id) {
+		return and().id(relation, id);
+	}
+
+	/**
+	 * Creates a new filter with an instance IDs condition for given
+	 * {@link EntityType} and instance IDs.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param ids        The instance IDs.
+	 * @return The created filter is returned.
+	 * @see #ids(EntityType, Collection)
+	 */
+	public static Filter idsOnly(EntityType entityType, Collection<String> ids) {
+		return and().ids(entityType, ids);
+	}
+
+	/**
+	 * Creates a new filter with an foreign IDs condition for given {@link Relation}
+	 * and instance IDs.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param ids      The instance IDs.
+	 * @return The created filter is returned.
+	 * @see #ids(Relation, Collection)
+	 */
+	public static Filter idsOnly(Relation relation, Collection<String> ids) {
+		return and().ids(relation, ids);
+	}
+
+	/**
+	 * Creates a new filter with an instance name condition for given
+	 * {@link EntityType} and instance name pattern.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param pattern    Is always case sensitive and may contain wildcard
+	 *                   characters as follows: "?" for one matching character and
+	 *                   "*" for a sequence of matching characters.
+	 * @return The created filter is returned.
+	 * @see #name(EntityType, String)
+	 */
+	public static Filter nameOnly(EntityType entityType, String pattern) {
+		return and().name(entityType, pattern);
+	}
+
+	/**
+	 * Creates a new instance of this class that implicitly adds
+	 * {@link BooleanOperator#AND} {@code FilterItem}s between {@link Condition}s or
+	 * merged filters.
+	 *
+	 * <pre>
+	 * Filter filter = Filter.and();
+	 * filter.add(conditionA); // conditionA
+	 * filter.add(conditionB); // conditionA AND conditionB
+	 * filter.invert(); // !(conditionA AND conditionB)
+	 * filter.merge(otherFilter); // !(conditionA AND conditionB) AND
+	 * 							// (otherFilter)
+	 * </pre>
+	 *
+	 * @return A newly created filter is returned.
+	 */
+	public static Filter and() {
+		return new Filter(FilterItem.AND);
+	}
+
+	/**
+	 * Creates a new instance of this class that implicitly adds
+	 * {@link BooleanOperator#OR} {@code FilterItem}s between {@link Condition}s or
+	 * merged filters.
+	 *
+	 * <pre>
+	 * Filter filter = Filter.or();
+	 * filter.add(conditionA); // conditionA
+	 * filter.add(conditionB); // conditionA OR conditionB
+	 * filter.invert(); // !(conditionA OR conditionB)
+	 * filter.merge(otherFilter); // !(conditionA OR conditionB) OR otherFilter
+	 * </pre>
+	 *
+	 * @return A newly created filter is returned.
+	 */
+	public static Filter or() {
+		return new Filter(FilterItem.OR);
+	}
+
+	/**
+	 * Adds all {@link Condition}s to this filter.
+	 *
+	 * @param conditions The {@link Condition}s that will be added.
+	 * @return Returns this filter.
+	 * @see Filter#add(Condition)
+	 */
+	public Filter addAll(List<Condition> conditions) {
+		conditions.forEach(this::add);
+		return this;
+	}
+
+	/**
+	 * Adds all {@link Condition}s to this filter.
+	 *
+	 * @param conditions The {@link Condition}s that will be added.
+	 * @return Returns this filter.
+	 * @see Filter#add(Condition)
+	 */
+	public Filter addAll(Condition... conditions) {
+		Arrays.stream(conditions).forEach(this::add);
+		return this;
+	}
+
+	/**
+	 * Adds a new instance ID condition ({@link ComparisonOperator#EQUAL}) for given
+	 * {@link EntityType} and instance ID to this filter.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param id         The instance ID.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter id(EntityType entityType, String id) {
+		add(ComparisonOperator.EQUAL.create(entityType.getIDAttribute(), id));
+		return this;
+	}
+
+	/**
+	 * Adds a new foreign ID condition ({@link ComparisonOperator#EQUAL}) for given
+	 * {@link Relation} and instance ID to this filter.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param id       The instance ID.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter id(Relation relation, String id) {
+		add(ComparisonOperator.EQUAL.create(relation.getAttribute(), id));
+		return this;
+	}
+
+	/**
+	 * Adds a new instance IDs condition ({@link ComparisonOperator#IN_SET}) for
+	 * given {@link EntityType} and instance IDs to this filter.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param ids        The instance IDs.
+	 * @return Returns this filter
+	 * @see #add(Condition)
+	 */
+	public Filter ids(EntityType entityType, Collection<String> ids) {
+		add(ComparisonOperator.IN_SET.create(entityType.getIDAttribute(),
+				ids.stream().distinct().toArray(String[]::new)));
+		return this;
+	}
+
+	/**
+	 * Adds a new foreign IDs condition ({@link ComparisonOperator#IN_SET}) for
+	 * given {@link Relation} and instance IDs to this filter.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param ids      The instance IDs.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter ids(Relation relation, Collection<String> ids) {
+		add(ComparisonOperator.IN_SET.create(relation.getAttribute(), ids.stream().distinct().toArray(String[]::new)));
+		return this;
+	}
+
+	/**
+	 * Adds a instance name condition ({@link ComparisonOperator#LIKE}) for given
+	 * {@link EntityType} and instance name pattern.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> If the given pattern equals "*", then no {@link Condition} will
+	 * be added since "*" means take all.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param pattern    Is always case sensitive and may contain wildcard
+	 *                   characters as follows: "?" for one matching character and
+	 *                   "*" for a sequence of matching characters.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter name(EntityType entityType, String pattern) {
+		if (!"*".equals(pattern)) {
+			add(ComparisonOperator.LIKE.create(entityType.getNameAttribute(), pattern));
+		}
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Condition} to this filter's {@link FilterItem} sequence.
+	 *
+	 * @param condition {@code Condition} that will be added.
+	 * @return Returns this filter.
+	 */
+	public Filter add(Condition condition) {
+		insertOperator();
+		filterItems.addLast(new FilterItem(condition));
+		return this;
+	}
+
+	/**
+	 * Merges all given filters with this filter.
+	 *
+	 * @param filters Filters that will be merged.
+	 * @return Returns this filter.
+	 * @see #merge(Filter)
+	 */
+	public Filter merge(List<Filter> filters) {
+		filters.stream().forEach(this::merge);
+		return this;
+	}
+
+	/**
+	 * Merges all given filters with this filter.
+	 *
+	 * @param filters Filters that will be merged.
+	 * @return Returns this filter.
+	 * @see #merge(Filter)
+	 */
+	public Filter merge(Filter... filters) {
+		Arrays.stream(filters).forEach(this::merge);
+		return this;
+	}
+
+	/**
+	 * The {@link FilterItem}s of the given filter are added to this filter. If
+	 * required, then parenthesis are implicitly added as shown in the example
+	 * below:
+	 *
+	 * <pre>
+	 * Filter filter1 = Filter.and();
+	 * Condition a = ...;
+	 * Condition b = ...;
+	 * filter1.addAll(a, b); // a AND b
+	 *
+	 * Filter filter2 = Filter.or();
+	 * Condition c = ...;
+	 * Condition d = ...;
+	 * Condition e = ...;
+	 * filter2.addAll(c, d, e); // c OR d OR e
+	 *
+	 * Filter filter = Filter.or();
+	 * filter.merge(filter1, filter2); // (filter1) OR filter2
+	 * </pre>
+	 *
+	 * @param filter Filter that will be merged.
+	 * @return Returns this filter.
+	 */
+	public Filter merge(Filter filter) {
+		boolean addBrackets = filter.hasMultiple() && operatorItem != filter.operatorItem && !filter.isInverted();
+		insertOperator();
+
+		if (addBrackets) {
+			filterItems.addLast(FilterItem.OPEN);
+		}
+
+		filter.filterItems.stream().forEach(filterItems::addLast);
+
+		if (addBrackets) {
+			filterItems.addLast(FilterItem.CLOSE);
+		}
+
+		return this;
+	}
+
+	/**
+	 * Inverts this filter by prepending the {@link BooleanOperator#NOT} to the
+	 * {@link FilterItem} sequence as shown in the following examples:
+	 *
+	 * <pre>
+	 * // inverting an AND filter
+	 * Filter andFilter = Filter.and();
+	 * Condition a = ...;      // any condition
+	 * Condition b = ...;      // another condition
+	 * andFilter.addAll(a, b); // a AND b
+	 * andFilter.invert();     // !(a AND b)
+	 *
+	 * // inverting an OR filter
+	 * Filter orFilter = Filter.or();
+	 * Condition a = ...;     // any condition
+	 * Condition b = ...;     // another condition
+	 * orFilter.addAll(a, b); // a OR b
+	 * orFilter.invert();     // !(a OR b)
+	 * orFilter.invert();     // IllegalStateException -&gt; filter is already inverted!
+	 * </pre>
+	 *
+	 * @return Returns this filter.
+	 * @throws IllegalStateException Thrown either if the current set of conditions
+	 *                               is empty or this filter is already inverted.
+	 */
+	public Filter invert() {
+		if (filterItems.isEmpty()) {
+			throw new IllegalStateException("Current set of conditions is empty.");
+		}
+
+		if (isInverted()) {
+			throw new IllegalStateException("Current set of conditions is already inverted.");
+		} else if (hasMultiple()) {
+			filterItems.addFirst(FilterItem.OPEN);
+			filterItems.addLast(FilterItem.CLOSE);
+		}
+
+		filterItems.addFirst(FilterItem.NOT);
+		return this;
+	}
+
+	/**
+	 * Checks whether this filter has no conditions at all.
+	 *
+	 * @return Returns {@code false} if at least one {@link Condition} is contained.
+	 */
+	public boolean isEmtpty() {
+		return filterItems.isEmpty();
+	}
+
+	/**
+	 * Returns a sequential stream with the internally stored {@link FilterItem}s as
+	 * its source.
+	 *
+	 * @return A stream over the contained {@code FilterItem}s is returned.
+	 */
+	public Stream<FilterItem> stream() {
+		return filterItems.stream();
+	}
+
+	/**
+	 * Returns an iterator over the {@link FilterItem}s contained in this filter in
+	 * proper sequence.
+	 *
+	 * @return The returned iterator does not support the {@link Iterator#remove()}
+	 *         operation.
+	 */
+	@Override
+	public Iterator<FilterItem> iterator() {
+		Iterator<FilterItem> internal = filterItems.iterator();
+		return new Iterator<FilterItem>() {
+
+			@Override
+			public boolean hasNext() {
+				return internal.hasNext();
+			}
+
+			@Override
+			public FilterItem next() {
+				return internal.next();
+			}
+		};
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * If required the {@link #operatorItem} is added to the end (tail) of the
+	 * {@link FilterItem} sequence.
+	 */
+	private void insertOperator() {
+		if (!filterItems.isEmpty()) {
+			filterItems.addLast(operatorItem);
+		}
+	}
+
+	/**
+	 * Determines whether the {@link FilterItem} sequence starts with the
+	 * {@link BooleanOperator#NOT}.
+	 *
+	 * @return True if this filter is inverted.
+	 */
+	private boolean isInverted() {
+		return !filterItems.isEmpty() && FilterItem.NOT == filterItems.getFirst();
+	}
+
+	/**
+	 * Determines whether multiple {@link FilterItem}s are contained.
+	 *
+	 * @return True if multiple {@code FilterItem}s are contained.
+	 */
+	private boolean hasMultiple() {
+		return filterItems.size() > 1;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof Filter)) {
+			return false;
+		}
+
+		Filter filter = (Filter) other;
+
+		// Deque does not implement equals
+		return Arrays.equals(this.filterItems.toArray(new FilterItem[0]), filter.filterItems.toArray(new FilterItem[0]))
+				&& Objects.equals(this.operatorItem, filter.operatorItem);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(filterItems, operatorItem);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return this.stream().map(i -> Objects.toString(i)).collect(Collectors.joining(""));
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/FilterItem.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/FilterItem.java
new file mode 100644
index 0000000..a295626
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/FilterItem.java
@@ -0,0 +1,224 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Objects;
+
+/**
+ * Filter item contains either a {@link Condition} or an
+ * {@link BooleanOperator}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class FilterItem {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * Contains the {@link BooleanOperator#AND}.
+	 */
+	static final FilterItem AND = new FilterItem(BooleanOperator.AND);
+
+	/**
+	 * Contains the {@link BooleanOperator#OR}.
+	 */
+	static final FilterItem OR = new FilterItem(BooleanOperator.OR);
+
+	/**
+	 * Contains the {@link BooleanOperator#NOT}.
+	 */
+	static final FilterItem NOT = new FilterItem(BooleanOperator.NOT);
+
+	/**
+	 * Contains the {@link BooleanOperator#OPEN}.
+	 */
+	static final FilterItem OPEN = new FilterItem(BracketOperator.OPEN);
+
+	/**
+	 * Contains the {@link BooleanOperator#CLOSE}.
+	 */
+	static final FilterItem CLOSE = new FilterItem(BracketOperator.CLOSE);
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Condition condition;
+	private final BooleanOperator booleanOperator;
+	private final BracketOperator bracketOperator;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param condition The {@link Condition}.
+	 */
+	FilterItem(Condition condition) {
+		this.condition = condition;
+		this.bracketOperator = null;
+		this.booleanOperator = null;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param booleanOperator The {@link BooleanOperator}.
+	 */
+	private FilterItem(BooleanOperator booleanOperator) {
+		this.condition = null;
+		this.bracketOperator = null;
+		this.booleanOperator = booleanOperator;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param bracketoperator The {@link BracketOperator}.
+	 */
+	private FilterItem(BracketOperator bracketoperator) {
+		this.condition = null;
+		this.booleanOperator = null;
+		this.bracketOperator = bracketoperator;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Checks whether an {@link BooleanOperator} is contained.
+	 *
+	 * @return True if an {@code BooleanOperator} is contained.
+	 */
+	public boolean isBooleanOperator() {
+		return booleanOperator != null;
+	}
+
+	/**
+	 * Returns the contained {@link BooleanOperator}.
+	 *
+	 * @return The {@code BooleanOperator} is returned.
+	 * @throws IllegalStateException Thrown if {@code BooleanOperator} is not
+	 *                               contained.
+	 */
+	public BooleanOperator getBooleanOperator() {
+		if (isBooleanOperator()) {
+			return booleanOperator;
+		}
+
+		throw new IllegalStateException("Item does not contain an booleanOperator.");
+	}
+
+	/**
+	 * Checks whether an {@link Condition} is contained.
+	 *
+	 * @return True if an {@code Condition} is contained.
+	 */
+	public boolean isCondition() {
+		return condition != null;
+	}
+
+	/**
+	 * Returns the contained {@link Condition}.
+	 *
+	 * @return The {@code Condition} is returned.
+	 * @throws IllegalStateException Thrown if {@code Condition} is not contained.
+	 */
+	public Condition getCondition() {
+		if (isCondition()) {
+			return condition;
+		}
+
+		throw new IllegalStateException("Item does not contain a condition.");
+	}
+
+	/**
+	 * Checks whether an {@link BrackerOperator} is contained.
+	 *
+	 * @return True if an {@code BracketOperator} is contained.
+	 */
+	public boolean isBracketOperator() {
+		return bracketOperator != null;
+	}
+
+	/**
+	 * Returns the contained {@link Condition}.
+	 *
+	 * @return The {@code Condition} is returned.
+	 * @throws IllegalStateException Thrown if {@code Condition} is not contained.
+	 */
+	public BracketOperator getBracketOperator() {
+		if (isBracketOperator()) {
+			return bracketOperator;
+		}
+
+		throw new IllegalStateException("Item does not contain a condition.");
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof FilterItem)) {
+			return false;
+		}
+
+		FilterItem filterItem = (FilterItem) other;
+
+		return Objects.equals(this.condition, filterItem.condition)
+				&& Objects.equals(this.booleanOperator, filterItem.booleanOperator)
+				&& Objects.equals(this.bracketOperator, filterItem.bracketOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(condition, booleanOperator, bracketOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		if (isBooleanOperator()) {
+			return " " + booleanOperator.toString() + " ";
+		} else if (isBracketOperator()) {
+			return bracketOperator.toString();
+		} else {
+			return condition.toString();
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/JoinType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/JoinType.java
new file mode 100644
index 0000000..da92cdd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/JoinType.java
@@ -0,0 +1,41 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * JoinType enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Query
+ */
+public enum JoinType {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Enforces an inner join.
+	 */
+	INNER,
+
+	/**
+	 * Enforces an outer join.
+	 */
+	OUTER
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Query.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Query.java
new file mode 100644
index 0000000..058a363
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Query.java
@@ -0,0 +1,351 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+
+/**
+ * Provides methods to easily build queries by adding select, join, group by and
+ * order by statements. Finally an optional {@link Filter} may be given to
+ * select data that match specified criteria.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Attribute
+ * @see Aggregation
+ * @see Relation
+ * @see JoinType
+ * @see Result
+ */
+public interface Query {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Checks whether given {@link EntityType} will be queried in any way (select or
+	 * join).
+	 *
+	 * @param entityType The checked {@code EntityType}.
+	 * @return True if given {@code EntityType} will be queried.
+	 */
+	boolean isQueried(EntityType entityType);
+
+	/**
+	 * Adds select statements for all {@link Attribute}s of each given
+	 * {@link EntityType}.
+	 *
+	 * @param entityTypes The {@code Attribute}s of each {@code EntityType} will be
+	 *                    passed to {@link #select(List)}.
+	 * @return This query is returned.
+	 */
+	default Query selectAll(List<EntityType> entityTypes) {
+		entityTypes.stream().map(EntityType::getAttributes).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds select statements for all {@link Attribute}s of each given
+	 * {@link EntityType}.
+	 *
+	 * @param entityTypes The {@code Attribute}s of each {@code EntityType} will be
+	 *                    passed to {@link #select(List)}.
+	 * @return This query is returned.
+	 */
+	default Query selectAll(EntityType... entityTypes) {
+		Arrays.stream(entityTypes).map(EntityType::getAttributes).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds select statements for all {@link Attribute}s identified by given names
+	 * at given {@link EntityType}.
+	 *
+	 * @param entityType The {@code EntityType} whose {@code Attribute}s will be
+	 *                   passed to {@link #select(Attribute)}.
+	 * @param names      The names of the {@code Attribute}s that have to be added.
+	 * @return This query is returned.
+	 * @see EntityType#getAttribute(String)
+	 */
+	default Query select(EntityType entityType, String... names) {
+		Arrays.stream(names).map(entityType::getAttribute).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for the ID {@link Attribute} of each given
+	 * {@link EntityType}.
+	 *
+	 * @param entityTypes The {@code EntityType}s whose ID {@code Attribute}s will
+	 *                    be passed to {@link #select(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query selectID(EntityType... entityTypes) {
+		Arrays.stream(entityTypes).map(EntityType::getIDAttribute).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #select(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query select(List<Attribute> attributes) {
+		attributes.forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #select(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query select(Attribute... attributes) {
+		Arrays.stream(attributes).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for given {@link Attribute}.
+	 *
+	 * @param attribute {@code Attribute} will be passed to
+	 *                  {@link #select(Attribute, Aggregation)} with
+	 *                  {@link Aggregation#NONE}.
+	 * @return This query is returned.
+	 */
+	default Query select(Attribute attribute) {
+		return select(attribute, Aggregation.NONE);
+	}
+
+	/**
+	 * Adds a select statement for given {@link Attribute} with given
+	 * {@link Aggregation} function.
+	 *
+	 * @param attribute   The {@code Attribute} a select statement will be added
+	 *                    for.
+	 * @param aggregation The {@code Aggregation} that will be applied.
+	 * @return This query is returned.
+	 */
+	Query select(Attribute attribute, Aggregation aggregation);
+
+	/**
+	 * For all unambiguous {@link Relation}s from the source {@link EntityType} to
+	 * each given target {@code EntityType} a join statement will be added.
+	 *
+	 * @param source  The source {@code EntityType}.
+	 * @param targets The unambiguous {@code Relation} for each target {@code
+	 * 		EntityType} is retrieved from the source {@code EntityType} using
+	 *                {@link EntityType#getRelation(EntityType)} and passed to
+	 *                {@link #join(Relation)}.
+	 * @return This query is returned.
+	 */
+	default Query join(EntityType source, EntityType... targets) {
+		Arrays.stream(targets).map(source::getRelation).forEach(this::join);
+		return this;
+	}
+
+	/**
+	 * Adds a join statement for each given {@link Relation}s.
+	 *
+	 * @param relations Each {@code Relation} will be passed to
+	 *                  {@link #join(Relation)}.
+	 * @return This query is returned.
+	 */
+	default Query join(List<Relation> relations) {
+		relations.forEach(this::join);
+		return this;
+	}
+
+	/**
+	 * Adds a join statement for each given {@link Relation}s.
+	 *
+	 * @param relations Each {@code Relation} will be passed to
+	 *                  {@link #join(Relation)}.
+	 * @return This query is returned.
+	 */
+	default Query join(Relation... relations) {
+		Arrays.stream(relations).forEach(this::join);
+		return this;
+	}
+
+	/**
+	 * Adds a join statement for given {@link Relation}.
+	 *
+	 * @param relation {@code Relation} will be passed to
+	 *                 {@link #join(Relation, JoinType)} with
+	 *                 {@link JoinType#INNER}.
+	 * @return This query is returned.
+	 */
+	default Query join(Relation relation) {
+		return join(relation, JoinType.INNER);
+	}
+
+	/**
+	 * Adds a join statement for given {@link Relation} with given {@link JoinType}
+	 * type.
+	 *
+	 * @param relation The {@code Relation} a join statement will be added for.
+	 * @param join     The {@code JoinType} type that will be applied.
+	 * @return This query is returned.
+	 */
+	Query join(Relation relation, JoinType join);
+
+	/**
+	 * Adds a group by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #group(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query group(List<Attribute> attributes) {
+		attributes.forEach(this::group);
+		return this;
+	}
+
+	/**
+	 * Adds a group by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #group(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query group(Attribute... attributes) {
+		Arrays.stream(attributes).forEach(this::group);
+		return this;
+	}
+
+	/**
+	 * Adds a group by statement for given {@link Attribute}.
+	 *
+	 * @param attribute The {@code Attribute} a group by statement will be added
+	 *                  for.
+	 * @return This query is returned.
+	 */
+	Query group(Attribute attribute);
+
+	/**
+	 * Adds an order by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #order(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query order(List<Attribute> attributes) {
+		attributes.forEach(this::order);
+		return this;
+	}
+
+	/**
+	 * Adds an order by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #order(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query order(Attribute... attributes) {
+		Arrays.stream(attributes).forEach(this::order);
+		return this;
+	}
+
+	/**
+	 * Adds an order by statement for given {@link Attribute}.
+	 *
+	 * @param attribute The {@code Attribute} is passed to
+	 *                  {@link #order(Attribute, boolean)} with
+	 *                  {@code ascending = true}.
+	 * @return This query is returned.
+	 */
+	default Query order(Attribute attribute) {
+		return order(attribute, true);
+	}
+
+	/**
+	 * Adds an order by statement for given {@link Attribute} with given ascending
+	 * flag.
+	 *
+	 * @param attribute The {@code Attribute} an order by statement will be added
+	 *                  for.
+	 * @param ascending The ascending flag that will be applied.
+	 * @return This query is returned.
+	 */
+	Query order(Attribute attribute, boolean ascending);
+
+	/**
+	 * Sets the maximum number of rows fetched by the query. 0 denotes no limit.
+	 *
+	 * @param limit number of maximum rows.
+	 * @return This query is returned.
+	 */
+	Query limit(int limit);
+
+	/**
+	 * Executes this query with an empty {@link Filter} and returns the
+	 * {@link Result}.
+	 *
+	 * @return {@code Optional} is empty if {@code Result} could not be found.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}.
+	 */
+	default Optional<Result> fetchSingleton() throws DataAccessException {
+		return fetchSingleton(Filter.and());
+	}
+
+	/**
+	 * Executes this query with given {@link Filter} and returns the {@link Result}.
+	 *
+	 * @param filter The criteria sequence.
+	 * @return {@code Optional} is empty if {@code Result} could not be found.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}.
+	 */
+	Optional<Result> fetchSingleton(Filter filter) throws DataAccessException;
+
+	/**
+	 * Executes this query with an empty {@link Filter} and returns the
+	 * {@link Result}s.
+	 *
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 */
+	default List<Result> fetch() throws DataAccessException {
+		return fetch(Filter.and());
+	}
+
+	/**
+	 * Executes this query with given {@link Filter} and returns the
+	 * {@link Result}s.
+	 *
+	 * @param filter The criteria sequence.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 */
+	List<Result> fetch(Filter filter) throws DataAccessException;
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/QueryService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/QueryService.java
new file mode 100644
index 0000000..7d2ee5e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/QueryService.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * The {@link QueryService} provides access to the low level query API.
+ * 
+ * A {@link Query}, created by this service, can be used to build and execute
+ * queries on the underlying datastore. The results are returned as a list of
+ * {@link Result}s.
+ *
+ * @since 1.0.0
+ */
+public interface QueryService {
+
+	/**
+	 * Creates a new and empty {@link Query}.
+	 *
+	 * @return Created {@code Query} is returned.
+	 */
+	Query createQuery();
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Record.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Record.java
new file mode 100644
index 0000000..0177dc6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Record.java
@@ -0,0 +1,181 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * A record corresponds to an instance of the underlying {@link EntityType}. It
+ * contains a subset of its {@link Value}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Attribute
+ */
+public final class Record {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<String, Value> values = new HashMap<>();
+	private final EntityType entityType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param entityType The {@link EntityType} this record is associated with.
+	 */
+	public Record(EntityType entityType) {
+		this.entityType = entityType;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the associated {@link EntityType}.
+	 *
+	 * @return The associated {@code EntityType} is returned.
+	 */
+	public EntityType getEntityType() {
+		return entityType;
+	}
+
+	/**
+	 * Returns all contained {@link Value}s mapped by their names.
+	 *
+	 * @return Available {@code Value}s in a mutable {@code Map} are returned.
+	 */
+	public Map<String, Value> getValues() {
+		return values;
+	}
+
+	/**
+	 * Returns the record ID, which is the ID of the instance, represented by this
+	 * record.
+	 *
+	 * @return Returns the ID of this record.
+	 * @throws IllegalStateException Thrown if the ID {@code Value} container is not
+	 *                               available.
+	 */
+	public String getID() {
+		Value idValue = getValues().get(getEntityType().getIDAttribute().getName());
+		if (idValue == null) {
+			throw new IllegalStateException("ID attribute was not selected.");
+		}
+
+		return idValue.extract();
+	}
+
+	/**
+	 * Returns the instance ID of the related entity referenced by the given
+	 * {@link Relation}.
+	 *
+	 * @param relation The foreign key {@code Relation}.
+	 * @return {@code Optional} is empty if there is no related entity.
+	 * @throws IllegalStateException Thrown if the requested foreign key was not
+	 *                               selected prior executing the query.
+	 */
+	public Optional<String> getID(Relation relation) {
+		Value idValue = getValues().get(relation.getName());
+		if (idValue == null) {
+			throw new IllegalStateException("Relation attribute '" + relation + "' was not selected.");
+		}
+
+		return Optional.ofNullable(idValue.isValid() ? idValue.extract() : null);
+	}
+
+	/**
+	 * Adds given {@link Value} to this record.
+	 *
+	 * @param value {@link Value} that will be added.
+	 * @throws IllegalArgumentException Thrown if given {@code Value} overwrites an
+	 *                                  existing one.
+	 */
+	public void addValue(Value value) {
+		if (values.put(value.getName(), value) != null) {
+			throw new IllegalArgumentException("Value with name '" + value.getName() + "' for entity type '"
+					+ entityType + "' record is already defined.");
+		}
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this record.
+	 *
+	 * @return The {@code String} representation of this record.
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("Record(EntityType = ").append(getEntityType());
+		return sb.append(", Values = ").append(getValues().values()).append(')').toString();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Merges given record with this instance. To be able to do so, the given record
+	 * must be compatible with this record. Records are compatible if the underlying
+	 * {@link EntityType} and the subset of {@link Value}s is the same.
+	 *
+	 * @param record The record that will be merged with this instance.
+	 * @return A new record with merged {@code Value}s is returned.
+	 * @throws IllegalArgumentException Thrown if given record is not compatible.
+	 */
+	Record merge(Record record) {
+		boolean entityTypeMissmatch = !getEntityType().equals(record.getEntityType());
+		boolean valuesMissmatch = getValues().size() != record.getValues().size();
+		if (entityTypeMissmatch || valuesMissmatch) {
+			throw new IllegalArgumentException("Unable to merge, incompatible record passed.");
+		}
+
+		Record mergedRecord = new Record(getEntityType());
+		getValues().keySet().stream().forEach(n -> mergedRecord.addValue(getValue(n).merge(record.getValue(n))));
+		return mergedRecord;
+	}
+
+	/**
+	 * Returns {@link Value} with given name.
+	 *
+	 * @param name Used as identifier.
+	 * @return {@code Value} with given name is returned.
+	 * @throws IllegalArgumentException Thrown if value with given name is not
+	 *                                  contained.
+	 */
+	Value getValue(String name) {
+		Value value = getValues().get(name);
+		if (value == null) {
+			throw new IllegalArgumentException("Value with name '" + name + "' not found.");
+		}
+
+		return value;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Result.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Result.java
new file mode 100644
index 0000000..8fb3e11
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Result.java
@@ -0,0 +1,168 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * A result consists of one or more {@link Record}s, which is mapped from an
+ * {@link EntityType}
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class Result implements Iterable<Record> {
+
+	private final Map<EntityType, Record> records = new HashMap<>();
+
+	/**
+	 * Adds given {@link Record} to this result.
+	 *
+	 * @param record {@code Record} that will be added.
+	 * @throws IllegalArgumentException Thrown if given {@code Record} overwrites an
+	 *                                  existing one.
+	 */
+	public void addRecord(Record record) {
+		if (records.put(record.getEntityType(), record) != null) {
+			throw new IllegalArgumentException(
+					"Record for entity type '" + record.getEntityType() + "' is already defined.");
+		}
+	}
+
+	/**
+	 * Returns the {@link Record} associated with given {@link EntityType}.
+	 *
+	 * @param entityType Used as identifier.
+	 * @return The {@code Record} associated with given {@code EntityType} is
+	 *         returned.
+	 * @throws IllegalArgumentException Thrown if associated {@code Record} does not
+	 *                                  exist.
+	 */
+	public Record getRecord(EntityType entityType) {
+		Record record = records.get(entityType);
+		if (record == null) {
+			throw new IllegalArgumentException("Record for entity type '" + entityType + "' is not available.");
+		}
+
+		return record;
+	}
+
+	/**
+	 * Removes the {@link Record} associated with given {@link EntityType} from this
+	 * result and returns it.
+	 *
+	 * @param entityType Used as identifier.
+	 * @return The removed {@code Record} associated with given {@code EntityType}
+	 *         is returned.
+	 * @throws IllegalArgumentException Thrown if associated {@code Record} does not
+	 *                                  exists.
+	 */
+	public Record removeRecord(EntityType entityType) {
+		Record record = records.remove(entityType);
+		if (record == null) {
+			throw new IllegalArgumentException("Record for entity type '" + entityType + "' is not available.");
+		}
+
+		return record;
+	}
+
+	/**
+	 * Returns the {@link Value} container associated with given {@link Attribute}
+	 * and no aggregation.
+	 *
+	 * @param attribute Used as identifier to find the associated {@code Value}.
+	 * @return Associated {@code Value} is returned.
+	 */
+	public Value getValue(Attribute attribute) {
+		return getValue(attribute, Aggregation.NONE);
+	}
+
+	/**
+	 * Returns the {@link Value} container associated with given {@link Attribute}
+	 * and {@link Aggregation}.
+	 *
+	 * @param attribute   Used as identifier to find the associated {@code Value}.
+	 * @param aggregation {@link Aggregation} used with the attribute.
+	 * @return Associated {@code Value} is returned.
+	 */
+	public Value getValue(Attribute attribute, Aggregation aggregation) {
+		String key;
+		if (Aggregation.NONE == aggregation) {
+			key = attribute.getName();
+		} else {
+			key = String.format("%s(%s)", aggregation.name(), attribute.getName());
+		}
+
+		return getRecord(attribute.getEntityType()).getValue(key);
+	}
+
+	/**
+	 * Merges given result with this instance. To be able to do so, the given result
+	 * must be compatible with this result. Results are compatible if the subset of
+	 * {@link Record}s is the same.
+	 *
+	 * @param result The result that will be merged with this instance.
+	 * @return A new result with merged {@code Record}s is returned.
+	 * @throws IllegalArgumentException Thrown if given result is not compatible.
+	 */
+	public Result merge(Result result) {
+		if (records.size() != result.records.size()) {
+			throw new IllegalArgumentException("Unable to merge, incompatible result passed.");
+		}
+
+		Result mergedResult = new Result();
+		records.keySet().stream().forEach(e -> mergedResult.addRecord(getRecord(e).merge(result.getRecord(e))));
+		return mergedResult;
+	}
+
+	/**
+	 * Returns a sequential stream with this result as its source.
+	 *
+	 * @return A sequential stream with records of this result.
+	 */
+	public Stream<Record> stream() {
+		return StreamSupport.stream(spliterator(), false);
+	}
+
+	/**
+	 * Returns an iterator over the {@link Record}s contained in this result.
+	 *
+	 * @return The iterator over the contained {@code Record}s is returned.
+	 */
+	@Override
+	public Iterator<Record> iterator() {
+		return records.values().iterator();
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this result.
+	 *
+	 * @return The {@code String} representation of this result.
+	 */
+	@Override
+	public String toString() {
+		return new StringBuilder("Result(Records = ").append(records.values()).append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchQuery.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchQuery.java
new file mode 100644
index 0000000..0a8b036
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchQuery.java
@@ -0,0 +1,171 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.search;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Result;
+
+/**
+ * This is an interface for predefined search query implementations.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Searchable
+ * @see Attribute
+ * @see Value
+ * @see Filter
+ * @see Result
+ */
+public interface SearchQuery {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns all {@link EntityType}s supported by this search query.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<EntityType> listEntityTypes();
+
+	/**
+	 * Returns the {@link Searchable}, which describes a hierarchical order of the
+	 * {@link EntityType}s supported by this search query.
+	 *
+	 * @return The {@code Searchable} root is returned.
+	 */
+	Searchable getSearchableRoot();
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute}. The
+	 * {@code Attribute} must be supported by this search query. The returned
+	 * {@code Value} sequence is intended to be used for building filter criteria
+	 * for this search query.
+	 *
+	 * @param attribute The {@code Attribute} whose distinct values will be queried.
+	 * @return A distinct {@code List} of all available {@code Value}s is returned.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the distinct {@code Value}
+	 *                             sequence.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #getFilterValues(Attribute, Filter)
+	 */
+	default List<Value> getFilterValues(Attribute attribute) throws DataAccessException {
+		return getFilterValues(attribute, Filter.and());
+	}
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute} and
+	 * {@link Filter}. Both must be fully supported by this search query. The
+	 * returned {@code Value} sequence is intended to be used for building filter
+	 * criteria for this search query.
+	 *
+	 * @param attribute The {@code Attribute} whose distinct values will be queried.
+	 * @param filter    The criteria sequence.
+	 * @return A distinct {@code List} of {@code Value}s is returned.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the distinct {@code Value}
+	 *                             sequence.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #getFilterValues(Attribute)
+	 */
+	List<Value> getFilterValues(Attribute attribute, Filter filter) throws DataAccessException;
+
+	/**
+	 * Executes this search query with given {@link EntityType}s. The {@code
+	 * EntityType}s must be fully supported by this search query. This method
+	 * selects all {@link Attribute}s of each given {@code EntityType}.
+	 *
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetchComplete(List, Filter)
+	 * @see #fetch(List)
+	 */
+	default List<Result> fetchComplete(List<EntityType> entityTypes) throws DataAccessException {
+		return fetchComplete(entityTypes, Filter.and());
+	}
+
+	/**
+	 * Executes this search query with given {@link EntityType}s and {@link Filter}.
+	 * Both must be fully supported by this search query. This method selects all
+	 * {@link Attribute}s of each given {@code EntityType}.
+	 *
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @param filter      The criteria sequence.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetchComplete(List)
+	 * @see #fetch(List, Filter)
+	 */
+	List<Result> fetchComplete(List<EntityType> entityTypes, Filter filter) throws DataAccessException;
+
+	/**
+	 * Executes this search query with given {@link Attribute}s. The {@code
+	 * Attribute}s must be fully supported by this search query. This method allows
+	 * fine grained {@link Result} configuration.
+	 *
+	 * @param attributes Select statements will be added for each {@code
+	 * 		Attribute}.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetch(List, Filter)
+	 * @see #fetchComplete(List)
+	 */
+	default List<Result> fetch(List<Attribute> attributes) throws DataAccessException {
+		return fetch(attributes, Filter.and());
+	}
+
+	/**
+	 * Executes this search query with given {@link Attribute}s and {@link Filter}.
+	 * Both must be fully supported by this search query. This method allows fine
+	 * grained {@link Result} configuration.
+	 *
+	 * @param attributes Select statements will be added for each {@code
+	 * 		Attribute}.
+	 * @param filter     The criteria sequence.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetch(List)
+	 * @see #fetchComplete(List, Filter)
+	 */
+	List<Result> fetch(List<Attribute> attributes, Filter filter) throws DataAccessException;
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchService.java
new file mode 100644
index 0000000..25c64cb
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchService.java
@@ -0,0 +1,371 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.search;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+
+/**
+ * This search service uses given {@link Entity} type to execute the associated
+ * predefined {@link SearchQuery} and returns the results.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Searchable
+ * @see Attribute
+ * @see Value
+ * @see Filter
+ * @see Result
+ */
+public interface SearchService {
+
+	/**
+	 * Returns all {@link Entity} types this search service provides a predefined
+	 * {@link SearchQuery} for.
+	 *
+	 * @return The returned {@code List} with supported types may be immutable.
+	 */
+	List<Class<? extends Entity>> listSearchableTypes();
+
+	/**
+	 * Returns all {@link EntityType}s supported by the {@link SearchQuery}
+	 * associated with given {@link Entity} type.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @return The returned {@code List} may be immutable.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 */
+	List<EntityType> listEntityTypes(Class<? extends Entity> entityClass);
+
+	/**
+	 * Returns the {@link Searchable}, which describes a hierarchical order of the
+	 * {@link EntityType}s supported by the {@link SearchQuery} associated with
+	 * given {@link Entity} type.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @return The {@code Searchable} root is returned.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 */
+	Searchable getSearchableRoot(Class<? extends Entity> entityClass);
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute}. The
+	 * {@code Attribute} must be supported by the {@link SearchQuery} associated
+	 * with given {@link Entity} type. The returned {@code Value} sequence is
+	 * intended to be used for building filter criteria.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attribute   The {@code Attribute} whose distinct values will be
+	 *                    queried.
+	 * @return A distinct {@code List} of all available {@code Value}s is returned.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  query or generating the distinct
+	 *                                  {@code Value} sequence.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #getFilterValues(Class, Attribute, Filter)
+	 */
+	default List<Value> getFilterValues(Class<? extends Entity> entityClass, Attribute attribute)
+			throws DataAccessException {
+		return getFilterValues(entityClass, attribute, Filter.and());
+	}
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute} and
+	 * {@link Filter}. Both must be fully supported by the {@link SearchQuery}
+	 * associated with given {@link Entity} type. The returned {@code Value}
+	 * sequence is intended to be used for building filter criteria.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attribute   The {@code Attribute} whose distinct values will be
+	 *                    queried.
+	 * @param filter      The criteria sequence.
+	 * @return A distinct {@code List} of {@code Value}s is returned.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  query or generating the distinct
+	 *                                  {@code Value} sequence.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #getFilterValues(Class, Attribute)
+	 */
+	List<Value> getFilterValues(Class<? extends Entity> entityClass, Attribute attribute, Filter filter)
+			throws DataAccessException;
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link EntityType}s.
+	 * The {@code EntityType}s must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method selects all
+	 * {@link Attribute}s of each given {@code EntityType}.
+	 *
+	 * It is only guaranteed that this method loads the selected entities, and their
+	 * relations among themselves. No information about additional related entities
+	 * is necessarily loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityCass  Used as the {@code SearchQuery} identifier.
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetch(Class, List)
+	 * @see Record#merge(Record)
+	 */
+	default <T extends Entity> List<T> fetchComplete(Class<T> entityCass, List<EntityType> entityTypes)
+			throws DataAccessException {
+		return fetchComplete(entityCass, entityTypes, Filter.and());
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link EntityType}s
+	 * and {@link Filter}. Both must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method selects all
+	 * {@link Attribute}s of each given {@code EntityType}.
+	 * 
+	 * It is only guaranteed that this method loads the selected entities, and their
+	 * relations among themselves. No information about additional related entities
+	 * is necessarily loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each.
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @param filter      The criteria sequence.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetch(Class, List, Filter)
+	 * @see Record#merge(Record)
+	 */
+	<T extends Entity> List<T> fetchComplete(Class<T> entityClass, List<EntityType> entityTypes, Filter filter)
+			throws DataAccessException;
+
+	/**
+	 * Executes the associated {@link SearchQuery} and returns all available
+	 * instances of the specified {@link Entity} type.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity, no
+	 * information about related entities is necessarily loaded.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @return All available entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #fetch(Class, Filter)
+	 */
+	default <T extends Entity> List<T> fetch(Class<T> entityClass) throws DataAccessException {
+		return fetch(entityClass, Filter.and());
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Filter}. The
+	 * {@code Filter} must be fully supported by the {@code SearchQuery} associated
+	 * with given {@link Entity} type. It is only guaranteed that this method loads
+	 * the selected entity, no information about related entities is necessarily
+	 * loaded.
+	 * 
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param filter      The criteria sequence.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetch(Class)
+	 */
+	default <T extends Entity> List<T> fetch(Class<T> entityClass, Filter filter) throws DataAccessException {
+		return fetch(entityClass, Collections.emptyList(), filter);
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Attribute}s.
+	 * The {@code Attribute}s must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method allows fine grained
+	 * {@link Record} configuration.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity or
+	 * attributes, no additional information about related entities is necessarily
+	 * loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attributes  Select statements will be added for each {@code
+	 * 		Attribute} .
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetchComplete(Class, List)
+	 * @see Record#merge(Record)
+	 */
+	default <T extends Entity> List<T> fetch(Class<T> entityClass, List<Attribute> attributes)
+			throws DataAccessException {
+		return fetch(entityClass, attributes, Filter.and());
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Attribute}s and
+	 * {@link Filter}. Both must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method allows fine grained
+	 * {@link Record} configuration.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity or
+	 * attributes, no additional information about related entities is necessarily
+	 * loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attributes  Select statements will be added for each {@code
+	 * 		Attribute} .
+	 * @param filter      The criteria sequence.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetchComplete(Class, List, Filter)
+	 * @see Record#merge(Record)
+	 */
+	<T extends Entity> List<T> fetch(Class<T> entityClass, List<Attribute> attributes, Filter filter)
+			throws DataAccessException;
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Attribute}s and
+	 * {@link Filter}. Both must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method allows fine grained
+	 * {@link Record} configuration. This method allows to specify a fulltext search
+	 * query string.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity or
+	 * attributes, no additional information about related entities is necessarily
+	 * loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attributes  Select statements will be added for each {@code
+	 * 		Attribute} .
+	 * @param filter      The criteria sequence.
+	 * @param query       The fulltext search query
+	 * @return All {@link Result}s found by the {@link SearchQuery} with given
+	 *         {@link Attribute}s.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see Record#merge(Record)
+	 */
+	default List<Result> fetchResults(Class<? extends Entity> entityClass, List<Attribute> attributes, Filter filter,
+			String query) throws DataAccessException {
+		throw new UnsupportedOperationException();
+	}
+
+	default boolean isTextSearchAvailable() {
+		return false;
+	}
+
+	@SuppressWarnings("unchecked")
+	default <T extends Entity> List<T> fetch(Class<T> entityClass, String query) throws DataAccessException {
+		return (List<T>) fetch(query).getOrDefault(entityClass, Collections.emptyList());
+	}
+
+	default Map<Class<? extends Entity>, List<Entity>> fetch(String query) throws DataAccessException {
+		throw new UnsupportedOperationException();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/Searchable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/Searchable.java
new file mode 100644
index 0000000..f87c317
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/Searchable.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.search;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+
+/**
+ * A searchable is used to describe the hierarchical order of
+ * {@link EntityType}s being used for searching.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see SearchService
+ * @see SearchQuery
+ */
+public interface Searchable {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns all related searchables.
+	 *
+	 * @return Returned {@code List} may be immutable.
+	 */
+	List<Searchable> getRelatedSearchables();
+
+	/**
+	 * Returns the {@link EntityType} represented by this searchable.
+	 *
+	 * @return The {@code EntityType} represented by this searchable is returned.
+	 */
+	EntityType getEntityType();
+
+	/**
+	 * Returns {@code true} if this searchable doesn't have further related
+	 * searchables.
+	 *
+	 * @return True if this instance does not relate further searchables.
+	 */
+	default boolean isLeaf() {
+		return getRelatedSearchables().isEmpty();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/AttributeImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/AttributeImpl.java
new file mode 100755
index 0000000..cb86c6d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/AttributeImpl.java
@@ -0,0 +1,63 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+public class AttributeImpl implements Attribute {
+
+	public enum Type {
+		ID, UNKNOWN;
+	}
+
+	Type type;
+
+	public AttributeImpl(Type type) {
+		this.type = type;
+	}
+
+	@Override
+	public EntityType getEntityType() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public String getName() {
+		return type.name();
+	}
+
+	@Override
+	public String getUnit() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public ValueType getValueType() {
+		switch (type) {
+		case ID:
+			return ValueType.STRING;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	@Override
+	public Enumeration<?> getEnumObj() {
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/BaseEntityManagerTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/BaseEntityManagerTest.java
new file mode 100644
index 0000000..35a225b
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/BaseEntityManagerTest.java
@@ -0,0 +1,76 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.junit.Test;
+
+public class BaseEntityManagerTest {
+
+	@Test
+	public void loadShouldReturnEntity() throws DataAccessException {
+
+		@SuppressWarnings("unchecked")
+		BaseEntityManager entityManager = mock(BaseEntityManager.class);
+		TestStep mockedTestStep = mock(TestStep.class);
+
+		when(entityManager.load(any(), anyString())).thenCallRealMethod();
+		when(entityManager.load(TestStep.class, Arrays.asList("id1"))).thenReturn(Arrays.asList(mockedTestStep));
+
+		assertThat(entityManager.load(TestStep.class, "id1")).isEqualTo(mockedTestStep);
+	}
+
+	@Test
+	public void loadNotExistingIdShouldThrowDataAccessException() throws DataAccessException {
+
+		@SuppressWarnings("unchecked")
+		BaseEntityManager entityManager = mock(BaseEntityManager.class);
+
+		when(entityManager.load(any(), anyString())).thenCallRealMethod();
+		when(entityManager.load(eq(TestStep.class), anyCollection())).thenReturn(Collections.<TestStep>emptyList());
+
+		assertThatThrownBy(() -> entityManager.load(TestStep.class, "xyz")).isInstanceOf(DataAccessException.class)
+				.hasMessageContaining("Failed to load entity by instance ID.");
+	}
+
+	@Test
+	public void loadNotUniqueIdShouldThrowDataAccessException() throws DataAccessException {
+
+		@SuppressWarnings("unchecked")
+		BaseEntityManager entityManager = mock(BaseEntityManager.class);
+		TestStep mockedTestStep1 = mock(TestStep.class);
+		TestStep mockedTestStep2 = mock(TestStep.class);
+
+		when(entityManager.load(any(), anyString())).thenCallRealMethod();
+		when(entityManager.load(TestStep.class, Arrays.asList("id1")))
+				.thenReturn(Arrays.asList(mockedTestStep1, mockedTestStep2));
+
+		assertThatThrownBy(() -> entityManager.load(TestStep.class, "id1")).isInstanceOf(DataAccessException.class)
+				.hasMessageContaining("Failed to load entity by instance ID.");
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/CoreImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/CoreImpl.java
new file mode 100755
index 0000000..62bd195
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/CoreImpl.java
@@ -0,0 +1,99 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+import org.eclipse.mdm.api.base.adapter.RelationStore;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * 
+ * Very basic implementation of the Core class. The contents is initialized via
+ * a given map (instead of using a database or some other method)
+ * 
+ * @author Florian Schmitt
+ */
+public class CoreImpl implements Core {
+
+	private Map<String, Value> values;
+	private EntityStore mutableStore;
+
+	public CoreImpl(Map<String, Value> values) {
+		super();
+		this.values = values;
+		this.mutableStore = new EntityStore();
+	}
+
+	@Override
+	public String getSourceName() {
+		return "UnitTestSource";
+	}
+
+	@Override
+	public String getTypeName() {
+		return "UnitTestType";
+	}
+
+	@Override
+	public String getID() {
+		return "4711l";
+	}
+
+	@Override
+	public void setID(String instanceID) {
+
+	}
+
+	@Override
+	public Map<String, Value> getValues() {
+		return values;
+	}
+
+	@Override
+	public void hideValues(Collection<String> names) {
+
+	}
+
+	@Override
+	public Map<String, Value> getAllValues() {
+		return values;
+	}
+
+	@Override
+	public EntityStore getMutableStore() {
+		return mutableStore;
+	}
+
+	@Override
+	public EntityStore getPermanentStore() {
+		return new EntityStore();
+	}
+
+	@Override
+	public ChildrenStore getChildrenStore() {
+		return new ChildrenStore();
+	}
+
+	@Override
+	public RelationStore getNtoMStore() {
+		return new RelationStore();
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityFactoryImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityFactoryImpl.java
new file mode 100755
index 0000000..b66eb08
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityFactoryImpl.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.User;
+
+/**
+ * 
+ * Very basic implementation of BaseEntityFactory for testing purposes. We
+ * deliver a core containing data on initialization to simulate other data
+ * sources.
+ * 
+ * @author Florian Schmitt
+ *
+ */
+public class EntityFactoryImpl extends BaseEntityFactory {
+
+	private Core core;
+
+	public EntityFactoryImpl(Core core) {
+		this.core = core;
+	}
+
+	@Override
+	protected Optional<User> getLoggedInUser() {
+		return Optional.ofNullable(null);
+	}
+
+	@Override
+	protected <T extends Entity> Core createCore(Class<T> entityClass) {
+		return core;
+	}
+
+	@Override
+	protected <T extends Entity> Core createCore(Class<T> entityClass, ContextType contextType) {
+		return core;
+	}
+
+	@Override
+	protected <T extends Entity> Core createCore(String name, Class<T> entityClass) {
+		return core;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityTypeImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityTypeImpl.java
new file mode 100755
index 0000000..510e9f5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityTypeImpl.java
@@ -0,0 +1,92 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.AttributeImpl.Type;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
+
+public class EntityTypeImpl implements EntityType {
+
+	@Override
+	public String getSourceName() {
+		return null;
+	}
+
+	@Override
+	public String getName() {
+		return null;
+	}
+
+	@Override
+	public String getId() {
+		return "0";
+	}
+
+	@Override
+	public List<Attribute> getAttributes() {
+		return null;
+	}
+
+	@Override
+	public Attribute getIDAttribute() {
+		return new AttributeImpl(Type.ID);
+	}
+
+	@Override
+	public Attribute getAttribute(String name) {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getParentRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getChildRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getInfoRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getRelations(RelationType relationType) {
+		return null;
+	}
+
+	@Override
+	public Relation getRelation(EntityType target) {
+		return null;
+	}
+
+	@Override
+	public Relation getRelation(EntityType target, String name) {
+		return null;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/RelationImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/RelationImpl.java
new file mode 100755
index 0000000..ab4a632
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/RelationImpl.java
@@ -0,0 +1,78 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
+
+public class RelationImpl implements Relation {
+
+	public enum AttributeType {
+		ID, UNKNOWN;
+	}
+
+	AttributeType type;
+
+	public RelationImpl(AttributeType type) {
+		this.type = type;
+	}
+
+	@Override
+	public String getName() {
+		return type.name();
+	}
+
+	@Override
+	public EntityType getSource() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public EntityType getTarget() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public RelationType getRelationType() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public Attribute getAttribute() {
+		switch (type) {
+		case ID:
+			return new AttributeImpl(AttributeImpl.Type.ID);
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	@Override
+	public boolean isOutgoing(RelationType relationType) {
+		return true;
+	}
+
+	@Override
+	public boolean isIncoming(RelationType relationType) {
+		return false;
+	}
+
+	@Override
+	public boolean isNtoM() {
+		return false;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextComponentTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextComponentTest.java
new file mode 100644
index 0000000..cbee14a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextComponentTest.java
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+
+public class ContextComponentTest {
+
+	@org.junit.Test
+	public void testGetContextRoot() {
+		BaseEntityFactory factory = spy(BaseEntityFactory.class);
+		Core rootCore = createCore("UNITUNDERTEST");
+		when(factory.createCore(ContextRoot.class, ContextType.UNITUNDERTEST)).thenReturn(rootCore);
+		Core componentCore = createCore("");
+		when(factory.createCore("Engine", ContextComponent.class)).thenReturn(componentCore);
+
+		ContextRoot contextRoot = factory.createContextRoot("Car", ContextType.UNITUNDERTEST);
+		ContextComponent contextComponent = factory.createContextComponent("Engine", contextRoot);
+
+		assertThat(contextComponent.getContextRoot()).isEqualTo(contextRoot);
+	}
+
+	private Core createCore(String type) {
+		Core core = mock(Core.class);
+
+		Map<String, Value> values = new HashMap<>();
+		values.put("Name", ValueType.STRING.create("Name"));
+		values.put("Version", ValueType.STRING.create("Version"));
+
+		when(core.getValues()).thenReturn(values);
+		when(core.getTypeName()).thenReturn(type);
+		when(core.getPermanentStore()).thenReturn(new EntityStore());
+		when(core.getChildrenStore()).thenReturn(new ChildrenStore());
+
+		return core;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextSensorTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextSensorTest.java
new file mode 100644
index 0000000..09ce5fd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextSensorTest.java
@@ -0,0 +1,62 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+
+public class ContextSensorTest {
+
+	@org.junit.Test
+	public void testGetContextComponent() {
+		BaseEntityFactory factory = spy(BaseEntityFactory.class);
+		Core rootCore = createCore("TESTEQUIPMENT");
+		when(factory.createCore(ContextRoot.class, ContextType.TESTEQUIPMENT)).thenReturn(rootCore);
+		Core componentCore = createCore("");
+		when(factory.createCore("SensorDevice", ContextComponent.class)).thenReturn(componentCore);
+		Core sensorCore = createCore("");
+		when(factory.createCore("Sensor", ContextSensor.class)).thenReturn(sensorCore);
+
+		ContextRoot contextRoot = factory.createContextRoot("SensorDevices", ContextType.TESTEQUIPMENT);
+		ContextComponent contextComponent = factory.createContextComponent("SensorDevice", contextRoot);
+		ContextSensor contextSensor = factory.createContextSensor("Sensor", contextComponent);
+
+		assertThat(contextSensor.getContextComponent()).isEqualTo(contextComponent);
+	}
+
+	private Core createCore(String type) {
+		Core core = mock(Core.class);
+
+		Map<String, Value> values = new HashMap<>();
+		values.put("Name", ValueType.STRING.create("Name"));
+		values.put("Version", ValueType.STRING.create("Version"));
+
+		when(core.getValues()).thenReturn(values);
+		when(core.getTypeName()).thenReturn(type);
+		when(core.getPermanentStore()).thenReturn(new EntityStore());
+		when(core.getChildrenStore()).thenReturn(new ChildrenStore());
+
+		return core;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ModelTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ModelTest.java
new file mode 100755
index 0000000..0b33be2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ModelTest.java
@@ -0,0 +1,376 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.CoreImpl;
+import org.eclipse.mdm.api.base.EntityFactoryImpl;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.massdata.UnitBuilder;
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.massdata.WriteRequestBuilder;
+import org.eclipse.mdm.api.base.model.MeasuredValues.ValueIterator;
+
+/**
+ * 
+ * some unit test to test functionality of org.eclipse.mdm.api.base.model. At
+ * this point, please don't expect anything near complete test coverage.
+ * 
+ * @author Florian Schmitt
+ *
+ */
+public class ModelTest {
+
+	// compare doubles up to this accuracy
+	private static final double EPSILON = 0.00005d;
+
+	/**
+	 * basic test for reading the value of a parameter.The intialization via maps is
+	 * needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void parameterValue() {
+		Map<String, Value> map = new HashMap<>();
+		map.put("DataType", new Value(ValueType.STRING, "DataType", null, true, ScalarType.FLOAT, ScalarType.class,
+				ScalarType.FLOAT, EnumRegistry.SCALAR_TYPE));
+		map.put("Value", ValueType.STRING.create("Value", null, true, "5.7"));
+		map.put("Name", ValueType.STRING.create("Name", null, true, "paramname"));
+		Core core = new CoreImpl(map);
+		Parameter tp = new Parameter(core);
+		Value vv = tp.getVirtualValue();
+		Float extracted = vv.extract();
+		assertEquals(5.7f, extracted, EPSILON);
+	}
+
+	/**
+	 * basic test for reading measured float values
+	 */
+	@org.junit.Test
+	public void measuredValueFloat() {
+		Float[] vals = { 1.0f, 2.0f, 3.7f, 2.1f };
+		boolean[] flags = { true, true, false, true };
+		MeasuredValues mv = new MeasuredValues(ScalarType.FLOAT, "Value1", "lightyears",
+				SequenceRepresentation.EXPLICIT, new double[0], false, AxisType.Y_AXIS, vals, flags);
+		ValueIterator<Float> valueIterator = mv.iterator();
+		int i = 0;
+		while (valueIterator.hasNext()) {
+			boolean isCurrentValid = valueIterator.isValid();
+			Float currentValue = valueIterator.next();
+			assertEquals(vals[i], currentValue, EPSILON);
+			assertEquals(flags[i], isCurrentValid);
+			i++;
+		}
+		assertEquals(i, vals.length);
+	}
+
+	/**
+	 * basic test for reading measured double values
+	 */
+	@org.junit.Test
+	public void measuredValueDouble() {
+		Double[] vals = { 1.0d, 2.0d, 3.7d, 2.1d };
+		boolean[] flags = { true, true, false, true };
+		MeasuredValues mv = new MeasuredValues(ScalarType.DOUBLE, "Value1", "lightyears",
+				SequenceRepresentation.EXPLICIT, new double[0], false, AxisType.Y_AXIS, vals, flags);
+		ValueIterator<Double> valueIterator = mv.iterator();
+		int i = 0;
+		while (valueIterator.hasNext()) {
+			boolean isCurrentValid = valueIterator.isValid();
+			Double currentValue = valueIterator.next();
+			assertEquals(vals[i], currentValue, EPSILON);
+			assertEquals(flags[i], isCurrentValid);
+			i++;
+		}
+		assertEquals(i, vals.length);
+	}
+
+	/**
+	 * basic test for reading measured string values
+	 */
+	@org.junit.Test
+	public void measuredValueString() {
+		String[] vals = { "str1", "str2", "str3", "str4" };
+		boolean[] flags = { true, true, false, true };
+		MeasuredValues mv = new MeasuredValues(ScalarType.STRING, "Value1", "lightyears",
+				SequenceRepresentation.EXPLICIT, new double[0], false, AxisType.Y_AXIS, vals, flags);
+		ValueIterator<String> valueIterator = mv.iterator();
+		int i = 0;
+		while (valueIterator.hasNext()) {
+			boolean isCurrentValid = valueIterator.isValid();
+			String currentValue = valueIterator.next();
+			assertEquals(vals[i], currentValue);
+			assertEquals(flags[i], isCurrentValid);
+			i++;
+		}
+		assertEquals(i, vals.length);
+	}
+
+	/**
+	 * basic test for reading attributes of the channel.The intialization via maps
+	 * is needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void getChannelAttrs() {
+		Map<String, Value> map = new HashMap<String, Value>();
+		float min_src = 5.7f;
+		float max_src = 10.23f;
+		map.put("Minimum", ValueType.DOUBLE.create("Minimum", "m/s", true, new Double(min_src)));
+		map.put("Maximum", ValueType.DOUBLE.create("Maximum", "m/s", true, new Double(max_src)));
+		Core core = new CoreImpl(map);
+		Channel ch = new Channel(core);
+		Double min = ch.getMinimum();
+		Double max = ch.getMaximum();
+		assertEquals(min, min_src, EPSILON);
+		assertEquals(max, max_src, EPSILON);
+	}
+
+	/**
+	 * basic test to read the default scalar type of a quantity. The intialization
+	 * via maps is needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void getQuantity() {
+		Map<String, Value> map = new HashMap<String, Value>();
+		map.put("DefDataType", new Value(ValueType.ENUMERATION, "name", "unit", true, ScalarType.FLOAT,
+				ScalarType.class, ScalarType.FLOAT, EnumRegistry.SCALAR_TYPE));
+		Core core = new CoreImpl(map);
+		Quantity quantity = new Quantity(core);
+		ScalarType defaultScalarType = quantity.getDefaultScalarType();
+		assertTrue(defaultScalarType.isFloat());
+	}
+
+	/**
+	 * basic test for building a write request
+	 */
+	@org.junit.Test
+	public void writeRequest() {
+		AxisType axisType = AxisType.X_AXIS;
+		Core core = new CoreImpl(new HashMap<>());
+		ChannelGroup channelGroup = new ChannelGroup(core);
+		Channel channel = new Channel(core);
+		WriteRequestBuilder wrb = WriteRequest.create(channelGroup, channel, axisType);
+		UnitBuilder ub = wrb.implicitConstant(ScalarType.DOUBLE, 0.7d);
+		WriteRequest wr = ub.build();
+		SequenceRepresentation sequenceRepresentation = wr.getSequenceRepresentation();
+		assertTrue(sequenceRepresentation.isConstant());
+		assertEquals(AxisType.X_AXIS, wr.getAxisType());
+	}
+
+	/**
+	 * basic test for getting a measurement channel and all necessary related
+	 * objects (measurment, and so on) via factory methods. The intialization via
+	 * maps is needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void entityFactory() {
+		Map<String, Value> map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, "pdnameabc"));
+		map.put("Length", ValueType.INTEGER.create("Length", null, true, 13));
+		map.put("Mass", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("Time", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("Temperature", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("Current", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("MolarAmount", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("LuminousIntensity", ValueType.INTEGER.create("Length", null, true, 0));
+		// TODO (Florian Schmitt): check if angle in lower case is correct
+		map.put("angle", ValueType.INTEGER.create("Length", null, true, 0));
+		Core core = new CoreImpl(map);
+		EntityFactoryImpl ef = new EntityFactoryImpl(core);
+		PhysicalDimension physicalDimension = ef.createPhysicalDimension("physdim");
+
+		map = new HashMap<String, Value>();
+		map.put("Offset", ValueType.DOUBLE.create("Length", null, true, 0d));
+		map.put("Factor", ValueType.DOUBLE.create("Length", null, true, 0d));
+		map.put("Name", ValueType.STRING.create("Name", null, true, "unitname"));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Unit unit = ef.createUnit("unit", physicalDimension);
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, "quantname"));
+		map.put("Version", ValueType.STRING.create("Version", null, true, "4711"));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		map.put("DefaultRank", ValueType.INTEGER.create("DefaultRank", null, true, 5));
+		map.put("DefDimension", ValueType.INTEGER_SEQUENCE.create("DefDimension", null, true, new int[] { 5 }));
+		map.put("DefTypeSize", ValueType.INTEGER.create("DefTypeSize", null, true, 8));
+		map.put("DefMQName", ValueType.STRING.create("DefMQName", null, true, "mqname"));
+		map.put("DefDataType", new Value(ValueType.ENUMERATION, "DefDataType", "", true, ScalarType.DOUBLE,
+				ScalarType.class, ScalarType.DOUBLE, EnumRegistry.SCALAR_TYPE));
+		map.put("ValidFlag", new Value(ValueType.ENUMERATION, "ValidFlag", "", false, VersionState.ARCHIVED,
+				VersionState.class, null, EnumRegistry.VERSION_STATE));
+		map.put("Description", ValueType.STRING.create("Description", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Quantity quantity = ef.createQuantity("quantity", unit);
+		// Note that default values are set in createQuantity and thus should
+		// differ from above.
+		assertEquals(ScalarType.FLOAT, quantity.getDefaultScalarType());
+		assertEquals((Integer) 1, quantity.getDefaultRank());
+		assertEquals("quantity", quantity.getName());
+		assertEquals(unit, quantity.getDefaultUnit());
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Test test = ef.createTest("mytest");
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		map.put("Optional", ValueType.BOOLEAN.create("Optional", null, true, null));
+		map.put("Sortindex", ValueType.INTEGER.create("Sortindex", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		TestStep testStep = ef.createTestStep("teststep", test);
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Measurement measurement = ef.createMeasurement("measurement", testStep);
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("Description", ValueType.STRING.create("Description", null, true, null));
+		map.put("Interpolation", new Value(ValueType.ENUMERATION, "Interpolation", "", true, null, Interpolation.class,
+				null, EnumRegistry.SCALAR_TYPE));
+		map.put("DataType", new Value(ValueType.ENUMERATION, "DataType", "", true, null, ScalarType.class, null,
+				EnumRegistry.SCALAR_TYPE));
+
+		map.put("TypeSize", ValueType.INTEGER.create("TypeSize", null, true, null));
+		map.put("Rank", ValueType.INTEGER.create("Rank", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Channel channel = ef.createChannel("channel", measurement, quantity);
+		assertEquals(Interpolation.NONE, channel.getInterpolation());
+	}
+
+	/**
+	 * basic test of some ValuType methods.
+	 */
+	@org.junit.Test
+	public void valueType() {
+		EnumRegistry.getInstance();
+		assertEquals(ValueType.SHORT_SEQUENCE.toSingleType(), ValueType.SHORT);
+		assertEquals(ValueType.DATE.toSequenceType(), ValueType.DATE_SEQUENCE);
+		assertEquals(ValueType.ENUMERATION_SEQUENCE.toSingleType(), ValueType.ENUMERATION);
+		assertEquals(ValueType.ENUMERATION.toSingleType(), ValueType.ENUMERATION);
+		assertEquals(ValueType.ENUMERATION, ValueType.ENUMERATION.valueOf(ValueType.ENUMERATION.toSingleType().name()));
+		assertEquals(Float.class, ValueType.FLOAT.getValueClass());
+		assertEquals(true, ValueType.DOUBLE.isAnyFloatType());
+		assertEquals(true, ValueType.DOUBLE.isDouble());
+		assertEquals(false, ValueType.DOUBLE.isFloat());
+		assertEquals(true, ValueType.FLOAT.isAnyFloatType());
+		assertEquals(false, ValueType.INTEGER.isAnyFloatType());
+		assertEquals(true, ValueType.INTEGER.isInteger());
+		assertEquals(false, ValueType.FLOAT.isInteger());
+		assertEquals(true, ValueType.FLOAT.isFloat());
+	}
+
+	/**
+	 * basic tests of some ScalarType methods
+	 */
+	@org.junit.Test
+	public void scalarType() {
+		assertEquals(ValueType.BYTE_SEQUENCE, ScalarType.BYTE.toValueType());
+		assertEquals(true, ScalarType.LONG.isLong());
+		assertEquals(false, ScalarType.DOUBLE_COMPLEX.isLong());
+	}
+
+	/**
+	 * basic test of some SequenceReprestentaion methods
+	 */
+	@org.junit.Test
+	public void sequenceRepresentation() {
+		assertNotEquals(SequenceRepresentation.EXPLICIT, SequenceRepresentation.IMPLICIT_CONSTANT);
+		assertTrue(SequenceRepresentation.EXPLICIT.isExplicit());
+		assertTrue(SequenceRepresentation.EXPLICIT_EXTERNAL.isExplicit());
+		assertTrue(SequenceRepresentation.EXPLICIT_EXTERNAL.isExternal());
+		assertFalse(SequenceRepresentation.EXPLICIT_EXTERNAL.isImplicit());
+		assertEquals(SequenceRepresentation.EXPLICIT.ordinal(), (Integer) 0);
+		assertEquals((Integer) 5, SequenceRepresentation.RAW_POLYNOMIAL.ordinal());
+		assertEquals((Integer) 7, SequenceRepresentation.EXPLICIT_EXTERNAL.ordinal());
+		assertEquals((Integer) 9, SequenceRepresentation.RAW_POLYNOMIAL_EXTERNAL.ordinal());
+		assertEquals((Integer) 10, SequenceRepresentation.RAW_LINEAR_CALIBRATED.ordinal());
+		assertEquals((Integer) 11, SequenceRepresentation.RAW_LINEAR_CALIBRATED_EXTERNAL.ordinal());
+	}
+
+	/**
+	 * basic tests of TypeSpecification
+	 */
+	@org.junit.Test
+	public void typeSpecification() {
+		assertNotEquals(TypeSpecification.BIT_INTEGER, TypeSpecification.BIT_FLOAT_BEO);
+		assertEquals(TypeSpecification.BOOLEAN, TypeSpecification.BOOLEAN);
+	}
+
+	/**
+	 * basic tests of AxisTzpe methods
+	 */
+	@org.junit.Test
+	public void axisType() {
+		assertTrue(AxisType.X_AXIS.isXAxis());
+		assertTrue(AxisType.Y_AXIS.isYAxis());
+		assertTrue(AxisType.XY_AXIS.isXYAxis());
+		assertFalse(AxisType.X_AXIS.isYAxis());
+		assertFalse(AxisType.Y_AXIS.isXYAxis());
+		assertFalse(AxisType.XY_AXIS.isXAxis());
+	}
+
+	/**
+	 * basic tests of VersionState enumeration
+	 */
+	@org.junit.Test
+	public void versionState() {
+		assertFalse(VersionState.ARCHIVED.isEditable());
+		assertTrue(VersionState.ARCHIVED.isArchived());
+		assertFalse(VersionState.ARCHIVED.isValid());
+		assertTrue(VersionState.EDITABLE.isEditable());
+		assertFalse(VersionState.EDITABLE.isArchived());
+		assertFalse(VersionState.EDITABLE.isValid());
+		assertFalse(VersionState.VALID.isEditable());
+		assertFalse(VersionState.VALID.isArchived());
+		assertTrue(VersionState.VALID.isValid());
+	}
+
+	/**
+	 * basic tests of interpolation enumeration
+	 */
+	@org.junit.Test
+	public void interpolation() {
+		assertTrue(Interpolation.LINEAR.isLinear());
+		assertFalse(Interpolation.NONE.isSpecific());
+		assertEquals(Interpolation.NONE.ordinal(), (Integer) 0);
+		assertEquals(Interpolation.LINEAR.ordinal(), (Integer) 1);
+		assertEquals(Interpolation.SPECIFIC.ordinal(), (Integer) 2);
+	}
+
+	@org.junit.Test
+	public void enumRegistry() {
+		EnumRegistry er = EnumRegistry.getInstance();
+		assertTrue(er.get("Interpolation") != null);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ValueTypeTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ValueTypeTest.java
new file mode 100644
index 0000000..fa2914e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ValueTypeTest.java
@@ -0,0 +1,79 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Before;
+
+public class ValueTypeTest {
+
+	@Before
+	public void init() {
+		EnumRegistry.getInstance();
+	}
+
+	@org.junit.Test
+	public void testExtractStringFromUnknown() {
+		Value v = ValueType.UNKNOWN.create("Name", "abcd");
+
+		assertThat((String) v.extract()).isEqualTo("abcd");
+		assertThat(v.extract(ValueType.UNKNOWN)).isEqualTo("abcd");
+	}
+
+	@org.junit.Test
+	public void testExtractString() {
+		Value v = ValueType.STRING.create("Name", "abcd");
+
+		assertThat((String) v.extract()).isEqualTo("abcd");
+		assertThat(v.extract(ValueType.STRING)).isEqualTo("abcd");
+	}
+
+	@org.junit.Test
+	public void testExtractInteger() {
+		Value v = ValueType.INTEGER.create("Id", 1);
+
+		assertThat((int) v.extract()).isEqualTo(1);
+		assertThat(v.extract(ValueType.INTEGER)).isEqualTo(1);
+	}
+
+	@org.junit.Test
+	public void testExtractIntegerSequence() {
+		int[] ints = new int[] { 1, 2, 3 };
+
+		Value v = ValueType.INTEGER_SEQUENCE.create("Ids", ints);
+
+		assertThat((int[]) v.extract()).isEqualTo(ints);
+		assertThat(v.extract(ValueType.INTEGER_SEQUENCE)).isEqualTo(ints);
+	}
+
+	@org.junit.Test
+	public void testExtractEnumeration() {
+		Value v = ValueType.ENUMERATION.create("ScalarTypeField", "", true, ScalarType.INTEGER,
+				EnumRegistry.SCALAR_TYPE);
+
+		assertThat(v.extract(ValueType.ENUMERATION)).isEqualTo(ScalarType.INTEGER);
+	}
+
+	@org.junit.Test
+	public void testExtractEnumerationSequence() {
+		ScalarType[] scalaTypes = new ScalarType[] { ScalarType.FLOAT, ScalarType.INTEGER };
+
+		Value v = ValueType.ENUMERATION_SEQUENCE.create("ScalarTypeSeqField", "", true, scalaTypes,
+				EnumRegistry.SCALAR_TYPE);
+
+		assertThat(v.extract(ValueType.ENUMERATION_SEQUENCE)).isEqualTo(scalaTypes);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/query/FilterTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/query/FilterTest.java
new file mode 100755
index 0000000..87b669d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/query/FilterTest.java
@@ -0,0 +1,113 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.eclipse.mdm.api.base.EntityTypeImpl;
+import org.eclipse.mdm.api.base.RelationImpl;
+import org.eclipse.mdm.api.base.RelationImpl.AttributeType;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test the Filter class
+ * 
+ * @author Alexander Nehmer
+ *
+ */
+public class FilterTest {
+
+	static String[] values = new String[] { "1", "2", "3" };
+
+	@Before
+	public void init() {
+		EnumRegistry.getInstance();
+	}
+
+	/**
+	 * Tests ids(EntityType entityType, Collection<String> ids)
+	 */
+	@Test
+	public void testIdsEntityType() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().ids(new EntityTypeImpl(), Arrays.asList(values));
+
+		String[] filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		Iterator<String> valuesIterator = Arrays.asList(values).iterator();
+		Iterator<String> filterConditionIterator = Arrays.stream(filterCondition).iterator();
+
+		while (valuesIterator.hasNext() && filterConditionIterator.hasNext()) {
+			assertEquals(valuesIterator.next(), filterConditionIterator.next());
+		}
+	}
+
+	/**
+	 * Tests ids(Relation relation, Collection<String> ids)
+	 */
+	@Test
+	public void testIdsRelation() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().ids(new RelationImpl(AttributeType.ID), Arrays.asList(values));
+
+		String[] filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		Iterator<String> valuesIterator = Arrays.asList(values).iterator();
+		Iterator<String> filterConditionIterator = Arrays.stream(filterCondition).iterator();
+
+		while (valuesIterator.hasNext() && filterConditionIterator.hasNext()) {
+			assertEquals(valuesIterator.next(), filterConditionIterator.next());
+		}
+	}
+
+	/**
+	 * Tests id(EntityType entityType, String id)
+	 */
+	@Test
+	public void testIdEntity() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().id(new EntityTypeImpl(), "1");
+
+		String filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		assertEquals(filterCondition, "1");
+	}
+
+	/**
+	 * Tests id(Relation relation, String id)
+	 */
+	@Test
+	public void testIdRelation() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().id(new RelationImpl(AttributeType.ID), "1");
+
+		String filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		assertEquals(filterCondition, "1");
+	}
+}
diff --git a/org.eclipse.mdm.api.default/.gitignore b/org.eclipse.mdm.api.default/.gitignore
new file mode 100644
index 0000000..49678ad
--- /dev/null
+++ b/org.eclipse.mdm.api.default/.gitignore
@@ -0,0 +1,17 @@
+# eclipse
+.classpath
+.project
+.settings/
+bin/
+
+# gradle
+.gradle
+build/
+
+# intellij
+.idea/
+out/
+*.ipr
+*.iml
+*.iws
+/bin/
diff --git a/org.eclipse.mdm.api.default/LICENSE.txt b/org.eclipse.mdm.api.default/LICENSE.txt
new file mode 100644
index 0000000..e48e096
--- /dev/null
+++ b/org.eclipse.mdm.api.default/LICENSE.txt
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0
+
+    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a) in the case of the initial Contributor, the initial content
+     Distributed under this Agreement, and
+
+  b) in the case of each subsequent Contributor:
+     i) changes to the Program, and
+     ii) additions to the Program;
+  where such changes and/or additions to the Program originate from
+  and are Distributed by that particular Contributor. A Contribution
+  "originates" from a Contributor if it was added to the Program by
+  such Contributor itself or anyone acting on such Contributor's behalf.
+  Contributions do not include changes or additions to the Program that
+  are not Modified Works.
+
+"Contributor" means any person or entity that Distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which
+are necessarily infringed by the use or sale of its Contribution alone
+or when combined with the Program.
+
+"Program" means the Contributions Distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement
+or any Secondary License (as applicable), including Contributors.
+
+"Derivative Works" shall mean any work, whether in Source Code or other
+form, that is based on (or derived from) the Program and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship.
+
+"Modified Works" shall mean any work in Source Code or other form that
+results from an addition to, deletion from, or modification of the
+contents of the Program, including, for purposes of clarity any new file
+in Source Code form that contains any contents of the Program. Modified
+Works shall not include works that contain only declarations,
+interfaces, types, classes, structures, or files of the Program solely
+in each case in order to link to, bind by name, or subclass the Program
+or Modified Works thereof.
+
+"Distribute" means the acts of a) distributing or b) making available
+in any manner that enables the transfer of a copy.
+
+"Source Code" means the form of a Program preferred for making
+modifications, including but not limited to software source code,
+documentation source, and configuration files.
+
+"Secondary License" means either the GNU General Public License,
+Version 2.0, or any later versions of that license, including any
+exceptions or additional permissions as identified by the initial
+Contributor.
+
+2. GRANT OF RIGHTS
+
+  a) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free copyright
+  license to reproduce, prepare Derivative Works of, publicly display,
+  publicly perform, Distribute and sublicense the Contribution of such
+  Contributor, if any, and such Derivative Works.
+
+  b) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free patent
+  license under Licensed Patents to make, use, sell, offer to sell,
+  import and otherwise transfer the Contribution of such Contributor,
+  if any, in Source Code or other form. This patent license shall
+  apply to the combination of the Contribution and the Program if, at
+  the time the Contribution is added by the Contributor, such addition
+  of the Contribution causes such combination to be covered by the
+  Licensed Patents. The patent license shall not apply to any other
+  combinations which include the Contribution. No hardware per se is
+  licensed hereunder.
+
+  c) Recipient understands that although each Contributor grants the
+  licenses to its Contributions set forth herein, no assurances are
+  provided by any Contributor that the Program does not infringe the
+  patent or other intellectual property rights of any other entity.
+  Each Contributor disclaims any liability to Recipient for claims
+  brought by any other entity based on infringement of intellectual
+  property rights or otherwise. As a condition to exercising the
+  rights and licenses granted hereunder, each Recipient hereby
+  assumes sole responsibility to secure any other intellectual
+  property rights needed, if any. For example, if a third party
+  patent license is required to allow Recipient to Distribute the
+  Program, it is Recipient's responsibility to acquire that license
+  before distributing the Program.
+
+  d) Each Contributor represents that to its knowledge it has
+  sufficient copyright rights in its Contribution, if any, to grant
+  the copyright license set forth in this Agreement.
+
+  e) Notwithstanding the terms of any Secondary License, no
+  Contributor makes additional grants to any Recipient (other than
+  those set forth in this Agreement) as a result of such Recipient's
+  receipt of the Program under the terms of a Secondary License
+  (if permitted under the terms of Section 3).
+
+3. REQUIREMENTS
+
+3.1 If a Contributor Distributes the Program in any form, then:
+
+  a) the Program must also be made available as Source Code, in
+  accordance with section 3.2, and the Contributor must accompany
+  the Program with a statement that the Source Code for the Program
+  is available under this Agreement, and informs Recipients how to
+  obtain it in a reasonable manner on or through a medium customarily
+  used for software exchange; and
+
+  b) the Contributor may Distribute the Program under a license
+  different than this Agreement, provided that such license:
+     i) effectively disclaims on behalf of all other Contributors all
+     warranties and conditions, express and implied, including
+     warranties or conditions of title and non-infringement, and
+     implied warranties or conditions of merchantability and fitness
+     for a particular purpose;
+
+     ii) effectively excludes on behalf of all other Contributors all
+     liability for damages, including direct, indirect, special,
+     incidental and consequential damages, such as lost profits;
+
+     iii) does not attempt to limit or alter the recipients' rights
+     in the Source Code under section 3.2; and
+
+     iv) requires any subsequent distribution of the Program by any
+     party to be under a license that satisfies the requirements
+     of this section 3.
+
+3.2 When the Program is Distributed as Source Code:
+
+  a) it must be made available under this Agreement, or if the
+  Program (i) is combined with other material in a separate file or
+  files made available under a Secondary License, and (ii) the initial
+  Contributor attached to the Source Code the notice described in
+  Exhibit A of this Agreement, then the Program may be made available
+  under the terms of such Secondary Licenses, and
+
+  b) a copy of this Agreement must be included with each copy of
+  the Program.
+
+3.3 Contributors may not remove or alter any copyright, patent,
+trademark, attribution notices, disclaimers of warranty, or limitations
+of liability ("notices") contained within the Program from any copy of
+the Program which they Distribute, provided that Contributors may add
+their own appropriate notices.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While this
+license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product
+offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes
+the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every
+other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits
+and other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program
+in a commercial product offering. The obligations in this section do not
+apply to any claims or Losses relating to any actual or alleged
+intellectual property infringement. In order to qualify, an Indemnified
+Contributor must: a) promptly notify the Commercial Contributor in
+writing of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those performance
+claims and warranties, and if a court requires any other Contributor to
+pay any damages as a result, the Commercial Contributor must pay
+those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all
+risks associated with its exercise of rights under this Agreement,
+including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs
+or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software
+or hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted and
+may only be modified in the following manner. The Agreement Steward
+reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement
+Steward has the right to modify this Agreement. The Eclipse Foundation
+is the initial Agreement Steward. The Eclipse Foundation may assign the
+responsibility to serve as the Agreement Steward to a suitable separate
+entity. Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always be
+Distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to Distribute the Program (including its
+Contributions) under the new version.
+
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted
+under this Agreement are reserved. Nothing in this Agreement is intended
+to be enforceable by any entity that is not a Contributor or Recipient.
+No third-party beneficiary rights are created under this Agreement.
+
+Exhibit A - Form of Secondary Licenses Notice
+
+"This Source Code may also be made available under the following
+Secondary Licenses when the conditions for such availability set forth
+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+version(s), and exceptions or additional permissions here}."
+
+  Simply including a copy of this Agreement, including this Exhibit A
+  is not sufficient to license the Source Code under Secondary Licenses.
+
+  If it is not possible or desirable to put the notice in a particular
+  file, then You may include the notice in a location (such as a LICENSE
+  file in a relevant directory) where a recipient would be likely to
+  look for such a notice.
+
+  You may add additional accurate notices of copyright ownership.
diff --git a/org.eclipse.mdm.api.default/NOTICE.txt b/org.eclipse.mdm.api.default/NOTICE.txt
new file mode 100644
index 0000000..56281c6
--- /dev/null
+++ b/org.eclipse.mdm.api.default/NOTICE.txt
@@ -0,0 +1,382 @@
+# Notices for Eclipse MDM|BL
+
+This content is produced and maintained by the Eclipse MDM|BL project,
+it is a project of the openMDM(R) Eclipse Working Group.
+
+* Project home: https://projects.eclipse.org/projects/technology.mdmbl
+
+## Trademarks
+
+Eclipse MDM|BL, MDM|BL and Eclipse openMDM(R) logo are registered trademarks
+of the Eclipse Foundation.
+
+## Copyright
+
+All content is the property of the following respective authors or their employers.
+For more information regarding authorship of content, please consult the listed
+source code repository logs.
+
+Copyright (c) 2016-2019 Gigatronik Ingolstadt GmbH
+Copyright (c) 2016-2020 Peak Solution GmbH
+Copyright (c) 2017-2018 science + computing AG Tuebingen (ATOS SE)
+Copyright (c) 2017-2018 Canoo Engineering AG
+Copyright (c) 2017 Florian Schmitt
+Copyright (c) 2017-2020 Angelika Wittek
+Copyright (c) 2018-2019 Elektronische Fahrwerksysteme GMBH
+Copyright (c) 2018-2020 Karakun AG
+Copyright (c) 2018-2020 Alexander Nehmer
+
+## Declared Project Licenses
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v. 2.0 which is available at
+http://www.eclipse.org/legal/epl-2.0.
+
+SPDX-License-Identifier: EPL-2.0
+
+## Source Code
+
+The project maintains the following source code repositories:
+
+org.eclipse.mdm.api.base.git	    - The openMDM(R) API.
+org.eclipse.mdm.api.default.git	    - Extension of the openMDM(R) API containing default elements.
+org.eclipse.mdm.api.odsadapter.git	- ODS implementation of persistence adapter.
+org.eclipse.mdm.nucleus.git	        - Core building blocks for the openMDM Business Logic and Web Frontend.
+
+## Third-party Content
+
+The Content includes items that have been sourced from third parties as set out below.
+If you did not receive this Content directly from the Eclipse Foundation, the following
+is provided for informational purposes only, and you should look to
+the Redistributor's license for terms and conditions of use.
+
+antlr4-4.5.3.jar(2.5.3)
+    * License: New BSD license
+
+aopalliance-repackaged-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+commons-codec-1.2.jar (1.2)
+    * License: Apache License, 2.0
+
+commons-httpclient-3.1.jar  (3.1)
+    * License: Apache License, 2.0
+
+commons-lang3-3.8.1.jar (3.8.1)
+    * License: Apache License, 2.0
+
+commons-text-1.6.jar (1.6)
+    * License: Apache License, 2.0
+
+gson-2.7.jar (2.7)
+    * License: Apache License, 2.0
+
+Google Guava Version: 25.0-jre  (25.0)
+    * License: Apache License, 2.0
+
+Gradle Wrapper (4.10.2)
+    * License: Apache License, 2.0
+
+hk2-api-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL-1.1
+
+hk2-locator-2.5.0-b05.jar(2.5.0-b05)
+    * License: CDDL
+
+hk2-utils-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+jackson-annotations-2.9.0.jar  (2.9.0)
+    * License: Apache License, 2.0
+
+jackson-core-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-databind-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-base-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-json-provider-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-module-jaxb-annotations-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+javassist-3.20.0-GA.jar  (2.20.0-GA)
+    * License: Apache 2.0
+
+jcl-over-slf4j-1.7.25.jar(1.7.25)
+    * License: MIT License
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL:  https://www.slf4j.org
+    * Source URL:   https://github.com/qos-ch/slf4j
+
+jersey-client-2.23.2.jar (2.23.2)
+     * License: CDDL
+
+jersey-common-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-2.23.2.jar  (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-core-2.23.3.jar(2.23.2)
+    * License: CDDL
+
+jersey-guava-2.23.2.jar  (2.23.2)
+    * License: Apache License, 2.0
+
+jersey-media-jaxb-2.23.2.jar(2.23.2)
+    * License: CDDL
+
+jersey-media-sse-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-media-multipart-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-server-2.23.2.jar (2.23.2)
+    * License: Apache-2.0
+
+log4j-over-slf4j-1.7.25.jar (1.7.25)
+    * License: Apache-2.0
+
+logback-classic-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+logback-core-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+mimepull-1.9.6.jar (1.9.4)
+    * License: CDDL
+
+openatfx-0.7.4.jar (0.7.4)
+    * License: Apache-2.0
+
+osgi-resource-locator-1.0.1.jar(1.0.1)
+    * License: CDDL
+
+protobuf-java-3.2.0.jar (3.2.0)
+    * License: New BSD license
+
+protobuf-java-util-3.2.0.jar  (3.2.0)
+    * License: New BSD license
+
+swagger-annotations-2.0.8.jar (2.0.8)
+    * License: Apache-2.0
+
+swagger-ui-3.23.0.jar (3.23.0)
+    * License: Apache-2.0
+
+slf4j-api-1.7.25.jar  (1.7.25)
+    * License: MIT license
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL: https://github.com/qos-ch/slf4j
+    * Source URL:  https://github.com/qos-ch/slf4j/releases/tag/v_1.7.25
+
+stax2-api-3.1.4.jar (3.1.4)
+    * License: BSD-2-Clause
+
+validation-api-1.1.0.Final.jar (1.1.0.Final)
+  * License: Apache License, 2.0
+
+vavr-0.9.1-sources.jar (0.9.1)
+  * License: Apache License, 2.0
+
+vavr-match-0.9.1.jar (0.9.1)
+  * License: Apache License, 2.0
+
+woodstox-core-asl-4.4.1.jar (4.4.1)
+  * License: Apache License, 2.0
+
+
+FFAMFAMFAM Silk Icon, Version 1.3
+    * License: Creative Commons Attribution 3.0 License
+    * Licence Path: https://creativecommons.org/licenses/by/3.0/
+    * Project: http://www.famfamfam.com/lab/icons/silk/
+    * Source:  http://www.famfamfam.com/lab/icons/silk/
+
+@angular/animations:7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/animations
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/cdk:7.1.1
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api
+    * Source:  https://github.com/angular/angular/releases/tag/7.1.1
+
+
+@angular/common@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/common
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4r
+
+@angular/compiler@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/core@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/forms@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/http@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser-dynamic@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/router@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+bootstrap@4.1.3
+    * License: MIT
+    * Licence Path: https://github.com/twbs/bootstrap/raw/master/LICENSE
+    * Project: https://getbootstrap.com/
+    * Source:  https://github.com/twbs/bootstrap
+
+class-transformer@0.1.6
+    * License: MIT
+    * Licence Path: https://github.com/typestack/class-transformer/blob/master/LICENSE
+    * Project: https://github.com/pleerock/class-transformer
+    * Source:  https://github.com/pleerock/class-transformer
+
+core-js@2.6.0
+    * License: MIT
+    * Licence Path: https://github.com/zloirock/core-js/raw/master/LICENSE
+    * Project: https://github.com/zloirock/core-js
+    * Source:  https://github.com/zloirock/core-js/releases/tag/v2.6.0
+
+file-saver@1.3.3
+    * License: MIT
+    * Licence Path: https://github.com/eligrey/FileSaver.js/raw/master/LICENSE.md
+    * Project: https://github.com/eligrey/FileSaver.js
+    * Source:  https://github.com/eligrey/FileSaver.js
+
+font-awesome@4.7.0
+    * License: MIT
+    * Licence Path: https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt
+    * Project: https://fontawesome.com/
+    * Source:  https://github.com/FortAwesome/Font-Awesome
+
+ng2-split-pane@1.3.1
+    * License: MIT
+    * Licence Path: https://github.com/wannabegeek/ng2-split-pane/raw/master/LICENSE
+    * Project: https://github.com/wannabegeek/ng2-split-pane
+    * Source:  https://github.com/wannabegeek/ng2-split-pane
+
+ngx-bootstrap@3.1.2
+    * License: MIT
+    * Licence Path: https://github.com/valor-software/ngx-bootstrap/blob/v3.1.2/LICENSE
+    * Project: https://valor-software.com/ngx-bootstrap
+    * Source:  https://github.com/valor-software/ngx-bootstrap/tree/v3.1.2
+
+@ngx-translate/core@11.0.1
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/core/blob/v11.0.1/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/core
+
+@ngx-translate/http-loader@4.0.0
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/http-loader/blob/v4.0.0/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/http-loader/tree/v4.0.0
+
+primeicons:1.0.0
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeicons/blob/1.0.0/LICENSE
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeicons/tree/1.0.0
+
+primeng@7.0.1
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeng/blob/7.0.1/LICENSE.md
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeng/tree/7.0.1
+
+rxjs@6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3
+
+rxjs-compat:6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3/compat
+
+tslib@1.9.0
+    * License: Apache-2.0
+    * Project: https://github.com/Microsoft/tslib
+    * Source:  https://github.com/Microsoft/tslib/tree/1.9.0
+
+zone.js@0.8.26
+    * License: MIT
+    * Licence Path: https://github.com/angular/zone.js/raw/master/LICENSE
+    * Project: https://github.com/angular
+    * Source:  https://github.com/angular/zone.js/releases/tag/v0.8.26
+
+OMG Event Service Specification (1.2)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/EVNT/1.2/
+* Source: https://www.omg.org/spec/EVNT/1.2/pdf
+
+OMG Notification Service Specification (1.1)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/NOT/
+* Source: https://www.omg.org/spec/NOT/1.1/PDF
+
+ods530.idl
+Date: Hoehenkirchen, 06/01/2016
+"The ASAM Board of Directors releases the IDL files for use under the EPL to the Eclipse IWG openMDM.
+This is valid for all versions of ASAM ODS 5.3.x.
+This permission is valid under the conditions of Eclipse will not modify the file."
+
+AvalonEvent.idl, CorbaFileServer.idl
+Date: 08/15/2016
+"Herewith, we release the generated Client-Source-Code generated from our CORBA IDLs, namely
+* CORBANotification Service (generated from „AvalonEvent.idl”)
+* CORBAFileServer (generated from „CorbaFileServer.idl“),
+Under the Eclipse Public License (EPL). This agreement does not include the „AvalonEvent.idl“ and
+„CorbaFileServer.idl“ itself, which remain protected property of HighQSoft. "
+
+## Cryptography
+
+Content may contain encryption software. The country in which you are currently
+may have restrictions on the import, possession, and use, and/or re-export to
+another country, of encryption software. BEFORE using any encryption software,
+please check the country's laws, regulations and policies concerning the import,
+possession, or use, and re-export of encryption software, to see if this is
+permitted.
diff --git a/org.eclipse.mdm.api.default/build.gradle b/org.eclipse.mdm.api.default/build.gradle
new file mode 100644
index 0000000..26035f0
--- /dev/null
+++ b/org.eclipse.mdm.api.default/build.gradle
@@ -0,0 +1,49 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+description = 'MDM API - Default Model'
+group = 'org.eclipse.mdm'
+version = '5.2.0M1-SNAPSHOT'
+
+apply plugin: 'java'
+apply plugin: 'maven'
+apply plugin: 'eclipse'
+
+repositories {
+	mavenLocal()
+	mavenCentral()
+}
+
+dependencies {
+	compile "org.eclipse.mdm:org.eclipse.mdm.api.base:${version}"
+
+	// testing
+	testCompile 'junit:junit:4.12'
+	testCompile 'org.mockito:mockito-core:2.13.0'
+	testCompile 'org.assertj:assertj-core:3.6.2'
+}
+
+jar {
+	metaInf { from 'NOTICE.txt' }
+	metaInf { from 'LICENSE.txt' }
+}
+
+task sourcesJar(type: Jar, dependsOn: classes) {
+	classifier = 'sources'
+	from sourceSets.main.allSource
+}
+
+artifacts {
+	archives sourcesJar
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.default/gradle.properties b/org.eclipse.mdm.api.default/gradle.properties
new file mode 100644
index 0000000..2ab5436
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradle.properties
@@ -0,0 +1,16 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+ 
+sourceCompatibility=1.8
+targetCompatibility=1.8
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.jar b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.properties b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82e006
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME

+distributionPath=wrapper/dists

+zipStoreBase=GRADLE_USER_HOME

+zipStorePath=wrapper/dists

+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip

diff --git a/org.eclipse.mdm.api.default/gradlew b/org.eclipse.mdm.api.default/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/org.eclipse.mdm.api.default/gradlew.bat b/org.eclipse.mdm.api.default/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windows variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/org.eclipse.mdm.api.default/settings.gradle b/org.eclipse.mdm.api.default/settings.gradle
new file mode 100644
index 0000000..c7402a5
--- /dev/null
+++ b/org.eclipse.mdm.api.default/settings.gradle
@@ -0,0 +1,15 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+rootProject.name = 'org.eclipse.mdm.api.default'
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContext.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContext.java
new file mode 100644
index 0000000..2831ec9
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContext.java
@@ -0,0 +1,28 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt;
+
+import org.eclipse.mdm.api.base.BaseApplicationContext;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+
+/**
+ * Extends the {@link BaseApplicationContext} interface to return
+ * {@link EntityFactory} and {@link EntityManager}.
+ *
+ * @since 1.0.0
+ */
+public interface ApplicationContext extends BaseApplicationContext<EntityFactory, EntityManager> {
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContextFactory.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContextFactory.java
new file mode 100644
index 0000000..2bdad67
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContextFactory.java
@@ -0,0 +1,27 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt;
+
+import org.eclipse.mdm.api.base.BaseApplicationContextFactory;
+
+/**
+ * Extends the {@link BaseApplicationContextFactory} interface to return an
+ * {@link ApplicationContext}.
+ *
+ * @since 1.0.0
+ */
+public interface ApplicationContextFactory extends BaseApplicationContextFactory<ApplicationContext> {
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/EntityManager.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/EntityManager.java
new file mode 100644
index 0000000..8298101
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/EntityManager.java
@@ -0,0 +1,167 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.model.Status;
+import org.eclipse.mdm.api.dflt.model.TemplateTest;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
+import org.eclipse.mdm.api.dflt.model.Versionable;
+
+/**
+ * Extends the {@link BaseEntityManager} interface with additional load methods
+ * dedicated to the default application models.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface EntityManager extends BaseEntityManager {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Loads the entity identified by given entity class, {@link ContextType} and
+	 * its instance ID.
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entity.
+	 * @param contextType The {@link ContextType}.
+	 * @param instanceID  The instance ID.
+	 * @return The entity with given instance ID is returned.
+	 * @throws DataAccessException Thrown if unable to retrieve the entity.
+	 */
+	default <T extends Entity> T load(Class<T> entityClass, ContextType contextType, String instanceID)
+			throws DataAccessException {
+		List<T> entities = load(entityClass, contextType, Collections.singletonList(instanceID));
+		if (entities.size() != 1) {
+			throw new DataAccessException("Failed to load entity by instance ID.");
+		}
+		return entities.get(0);
+
+	}
+
+	<T extends Entity> List<T> load(Class<T> entityClass, ContextType contextType, Collection<String> instanceIDs)
+			throws DataAccessException;
+
+	/**
+	 * Loads all available entities of given type.
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	List<CatalogComponent> catalogComponents = entityManager.loadAll(CatalogComponent.class, UNITUNDERTEST);
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @param contextType The {@link ContextType}.
+	 * @return Entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 * @see #loadAll(Class, ContextType, String)
+	 */
+	default <T extends Entity> List<T> loadAll(Class<T> entityClass, ContextType contextType)
+			throws DataAccessException {
+		return loadAll(entityClass, contextType, "*");
+	}
+
+	/**
+	 * Loads all available entities of given type whose name fulfills the given
+	 * pattern.
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	// retrieve all template roots whose name starts with 'Example'
+	 * 	List<TemplateRoot> templateRoots = entityManager.loadAll(TemplateRoot.class, UNITUNDERTEST, "Example*");
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @param contextType The {@link ContextType}.
+	 * @param pattern     Is always case sensitive and may contain wildcard
+	 *                    characters as follows: "?" for one matching character and
+	 *                    "*" for a sequence of matching characters.
+	 * @return Matched entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 * @see #loadAll(Class)
+	 */
+	<T extends Entity> List<T> loadAll(Class<T> entityClass, ContextType contextType, String pattern)
+			throws DataAccessException;
+
+	/**
+	 * Loads the latest valid {@link Versionable} entity of given type and name.
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entity.
+	 * @param name        The exact name of the requested entity.
+	 * @return Optional is empty if no such entity was found
+	 * @throws DataAccessException Thrown if unable to retrieve the entity.
+	 */
+	default <T extends Versionable> Optional<T> loadLatestValid(Class<T> entityClass, String name)
+			throws DataAccessException {
+		return loadAll(entityClass, name).stream().filter(v -> v.nameEquals(name)).filter(Versionable::isValid)
+				.max(Versionable.COMPARATOR);
+	}
+
+	/**
+	 * Loads the latest valid {@link Versionable} entity of given type,
+	 * {@link ContextType} and name.
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entity.
+	 * @param contextType The {@code ContextType}.
+	 * @param name        The exact name of the requested entity.
+	 * @return Optional is empty if no such entity was found
+	 * @throws DataAccessException Thrown if unable to retrieve the entity.
+	 */
+	default <T extends Versionable> Optional<T> loadLatestValid(Class<T> entityClass, ContextType contextType,
+			String name) throws DataAccessException {
+		return loadAll(entityClass, contextType, name).stream().filter(v -> v.nameEquals(name))
+				.filter(Versionable::isValid).max(Versionable.COMPARATOR);
+	}
+
+	<T extends StatusAttachable> List<T> loadAll(Class<T> entityClass, Status status, String pattern);
+
+	/**
+	 * Loads the refereced {@link TemplateTest} for a {@link Test}.
+	 * 
+	 * @param test {@link Test} referencing the desired template
+	 * @return {@link Optional} with the loaded {@link TemplateTest}
+	 */
+	Optional<TemplateTest> loadTemplate(Test test);
+
+	/**
+	 * Loads the referenced {@link TemplateTestStep} for a {@link TestStep}
+	 * 
+	 * @param testStep {@link TestStep} referencing the desired template
+	 * @return {@link Optional} with the loaded {@link TemplateTestStep}
+	 */
+	Optional<TemplateTestStep> loadTemplate(TestStep testStep);
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogAttribute.java
new file mode 100644
index 0000000..ac6c20d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogAttribute.java
@@ -0,0 +1,321 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Implementation of the catalog attribute entity type. A catalog attribute is a
+ * generic attribute description to store context data ("as measured", "as
+ * ordered"). It always belongs to a {@link CatalogComponent} or a
+ * {@link CatalogSensor}. Its name has to be unique within the parent and may
+ * not be changed, once written.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogComponent
+ * @see CatalogSensor
+ */
+public class CatalogAttribute extends BaseEntity implements Deletable, Describable, Sortable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'ValueListReference' attribute name.
+	 */
+	public static final String ATTR_VALUE_LIST_REFERENCE = "ValueListRef";
+
+	/**
+	 * The 'ValueCopyable' attribute name.
+	 */
+	public static final String ATTR_VALUE_COPYABLE = "ValueCopyable";
+
+	/**
+	 * The 'ActionRequestClassname' attribute name.
+	 */
+	public static final String ATTR_ACTION_REQUEST_CLASSNAME = "ActionRequestClassname";
+
+	/**
+	 * The <u>virtual</u> '{@literal @}EnumerationName' attribute name.
+	 */
+	public static final String VATTR_ENUMERATION_NAME = "@EnumerationName";
+
+	/**
+	 * The <u>virtual</u> '{@literal @}ScalarType' attribute name.
+	 */
+	public static final String VATTR_SCALAR_TYPE = "@ScalarType";
+
+	/**
+	 * The <u>virtual</u> '{@literal @}Sequence' attribute name.
+	 */
+	public static final String VATTR_SEQUENCE = "@Sequence";
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private Enumeration<?> enumerationObj;
+	private final Value scalarTypeValue;
+	private final Value sequenceValue;
+
+	private Unit unit;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	CatalogAttribute(Core core) {
+		super(core);
+
+		Map<String, Value> values = core.getValues();
+		EnumRegistry er = EnumRegistry.getInstance();
+		Value enumValue = values.remove(VATTR_ENUMERATION_NAME);
+		if (enumValue != null) {
+			enumerationObj = er.get(enumValue.extract(ValueType.STRING));
+		}
+		scalarTypeValue = values.remove(VATTR_SCALAR_TYPE);
+		sequenceValue = values.remove(VATTR_SEQUENCE);
+
+		unit = core.getMutableStore().get(Unit.class);
+		core.getMutableStore().remove(Unit.class);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Checks whether it is allowed to store other data than those provided via
+	 * related {@link ValueList}.
+	 *
+	 * @return Returns {@code false} if it is allowed to store other values then
+	 *         those provided.
+	 */
+	public Boolean isValueListReference() {
+		boolean valueListReference = getValue(ATTR_VALUE_LIST_REFERENCE).extract();
+		return valueListReference && getValueList().isPresent();
+	}
+
+	/**
+	 * Sets a new value reference flag for this catalog attribute.
+	 *
+	 * @param valueListReference The new value list reference flag.
+	 */
+	public void setValueListReference(Boolean valueListReference) {
+		getValue(ATTR_VALUE_LIST_REFERENCE).set(valueListReference);
+	}
+
+	/**
+	 * Checks whether it is allowed to copy the contained value in case of an
+	 * associated descriptive component is copied.
+	 *
+	 * @return Returns {@code true} if it allowed to copy a contained value.
+	 */
+	public Boolean isValueCopyable() {
+		return getValue(ATTR_VALUE_COPYABLE).extract();
+	}
+
+	/**
+	 * Sets a new value copyable flag for this catalog attribute.
+	 *
+	 * @param valueCopyable The new value copyable flag.
+	 */
+	public void setValueCopyable(Boolean valueCopyable) {
+		getValue(ATTR_VALUE_COPYABLE).set(valueCopyable);
+	}
+
+	/**
+	 * Returns the action request class name of this catalog attribute.
+	 *
+	 * @return The action request class name is returned.
+	 */
+	public String getActionRequestClassname() {
+		return getValue(ATTR_ACTION_REQUEST_CLASSNAME).extract();
+	}
+
+	/**
+	 * Sets a new action request class name for this attribute.
+	 *
+	 * @param actionRequestClassname The new action request class name.
+	 */
+	public void setActionRequestClassname(String actionRequestClassname) {
+		getValue(ATTR_ACTION_REQUEST_CLASSNAME).set(actionRequestClassname);
+	}
+
+	/**
+	 * Returns the related {@link ValueList}.
+	 *
+	 * @return {@code Optional} is empty if no {@code ValueList} is related.
+	 */
+	public Optional<ValueList> getValueList() {
+		return Optional.ofNullable(getCore().getMutableStore().get(ValueList.class));
+	}
+
+	/**
+	 * Replaces current {@link ValueList} relation with the given one.
+	 *
+	 * @param valueList The new {@code ValueList} may be null.
+	 */
+	public void setValueList(ValueList valueList) {
+		if (valueList == null) {
+			getCore().getMutableStore().remove(ValueList.class);
+			setValueListReference(Boolean.FALSE);
+		} else {
+			getCore().getMutableStore().set(valueList);
+		}
+	}
+
+	/**
+	 * Returns the parent {@link CatalogComponent}.
+	 *
+	 * @return {@code Optional} is empty if a {@link CatalogSensor} is parent of
+	 *         this catalog attribute.
+	 * @see #getCatalogSensor()
+	 */
+	public Optional<CatalogComponent> getCatalogComponent() {
+		return Optional.ofNullable(getCore().getPermanentStore().get(CatalogComponent.class));
+	}
+
+	/**
+	 * Returns the parent {@link CatalogSensor}.
+	 *
+	 * @return {@code Optional} is empty if a {@link CatalogComponent} is parent of
+	 *         this catalog attribute.
+	 * @see #getCatalogComponent()
+	 */
+	public Optional<CatalogSensor> getCatalogSensor() {
+		return Optional.ofNullable(getCore().getPermanentStore().get(CatalogSensor.class));
+	}
+
+	/**
+	 * Returns the virtual and unmodifiable {@link ValueType} of this catalog
+	 * attribute.
+	 *
+	 * @return The {@code ValueType} is returned.
+	 */
+	public ValueType<?> getValueType() {
+		ScalarType scalarType = scalarTypeValue.extract();
+		Boolean sequence = sequenceValue.extract();
+		return sequence.booleanValue() ? scalarType.toValueType() : scalarType.toSingleValueType();
+	}
+
+	/**
+	 * Returns the virtual and unmodifiable enumeration class of this catalog
+	 * attribute.
+	 *
+	 * @return The enumeration class is returned.
+	 * @throws IllegalStateException Thrown if this catalog attribute's
+	 *                               {@link ValueType} returns {@code true} when
+	 *                               {@link ValueType#isEnumerationType()} is
+	 *                               called.
+	 */
+	@SuppressWarnings("rawtypes")
+	public Enumeration getEnumerationObject() {
+		if (!getValueType().isEnumerationType()) {
+			throw new IllegalStateException("Catalog attribute is not of type enumeration.");
+		}
+		return enumerationObj;
+	}
+
+	/**
+	 * Returns the {@link Unit} of this catalog attribute.
+	 *
+	 * @return {@code Optional} is empty if no unit is defined.
+	 */
+	public Optional<Unit> getUnit() {
+		return Optional.ofNullable(unit);
+	}
+
+	/**
+	 * Sets a new {@link Unit} for this catalog attribute.
+	 *
+	 * @param unit The new {@code Unit} may be null.
+	 */
+	public void setUnit(Unit unit) {
+		this.unit = unit;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+
+		ScalarType scalarType = scalarTypeValue.extract();
+		sb.append("ScalarType = ").append(scalarType);
+		if (scalarType.isEnumeration()) {
+			sb.append(", EnumerationObject = ").append(getEnumerationObject());
+		}
+
+		sb.append(", Sequence = ").append((boolean) sequenceValue.extract());
+
+		Optional<Unit> catalogUnit = getUnit();
+		if (catalogUnit.isPresent()) {
+			sb.append(", Unit = ").append(catalogUnit.get());
+		}
+
+		sb.append(", ").append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		return sb.append(')').toString();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Sets {@link ValueType} of this catalog attribute.
+	 *
+	 * @param valueType The {@link ValueType}.
+	 */
+	void setValueType(ValueType<?> valueType) {
+		Enumeration<?> scalarTypeEnum = EnumRegistry.getInstance().get(EnumRegistry.SCALAR_TYPE);
+		scalarTypeValue.set(scalarTypeEnum.valueOf(valueType.toSingleType().name()));
+		sequenceValue.set(valueType.isSequence());
+	}
+
+	/**
+	 * Sets enumeration Object of this catalog attribute.
+	 *
+	 * @param enumerationObj The enumeration.
+	 */
+	void setEnumerationObj(Enumeration<?> enumerationObj) {
+		setValueType(ValueType.ENUMERATION);
+		this.enumerationObj = enumerationObj;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogComponent.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogComponent.java
new file mode 100644
index 0000000..f91dc18
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogComponent.java
@@ -0,0 +1,192 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the catalog component entity type. A catalog component acts
+ * as a container to store context data ("as measured", "as ordered"). Each
+ * catalog component has a corresponding entity type whose name is equal to the
+ * name of the catalog component. Therefore the name of a catalog component has
+ * to be unique and is not allowed to be modified, once written. A catalog
+ * component consists of {@link CatalogAttribute} which describe the attributes
+ * of this container. In case of {@link ContextType#TESTEQUIPMENT} it may have
+ * {@link CatalogSensor}s which describe the available measurement sensors.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogAttribute
+ * @see CatalogSensor
+ */
+public class CatalogComponent extends BaseEntity implements Datable, Deletable, Describable {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ContextType contextType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	CatalogComponent(Core core) {
+		super(core);
+
+		String typeName = core.getTypeName().toUpperCase(Locale.ROOT);
+		for (ContextType contextTypeCandidate : ContextType.values()) {
+			if (typeName.contains(contextTypeCandidate.name())) {
+				contextType = contextTypeCandidate;
+				return;
+			}
+		}
+
+		throw new IllegalStateException("Core is incompatible.");
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextType} of this catalog component.
+	 *
+	 * @return The {@code ContextType} is returned.
+	 */
+	public ContextType getContextType() {
+		return contextType;
+	}
+
+	/**
+	 * Returns the {@link CatalogAttribute} identified by given name.
+	 *
+	 * @param name The name of the {@code CatalogAttribute}.
+	 * @return The {@code Optional} is empty if a {@code CatalogAttribute} with
+	 *         given name does not exist.
+	 */
+	public Optional<CatalogAttribute> getCatalogAttribute(String name) {
+		return getCatalogAttributes().stream().filter(ca -> ca.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link CatalogAttribute}s related to this catalog
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<CatalogAttribute> getCatalogAttributes() {
+		return getCore().getChildrenStore().get(CatalogAttribute.class);
+	}
+
+	/**
+	 * Removes the {@link CatalogAttribute} identified by given name.
+	 *
+	 * @param name Name of the {@code CatalogAttribute} that has to be removed.
+	 * @return Returns {@code true} if the {@code CatalogAttribute} with given name
+	 *         has been removed.
+	 */
+	public boolean removeCatalogAttribute(String name) {
+		Optional<CatalogAttribute> catalogAttribute = getCatalogAttribute(name);
+		if (catalogAttribute.isPresent()) {
+			getCore().getChildrenStore().remove(catalogAttribute.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns the {@link CatalogSensor} identified by given name.
+	 *
+	 * @param name The name of the {@code CatalogSensor}.
+	 * @return The {@code Optional} is empty if a {@code CatalogSensor} with given
+	 *         name does not exist.
+	 */
+	public Optional<CatalogSensor> getCatalogSensor(String name) {
+		return getCatalogSensors().stream().filter(cs -> cs.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link CatalogSensor}s related to this catalog
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<CatalogSensor> getCatalogSensors() {
+		if (contextType.isTestEquipment()) {
+			return getCore().getChildrenStore().get(CatalogSensor.class);
+		}
+
+		return Collections.emptyList();
+	}
+
+	/**
+	 * Removes the {@link CatalogSensor} identified by given name.
+	 *
+	 * @param name Name of the {@code CatalogSensor} that has to be removed.
+	 * @return Returns {@code true} if the {@code CatalogSensor} with given name has
+	 *         been removed.
+	 */
+	public boolean removeCatalogSensor(String name) {
+		Optional<CatalogSensor> catalogSensor = getCatalogSensor(name);
+		if (catalogSensor.isPresent()) {
+			getCore().getChildrenStore().remove(catalogSensor.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append("ContextType = ").append(getContextType()).append(", ");
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<CatalogAttribute> catalogAttributes = getCatalogAttributes();
+		if (!catalogAttributes.isEmpty()) {
+			sb.append(", CatalogAttributes = ").append(catalogAttributes);
+		}
+
+		List<CatalogSensor> catalogSensors = getCatalogSensors();
+		if (!catalogSensors.isEmpty()) {
+			sb.append(", CatalogSensors = ").append(catalogSensors);
+		}
+
+		return sb.append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogSensor.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogSensor.java
new file mode 100644
index 0000000..d365abd
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogSensor.java
@@ -0,0 +1,126 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the catalog sensor entity type. A catalog sensor acts as a
+ * container to store sensor context data ("as measured", "as ordered"). It
+ * always belongs to a {@link CatalogComponent} of type
+ * {@link ContextType#TESTEQUIPMENT}. Each catalog sensor has a corresponding
+ * entity type whose name is equal to the name of the catalog sensor. Therefore
+ * the name of a catalog sensor has to be unique and is not allowed to be
+ * modified, once written. A catalog sensor consists of {@link CatalogAttribute}
+ * which describe the attributes of this container.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogComponent
+ * @see CatalogComponent
+ */
+public class CatalogSensor extends BaseEntity implements Datable, Deletable, Describable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	CatalogSensor(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the parent {@link CatalogComponent}.
+	 *
+	 * @return The parent {@code CatalogComponent} is returned.
+	 */
+	public CatalogComponent getCatalogComponent() {
+		return getCore().getPermanentStore().get(CatalogComponent.class);
+	}
+
+	/**
+	 * Returns the {@link CatalogAttribute} identified by given name.
+	 *
+	 * @param name The name of the {@code CatalogAttribute}.
+	 * @return The {@code Optional} is empty if a {@code CatalogAttribute} with
+	 *         given name does not exist.
+	 */
+	public Optional<CatalogAttribute> getCatalogAttribute(String name) {
+		return getCatalogAttributes().stream().filter(ca -> ca.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link CatalogAttribute}s related to this catalog
+	 * sensor.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<CatalogAttribute> getCatalogAttributes() {
+		return getCore().getChildrenStore().get(CatalogAttribute.class);
+	}
+
+	/**
+	 * Removes the {@link CatalogAttribute} identified by given name.
+	 *
+	 * @param name Name of the {@code CatalogAttribute} that has to be removed.
+	 * @return Returns {@code true} if the {@code CatalogAttribute} with given name
+	 *         has been removed.
+	 */
+	public boolean removeCatalogAttribute(String name) {
+		Optional<CatalogAttribute> catalogAttribute = getCatalogAttribute(name);
+		if (catalogAttribute.isPresent()) {
+			getCore().getChildrenStore().remove(catalogAttribute.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<CatalogAttribute> catalogAttributes = getCatalogAttributes();
+		if (!catalogAttributes.isEmpty()) {
+			sb.append(", CatalogAttributes = ").append(catalogAttributes);
+		}
+
+		return sb.append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Classification.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Classification.java
new file mode 100644
index 0000000..6cb91ff
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Classification.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+
+public class Classification extends BaseEntity {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Classification(Core core) {
+		super(core);
+	}
+
+	/**
+	 * Assigns this status to given {@link StatusAttachable}s.
+	 *
+	 * @param <T>               The status attachable type.
+	 * @param statusAttachables This status will be assigned to all of them.
+	 */
+	public <T extends StatusAttachable> void assign(List<T> statusAttachables) {
+		statusAttachables.forEach(this::assign);
+	}
+
+	/**
+	 * Assigns this status to given {@link StatusAttachable}.
+	 *
+	 * @param <T>              The status attachable type.
+	 * @param statusAttachable This status will be assigned to it.
+	 */
+	public <T extends StatusAttachable> void assign(T statusAttachable) {
+		getCore(statusAttachable).getMutableStore().set(this);
+	}
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Domain.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Domain.java
new file mode 100644
index 0000000..f31fcdd
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Domain.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Describable;
+
+public class Domain extends BaseEntity implements Describable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Domain(Core core) {
+		super(core);
+	}
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/EntityFactory.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/EntityFactory.java
new file mode 100644
index 0000000..d18d760
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/EntityFactory.java
@@ -0,0 +1,1244 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextSensor;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Quantity;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.model.VersionState;
+
+/**
+ * Creates new entities of the default application model.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public abstract class EntityFactory extends BaseEntityFactory {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link Role}.
+	 *
+	 * @param name Name of the created {@code Role}.
+	 * @return The created {@code Role} is returned.
+	 */
+	public Role createRole(String name) {
+		Role role = new Role(createCore(Role.class));
+
+		// properties
+		role.setName(name);
+
+		return role;
+	}
+
+	/**
+	 * Always throws an UnsupportedOperationException since in a default model each
+	 * {@link Test} has a parent {@link Pool}.
+	 *
+	 * @throws UnsupportedOperationException Is always thrown.
+	 */
+	@Override
+	public Test createTest(String name) {
+		throw new UnsupportedOperationException("Test requires a parent Pool.");
+	}
+
+	/**
+	 * Creates a new {@link Project}.
+	 *
+	 * @param name Name of the created {@code Project}.
+	 * @return The created {@code Project} is returned.
+	 */
+	public Project createProject(String name) {
+		Project project = new Project(createCore(Project.class));
+
+		// properties
+		project.setName(name);
+
+		return project;
+	}
+
+	/**
+	 * Creates a new {@link Pool} for given {@link Project}.
+	 *
+	 * @param name    Name of the created {@code Pool}.
+	 * @param project The parent {@code Project}.
+	 * @return The created {@code Pool} is returned.
+	 */
+	public Pool createPool(String name, Project project) {
+		Pool pool = new Pool(createCore(Pool.class));
+
+		// relations
+		getCore(pool).getPermanentStore().set(project);
+		getCore(project).getChildrenStore().add(pool);
+
+		// properties
+		pool.setName(name);
+
+		return pool;
+	}
+
+	/**
+	 * Creates a new {@link Test} for given {@link Pool}.
+	 *
+	 * @param name Name of the created {@code Test}.
+	 * @param pool The parent {@code Pool}.
+	 * @return The created {@code Test} is returned.
+	 */
+	public Test createTest(String name, Pool pool) {
+		return createTest(name, pool, (Status) null);
+	}
+
+	/**
+	 * Creates a new {@link Test} for given {@link Pool} using given
+	 * {@link TemplateTest}.
+	 *
+	 * @param name         Name of the created {@code Test}.
+	 * @param pool         The parent {@code Pool}.
+	 * @param templateTest The template the returned {@code Test} will be derived
+	 *                     from.
+	 * @return The created {@code Test} is returned.
+	 */
+	// TODO make a decision: status in or out!
+	public Test createTest(String name, Pool pool, TemplateTest templateTest) {
+		return createTest(name, pool, null, null, templateTest);
+	}
+
+	/**
+	 * Creates a new {@link ContextRoot} for given {@link TestStep} using given
+	 * {@link TemplateRoot}.
+	 *
+	 * @param testStep     The parent {@code TestStep}.
+	 * @param templateRoot The template the returned {@code ContextRoot} will be
+	 *                     derived from.
+	 * @return The created {@code ContextRoot} is returned.
+	 */
+	public ContextRoot createContextRoot(TestStep testStep, TemplateRoot templateRoot) {
+		ContextRoot contextRoot = createContextRoot(templateRoot);
+
+		// relations
+		getCore(testStep).getMutableStore().set(contextRoot, templateRoot.getContextType());
+
+		return contextRoot;
+	}
+
+	/**
+	 * Creates a new {@link ContextRoot} for given {@link Measurement} using given
+	 * {@link TemplateRoot}.
+	 *
+	 * @param measurement  The parent {@code Measurement}.
+	 * @param templateRoot The template the returned {@code ContextRoot} will be
+	 *                     derived from.
+	 * @return The created {@code ContextRoot} is returned.
+	 */
+	public ContextRoot createContextRoot(Measurement measurement, TemplateRoot templateRoot) {
+		return createContextRoot(Arrays.asList(measurement), templateRoot);
+	}
+
+	/**
+	 * Creates a new {@link ContextRoot} for given {@link List} if
+	 * {@link Measurement}s using given {@link TemplateRoot}. If List is null or
+	 * empty context root is created with no relations.
+	 *
+	 * @param measurements The parent {@code Measurement}.
+	 * @param templateRoot The template the returned {@code ContextRoot} will be
+	 *                     derived from.
+	 * @return The created {@code ContextRoot} is returned.
+	 */
+	public ContextRoot createContextRoot(List<Measurement> measurements, TemplateRoot templateRoot) {
+		ContextRoot contextRoot = createContextRoot(templateRoot);
+
+		// relations
+		if (measurements != null && !measurements.isEmpty()) {
+			measurements.forEach(m -> getCore(m).getMutableStore().set(contextRoot, templateRoot.getContextType()));
+		}
+
+		return contextRoot;
+	}
+
+	/**
+	 * Creates a new {@link ContextRoot} using given {@link TemplateRoot}.
+	 *
+	 * @param templateRoot The template the returned {@code ContextRoot} will be
+	 *                     derived from.
+	 * @return The created {@code ContextRoot} is returned.
+	 */
+	public ContextRoot createContextRoot(TemplateRoot templateRoot) {
+		ContextRoot contextRoot = createContextRoot(templateRoot.getName(), templateRoot.getContextType());
+
+		// relations
+		getCore(contextRoot).getMutableStore().set(templateRoot);
+
+		// create default active and mandatory context components
+		templateRoot.getTemplateComponents().stream()
+				.filter(TemplateComponent.IS_DEFAULT_ACTIVE.or(TemplateComponent.IS_MANDATORY))
+				.forEach(templateComponent -> {
+					createContextComponent(templateComponent.getName(), contextRoot);
+				});
+
+		return contextRoot;
+	}
+
+	/**
+	 * @throws IllegalArgumentException Thrown if given name is already in use or
+	 *                                  {@link TemplateComponent} with given name
+	 *                                  does not exist.
+	 */
+	@Override
+	public ContextComponent createContextComponent(String name, ContextRoot contextRoot) {
+		if (contextRoot.getContextComponent(name).isPresent()) {
+			throw new IllegalArgumentException("Context component with name '" + name + "' already exists.");
+		}
+
+		TemplateRoot templateRoot = TemplateRoot.of(contextRoot)
+				.orElseThrow(() -> new IllegalArgumentException("Template root is not available."));
+
+		Optional<TemplateComponent> templateComponent = templateRoot.getTemplateComponent(name);
+		if (templateComponent.isPresent()) {
+			// recursively create missing parent context components
+			templateComponent.get().getParentTemplateComponent()
+					.filter(tc -> !contextRoot.getContextComponent(tc.getName()).isPresent())
+					.ifPresent(tc -> createContextComponent(tc.getName(), contextRoot));
+
+			// create context component if not already done
+			if (!contextRoot.getContextComponent(name).isPresent()) {
+				ContextComponent contextComponent = super.createContextComponent(
+						templateComponent.get().getCatalogComponent().getName(), contextRoot);
+
+				// relations
+				getCore(contextComponent).getMutableStore().set(templateComponent.get());
+
+				// properties
+				contextComponent.setName(name);
+				contextComponent
+						.setMimeType(contextComponent.getMimeType().addSubType(templateComponent.get().getName()));
+				hideValues(getCore(contextComponent), templateComponent.get().getTemplateAttributes());
+				templateComponent.get().getTemplateAttributes().forEach(ta -> {
+					contextComponent.getValue(ta.getName()).set(ta.getDefaultValue().extract());
+				});
+
+				// create default active and mandatory child context components
+				templateComponent.get().getTemplateComponents().stream().filter(TemplateComponent.IS_IMPLICIT_CREATE)
+						.forEach(childTemplateComponent -> {
+							createContextComponent(childTemplateComponent.getName(), contextRoot);
+						});
+
+				// create default active and mandatory context sensors
+				templateComponent.get().getTemplateSensors().stream().filter(TemplateSensor.IS_IMPLICIT_CREATE)
+						.forEach(templateSensor -> {
+							createContextSensor(templateSensor.getName(), contextComponent);
+						});
+
+				return contextComponent;
+			}
+		}
+
+		throw new IllegalArgumentException("Template component with name '" + name + "' does not exist.");
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public ContextSensor createContextSensor(String name, ContextComponent contextComponent) {
+		if (contextComponent.getContextSensor(name).isPresent()) {
+			throw new IllegalArgumentException("Context sensor with name '" + name + "' already exists.");
+		}
+
+		TemplateComponent templateComponent = TemplateComponent.of(contextComponent)
+				.orElseThrow(() -> new IllegalArgumentException("Template component is not available."));
+
+		Optional<TemplateSensor> templateSensor = templateComponent.getTemplateSensor(name);
+		if (templateSensor.isPresent()) {
+			ContextSensor contextSensor = super.createContextSensor(templateSensor.get().getCatalogSensor().getName(),
+					contextComponent);
+
+			// relations
+			getCore(contextSensor).getMutableStore().set(templateSensor.get());
+
+			// properties
+			contextSensor.setName(name);
+			hideValues(getCore(contextSensor), templateSensor.get().getTemplateAttributes());
+			templateSensor.get().getTemplateAttributes().forEach(ta -> {
+				contextSensor.getValue(ta.getName()).set(ta.getDefaultValue().extract());
+			});
+
+			return contextSensor;
+		}
+
+		throw new IllegalArgumentException("Template sensor with name '" + name + "' does not exist.");
+	}
+
+	/**
+	 * Creates a new {@link CatalogComponent} with given {@link ContextType} and
+	 * name.
+	 *
+	 * @param contextType The {@code ContextType}.
+	 * @param name        Name of the created {@code CatalogComponent}.
+	 * @return The created {@code CatalogComponent} is returned.
+	 * @throws IllegalArgumentException Thrown if name is not allowed.
+	 */
+	public CatalogComponent createCatalogComponent(ContextType contextType, String name) {
+		validateCatalogName(name, false);
+
+		CatalogComponent catalogComponent = new CatalogComponent(createCore(CatalogComponent.class, contextType));
+
+		// properties
+		catalogComponent.setName(name);
+		catalogComponent.setDateCreated(LocalDateTime.now());
+		catalogComponent.getValue("ValidFlag").set(VersionState.VALID);
+
+		return catalogComponent;
+	}
+
+	/**
+	 * Creates a new {@link CatalogAttribute} for given {@link CatalogComponent}.
+	 * The {@link ValueType} may be one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link ValueType#STRING}</li>
+	 * <li>{@link ValueType#STRING_SEQUENCE}</li>
+	 * <li>{@link ValueType#DATE}</li>
+	 * <li>{@link ValueType#DATE_SEQUENCE}</li>
+	 * <li>{@link ValueType#BOOLEAN}</li>
+	 * <li>{@link ValueType#BOOLEAN_SEQUENCE}</li>
+	 * <li>{@link ValueType#BYTE}</li>
+	 * <li>{@link ValueType#BYTE_SEQUENCE}</li>
+	 * <li>{@link ValueType#SHORT}</li>
+	 * <li>{@link ValueType#SHORT_SEQUENCE}</li>
+	 * <li>{@link ValueType#INTEGER}</li>
+	 * <li>{@link ValueType#INTEGER_SEQUENCE}</li>
+	 * <li>{@link ValueType#LONG}</li>
+	 * <li>{@link ValueType#LONG_SEQUENCE}</li>
+	 * <li>{@link ValueType#FLOAT}</li>
+	 * <li>{@link ValueType#FLOAT_SEQUENCE}</li>
+	 * <li>{@link ValueType#DOUBLE}</li>
+	 * <li>{@link ValueType#DOUBLE_SEQUENCE}</li>
+	 * <li>{@link ValueType#BYTE_STREAM}</li>
+	 * <li>{@link ValueType#BYTE_STREAM_SEQUENCE}</li>
+	 * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+	 * <li>{@link ValueType#FLOAT_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+	 * <li>{@link ValueType#DOUBLE_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link ValueType#FILE_LINK}</li>
+	 * <li>{@link ValueType#FILE_LINK_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 *
+	 * @param name             Name of the created {@code CatalogAttribute}.
+	 * @param valueType        The {@code ValueType}.
+	 * @param catalogComponent The parent {@code CatalogComponent}.
+	 * @return The created {@code CatalogAttribute} is returned.
+	 * @throws IllegalArgumentException Thrown if given name is already in use or
+	 *                                  not allowed or given {@code ValueType} is
+	 *                                  not supported.
+	 */
+	public CatalogAttribute createCatalogAttribute(String name, ValueType<?> valueType,
+			CatalogComponent catalogComponent) {
+		validateCatalogName(name, true);
+
+		if (catalogComponent.getCatalogAttribute(name).isPresent()) {
+			throw new IllegalArgumentException("Catalog attribute with name '" + name + "' already exists.");
+		} else if (valueType.isEnumerationType() || valueType.isByteStreamType() || valueType.isUnknown()
+				|| valueType.isBlob()) {
+			throw new IllegalArgumentException("Value type '" + valueType + "' is not allowed.");
+		}
+
+		CatalogAttribute catalogAttribute = new CatalogAttribute(
+				createCore(CatalogAttribute.class, catalogComponent.getContextType()));
+
+		// relations
+		getCore(catalogAttribute).getPermanentStore().set(catalogComponent);
+		getCore(catalogComponent).getChildrenStore().add(catalogAttribute);
+
+		// properties
+		catalogAttribute.setName(name);
+		catalogAttribute.setValueType(valueType);
+		catalogAttribute.setSortIndex(nextIndex(catalogComponent.getCatalogAttributes()));
+
+		return catalogAttribute;
+	}
+
+	/**
+	 * Creates a new {@link CatalogAttribute} for given {@link CatalogComponent}.
+	 *
+	 * @param name              Name of the created {@code CatalogAttribute}.
+	 * @param enumerationObject The enumeration.
+	 * @param catalogComponent  The parent {@code CatalogComponent}.
+	 * @return The created {@code CatalogAttribute} is returned.
+	 * @throws IllegalArgumentException Thrown if given name is already in use or
+	 *                                  not allowed or given enumeration class is
+	 *                                  not supported.
+	 */
+	public CatalogAttribute createCatalogAttribute(String name, Enumeration<?> enumerationObj,
+			CatalogComponent catalogComponent) {
+		validateCatalogName(name, true);
+		validateEnum(enumerationObj);
+		if (catalogComponent.getCatalogAttribute(name).isPresent()) {
+			throw new IllegalArgumentException("Catalog attribute with name '" + name + "' already exists.");
+		}
+
+		CatalogAttribute catalogAttribute = new CatalogAttribute(
+				createCore(CatalogAttribute.class, catalogComponent.getContextType()));
+
+		// relations
+		getCore(catalogAttribute).getPermanentStore().set(catalogComponent);
+		getCore(catalogComponent).getChildrenStore().add(catalogAttribute);
+
+		// properties
+		catalogAttribute.setName(name);
+		catalogAttribute.setEnumerationObj(enumerationObj);
+		catalogAttribute.setSortIndex(nextIndex(catalogComponent.getCatalogAttributes()));
+
+		return catalogAttribute;
+	}
+
+	/**
+	 * Creates a new {@link CatalogAttribute} for given {@link CatalogSensor}. The
+	 * {@link ValueType} may be one of the following like in
+	 * {@link #createCatalogAttribute(String, ValueType, CatalogComponent)}:
+	 *
+	 * @param name          Name of the created {@code CatalogAttribute}.
+	 * @param valueType     The {@code ValueType}.
+	 * @param catalogSensor The parent {@code CatalogSensor}.
+	 * @return The created {@code CatalogAttribute} is returned.
+	 * @throws IllegalArgumentException Thrown if given name is already in use or
+	 *                                  not allowed or given {@code ValueType} is
+	 *                                  not supported.
+	 */
+	public CatalogAttribute createCatalogSensorAttribute(String name, ValueType<?> valueType,
+			CatalogSensor catalogSensor) {
+		validateCatalogName(name, true);
+
+		if (catalogSensor.getCatalogAttribute(name).isPresent()) {
+			throw new IllegalArgumentException("CatalogSensor attribute with name '" + name + "' already exists.");
+		} else if (valueType.isEnumerationType() || valueType.isByteStreamType() || valueType.isUnknown()
+				|| valueType.isBlob()) {
+			throw new IllegalArgumentException("Value type '" + valueType + "' is not allowed.");
+		}
+
+		CatalogAttribute catalogAttribute = new CatalogAttribute(createCore(CatalogAttribute.class));
+
+		// relations
+		getCore(catalogAttribute).getPermanentStore().set(catalogSensor);
+		getCore(catalogSensor).getChildrenStore().add(catalogAttribute);
+
+		// properties
+		catalogAttribute.setName(name);
+		catalogAttribute.setValueType(valueType);
+		catalogAttribute.setSortIndex(nextIndex(catalogSensor.getCatalogAttributes()));
+
+		return catalogAttribute;
+	}
+
+	/**
+	 * Creates a new {@link CatalogSensor} for given {@link CatalogComponent}.
+	 *
+	 * @param name              Name of the created {@code CatalogSensor}.
+	 * @param enumerationObject The enumeration.
+	 * @param catalogComponent  The parent {@code CatalogComponent}.
+	 * @return The created {@code CatalogSensor} is returned.
+	 * @throws IllegalArgumentException Thrown if given name is already in use or
+	 *                                  not allowed
+	 */
+	public CatalogSensor createCatalogSensor(String name, CatalogComponent catalogComponent) {
+		validateCatalogName(name, false);
+
+		if (!catalogComponent.getContextType().isTestEquipment()) {
+			throw new IllegalArgumentException("Catalog component is not of type 'TESTEQUIPMENT'");
+		} else if (catalogComponent.getCatalogSensor(name).isPresent()) {
+			throw new IllegalArgumentException("Catalog sensor with name '" + name + "' already exists.");
+		}
+
+		CatalogSensor catalogSensor = new CatalogSensor(createCore(CatalogSensor.class));
+
+		// relations
+		getPermanentStore(catalogSensor).set(catalogComponent);
+		getChildrenStore(catalogComponent).add(catalogSensor);
+
+		// properties
+		catalogSensor.setName(name);
+		catalogSensor.setDateCreated(LocalDateTime.now());
+
+		return catalogSensor;
+	}
+
+	/**
+	 * Creates a new {@link TemplateRoot} with given {@link ContextType} and name.
+	 *
+	 * @param contextType The {@code ContextType}.
+	 * @param name        Name of the created {@code TemplateRoot}.
+	 * @return The created {@code TemplateRoot} is returned.
+	 */
+	public TemplateRoot createTemplateRoot(ContextType contextType, String name) {
+		TemplateRoot templateRoot = new TemplateRoot(createCore(TemplateRoot.class, contextType));
+
+		// properties
+		templateRoot.setName(name);
+		templateRoot.setDateCreated(LocalDateTime.now());
+		templateRoot.setVersionState(VersionState.EDITABLE);
+		templateRoot.setVersion(Integer.valueOf(1));
+
+		return templateRoot;
+	}
+
+	/**
+	 * Creates a new {@link TemplateComponent} for given {@link TemplateRoot} using
+	 * given {@link CatalogComponent}.
+	 *
+	 * @param name             Name of the created {@code TemplateComponent}.
+	 * @param templateRoot     The parent {@code TemplateRoot}.
+	 * @param catalogComponent The associated {@link CatalogComponent}.
+	 * @return The created {@code TemplateComponent} is returned.
+	 * @throws IllegalArgumentException Thrown if {@code ContextType} of {@code
+	 * 		TemplateRoot}            and {@code CatalogComponent} do not match or
+	 *                                  given name is already in use.
+	 */
+	public TemplateComponent createTemplateComponent(String name, TemplateRoot templateRoot,
+			CatalogComponent catalogComponent) {
+		if (!templateRoot.getContextType().equals(catalogComponent.getContextType())) {
+			throw new IllegalArgumentException("Context type of template root and catalog component do not match.");
+		} else if (templateRoot.getTemplateComponent(name).isPresent()) {
+			throw new IllegalArgumentException("Template component with name '" + name + "' already exists.");
+		}
+
+		TemplateComponent templateComponent = new TemplateComponent(
+				createCore(TemplateComponent.class, templateRoot.getContextType()));
+
+		// relations
+		getCore(templateComponent).getPermanentStore().set(templateRoot);
+		getCore(templateComponent).getMutableStore().set(catalogComponent);
+		getCore(templateRoot).getChildrenStore().add(templateComponent);
+
+		// properties
+		templateComponent.setName(name);
+		templateComponent.setOptional(Boolean.TRUE);
+		templateComponent.setDefaultActive(Boolean.TRUE);
+		templateComponent.setSeriesConstant(Boolean.TRUE);
+		templateComponent.setSortIndex(nextIndex(templateRoot.getTemplateComponents()));
+
+		// create template attributes
+		catalogComponent.getCatalogAttributes().forEach(ca -> createTemplateAttribute(ca.getName(), templateComponent));
+
+		return templateComponent;
+	}
+
+	/**
+	 * Creates a new {@link TemplateComponent} for given {@link TemplateComponent}
+	 * using given {@link CatalogComponent}.
+	 *
+	 * @param name                     Name of the created
+	 *                                 {@code TemplateComponent}.
+	 * @param partentComponentTemplate The parent {@code TemplateComponent}.
+	 * @param catalogComponent         The associated {@link CatalogComponent}.
+	 * @return The created {@code TemplateComponent} is returned.
+	 * @throws IllegalArgumentException Thrown if {@code ContextType} of {@code
+	 * 		TemplateComponent}       and {@code CatalogComponent} do not match or
+	 *                                  given name is already in use.
+	 */
+	public TemplateComponent createTemplateComponent(String name, TemplateComponent partentComponentTemplate,
+			CatalogComponent catalogComponent) {
+		TemplateRoot templateRoot = partentComponentTemplate.getTemplateRoot();
+		if (!templateRoot.getContextType().equals(catalogComponent.getContextType())) {
+			throw new IllegalArgumentException("Context type of template root and catalog component do not match.");
+		} else if (templateRoot.getTemplateComponent(name).isPresent()) {
+			throw new IllegalArgumentException("Template component with name '" + name + "' already exists.");
+		}
+
+		TemplateComponent templateComponent = new TemplateComponent(
+				createCore(TemplateComponent.class, templateRoot.getContextType()));
+
+		// relations
+		getCore(templateComponent).getPermanentStore().set(partentComponentTemplate);
+		getCore(templateComponent).getMutableStore().set(catalogComponent);
+		getCore(partentComponentTemplate).getChildrenStore().add(templateComponent);
+
+		// properties
+		templateComponent.setName(name);
+		templateComponent.setOptional(Boolean.TRUE);
+		templateComponent.setDefaultActive(Boolean.TRUE);
+		templateComponent.setSeriesConstant(Boolean.TRUE);
+		templateComponent.setSortIndex(nextIndex(partentComponentTemplate.getTemplateComponents()));
+
+		// create template attributes
+		catalogComponent.getCatalogAttributes().forEach(ca -> createTemplateAttribute(ca.getName(), templateComponent));
+
+		return templateComponent;
+	}
+
+	/**
+	 * Creates a new {@link TemplateAttribute} for given {@link TemplateComponent}.
+	 *
+	 * @param name              Name of the created {@code TemplateAttribute}.
+	 * @param templateComponent The parent {@code TemplateComponent}.
+	 * @return The created {@code TemplateAttribute} is returned.
+	 * @throws IllegalArgumentException Thrown if given name is already in use.
+	 */
+	public TemplateAttribute createTemplateAttribute(String name, TemplateComponent templateComponent) {
+		if (templateComponent.getTemplateAttribute(name).isPresent()) {
+			throw new IllegalArgumentException("Template attribute with name '" + name + "' already exists.");
+		}
+
+		CatalogComponent catalogComponent = templateComponent.getCatalogComponent();
+		Optional<CatalogAttribute> catalogAttribute = catalogComponent.getCatalogAttribute(name);
+		if (catalogAttribute.isPresent()) {
+			TemplateAttribute templateAttribute = new TemplateAttribute(
+					createCore(TemplateAttribute.class, catalogComponent.getContextType()));
+
+			// relations
+			getCore(templateAttribute).getPermanentStore().set(templateComponent);
+			getCore(templateAttribute).getMutableStore().set(catalogAttribute.get());
+			getCore(templateComponent).getChildrenStore().add(templateAttribute);
+
+			// properties
+			templateAttribute.setName(name);
+			templateAttribute.setValueReadOnly(Boolean.FALSE);
+			templateAttribute.setOptional(Boolean.TRUE);
+
+			return templateAttribute;
+		}
+
+		throw new IllegalArgumentException("Catalog attribute with name '" + name + "' does not exists.");
+	}
+
+	/**
+	 * Creates a new {@link TemplateSensor} for given {@link TemplateComponent}
+	 * based on the given {@link CatalogSensor}.
+	 *
+	 * @param name              Name of the created {@code TemplateAttribute}.
+	 * @param templateComponent The parent {@code TemplateComponent}.
+	 * @param catalogSensor     reference CatalogSensor
+	 * @param quantity          Quantity to create {@link TemplateSensor} for
+	 * @return The created {@code TemplateSensor} is returned.
+	 * @throws IllegalArgumentException Thrown if given name is already in use.
+	 */
+	public TemplateSensor createTemplateSensor(String name, TemplateComponent templateComponent,
+			CatalogSensor catalogSensor, Quantity quantity) {
+		if (templateComponent.getTemplateSensor(name).isPresent()) {
+			throw new IllegalArgumentException("Template sensor with name '" + name + "' already exists.");
+		}
+
+		if (catalogSensor != null) {
+			TemplateSensor templateSensor = new TemplateSensor(createCore(TemplateSensor.class));
+			// create all implicit TemplateAttributes
+			for (CatalogAttribute catAttr : catalogSensor.getCatalogAttributes()) {
+				TemplateAttribute tplAttr = new TemplateAttribute(createCore(TemplateAttribute.class));
+				tplAttr.setName(catAttr.getName());
+				tplAttr.setValueReadOnly(Boolean.FALSE);
+				tplAttr.setOptional(Boolean.TRUE);
+				getPermanentStore(tplAttr).set(templateSensor);
+				getMutableStore(tplAttr).set(catAttr);
+				getCore(templateSensor).getChildrenStore().add(tplAttr);
+			}
+
+			// relations
+			getPermanentStore(templateSensor).set(templateComponent);
+			getMutableStore(templateSensor).set(catalogSensor);
+			getMutableStore(templateSensor).set(quantity);
+			getChildrenStore(templateComponent).add(templateSensor);
+
+			// properties
+			templateSensor.setName(name);
+			templateSensor.setDefaultActive(true);
+			templateSensor.setOptional(Boolean.TRUE);
+
+			return templateSensor;
+		}
+
+		throw new IllegalArgumentException("Catalog attribute with name '" + name + "' does not exists.");
+	}
+
+	/**
+	 * Creates a new {@link TemplateTestStep}.
+	 *
+	 * @param name Name of the created {@code TemplateTestStep}.
+	 * @return The created {@code TemplateTestStep} is returned.
+	 */
+	public TemplateTestStep createTemplateTestStep(String name) {
+		TemplateTestStep templateTestStep = new TemplateTestStep(createCore(TemplateTestStep.class));
+
+		// properties
+		templateTestStep.setName(name);
+		templateTestStep.setDateCreated(LocalDateTime.now());
+		templateTestStep.setVersionState(VersionState.EDITABLE);
+		templateTestStep.setVersion(Integer.valueOf(1));
+
+		return templateTestStep;
+	}
+
+	/**
+	 * Creates a new {@link TemplateTest}.
+	 *
+	 * @param name Name of the created {@code TemplateTest}.
+	 * @return The created {@code TemplateTest} is returned.
+	 */
+	public TemplateTest createTemplateTest(String name) {
+		TemplateTest templateTest = new TemplateTest(createCore(TemplateTest.class));
+
+		// properties
+		templateTest.setName(name);
+		templateTest.setDateCreated(LocalDateTime.now());
+		templateTest.setVersion(Integer.valueOf(1));
+		templateTest.setVersionState(VersionState.EDITABLE);
+
+		return templateTest;
+	}
+
+	/**
+	 * Creates a new {@link TemplateTestStepUsage} for given {@link TemplateTest}
+	 * using given {@link TemplateTestStep}.
+	 *
+	 * @param name             Name of the created {@code TemplateTestStepUsage}.
+	 * @param templateTest     The parent {@link TemplateTest}.
+	 * @param templateTestStep The related {@link TemplateTestStep}.
+	 * @return The created {@code TemplateTestStepUsage} is returned.
+	 */
+	public TemplateTestStepUsage createTemplateTestStepUsage(String name, TemplateTest templateTest,
+			TemplateTestStep templateTestStep) {
+		if (templateTest.getTemplateTestStepUsage(name).isPresent()) {
+			throw new IllegalArgumentException("Template test step usage with name '" + name + "' already exists.");
+		}
+
+		TemplateTestStepUsage templateTestStepUsage = new TemplateTestStepUsage(
+				createCore(TemplateTestStepUsage.class));
+
+		// relations
+		getCore(templateTestStepUsage).getPermanentStore().set(templateTest);
+		getCore(templateTestStepUsage).getMutableStore().set(templateTestStep);
+		getCore(templateTest).getChildrenStore().add(templateTestStepUsage);
+
+		// properties
+		templateTestStepUsage.setName(name);
+		templateTestStepUsage.setOptional(Boolean.TRUE);
+		templateTestStepUsage.setDefaultActive(Boolean.TRUE);
+		templateTestStepUsage.setSortIndex(nextIndex(templateTest.getTemplateTestStepUsages()));
+
+		return templateTestStepUsage;
+	}
+
+	/**
+	 * Creates a new {@link ValueList}.
+	 *
+	 * @param name Name of the created {@code ValueList}.
+	 * @return The created {@code ValueList} is returned.
+	 */
+	public ValueList createValueList(String name) {
+		ValueList valueList = new ValueList(createCore(ValueList.class));
+
+		// properties
+		valueList.setName(name);
+		valueList.setDateCreated(LocalDateTime.now());
+
+		return valueList;
+	}
+
+	/**
+	 * Creates a new {@link ValueListValue} for given {@link ValueList}.
+	 *
+	 * @param name      Name of the created {@code ValueListValue}.
+	 * @param valueList The parent {@code ValueList}.
+	 * @return The created {@code ValueListValue} is returned.
+	 */
+	public ValueListValue createValueListValue(String name, ValueList valueList) {
+		if (valueList.getValueListValue(name).isPresent()) {
+			throw new IllegalArgumentException("Value list value with name '" + name + "' already exists.");
+		}
+
+		ValueListValue valueListValue = new ValueListValue(createCore(ValueListValue.class));
+
+		// relations
+		getCore(valueListValue).getPermanentStore().set(valueList);
+		getCore(valueList).getChildrenStore().add(valueListValue);
+
+		// properties
+		valueListValue.setName(name);
+		valueListValue.setSortIndex(nextIndex(valueList.getValueListValues()));
+
+		// this property is hidden by the public API and is not allowed to be
+		// modified!
+		valueListValue.getValue(ValueListValue.ATTR_SCALAR_TYPE).set(ScalarType.STRING);
+
+		return valueListValue;
+	}
+
+	/**
+	 * Creates a new {@link Classification} for given {@link Domain},
+	 * {@link ProjectDomain} and {@link Status}.
+	 * 
+	 * @param domain        The {@link Domain} for the {@link Classification}
+	 * @param projectDomain The {@link ProjectDomain} for the {@link Classification}
+	 * @param status        The {@link Status} for the {@link Classification}
+	 * @return The created {@link Classification} is returned.
+	 */
+	public Classification createClassification(Domain domain, ProjectDomain projectDomain, Status status) {
+		String name = String.format("ProjDomainId_%s.DomainId_%s.StatusId_%s", projectDomain.getID(), domain.getID(),
+				status.getID());
+		return createClassification(name, status, projectDomain, domain);
+	}
+
+	/**
+	 * Creates a new {@link Classification} for given {@link Domain},
+	 * {@link ProjectDomain} and {@link Status}.
+	 * 
+	 * @param name          The name for the {@link Classification}
+	 * @param status        The {@link Status} for the {@link Classification}
+	 * @param projectDomain The {@link ProjectDomain} for the {@link Classification}
+	 * @param domain        The {@link Domain} for the {@link Classification}
+	 * @return The created {@link Classification} is returned.
+	 */
+	public Classification createClassification(String name, Status status, ProjectDomain projectDomain, Domain domain) {
+		Classification classification = new Classification(createCore(Classification.class));
+
+		getMutableStore(classification).set(status);
+		getMutableStore(classification).set(projectDomain);
+		getMutableStore(classification).set(domain);
+
+		// properties
+		classification.setName(name);
+
+		return classification;
+	}
+
+	/**
+	 * Creates a new {@link ProjectDomain} with given name.
+	 * 
+	 * @param name Name of the {@link ProjectDomain}
+	 * @return The created {@link ProjectDomain} is returned.
+	 */
+	public ProjectDomain createProjectDomain(String name) {
+		ProjectDomain projectDomain = new ProjectDomain(createCore(ProjectDomain.class));
+		// properties
+		projectDomain.setName(name);
+		return projectDomain;
+	}
+
+	/**
+	 * Creates a new {@link Domain} with given name.
+	 * 
+	 * @param name Name of the {@link Domain}
+	 * @return The created {@link Domain} is returned.
+	 */
+	public Domain createDomain(String name) {
+		Domain domain = new Domain(createCore(Domain.class));
+
+		// properties
+		domain.setName(name);
+		return domain;
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link Test} for given {@link Pool} using given
+	 * {@link TemplateTest}.
+	 *
+	 * @param name           Name of the created {@code Test}.
+	 * @param pool           The parent {@code Pool}.
+	 * @param statusTest     The related {@link Status} of the created {@code
+	 * 		Test}         .
+	 * @param statusTestStep The related {@link Status} of the created {@code
+	 * 		TestStep}     .
+	 * @param templateTest   The template the returned {@code Test} will be derived
+	 *                       from.
+	 * @return The created {@code Test} is returned.
+	 */
+	// TODO make a decision: status in or out!
+	protected Test createTest(String name, Pool pool, Status statusTest, Status statusTestStep,
+			TemplateTest templateTest) {
+		Test test = createTest(name, pool, statusTest);
+
+		// relations
+		getCore(test).getMutableStore().set(templateTest);
+
+		// create default active and mandatory test steps according to the
+		// template
+		templateTest.getTemplateTestStepUsages().stream().filter(TemplateTestStepUsage.IS_IMPLICIT_CREATE)
+				.map(TemplateTestStepUsage::getTemplateTestStep).forEach(templateTestStep -> {
+					createTestStep(test, statusTestStep, templateTestStep);
+				});
+
+		return test;
+	}
+
+	/**
+	 * Creates a new {@link Test} for given {@link Pool} using given name,
+	 * {@link TemplateTest} and {@link Classification}.
+	 * 
+	 * @param name           Name of the created {@code Test}.
+	 * @param pool           The parent {@code Pool}.
+	 * @param templateTest   The template the returned {@code Test} will be derived
+	 *                       from.
+	 * @param classification The {@link Classification} for the created
+	 *                       {@link Test}.
+	 * @param withTestSteps  If true, {@link TestStep}s are automatically created
+	 *                       based on configured {@link TemplateTestStepUsage}.
+	 * @return The created {@code Test} is returned.
+	 */
+	public Test createTest(String name, Pool pool, TemplateTest templateTest, Classification classification,
+			boolean withTestSteps) {
+		// TODO
+		Test test = createTest(name, pool);
+
+		// relations
+		if (templateTest != null) {
+			getCore(test).getMutableStore().set(templateTest);
+		}
+		getCore(test).getMutableStore().set(classification);
+
+		if (withTestSteps && templateTest != null) {
+			// create default active and mandatory test steps according to the
+			// template
+			templateTest.getTemplateTestStepUsages().stream().filter(TemplateTestStepUsage.IS_IMPLICIT_CREATE)
+					.map(TemplateTestStepUsage::getTemplateTestStep).forEach(templateTestStep -> {
+						createTestStep(test, templateTestStep, classification);
+					});
+		}
+
+		return test;
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given
+	 * {@link TemplateTestStep} and {@link Classification}.
+	 * 
+	 * @param test             The parent {@code Test}.
+	 * @param templateTestStep The template the returned {@code TestStep} will be
+	 *                         derived from.
+	 * @param classification   The {@link Classification} for the created
+	 *                         {@link TestStep}.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStep(Test test, TemplateTestStep templateTestStep, Classification classification) {
+		TestStep testStep = createTestStep(test, templateTestStep);
+		getCore(testStep).getMutableStore().set(classification);
+		return testStep;
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given
+	 * {@link TemplateTestStep} and {@link Classification}.
+	 * 
+	 * @param name           Name of the created {@code TestStep}.
+	 * @param test           The parent {@code Test}.
+	 * @param classification The {@link Classification} for the created
+	 *                       {@link TestStep}.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStep(String name, Test test, Classification classification) {
+		TestStep testStep = createTestStep(name, test);
+		getCore(testStep).getMutableStore().set(classification);
+		return testStep;
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given name,
+	 * {@link TemplateTestStep} and {@link Classification}.
+	 * 
+	 * @param name             Name of the created {@code TestStep}.
+	 * @param test             The parent {@code Test}.
+	 * @param templateTestStep The template the returned {@code TestStep} will be
+	 *                         derived from.
+	 * @param classification   The {@link Classification} for the created
+	 *                         {@link TestStep}.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStep(String name, Test test, TemplateTestStep templateTestStep,
+			Classification classification) {
+		TestStep testStep = createTestStep(test, templateTestStep);
+		getCore(testStep).getMutableStore().set(classification);
+		testStep.setName(name);
+		return testStep;
+	}
+
+	/**
+	 * Create a new {@link ExtSystem}
+	 * @param name The name of the external system
+	 * @return
+	 */
+	public ExtSystem createExtSystem(String name) {
+		ExtSystem extSystem = new ExtSystem(createCore(ExtSystem.class));
+		extSystem.setName(name);
+		return extSystem;
+	}
+
+	/**
+	 * Create a new {@link ExtSystemAttribute}
+	 * @param name        The name of the external system attribute
+	 * @param extSystem   The parent {@link ExtSystem}
+	 * @return
+	 */
+	public ExtSystemAttribute createExtSystemAttribute(String name, ExtSystem extSystem) {
+		ExtSystemAttribute extSystemAttribute = new ExtSystemAttribute(createCore(ExtSystemAttribute.class));
+		getCore(extSystemAttribute).getPermanentStore().set(extSystem);
+		getCore(extSystem).getChildrenStore().add(extSystemAttribute);
+		extSystemAttribute.setName(name);
+		return extSystemAttribute;
+	}
+
+	/**
+	 * Create a new {@link MDMAttribute}
+	 * @param name                The name of the mdm attribute
+	 * @param extSystemAttribute  The parent {@link ExtSystemAttribute}
+	 * @return
+	 */
+	public MDMAttribute createMDMAttribute(String name, ExtSystemAttribute extSystemAttribute) {
+		MDMAttribute mdmAttribute = new MDMAttribute(createCore(MDMAttribute.class));
+		getCore(mdmAttribute).getPermanentStore().set(extSystemAttribute);
+		getCore(extSystemAttribute).getChildrenStore().add(mdmAttribute);
+		mdmAttribute.setName(name);
+		String[] values = name.split("\\.");
+		if(values.length == 3) {
+			mdmAttribute.setComponentType(values[0]);
+			mdmAttribute.setComponentName(values[1]);
+			mdmAttribute.setAttributeName(values[2]);
+		}
+		return mdmAttribute;
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given
+	 * {@link TemplateTestStep} and {@link Classification}. Doesn't create context
+	 * roots
+	 * 
+	 * @param test             The parent {@code Test}.
+	 * @param templateTestStep The template the returned {@code TestStep} will be
+	 *                         derived from.
+	 * @param classification   The {@link Classification} for the created
+	 *                         {@link TestStep}.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStepWithOutContextRoots(Test test, TemplateTestStep templateTestStep,
+			Classification classification) {
+		TestStep testStep = createTestStepWithOutContextRoots(test, templateTestStep);
+		getCore(testStep).getMutableStore().set(classification);
+		return testStep;
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given
+	 * {@link TemplateTestStep}. Doesn't create context roots
+	 *
+	 * @param test             The parent {@code Test}.
+	 * @param templateTestStep The template the returned {@code TestStep} will be
+	 *                         derived from.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStepWithOutContextRoots(Test test, TemplateTestStep templateTestStep) {
+		return createTestStepWithOutContextRoots(test, null, templateTestStep);
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given
+	 * {@link TemplateTestStep}.
+	 *
+	 * @param test             The parent {@code Test}.
+	 * @param status           The related {@link Status}.
+	 * @param templateTestStep The template the returned {@code TestStep} will be
+	 *                         derived from.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	// TODO make a decision: status in or out!
+	protected TestStep createTestStepWithOutContextRoots(Test test, Status status, TemplateTestStep templateTestStep) {
+		TemplateTest templateTest = TemplateTest.of(test)
+				.orElseThrow(() -> new IllegalArgumentException("Template test is not available."));
+		if (!templateTest.contains(templateTestStep)) {
+			throw new IllegalArgumentException("Template test step is not part of the test template.");
+		}
+
+		TestStep testStep = createTestStep(templateTestStep.getName(), test, status);
+
+		// relations
+		getCore(testStep).getMutableStore().set(templateTestStep);
+
+		return testStep;
+	}
+
+	/**
+	 * Creates a new {@link Test} for given {@link Pool}.
+	 *
+	 * @param name   Name of the created {@code Test}.
+	 * @param pool   The parent {@code Pool}.
+	 * @param status The related {@link Status}.
+	 * @return The created {@code Test} is returned.
+	 */
+	// TODO make a decision: status in or out!
+	protected Test createTest(String name, Pool pool, Status status) {
+		Test test = super.createTest(name);
+
+		// relations
+		getCore(test).getPermanentStore().set(pool);
+		getCore(pool).getChildrenStore().add(test);
+
+		return test;
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given
+	 * {@link TemplateTestStep}.
+	 *
+	 * @param test             The parent {@code Test}.
+	 * @param templateTestStep The template the returned {@code TestStep} will be
+	 *                         derived from.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStep(Test test, TemplateTestStep templateTestStep) {
+		return createTestStep(test, null, templateTestStep);
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test} using given
+	 * {@link TemplateTestStep}.
+	 *
+	 * @param test             The parent {@code Test}.
+	 * @param status           The related {@link Status}.
+	 * @param templateTestStep The template the returned {@code TestStep} will be
+	 *                         derived from.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	// TODO make a decision: status in or out!
+	protected TestStep createTestStep(Test test, Status status, TemplateTestStep templateTestStep) {
+
+		TestStep testStep = createTestStepWithOutContextRoots(test, status, templateTestStep);
+
+		// create initial context roots
+		templateTestStep.getTemplateRoots().forEach(templateRoot -> createContextRoot(testStep, templateRoot));
+
+		return testStep;
+	}
+
+	/**
+	 * Creates a new {@link TestStep} for given {@link Test}.
+	 *
+	 * @param name   Name of the created {@code Test}.
+	 * @param test   The parent {@code Test}.
+	 * @param status The related {@link Status}.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	// TODO make a decision: status in or out!
+	protected TestStep createTestStep(String name, Test test, Status status) {
+		TestStep testStep = super.createTestStep(name, test);
+
+		if (status != null) {
+			status.assign(testStep);
+		}
+
+		return testStep;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected <T extends BaseEntity> T createBaseEntity(Class<T> clazz, Core core) {
+		try {
+			Constructor<T> constructor = clazz.getDeclaredConstructor(Core.class);
+			try {
+				return constructor.newInstance(core);
+			} catch (IllegalAccessException exc) {
+				return super.createBaseEntity(clazz, core);
+			}
+		} catch (NoSuchMethodException | InvocationTargetException | InstantiationException exc) {
+			throw new IllegalStateException(exc.getMessage(), exc);
+		}
+	}
+
+	/**
+	 * Checks whether given enumeration is defined in the application model or not.
+	 *
+	 * @param enumerationObj The checked enumeration class.
+	 * @throws IllegalArgumentException Thrown if given enumeration class is not
+	 *                                  supported.
+	 */
+	protected abstract void validateEnum(Enumeration<?> enumerationObj);
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Checks whether given catalog name is allowed or not.
+	 *
+	 * @param name            The checked name.
+	 * @param isAttributeName Flag indicates whether given name is for a catalog
+	 *                        attribute.
+	 * @throws IllegalArgumentException Thrown if given name is not allowed.
+	 */
+	private static void validateCatalogName(String name, boolean isAttributeName) {
+		if (!isValidCatalogName(name)) {
+			throw new IllegalArgumentException(
+					"A catalog name is not allowed to be empty and " + "must not exceed 30 characters.");
+		} else if (name.toLowerCase(Locale.ROOT).startsWith("ao")) {
+			throw new IllegalArgumentException("A catalog name is not allowed to " + "start with 'ao' (case ignored).");
+		} else if (!name.matches("^[\\w]+$")) {
+			throw new IllegalArgumentException(
+					"A calatog name may only constists of the " + "following characters: a-z, A-Z, 0-9 or _.");
+		} else if (isAttributeName && Arrays.asList("id", "name", "mimetype").contains(name.toLowerCase(Locale.ROOT))) {
+			throw new IllegalArgumentException(
+					"A catalog attribute name is not allowed to be " + "'id', 'name' or 'mimetype' (case ignored).");
+		}
+	}
+
+	/**
+	 * Checks whether given catalog name is valid
+	 *
+	 * @param name The checked name.
+	 * @return Returns {@code true} if name is a valid catalog name
+	 */
+	private static boolean isValidCatalogName(String name) {
+		return name != null && !name.isEmpty() && name.length() <= 30;
+	}
+
+	/**
+	 * Hides {@link Value} containers missing in the templates.
+	 *
+	 * @param contextCore        The {@link ContextComponent} {@link Core}.
+	 * @param templateAttributes The {@link TemplateAttribute}s of the template.
+	 */
+	private static void hideValues(Core contextCore, List<TemplateAttribute> templateAttributes) {
+		Set<String> names = new HashSet<>(contextCore.getValues().keySet());
+		names.remove(Entity.ATTR_NAME);
+		names.remove(Entity.ATTR_MIMETYPE);
+		templateAttributes.stream().map(Entity::getName).forEach(names::remove);
+		contextCore.hideValues(names);
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystem.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystem.java
new file mode 100644
index 0000000..a6c45b2
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystem.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+
+/**
+ * Implementation of an external system entity type. An external system
+ * attribute contains several mdm attributes.
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class ExtSystem extends BaseEntity implements Describable, Deletable {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	protected ExtSystem(Core core) {
+		super(core);
+	}
+
+	public List<ExtSystemAttribute> getAttributes() {
+		return getExtSystemAttributes();
+	}
+
+	/**
+	 * Returns all available {@link ExtSystemAttribute}s related to this external
+	 * system.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<ExtSystemAttribute> getExtSystemAttributes() {
+		return getCore().getChildrenStore().get(ExtSystemAttribute.class);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystemAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystemAttribute.java
new file mode 100644
index 0000000..806ba57
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystemAttribute.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+
+/**
+ * Implementation of an external system attribute entity type. An external
+ * system attribute contains several mdm attributes.
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class ExtSystemAttribute extends BaseEntity implements Describable, Deletable {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	protected ExtSystemAttribute(Core core) {
+		super(core);
+	}
+
+	public List<MDMAttribute> getAttributes() {
+		return getMDMAttributes();
+	}
+
+	/**
+	 * Returns all available {@link MDMAttribute}s related to this external system
+	 * attribute.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<MDMAttribute> getMDMAttributes() {
+		return getCore().getChildrenStore().get(MDMAttribute.class);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/MDMAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/MDMAttribute.java
new file mode 100644
index 0000000..85b049d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/MDMAttribute.java
@@ -0,0 +1,98 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+
+/**
+ * Implementation of an external system entity type. An external system
+ * attribute contains several mdm attributes.
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class MDMAttribute extends BaseEntity implements Describable, Deletable {
+
+	public static final String ATTR_COMPONENT_TYPE = "CompType";
+	public static final String ATTR_COMPONENT_NAME = "CompName";
+	public static final String ATTR_ATTRIBUTE_NAME = "AttrName";
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	protected MDMAttribute(Core core) {
+		super(core);
+	}
+
+	/**
+	 * Returns the component type for this attribute
+	 *
+	 * @return Returns the component type
+	 */
+	public String getComponentType() {
+		return getValue(ATTR_COMPONENT_TYPE).extract();
+	}
+
+	/**
+	 * Sets the component type for this attribute
+	 *
+	 * @param compType The component type
+	 */
+	public void setComponentType(String compType) {
+		getValue(ATTR_COMPONENT_TYPE).set(compType);
+	}
+
+	/**
+	 * Returns the component name for this attribute
+	 *
+	 * @return Returns the component name
+	 */
+	public String getComponentName() {
+		return getValue(ATTR_COMPONENT_NAME).extract();
+	}
+
+	/**
+	 * Sets the component name for this attribute
+	 *
+	 * @param compName The component name
+	 */
+	public void setComponentName(String compName) {
+		getValue(ATTR_COMPONENT_NAME).set(compName);
+	}
+
+	/**
+	 * Returns the attribute name for this attribute
+	 *
+	 * @return Returns the attribute name
+	 */
+	public String getAttributeName() {
+		return getValue(ATTR_ATTRIBUTE_NAME).extract();
+	}
+
+	/**
+	 * Sets the attribute name for this attribute
+	 *
+	 * @param attrName The attribute name
+	 */
+	public void setAttributeName(String attrName) {
+		getValue(ATTR_ATTRIBUTE_NAME).set(attrName);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Pool.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Pool.java
new file mode 100644
index 0000000..bac6ce7
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Pool.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Test;
+
+/**
+ * Implementation of the pool entity type. The pool entity is used to establish
+ * a further navigation structure through the stored measurement data. Its name
+ * may be freely chosen but has to to be unique. A project contains {@link Test}
+ * entities as its children.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see Project
+ * @see Test
+ */
+public class Pool extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Project} parent type.
+	 */
+	public static final Class<Project> PARENT_TYPE_PROJECT = Project.class;
+
+	/**
+	 * The {@link Test} child type.
+	 */
+	public static final Class<Test> CHILD_TYPE_TEST = Test.class;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Pool(Core core) {
+		super(core);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Project.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Project.java
new file mode 100644
index 0000000..2c71b4d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Project.java
@@ -0,0 +1,53 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+
+/**
+ * Implementation of the project entity type. The project is the top level of
+ * stored measurement data. Its name may be freely chosen but has to to be
+ * unique. A project contains {@link Pool} entities as its children.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see Pool
+ */
+public class Project extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Pool} child type.
+	 */
+	public static final Class<Pool> CHILD_TYPE_POOL = Pool.class;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Project(Core core) {
+		super(core);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ProjectDomain.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ProjectDomain.java
new file mode 100644
index 0000000..dae7b14
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ProjectDomain.java
@@ -0,0 +1,35 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Describable;
+
+public class ProjectDomain extends BaseEntity implements Describable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ProjectDomain(Core core) {
+		super(core);
+	}
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Role.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Role.java
new file mode 100644
index 0000000..de12617
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Role.java
@@ -0,0 +1,55 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.User;
+
+/**
+ * Implementation of the role entity type. Each role can contain multiple
+ * {@link User} and each {@link User} can be assigned multiple {@link Role}s.
+ */
+public class Role extends BaseEntity implements Deletable, Describable {
+
+	public static final String ATTR_SUPERUSER_FLAG = "SuperuserFlag";
+	public static final String REL_GROUPS2USERS = "groups2users";
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Role(Core core) {
+		super(core);
+		getValue(ATTR_SUPERUSER_FLAG).set((short) 0);
+	}
+
+	/**
+	 * @param user User to add
+	 */
+	public void addUser(User user) {
+		getCore().getNtoMStore().add(REL_GROUPS2USERS, user);
+	}
+
+	/**
+	 * @param user {@link User} to remove
+	 */
+	public void removeUser(User user) {
+		getCore().getNtoMStore().remove(REL_GROUPS2USERS, user);
+	}
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Status.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Status.java
new file mode 100644
index 0000000..702ad32
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Status.java
@@ -0,0 +1,94 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Implementation of the status entity type. A status may be attached to
+ * {@link StatusAttachable} entities like {@link Test} or {@link TestStep} to
+ * indicate they have a state in a complete workflow.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class Status extends BaseEntity implements Describable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Status(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Assigns this status to given {@link StatusAttachable}s.
+	 *
+	 * @param <T>               The status attachable type.
+	 * @param statusAttachables This status will be assigned to all of them.
+	 */
+	public <T extends StatusAttachable> void assign(List<T> statusAttachables) {
+		statusAttachables.forEach(this::assign);
+	}
+
+	/**
+	 * Assigns this status to given {@link StatusAttachable}.
+	 *
+	 * @param <T>              The status attachable type.
+	 * @param statusAttachable This status will be assigned to it.
+	 */
+	public <T extends StatusAttachable> void assign(T statusAttachable) {
+		Classification classification = getCore(statusAttachable).getMutableStore().get(Classification.class);
+		if (classification == null) {
+			throw new DataAccessException("Mandatory element classification not found!");
+		}
+
+		getCore(classification).getMutableStore().set(this);
+	}
+
+	/**
+	 * Returns the {@link Status} attached to given {@link StatusAttachable}.
+	 *
+	 * @param statusAttachable The {@code StatusAttachable}.
+	 * @return Optional is empty if no {@code Status} is attached.
+	 */
+	public static Optional<Status> of(StatusAttachable statusAttachable) {
+		Classification classification = getCore(statusAttachable).getMutableStore().get(Classification.class);
+		if (classification == null) {
+			return Optional.empty();
+		}
+		return Optional.ofNullable(getCore(classification).getMutableStore().get(Status.class));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/SystemParameter.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/SystemParameter.java
new file mode 100644
index 0000000..310a654
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/SystemParameter.java
@@ -0,0 +1,28 @@
+/*******************************************************************************

+ * Copyright (c) 2020 Contributors to the Eclipse Foundation

+ *

+ * See the NOTICE file(s) distributed with this work for additional

+ * information regarding copyright ownership.

+ *

+ * This program and the accompanying materials are made available under the

+ * terms of the Eclipse Public License v. 2.0 which is available at

+ * http://www.eclipse.org/legal/epl-2.0.

+ *

+ * SPDX-License-Identifier: EPL-2.0

+ *******************************************************************************/

+package org.eclipse.mdm.api.dflt.model;

+

+import org.eclipse.mdm.api.base.adapter.Core;

+import org.eclipse.mdm.api.base.model.BaseEntity;

+

+/**

+ * @author akn

+ *

+ */

+public class SystemParameter extends BaseEntity {

+

+	SystemParameter(Core core) {

+		super(core);

+	}

+

+}

diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateAttribute.java
new file mode 100644
index 0000000..998862b
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateAttribute.java
@@ -0,0 +1,408 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.DoubleComplex;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.FloatComplex;
+import org.eclipse.mdm.api.base.model.MimeType;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Implementation of the template attribute entity type. A template attribute
+ * adds meta data to a {@link CatalogAttribute} it is associated with. It always
+ * belongs to a {@link TemplateComponent} or a {@link TemplateSensor}. Its name
+ * is the same as the name of the associated {@code CatalogAttribute} and is not
+ * allowed to be modified at all.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateComponent
+ * @see TemplateSensor
+ */
+public class TemplateAttribute extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * This {@code Comparator} compares {@link TemplateAttribute}s by the sort index
+	 * of their corresponding {@link CatalogAttribute} in ascending order.
+	 */
+	public static final Comparator<TemplateAttribute> COMPARATOR = Comparator
+			.comparing(ta -> ta.getCatalogAttribute().getSortIndex());
+
+	/**
+	 * The 'DefaultValue' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_VALUE = "DefaultValue";
+
+	/**
+	 * The 'ValueReadOnly' attribute name.
+	 */
+	public static final String ATTR_VALUE_READONLY = "ValueReadonly";
+
+	/**
+	 * The 'Optional' attribute name.
+	 */
+	public static final String ATTR_OPTIONAL = "Obligatory";
+
+	private static final Map<ValueType<?>, Function<String, Object>> VALUETYPE_FUNCTION_MAP = new HashMap<>();
+
+	static {
+		VALUETYPE_FUNCTION_MAP.put(ValueType.STRING, v -> v);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.DATE, v -> LocalDateTime.parse(v, Value.LOCAL_DATE_TIME_FORMATTER));
+		VALUETYPE_FUNCTION_MAP.put(ValueType.BOOLEAN, Boolean::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.BYTE, Byte::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.SHORT, Short::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.INTEGER, Integer::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.LONG, Long::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.FLOAT, Float::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.DOUBLE, Double::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.FLOAT_COMPLEX, FloatComplex::valueOf);
+		VALUETYPE_FUNCTION_MAP.put(ValueType.DOUBLE_COMPLEX, DoubleComplex::valueOf);
+	}
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TemplateAttribute(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the default {@link Value} of this template attribute.
+	 *
+	 * @return The default {@code Value} is returned.
+	 */
+	@SuppressWarnings({ "rawtypes" })
+	public Value getDefaultValue() {
+		ValueType valueType = getCatalogAttribute().getValueType();
+		Value defaultValue = getValue(ATTR_DEFAULT_VALUE);
+		boolean isValid = defaultValue.isValid();
+		String value = defaultValue.extract();
+		if (valueType.isEnumerationType()) {
+			Enumeration enumObject = getCatalogAttribute().getEnumerationObject();
+			return valueType.create(getName(), "", isValid, isValid ? enumObject.valueOf(value) : null,
+					enumObject.getName());
+		} else {
+			return valueType.create(getName(), isValid ? parse(value, valueType) : null);
+		}
+	}
+
+	/**
+	 * Sets a new default value for this template attribute. Given input will be
+	 * stored in its {@link String} representation.
+	 *
+	 * @param input The new default value.
+	 */
+	public void setDefaultValue(Object input) {
+		if (input == null) {
+			getValue(ATTR_DEFAULT_VALUE).set(null);
+			return;
+		}
+
+		ValueType<?> valueType = getCatalogAttribute().getValueType();
+		boolean sequence = valueType.isSequence();
+
+		// if this passes -> input is valid
+		Value value = valueType.create("notRelevant", input);
+
+		String stringValue;
+		if (valueType.isFileLinkType()) {
+			stringValue = getStringValueForFileLinkType(value, sequence);
+		} else if (valueType.isDateType()) {
+			LocalDateTime[] values = sequence ? value.extract() : new LocalDateTime[] { value.extract() };
+			stringValue = Stream.of(values).map(ldt -> ldt.format(Value.LOCAL_DATE_TIME_FORMATTER))
+					.collect(Collectors.joining(","));
+		} else {
+			if (input.getClass().isArray()) {
+				stringValue = IntStream.range(0, Array.getLength(input)).mapToObj(i -> Array.get(input, i).toString())
+						.collect(Collectors.joining(","));
+			} else {
+				stringValue = value.extract().toString();
+			}
+		}
+
+		getValue(ATTR_DEFAULT_VALUE).set(stringValue);
+	}
+
+	/**
+	 * Returns the value read only flag of this template attribute.
+	 *
+	 * @return Returns {@code true} if it is not allowed to modify {@link Value}s
+	 *         derived from this template attribute.
+	 */
+	public Boolean isValueReadOnly() {
+		return getValue(ATTR_VALUE_READONLY).extract();
+	}
+
+	/**
+	 * Sets a new value read only flag for this template attribute.
+	 *
+	 * @param valueReadOnly The new value read only flag.
+	 */
+	public void setValueReadOnly(Boolean valueReadOnly) {
+		getValue(ATTR_VALUE_READONLY).set(valueReadOnly);
+	}
+
+	/**
+	 * Returns the optional flag of this template attribute.
+	 *
+	 * @return Returns {@code true} if it is allowed to omit a {@link Value} derived
+	 *         from this template attribute.
+	 */
+	public Boolean isOptional() {
+		boolean mandatory = getValue(ATTR_OPTIONAL).extract();
+		return mandatory ? Boolean.FALSE : Boolean.TRUE;
+	}
+
+	/**
+	 * Sets a new optional flag for this template attribute.
+	 *
+	 * @param optional The new optional flag.
+	 */
+	public void setOptional(Boolean optional) {
+		getValue(ATTR_OPTIONAL).set(optional ? Boolean.FALSE : Boolean.TRUE);
+	}
+
+	/**
+	 * Returns the {@link CatalogAttribute} this template attribute is associated
+	 * with.
+	 *
+	 * @return The associated {@code CatalogAttribute} is returned.
+	 */
+	public CatalogAttribute getCatalogAttribute() {
+		return getCore().getMutableStore().get(CatalogAttribute.class);
+	}
+
+	/**
+	 * Returns the {@link TemplateRoot} this template attribute belongs to.
+	 *
+	 * @return The {@code TemplateRoot} is returned.
+	 */
+	public TemplateRoot getTemplateRoot() {
+		Optional<TemplateComponent> templateComponent = getTemplateComponent();
+		Optional<TemplateSensor> templateSensor = getTemplateSensor();
+		if (templateComponent.isPresent()) {
+			return templateComponent.get().getTemplateRoot();
+		} else if (templateSensor.isPresent()) {
+			return templateSensor.get().getTemplateRoot();
+		} else {
+			throw new IllegalStateException("Parent entity is unknown.");
+		}
+	}
+
+	/**
+	 * Returns the parent {@link TemplateComponent} of this template attribute.
+	 *
+	 * @return {@code Optional} is empty if a {@link TemplateSensor} is parent of
+	 *         this template attribute.
+	 * @see #getTemplateSensor()
+	 */
+	public Optional<TemplateComponent> getTemplateComponent() {
+		return Optional.ofNullable(getCore().getPermanentStore().get(TemplateComponent.class));
+	}
+
+	/**
+	 * Returns the parent {@link TemplateSensor} of this template attribute.
+	 *
+	 * @return {@code Optional} is empty if a {@link TemplateComponent} is parent of
+	 *         this template attribute.
+	 * @see #getTemplateComponent()
+	 */
+	public Optional<TemplateSensor> getTemplateSensor() {
+		return Optional.ofNullable(getCore().getPermanentStore().get(TemplateSensor.class));
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Parses given {@code String} to the corresponding type of given
+	 * {@link ValueType}.
+	 *
+	 * @param value     The {@code String} value.
+	 * @param valueType Used to resolve the corresponding converter.
+	 * @return The parsed object is returned.
+	 */
+	private static Object parse(String value, ValueType<?> valueType) {
+		if (valueType.isFileLinkType()) {
+			Pattern pattern = Pattern.compile("([^,].*?)\\[(.*?),(.*?)\\]");
+			Matcher matcher = pattern.matcher(value);
+			List<FileLink> fileLinks = new ArrayList<>();
+			while (matcher.find()) {
+				fileLinks.add(FileLinkParser.parse(matcher.group()));
+			}
+
+			return valueType.isSequence() ? fileLinks.toArray(new FileLink[fileLinks.size()]) : fileLinks.get(0);
+		} else {
+			Function<String, Object> converter = getParser(valueType);
+			if (valueType.isSequence()) {
+				List<Object> values = Stream.of(value.split(",")).map(converter).collect(Collectors.toList());
+				Object array = Array.newInstance(valueType.getValueClass().getComponentType(), values.size());
+
+				if (valueType.getValueClass().getComponentType().isPrimitive()) {
+					IntStream.range(0, values.size()).forEach(i -> Array.set(array, i, values.get(i)));
+				} else {
+					values.toArray((Object[]) array);
+				}
+
+				return array;
+			} else {
+				return converter.apply(value);
+			}
+		}
+	}
+
+	/**
+	 * Returns the {@code String} conversion function for given {@link ValueType}.
+	 *
+	 * @param valueType Used as identifier.
+	 * @return The {@code String} conversion {@code Function} is returned.
+	 * @throws IllegalArgumentException Thrown if a corresponding {@code String} is
+	 *                                  not supported.
+	 */
+	private static Function<String, Object> getParser(ValueType<?> valueType) {
+		Function<String, Object> converter = VALUETYPE_FUNCTION_MAP.get(valueType);
+		if (converter == null) {
+			throw new IllegalArgumentException("String conversion for value type '" + valueType + "' not supported.");
+		}
+		return converter;
+	}
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * Utility class restore a {@link FileLink} from given {@code String}.
+	 */
+	private static final class FileLinkParser {
+
+		// ======================================================================
+		// Class variables
+		// ======================================================================
+
+		// markers
+		private static final String NO_DESC_MARKER = "NO_DESC#";
+		private static final String LOCAL_MARKER = "LOCALPATH#";
+
+		// pattern group names
+		private static final String DESCRIPTION = "description";
+		private static final String MIMETYPE = "mimetype";
+		private static final String PATH = "path";
+
+		// pattern
+		private static final Pattern FILE_LINK_PATTERN = Pattern
+				.compile("(?<" + DESCRIPTION + ">.*?)\\[(?<" + MIMETYPE + ">.*?),(?<" + PATH + ">.*?)\\]");
+
+		// ======================================================================
+		// Public methods
+		// ======================================================================
+
+		/**
+		 * Parses given {@code String} and returns it as {@link FileLink}.
+		 *
+		 * @param value The {@code String} value which will be parsed.
+		 * @return The corresponding {@code FileLink} is returned.
+		 */
+		public static FileLink parse(String value) {
+			Matcher matcher = FILE_LINK_PATTERN.matcher(value);
+			if (!matcher.find()) {
+				throw new IllegalStateException("Unable to restore file link.");
+			}
+			String description = matcher.group(DESCRIPTION);
+			String path = matcher.group(PATH);
+			FileLink fileLink;
+			if (path.startsWith(LOCAL_MARKER)) {
+				try {
+					fileLink = FileLink.newLocal(Paths.get(path.replaceFirst(LOCAL_MARKER, "")));
+				} catch (IOException e) {
+					throw new IllegalStateException("Unable to restore local file link.", e);
+				}
+			} else {
+				fileLink = FileLink.newRemote(path, new MimeType(matcher.group(MIMETYPE)), description);
+			}
+
+			fileLink.setDescription(NO_DESC_MARKER.equals(description) ? null : description);
+			return fileLink;
+		}
+
+	}
+
+	/**
+	 * Get string value for FileLinkType
+	 *
+	 * @param value    The {@code Value} value.
+	 * @param sequence The {@code boolean} sequence.
+	 * @return Return {@code String} string value for FileLinkType
+	 */
+	private String getStringValueForFileLinkType(Value value, boolean sequence) {
+		FileLink[] values = sequence ? value.extract() : new FileLink[] { value.extract() };
+		return Stream.of(values).map(fl -> {
+			StringBuilder sb = new StringBuilder();
+			if (fl.getDescription().isEmpty()) {
+				sb.append(FileLinkParser.NO_DESC_MARKER);
+			} else {
+				sb.append(fl.getDescription());
+			}
+			sb.append('[').append(fl.getMimeType()).append(',');
+			if (fl.isRemote()) {
+				sb.append(fl.getRemotePath());
+			} else if (fl.isLocal()) {
+				sb.append(FileLinkParser.LOCAL_MARKER).append(fl.getLocalStream());
+			} else {
+				throw new IllegalStateException("File link is neither in local nor remote state: " + fl);
+			}
+
+			return sb.append(']');
+		}).collect(Collectors.joining(","));
+	}
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateComponent.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateComponent.java
new file mode 100644
index 0000000..8caa7d2
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateComponent.java
@@ -0,0 +1,400 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template component entity type. A template attribute
+ * adds meta data to a {@link CatalogComponent} it is associated with. It always
+ * belongs to a template root or another template component. Its name has to be
+ * unique within all template components belonging to the same
+ * {@link TemplateRoot}. A template component may define {@link TemplateSensor}s
+ * where each extends a {@link CatalogSensor} provided by the associated {@code
+ * CatalogComponent}. It may define {@link TemplateAttribute}s where each
+ * uniquely extends a {@link CatalogAttribute} provided by the associated
+ * {@code CatalogComponent}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogComponent
+ * @see TemplateRoot
+ * @see TemplateAttribute
+ * @see TemplateSensor
+ */
+public class TemplateComponent extends BaseEntity implements Deletable, Sortable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The optional flag {@code Predicate}.
+	 */
+	public static final Predicate<TemplateComponent> IS_OPTIONAL = TemplateComponent::isOptional;
+
+	/**
+	 * The mandatory flag {@code Predicate}. This is the inversion of
+	 * {@link #IS_OPTIONAL} {@code Predicate}.
+	 */
+	public static final Predicate<TemplateComponent> IS_MANDATORY = IS_OPTIONAL.negate();
+
+	/**
+	 * The default active flag {@code Predicate}.
+	 */
+	public static final Predicate<TemplateComponent> IS_DEFAULT_ACTIVE = TemplateComponent::isDefaultActive;
+
+	/**
+	 * The series constant flag {@code Predicate}.
+	 */
+	public static final Predicate<TemplateComponent> IS_SERIES_CONSTANT = TemplateComponent::isSeriesConstant;
+
+	/**
+	 * The series variable flag {@code Predicate}. This is the inversion of the
+	 * {@link #IS_SERIES_CONSTANT} {@code Predicate}.
+	 */
+	public static final Predicate<TemplateComponent> IS_SERIES_VARIABLE = IS_SERIES_CONSTANT.negate();
+
+	/**
+	 * The implicit create flag {@code Predicate}. This is an OR combination of
+	 * {@link #IS_DEFAULT_ACTIVE} and {@link #IS_MANDATORY} {@code Predicate}s.
+	 */
+	public static final Predicate<TemplateComponent> IS_IMPLICIT_CREATE = IS_DEFAULT_ACTIVE.or(IS_MANDATORY);
+
+	/**
+	 * The 'TestStepSeriesVariable' attribute name.
+	 */
+	public static final String ATTR_SERIES_CONSTANT = "TestStepSeriesVariable";
+
+	/**
+	 * The 'DefaultActive' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_ACTIVE = "DefaultActive";
+
+	/**
+	 * The 'Optional' attribute name.
+	 */
+	public static final String ATTR_OPTIONAL = "Optional";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TemplateComponent(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the optional flag of this template component.
+	 *
+	 * @return Returns {@code true} if it is allowed to omit a
+	 *         {@link ContextComponent} derived from this template component.
+	 */
+	public Boolean isOptional() {
+		return getValue(ATTR_OPTIONAL).extract();
+	}
+
+	/**
+	 * Sets a new optional flag for this template component.
+	 *
+	 * @param optional The new optional flag.
+	 */
+	public void setOptional(Boolean optional) {
+		getValue(ATTR_OPTIONAL).set(optional);
+	}
+
+	/**
+	 * Returns the default active flag of this template component.
+	 *
+	 * @return Returns {@code true} if a {@link ContextComponent} has to be created
+	 *         automatically each time a new {@link ContextRoot} is derived from the
+	 *         {@link TemplateRoot} this template component belongs to.
+	 */
+	public Boolean isDefaultActive() {
+		return getValue(ATTR_DEFAULT_ACTIVE).extract();
+	}
+
+	/**
+	 * Sets a new default active flag for this template component.
+	 *
+	 * @param defaultActive The new default active flag.
+	 */
+	public void setDefaultActive(Boolean defaultActive) {
+		getValue(ATTR_DEFAULT_ACTIVE).set(defaultActive);
+	}
+
+	/**
+	 * Returns the series constant flag of this template component.
+	 *
+	 * @return Returns {@code true} if the {@link ContextComponent}'s {@link Value}s
+	 *         across {@link TestStep} siblings contain the same values.
+	 */
+	public Boolean isSeriesConstant() {
+		return getValue(ATTR_SERIES_CONSTANT).extract();
+	}
+
+	/**
+	 * Sets a new series constant flag for this template component.
+	 *
+	 * @param seriesConstant The new series constant flag.
+	 */
+	public void setSeriesConstant(Boolean seriesConstant) {
+		getValue(ATTR_SERIES_CONSTANT).set(seriesConstant);
+	}
+
+	/**
+	 * Returns the {@link CatalogComponent} this template component is associated
+	 * with.
+	 *
+	 * @return The associated {@code CatalogComponent} is returned.
+	 */
+	public CatalogComponent getCatalogComponent() {
+		return getCore().getMutableStore().get(CatalogComponent.class);
+	}
+
+	/**
+	 * Returns the {@link TemplateRoot} this template component belongs to.
+	 *
+	 * @return The {@code TemplateRoot} is returned.
+	 */
+	public TemplateRoot getTemplateRoot() {
+		TemplateRoot templateRoot = getCore().getPermanentStore().get(TemplateRoot.class);
+		if (templateRoot == null) {
+			return getParentTemplateComponent()
+					.orElseThrow(() -> new IllegalStateException("Parent entity is unknown.")).getTemplateRoot();
+		}
+
+		return templateRoot;
+	}
+
+	/**
+	 * Returns the parent {@link TemplateComponent} of this template component.
+	 *
+	 * @return {@code Optional} is empty if this template component is an immediate
+	 *         child of the {@link TemplateRoot}.
+	 * @see #getTemplateRoot()
+	 */
+	public Optional<TemplateComponent> getParentTemplateComponent() {
+		return Optional.ofNullable(getCore().getPermanentStore().get(TemplateComponent.class));
+	}
+
+	/**
+	 * Returns the {@link TemplateAttribute} identified by given name.
+	 *
+	 * @param name The name of the {@code TemplateAttribute}.
+	 * @return The {@code Optional} is empty if a {@code TemplateAttribute} with
+	 *         given name does not exist.
+	 */
+	public Optional<TemplateAttribute> getTemplateAttribute(String name) {
+		return getTemplateAttributes().stream().filter(ta -> ta.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link TemplateAttribute}s related to this template
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TemplateAttribute> getTemplateAttributes() {
+		return getCore().getChildrenStore().get(TemplateAttribute.class);
+	}
+
+	/**
+	 * Removes the {@link TemplateAttribute} identified by given name.
+	 *
+	 * @param name Name of the {@code TemplateAttribute} that has to be removed.
+	 * @return Returns {@code true} if the {@code TemplateAttribute} with given name
+	 *         has been removed.
+	 */
+	public boolean removeTemplateAttribute(String name) {
+		Optional<TemplateAttribute> templateAttribute = getTemplateAttribute(name);
+		if (templateAttribute.isPresent()) {
+			getCore().getChildrenStore().remove(templateAttribute.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns the {@link TemplateComponent} identified by given name.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> The names of <u>all</u> template components belonging to the
+	 * same {@link TemplateRoot} must have unique names (no matter they are
+	 * immediate children or not). Therefore, if this template component does not
+	 * have an immediate template component with the given name, this lookup request
+	 * is recursively delegated to all of its child template components.
+	 *
+	 * @param name The name of the {@code TemplateComponent}.
+	 * @return The {@code Optional} is empty if a {@code TemplateComponent} with
+	 *         given name does not exist (neither this template component nor one of
+	 *         its children has a template component with given name).
+	 */
+	public Optional<TemplateComponent> getTemplateComponent(String name) {
+		List<TemplateComponent> templateComponents = getTemplateComponents();
+		Optional<TemplateComponent> templateComponent = templateComponents.stream().filter(tc -> tc.nameEquals(name))
+				.findAny();
+		if (templateComponent.isPresent()) {
+			return templateComponent;
+		}
+
+		return templateComponents.stream().map(ct -> ct.getTemplateComponent(name)).filter(Optional::isPresent)
+				.map(Optional::get).findAny();
+	}
+
+	/**
+	 * Returns all immediate {@link TemplateComponent}s related to this template
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TemplateComponent> getTemplateComponents() {
+		return getCore().getChildrenStore().get(TemplateComponent.class);
+	}
+
+	/**
+	 * Removes the {@link TemplateComponent} identified by given name.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> The names of <u>all</u> template components belonging to the
+	 * same {@link TemplateRoot} must have unique names (no matter they are
+	 * immediate children or not). Therefore, if this template component does not
+	 * have an immediate template component with the given name, this remove request
+	 * is recursively delegated to all of its child template components.
+	 *
+	 * @param name Name of the {@code TemplateComponent} that has to be removed.
+	 * @return Returns {@code true} if the {@code TemplateComponent} with given name
+	 *         has been removed.
+	 */
+	public boolean removeTemplateComponent(String name) {
+		Optional<TemplateComponent> templateComponent = getTemplateComponent(name);
+		if (templateComponent.isPresent()) {
+			Optional<TemplateComponent> parentTemplateComponent = templateComponent.get().getParentTemplateComponent();
+			if (parentTemplateComponent.isPresent()) {
+				parentTemplateComponent.get().removeTemplateComponent(name);
+			} else {
+				getCore().getChildrenStore().remove(templateComponent.get());
+			}
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns the {@link TemplateSensor} identified by given name.
+	 *
+	 * @param name The name of the {@code TemplateSensor}.
+	 * @return The {@code Optional} is empty if a {@code TemplateSensor} with given
+	 *         name does not exist.
+	 */
+	public Optional<TemplateSensor> getTemplateSensor(String name) {
+		return getTemplateSensors().stream().filter(ts -> ts.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link TemplateSensor}s related to this template
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TemplateSensor> getTemplateSensors() {
+		if (getCatalogComponent().getContextType().isTestEquipment()) {
+			return getCore().getChildrenStore().get(TemplateSensor.class);
+		}
+
+		return Collections.emptyList();
+	}
+
+	/**
+	 * Removes the {@link TemplateSensor} identified by given name.
+	 *
+	 * @param name Name of the {@code TemplateSensor} that has to be removed.
+	 * @return Returns {@code true} if the {@code TemplateSensor} with given name
+	 *         has been removed.
+	 */
+	public boolean removeTemplateSensor(String name) {
+		Optional<TemplateSensor> templateSensor = getTemplateSensor(name);
+		if (templateSensor.isPresent()) {
+			getCore().getChildrenStore().remove(templateSensor.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<TemplateAttribute> templateAttributes = getTemplateAttributes();
+		if (!templateAttributes.isEmpty()) {
+			sb.append(", TemplateAttributes = ").append(templateAttributes);
+		}
+
+		List<TemplateSensor> templateSensors = getTemplateSensors();
+		if (!templateSensors.isEmpty()) {
+			sb.append(", TemplateSensors = ").append(templateSensors);
+		}
+
+		List<TemplateComponent> templateComponents = getTemplateComponents();
+		if (!templateComponents.isEmpty()) {
+			sb.append(", TemplateComponents = ").append(templateComponents);
+		}
+
+		return sb.append(')').toString();
+	}
+
+	/**
+	 * Returns the {@link TemplateComponent} the given {@link ContextComponent} is
+	 * derived from.
+	 *
+	 * @param contextComponent The {@code ContextComponent} whose {@code
+	 * 		TemplateComponent} is requested.
+	 * @return {@code Optional} is empty if the given {@code ContextComponent} is
+	 *         not derived from a template, which is data source specific.
+	 */
+	public static Optional<TemplateComponent> of(ContextComponent contextComponent) {
+		return Optional.ofNullable(getCore(contextComponent).getMutableStore().get(TemplateComponent.class));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateRoot.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateRoot.java
new file mode 100644
index 0000000..21f04a1
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateRoot.java
@@ -0,0 +1,187 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template attribute entity type. A template root defines
+ * a tree of {@code TemplateComponent}s. Such a tree forms a hierarchical
+ * template structure which is used to describe the composition of a
+ * {@link ContextRoot}. A template root implements the {@link Versionable}
+ * interface and hence has a version and a state. As long as
+ * {@link #isEditable()} returns {@code true} any part of that template root is
+ * allowed to be modified. Once a template root is set to be valid
+ * ({@link #isValid()} == {@code true}) it may be used to compose a
+ * {@link TemplateTestStep} and then is no longer allowed to be modified in any
+ * way. If a valid template root needs to be modified, then a deep copy with a
+ * unique name and version combination has to be created (deep copy means new
+ * instances).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateComponent
+ * @see Versionable
+ */
+public class TemplateRoot extends BaseEntity implements Deletable, Versionable {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ContextType contextType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TemplateRoot(Core core) {
+		super(core);
+
+		String typeName = core.getTypeName().toUpperCase(Locale.ROOT);
+		for (ContextType contextTypeCandidate : ContextType.values()) {
+			if (typeName.contains(contextTypeCandidate.name())) {
+				contextType = contextTypeCandidate;
+				return;
+			}
+		}
+
+		throw new IllegalStateException("Core is incompatible.");
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextType} of this template root.
+	 *
+	 * @return The {@code ContextType} is returned.
+	 */
+	public ContextType getContextType() {
+		return contextType;
+	}
+
+	/**
+	 * Returns the {@link TemplateComponent} identified by given name.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> The names of <u>all</u> {@code TemplateComponent}s belonging to
+	 * the same template root must have unique names (no matter they are immediate
+	 * children or not). Therefore, if this template root does not have an immediate
+	 * {@code TemplateComponent} with the given name, this lookup request is
+	 * recursively delegated to all of its child {@code TemplateComponent}s.
+	 *
+	 * @param name The name of the {@code TemplateComponent}.
+	 * @return The {@code Optional} is empty if a {@code TemplateComponent} with
+	 *         given name does not exist at all within this template root.
+	 */
+	public Optional<TemplateComponent> getTemplateComponent(String name) {
+		List<TemplateComponent> templateComponents = getTemplateComponents();
+		Optional<TemplateComponent> templateComponent = templateComponents.stream().filter(tc -> tc.nameEquals(name))
+				.findAny();
+		if (templateComponent.isPresent()) {
+			return templateComponent;
+		}
+
+		return templateComponents.stream().map(tc -> tc.getTemplateComponent(name)).filter(Optional::isPresent)
+				.map(Optional::get).findAny();
+	}
+
+	/**
+	 * Returns all immediate {@link TemplateComponent}s related to this template
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TemplateComponent> getTemplateComponents() {
+		return getCore().getChildrenStore().get(TemplateComponent.class);
+	}
+
+	/**
+	 * Removes the {@link TemplateComponent} identified by given name.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> The names of <u>all</u> {@code TemplateComponent}s belonging to
+	 * the same template roots must have unique names (no matter they are immediate
+	 * children or not). Therefore, if this template root does not have an immediate
+	 * {@code TemplateComponent} with the given name, this remove request is
+	 * recursively delegated to all of its child {@code TemplateComponent}s.
+	 *
+	 * @param name Name of the {@code TemplateComponent} that has to be removed.
+	 * @return Returns {@code true} if the {@code TemplateComponent} with given name
+	 *         has been removed.
+	 */
+	public boolean removeTemplateComponent(String name) {
+		Optional<TemplateComponent> templateComponent = getTemplateComponent(name);
+		if (templateComponent.isPresent()) {
+			Optional<TemplateComponent> parentTemplateComponent = templateComponent.get().getParentTemplateComponent();
+			if (parentTemplateComponent.isPresent()) {
+				parentTemplateComponent.get().removeTemplateComponent(name);
+			} else {
+				getCore().getChildrenStore().remove(templateComponent.get());
+			}
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append("ContextType = ").append(getContextType()).append(", ");
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<TemplateComponent> templateComponents = getTemplateComponents();
+		if (!templateComponents.isEmpty()) {
+			sb.append(", TemplateComponents = ").append(templateComponents);
+		}
+
+		return sb.append(')').toString();
+	}
+
+	/**
+	 * Returns the {@link TemplateRoot} the given {@link ContextRoot} is derived
+	 * from.
+	 *
+	 * @param contextRoot The {@code ContextRoot} whose {@code TemplateRoot} is
+	 *                    requested.
+	 * @return {@code Optional} is empty if the given {@code ContextRoot} is not
+	 *         derived from a template, which is data source specific.
+	 */
+	public static Optional<TemplateRoot> of(ContextRoot contextRoot) {
+		return Optional.ofNullable(getCore(contextRoot).getMutableStore().get(TemplateRoot.class));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateSensor.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateSensor.java
new file mode 100644
index 0000000..6d38c4a
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateSensor.java
@@ -0,0 +1,337 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextSensor;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Quantity;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template sensor entity type. A template sensor adds
+ * meta data to a {@link CatalogSensor} it is associated with. It always belongs
+ * to a template component or a template sensor. Its name has to be unique
+ * within all template sensors belonging to the same {@link TemplateComponent}.
+ * A template sensor define {@link TemplateAttribute}s where each uniquely
+ * extends a {@link CatalogAttribute} provided by the associated {@code
+ * CatalogSensor}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogSensor
+ * @see TemplateComponent
+ * @see TemplateAttribute
+ */
+public class TemplateSensor extends BaseEntity implements Deletable, Describable, Sortable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The optional flag {@code Predicate}.
+	 */
+	public static final Predicate<TemplateSensor> IS_OPTIONAL = TemplateSensor::isOptional;
+
+	/**
+	 * The mandatory flag {@code Predicate}. This is the inversion of
+	 * {@link #IS_OPTIONAL} {@code Predicate}.
+	 */
+	public static final Predicate<TemplateSensor> IS_MANDATORY = IS_OPTIONAL.negate();
+
+	/**
+	 * The default active flag {@code Predicate}.
+	 */
+	public static final Predicate<TemplateSensor> IS_DEFAULT_ACTIVE = TemplateSensor::isDefaultActive;
+
+	/**
+	 * The implicit create flag {@code Predicate}. This is an OR combination of
+	 * {@link #IS_DEFAULT_ACTIVE} and {@link #IS_MANDATORY} {@code Predicate}s.
+	 */
+	public static final Predicate<TemplateSensor> IS_IMPLICIT_CREATE = IS_DEFAULT_ACTIVE.or(IS_MANDATORY);
+
+	/**
+	 * The 'Optional' attribute name.
+	 */
+	public static final String ATTR_OPTIONAL = "Optional";
+
+	/**
+	 * The 'DefaultActive' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_ACTIVE = "DefaultActive";
+
+	/**
+	 * The 'MeasuredValuesEditable' attribute name.
+	 */
+	public static final String ATTR_MEASRED_VALUES_EDITABLE = "MeaQuantityValuesEditable";
+
+	/**
+	 * The 'MeasuredValuesGeneratorName' attribute name.
+	 */
+	public static final String ATTR_MEASRED_VALUES_GENERATOR_NAME = "MeaQuantityEditorPlugin";
+
+	/**
+	 * The 'MeasuredValuesIndependent' attribute name.
+	 */
+	public static final String ATTR_MEASRED_VALUES_INDEPENDENT = "MeaQuantityIndependent";
+
+	/**
+	 * The 'MeasuredValuesAxisType' attribute name.
+	 */
+	public static final String ATTR_MEASRED_VALUES_AXISTYPE = "MeaQuantityAxisType";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TemplateSensor(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the measured values editable flag of this template sensor.
+	 *
+	 * @return The measured values editable flag is returned.
+	 */
+	public Boolean areMeasuredValuesEditable() {
+		return getValue(ATTR_MEASRED_VALUES_EDITABLE).extract();
+	}
+
+	/**
+	 * Sets a new measured values editable flag for this template sensor.
+	 *
+	 * @param measuredValuesEditable The measured values editable flag.
+	 */
+	public void setMeasuredValuesEditable(Boolean measuredValuesEditable) {
+		getValue(ATTR_MEASRED_VALUES_EDITABLE).set(measuredValuesEditable);
+	}
+
+	/**
+	 * Returns the measured values generator name of this template sensor.
+	 *
+	 * @return The measured values generator name is returned.
+	 */
+	public String getMeasuredValuesGeneratorName() {
+		return getValue(ATTR_MEASRED_VALUES_GENERATOR_NAME).extract();
+	}
+
+	/**
+	 * Sets a new measured values generator name for this template sensor.
+	 *
+	 * @param measuredValuesGeneratorName The measured values generator name.
+	 */
+	public void setMeasuredValuesGeneratorName(String measuredValuesGeneratorName) {
+		getValue(ATTR_MEASRED_VALUES_GENERATOR_NAME).set(measuredValuesGeneratorName);
+	}
+
+	/**
+	 * Returns the measured values independent flag of this template sensor.
+	 *
+	 * @return The measured values independent flag is returned.
+	 */
+	public Boolean areMeasuredValuesIndependent() {
+		return getValue(ATTR_MEASRED_VALUES_INDEPENDENT).extract();
+	}
+
+	/**
+	 * Sets a new measured values independent flag for this template sensor.
+	 *
+	 * @param measuredValuesIndependent The measured values independent flag.
+	 */
+	public void setMeasuredValuesIndependent(Boolean measuredValuesIndependent) {
+		getValue(ATTR_MEASRED_VALUES_INDEPENDENT).set(measuredValuesIndependent);
+	}
+
+	/**
+	 * Returns the measured values {@link AxisType} of this template sensor.
+	 *
+	 * @return The measured values {@code AxisType} is returned.
+	 */
+	public AxisType getMeasuredValuesAxisType() {
+		return getValue(ATTR_MEASRED_VALUES_AXISTYPE).extract();
+	}
+
+	/**
+	 * Sets a new measured values {@link AxisType} for this template sensor.
+	 *
+	 * @param axisType The measured values {@code AxisType}.
+	 */
+	public void setMeasuredValuesAxisType(AxisType axisType) {
+		getValue(ATTR_MEASRED_VALUES_AXISTYPE).set(axisType);
+	}
+
+	/**
+	 * Returns the optional flag of this template sensor.
+	 *
+	 * @return Returns {@code true} if it is allowed to omit a {@link ContextSensor}
+	 *         derived from this template sensor.
+	 */
+	public Boolean isOptional() {
+		return getValue(ATTR_OPTIONAL).extract();
+	}
+
+	/**
+	 * Sets a new optional flag for this template sensor.
+	 *
+	 * @param optional The new optional flag.
+	 */
+	public void setOptional(Boolean optional) {
+		getValue(ATTR_OPTIONAL).set(optional);
+	}
+
+	/**
+	 * Returns the default active flag of this template sensor.
+	 *
+	 * @return Returns {@code true} if a {@link ContextSensor} has to be created
+	 *         automatically each time a new {@link ContextComponent} is derived
+	 *         from the {@link TemplateComponent} this template sensor belongs to.
+	 */
+	public Boolean isDefaultActive() {
+		return getValue(ATTR_DEFAULT_ACTIVE).extract();
+	}
+
+	/**
+	 * Sets a new default active flag for this template sensor.
+	 *
+	 * @param defaultActive The new default active flag.
+	 */
+	public void setDefaultActive(Boolean defaultActive) {
+		getValue(ATTR_DEFAULT_ACTIVE).set(defaultActive);
+	}
+
+	/**
+	 * Returns the {@link CatalogSensor} this template sensor is associated with.
+	 *
+	 * @return The associated {@code CatalogSensor} is returned.
+	 */
+	public CatalogSensor getCatalogSensor() {
+		return getCore().getMutableStore().get(CatalogSensor.class);
+	}
+
+	/**
+	 * Returns the {@link Quantity} measured data are associated with.
+	 *
+	 * @return The {@code Quantity} is returned.
+	 */
+	public Quantity getQuantity() {
+		return getCore().getMutableStore().get(Quantity.class);
+	}
+
+	/**
+	 * Returns the {@link TemplateRoot} this template sensor belongs to.
+	 *
+	 * @return The {@code TemplateRoot} is returned.
+	 */
+	public TemplateRoot getTemplateRoot() {
+		return getTemplateComponent().getTemplateRoot();
+	}
+
+	/**
+	 * Returns the parent {@link TemplateComponent} of this template sensor.
+	 *
+	 * @return The parent {@code TemplateComponent} is returned.
+	 */
+	public TemplateComponent getTemplateComponent() {
+		return getCore().getPermanentStore().get(TemplateComponent.class);
+	}
+
+	/**
+	 * Returns the {@link TemplateAttribute} identified by given name.
+	 *
+	 * @param name The name of the {@code TemplateAttribute}.
+	 * @return The {@code Optional} is empty if a {@code TemplateAttribute} with
+	 *         given name does not exist.
+	 */
+	public Optional<TemplateAttribute> getTemplateAttribute(String name) {
+		return getTemplateAttributes().stream().filter(ta -> ta.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link TemplateAttribute}s related to this template
+	 * sensor.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TemplateAttribute> getTemplateAttributes() {
+		return getCore().getChildrenStore().get(TemplateAttribute.class);
+	}
+
+	/**
+	 * Removes the {@link TemplateAttribute} identified by given name.
+	 *
+	 * @param name Name of the {@code TemplateAttribute} that has to be removed.
+	 * @return Returns {@code true} if the {@code TemplateAttribute} with given name
+	 *         has been removed.
+	 */
+	public boolean removeTemplateAttribute(String name) {
+		Optional<TemplateAttribute> templateAttribute = getTemplateAttribute(name);
+		if (templateAttribute.isPresent()) {
+			getCore().getChildrenStore().remove(templateAttribute.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<TemplateAttribute> templateAttributes = getTemplateAttributes();
+		if (!templateAttributes.isEmpty()) {
+			sb.append(", TemplateAttributes = ").append(templateAttributes);
+		}
+
+		return sb.append(')').toString();
+	}
+
+	/**
+	 * Returns the {@link TemplateSensor} the given {@link ContextSensor} is derived
+	 * from.
+	 *
+	 * @param contextSensor The {@code ContextSensor} whose {@code
+	 * 		TemplateSensor} is requested.
+	 * @return {@code Optional} is empty if the given {@code ContextSensor} is not
+	 *         derived from a template, which is data source specific.
+	 */
+	public static Optional<TemplateSensor> of(ContextSensor contextSensor) {
+		return Optional.ofNullable(getCore(contextSensor).getMutableStore().get(TemplateSensor.class));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTest.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTest.java
new file mode 100644
index 0000000..2d39ad8
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTest.java
@@ -0,0 +1,224 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template test entity type. A template test consists of
+ * {@link TemplateTestStepUsage}s with unique names. It describes a template for
+ * a test run and provides meta data to resolve hooks and data sources for
+ * naming, property validation, resolution and other purposes. A template test
+ * implements the {@link Versionable} interface and hence has a version and a
+ * state. As long as {@link #isEditable()} returns {@code true} any part of that
+ * template test is allowed to be modified. Once a template test is set to be
+ * valid ({@link #isValid()} == {@code true}) it may be used to define a test
+ * run therefore is no longer allowed to be modified in any way. If a valid
+ * template test needs to be modified, then a deep copy with a unique name and
+ * version combination has to be created (deep copy means new instances).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateTestStepUsage
+ * @see Versionable
+ */
+public class TemplateTest extends BaseEntity implements Deletable, Describable, Versionable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'NameHelperClassname' attribute name.
+	 */
+	public static final String ATTR_NAMEHELPER_CLASSNAME = "NameHelperClassname";
+
+	/**
+	 * The 'DataSourcePluginClassnames' attribute name.
+	 */
+	public static final String ATTR_DATASOURCE_PLUGIN_CLASSNAMES = "DataSourcePluginClassnames";
+
+	/**
+	 * The 'TestOrderActionClassnames' attribute name.
+	 */
+	public static final String ATTR_TEST_ORDER_ACTION_CLASSNAMES = "TestOrderActionClassnames";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TemplateTest(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name helper class name of this template test.
+	 *
+	 * @return The name helper class name is returned.
+	 */
+	public String getNameHelperClassname() {
+		return getValue(ATTR_NAMEHELPER_CLASSNAME).extract();
+	}
+
+	/**
+	 * Sets a new name helper class name for this template test.
+	 *
+	 * @param nameHelperClassname The new name helper class name.
+	 */
+	public void setNameHelperClassname(String nameHelperClassname) {
+		getValue(ATTR_NAMEHELPER_CLASSNAME).set(nameHelperClassname);
+	}
+
+	/**
+	 * Returns the data source plug-in class names of this template test.
+	 *
+	 * @return The data source plug-in class names are returned.
+	 */
+	public String[] getDataSourcePluginClassnames() {
+		return getValue(ATTR_DATASOURCE_PLUGIN_CLASSNAMES).extract();
+	}
+
+	/**
+	 * Sets new data source plug-in class names for this template test.
+	 *
+	 * @param dataSourcePluginClassnames The new data source plug-in class names.
+	 */
+	public void setDataSourceClassnames(String[] dataSourcePluginClassnames) {
+		getValue(ATTR_DATASOURCE_PLUGIN_CLASSNAMES).set(dataSourcePluginClassnames);
+	}
+
+	/**
+	 * Returns the test order action class names of this template test.
+	 *
+	 * @return The test order action class names are returned.
+	 */
+	public String[] getTestOrderActionClassnames() {
+		return getValue(ATTR_TEST_ORDER_ACTION_CLASSNAMES).extract();
+	}
+
+	/**
+	 * Sets new test order action class names for this template test.
+	 *
+	 * @param testOrderActionClassnames The new test order action class names.
+	 */
+	public void setTestOrderActionClassnames(String[] testOrderActionClassnames) {
+		getValue(ATTR_TEST_ORDER_ACTION_CLASSNAMES).set(testOrderActionClassnames);
+	}
+
+	/**
+	 * Returns the {@link TemplateTestStepUsage} identified by given name.
+	 *
+	 * @param name The name of the {@code TemplateTestStepUsage}.
+	 * @return The {@code Optional} is empty if a {@code TemplateTestStepUsage} with
+	 *         given name does not exist.
+	 */
+	public Optional<TemplateTestStepUsage> getTemplateTestStepUsage(String name) {
+		return getTemplateTestStepUsages().stream().filter(ttsu -> ttsu.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link TemplateTestStepUsage}s related to this template
+	 * test.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TemplateTestStepUsage> getTemplateTestStepUsages() {
+		return getCore().getChildrenStore().get(TemplateTestStepUsage.class);
+	}
+
+	/**
+	 * Removes the {@link TemplateTestStepUsage} identified by given name.
+	 *
+	 * @param name Name of the {@code TemplateTestStepUsage} that has to be removed.
+	 * @return Returns {@code true} if the {@code TemplateTestStepUsage} with given
+	 *         name has been removed.
+	 */
+	public boolean removeTemplateTestStepUsage(String name) {
+		Optional<TemplateTestStepUsage> templateTestStepUsage = getTemplateTestStepUsage(name);
+		if (templateTestStepUsage.isPresent()) {
+			getCore().getChildrenStore().remove(templateTestStepUsage.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<TemplateTestStepUsage> templateTestStepUsages = getTemplateTestStepUsages();
+		if (!templateTestStepUsages.isEmpty()) {
+			sb.append(", TemplateTestStepUsages = ").append(templateTestStepUsages);
+		}
+
+		return sb.append(')').toString();
+	}
+
+	/**
+	 * Returns the {@link TemplateComponent} the given {@link ContextComponent} is
+	 * derived from.
+	 *
+	 * @param test The {@code ContextComponent} whose {@code TemplateComponent} is
+	 *             requested.
+	 * @return {@code Optional} is empty if the given {@code ContextComponent} is
+	 *         not derived from a template, which is data source specific.
+	 */
+	public static Optional<TemplateTest> of(Test test) {
+		return Optional.ofNullable(getCore(test).getMutableStore().get(TemplateTest.class));
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Checks whether given {@link TemplateTestStepUsage} is contained in this
+	 * template test.
+	 *
+	 * @param templateTestStep The {@code TemplateTestStepUsage}.
+	 * @return Returns {@code true} if given {@code TemplateTestStepUsage} is
+	 *         contained in this template test.
+	 */
+	boolean contains(TemplateTestStep templateTestStep) {
+		return getTemplateTestStepUsages().stream().map(TemplateTestStepUsage::getTemplateTestStep)
+				.filter(tts -> tts.getName().equals(templateTestStep.getName()))
+				.filter(tts -> tts.getVersion().equals(templateTestStep.getVersion())).findFirst().isPresent();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStep.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStep.java
new file mode 100644
index 0000000..1690562
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStep.java
@@ -0,0 +1,127 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.TestStep;
+
+/**
+ * Implementation of the template test step entity type. A template test step
+ * describes the composition of {@link TemplateRoot}s which in finally is a
+ * template for a persisted context description ("as measured", "as ordered"). A
+ * template test step implements the {@link Versionable} interface and hence has
+ * a version and a state. As long as {@link #isEditable()} returns {@code
+ * true} any part of that template test step is allowed to be modified. Once a
+ * template test step is set to be valid ({@link #isValid()} == {@code true}) it
+ * may be used to compose a {@link TemplateTest} and then is no longer allowed
+ * to be modified in any way. If a valid template test step needs to be
+ * modified, then a deep copy with a unique name and version combination has to
+ * be created (deep copy means new instances).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateRoot
+ * @see Versionable
+ */
+public class TemplateTestStep extends BaseEntity implements Deletable, Describable, Versionable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TemplateTestStep(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the related {@link TemplateRoot} with given {@link ContextType} of
+	 * this template test step.
+	 *
+	 * @param contextType Used as identifier.
+	 * @return {@code Optional} is empty if a {@code TemplateRoot} of given
+	 *         {@code ContextType} does not exist.
+	 */
+	public Optional<TemplateRoot> getTemplateRoot(ContextType contextType) {
+		return Optional.ofNullable(getCore().getMutableStore().get(TemplateRoot.class, contextType));
+	}
+
+	/**
+	 * Returns all available {@link TemplateRoot}s related to this template test
+	 * step.
+	 *
+	 * @return Returns {@code List} contains up to 3 {@code TemplateRoot}s with
+	 *         distinct {@link ContextType}s.
+	 */
+	public List<TemplateRoot> getTemplateRoots() {
+		List<TemplateRoot> templateRoots = new ArrayList<>();
+		getTemplateRoot(ContextType.UNITUNDERTEST).ifPresent(templateRoots::add);
+		getTemplateRoot(ContextType.TESTSEQUENCE).ifPresent(templateRoots::add);
+		getTemplateRoot(ContextType.TESTEQUIPMENT).ifPresent(templateRoots::add);
+		return templateRoots;
+	}
+
+	/**
+	 * Replaces current {@link TemplateRoot} with the given one.
+	 *
+	 * @param templateRoot Is not allowed to be null.
+	 * @see #removeTemplateRoot(ContextType)
+	 */
+	public void setTemplateRoot(TemplateRoot templateRoot) {
+		getCore().getMutableStore().set(templateRoot, templateRoot.getContextType());
+	}
+
+	/**
+	 * Removes current {@link TemplateRoot} with given {@link ContextType}.
+	 *
+	 * @param contextType Used as identifier.
+	 * @return Returns {@code true} if the {@code TemplateRoot} has been removed.
+	 */
+	public boolean removeTemplateRoot(ContextType contextType) {
+		boolean contained = getTemplateRoot(contextType).isPresent();
+		getCore().getMutableStore().remove(TemplateRoot.class, contextType);
+		return contained;
+	}
+
+	/**
+	 * Returns the {@link TemplateTestStep} the given {@link TestStep} is derived
+	 * from.
+	 *
+	 * @param testStep The {@code TestStep} whose {@code TemplateTestStep} is
+	 *                 requested.
+	 * @return {@code Optional} is empty if the given {@code TestStep} is not
+	 *         derived from a template.
+	 */
+	public static Optional<TemplateTestStep> of(TestStep testStep) {
+		return Optional.ofNullable(getCore(testStep).getMutableStore().get(TemplateTestStep.class));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStepUsage.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStepUsage.java
new file mode 100644
index 0000000..e7323c1
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStepUsage.java
@@ -0,0 +1,148 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.function.Predicate;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+
+/**
+ * Implementation of the template test step usage entity type. A template test
+ * relates a {@link TemplateTestStep} with a parent {@link TemplateTest} (n:m).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateTest
+ * @see TemplateTestStep
+ */
+public class TemplateTestStepUsage extends BaseEntity implements Deletable, Sortable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The optional flag {@code Predicate}.
+	 */
+	public static final Predicate<TemplateTestStepUsage> IS_OPTIONAL = TemplateTestStepUsage::isOptional;
+
+	/**
+	 * The mandatory flag {@code Predicate}. This is the inversion of
+	 * {@link #IS_OPTIONAL} {@code Predicate}.
+	 */
+	public static final Predicate<TemplateTestStepUsage> IS_MANDATORY = IS_OPTIONAL.negate();
+
+	/**
+	 * The default active flag {@code Predicate}.
+	 */
+	public static final Predicate<TemplateTestStepUsage> IS_DEFAULT_ACTIVE = TemplateTestStepUsage::isDefaultActive;
+
+	/**
+	 * The implicit create flag {@code Predicate}. This is an OR combination of
+	 * {@link #IS_DEFAULT_ACTIVE} and {@link #IS_MANDATORY} {@code Predicate}s.
+	 */
+	public static final Predicate<TemplateTestStepUsage> IS_IMPLICIT_CREATE = IS_DEFAULT_ACTIVE.or(IS_MANDATORY);
+
+	/**
+	 * The 'DefaultActive' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_ACTIVE = "DefaultActive";
+
+	/**
+	 * The 'Optional' attribute name.
+	 */
+	public static final String ATTR_OPTIONAL = "Optional";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TemplateTestStepUsage(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the default active flag of this template test step usage.
+	 *
+	 * @return Returns {@code true} if a {@link TestStep} has to be created
+	 *         automatically each time a new {@link Test} is derived from the
+	 *         {@link TemplateTest} this template test step usage belongs to.
+	 */
+	public Boolean isDefaultActive() {
+		return getValue(ATTR_DEFAULT_ACTIVE).extract();
+	}
+
+	/**
+	 * Sets a new default active flag for this template test step usage.
+	 *
+	 * @param defaultActive The new default active flag.
+	 */
+	public void setDefaultActive(Boolean defaultActive) {
+		getValue(ATTR_DEFAULT_ACTIVE).set(defaultActive);
+	}
+
+	/**
+	 * Returns the optional flag of this template test step.
+	 *
+	 * @return Returns {@code true} if it is allowed to omit a {@link TestStep}
+	 *         derived from this template test step usage.
+	 */
+	public Boolean isOptional() {
+		return getValue(ATTR_OPTIONAL).extract();
+	}
+
+	/**
+	 * Sets a new optional flag for this template test step usage.
+	 *
+	 * @param optional The new optional flag.
+	 */
+	public void setOptional(Boolean optional) {
+		getValue(ATTR_OPTIONAL).set(optional);
+	}
+
+	/**
+	 * Returns the parent {@link TemplateTest}.
+	 *
+	 * @return The parent {@code TemplateTest} is returned.
+	 */
+	public TemplateTest getTemplateTest() {
+		return getCore().getPermanentStore().get(TemplateTest.class);
+	}
+
+	/**
+	 * Returns the {@link TemplateTestStep} related to this template test step
+	 * usage.
+	 *
+	 * @return The {@code TemplateTestStep} is returned.
+	 */
+	public TemplateTestStep getTemplateTestStep() {
+		return getCore().getMutableStore().get(TemplateTestStep.class);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/UserParameter.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/UserParameter.java
new file mode 100644
index 0000000..7997ab7
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/UserParameter.java
@@ -0,0 +1,28 @@
+/*******************************************************************************

+ * Copyright (c) 2020 Contributors to the Eclipse Foundation

+ *

+ * See the NOTICE file(s) distributed with this work for additional

+ * information regarding copyright ownership.

+ *

+ * This program and the accompanying materials are made available under the

+ * terms of the Eclipse Public License v. 2.0 which is available at

+ * http://www.eclipse.org/legal/epl-2.0.

+ *

+ * SPDX-License-Identifier: EPL-2.0

+ *******************************************************************************/

+package org.eclipse.mdm.api.dflt.model;

+

+import org.eclipse.mdm.api.base.adapter.Core;

+import org.eclipse.mdm.api.base.model.BaseEntity;

+

+/**

+ * @author akn

+ *

+ */

+public class UserParameter extends BaseEntity {

+

+	UserParameter(Core core) {

+		super(core);

+	}

+

+}

diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueList.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueList.java
new file mode 100644
index 0000000..b6327b3
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueList.java
@@ -0,0 +1,110 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the value list entity type. A value list provides a set of
+ * default values which may be used as options while defining default values in
+ * templates or modifying context data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see ValueListValue
+ * @see CatalogAttribute
+ */
+public class ValueList extends BaseEntity implements Datable, Describable, Deletable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ValueList(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ValueListValue} identified by given name.
+	 *
+	 * @param name The name of the {@code ValueListValue}.
+	 * @return The {@code Optional} is empty if a {@code ValueListValue} with given
+	 *         name does not exist.
+	 */
+	public Optional<ValueListValue> getValueListValue(String name) {
+		return getValueListValues().stream().filter(vlv -> vlv.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link ValueListValue}s related to this value list.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<ValueListValue> getValueListValues() {
+		return getCore().getChildrenStore().get(ValueListValue.class);
+	}
+
+	/**
+	 * Removes the {@link ValueListValue} identified by given name.
+	 *
+	 * @param name Name of the {@code ValueListValue} that has to be removed.
+	 * @return Returns {@code true} if the {@code ValueListValues} with given name
+	 *         has been removed.
+	 */
+	public boolean removeValueListValue(String name) {
+		Optional<ValueListValue> valueListValue = getValueListValue(name);
+		if (valueListValue.isPresent()) {
+			getCore().getChildrenStore().remove(valueListValue.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<ValueListValue> valueListValues = getValueListValues();
+		if (!valueListValues.isEmpty()) {
+			sb.append(", ValueListValues = ").append(valueListValues);
+		}
+
+		return sb.append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueListValue.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueListValue.java
new file mode 100644
index 0000000..936ad5f
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueListValue.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Sortable;
+
+/**
+ * Implementation of the value list value entity type. A value list value is a
+ * unique value option within the parent {@link ValueList}. Therefore the names
+ * of the value list values within a {@code ValueList} have to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see ValueList
+ */
+public class ValueListValue extends BaseEntity implements Deletable, Describable, Sortable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'ScalarType' attribute name.
+	 */
+	public static final String ATTR_SCALAR_TYPE = "DataType";
+
+	/**
+	 * The 'Value' attribute name.
+	 */
+	public static final String ATTR_VALUE = "Value";
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ValueListValue(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setName(String name) {
+		getValue(ATTR_VALUE).set(name);
+		super.setName(name);
+	}
+
+	/**
+	 * Returns the parent {@link ValueList}.
+	 *
+	 * @return The parent {@code ValueList} is returned.
+	 */
+	public ValueList getValueList() {
+		return getCore().getPermanentStore().get(ValueList.class);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Versionable.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Versionable.java
new file mode 100644
index 0000000..4ca00f4
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Versionable.java
@@ -0,0 +1,120 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Comparator;
+
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.VersionState;
+
+/**
+ * This interface extends the {@link Datable} interface and provides getter and
+ * setter methods for the 'Version' and 'VersionState' fields of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface Versionable extends Datable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * This {@code Comparator} compares {@link Versionable}s by their name (in
+	 * ascending order) and version (in descending order).
+	 */
+	Comparator<Versionable> COMPARATOR = Comparator.comparing(Versionable::getName)
+			.thenComparing(Comparator.comparing(Versionable::getVersion).reversed());
+
+	/**
+	 * The 'Version' attribute name.
+	 */
+	String ATTR_VERSION = "Version";
+
+	/**
+	 * The 'VersionState' attribute name.
+	 */
+	String ATTR_VERSION_STATE = "ValidFlag";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the version of this entity.
+	 *
+	 * @return The version is returned.
+	 */
+	default Integer getVersion() {
+		return Integer.valueOf(getValue(ATTR_VERSION).extract());
+	}
+
+	/**
+	 * Sets new version for this entity.
+	 *
+	 * @param version The new version.
+	 */
+	default void setVersion(Integer version) {
+		getValue(ATTR_VERSION).set(version.toString());
+	}
+
+	/**
+	 * Returns the {@link VersionState} of this entity.
+	 *
+	 * @return The {@code VersionState} is returned.
+	 */
+	default VersionState getVersionState() {
+		return getValue(ATTR_VERSION_STATE).extract();
+	}
+
+	/**
+	 * Sets new {@link VersionState} for this entity.
+	 *
+	 * @param versionState The new {@code VersionState}.
+	 */
+	default void setVersionState(VersionState versionState) {
+		getValue(ATTR_VERSION_STATE).set(versionState);
+	}
+
+	/**
+	 * Checks whether parts of this versionable are allowed to be modified.
+	 *
+	 * @return Returns {@code true} if modifications are allowed.
+	 */
+	default boolean isEditable() {
+		return getVersionState().isEditable();
+	}
+
+	/**
+	 * Checks whether this versionable is valid and therefore is no longer allowed
+	 * to be modified.
+	 *
+	 * @return Returns {@code true} if this versionable is valid.
+	 */
+	default boolean isValid() {
+		return getVersionState().isValid();
+	}
+
+	/**
+	 * Checks whether this versionable is archived.
+	 *
+	 * @return Returns {@code true} if this versionable is archived.
+	 */
+	default boolean isArchived() {
+		return getVersionState().isArchived();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.default/src/test/java/org/eclipse/mdm/api/dflt/model/EntityFactoryTest.java b/org.eclipse.mdm.api.default/src/test/java/org/eclipse/mdm/api/dflt/model/EntityFactoryTest.java
new file mode 100644
index 0000000..fe77bdb
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/test/java/org/eclipse/mdm/api/dflt/model/EntityFactoryTest.java
@@ -0,0 +1,43 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.junit.Test;
+
+public class EntityFactoryTest {
+
+	@Test
+	public void createBaseEntities() {
+		EntityFactory entityFactory = mock(EntityFactory.class);
+		when(entityFactory.createBaseEntity(any(), any())).thenCallRealMethod();
+
+		// The Entities below were chosen as representatives of their respective
+		// packages since their constructors don't do anything with the Core instances
+		// passed to them, so a null pointer is sufficient for this test.
+
+		// Channel class is in package org.eclipse.mdm.api.base.model
+		// (BaseEntityFactory's package):
+		assertThat(entityFactory.createBaseEntity(Channel.class, null)).isInstanceOf(Channel.class);
+		// CatalogSensor class is in package org.eclipse.mdm.api.dflt.model
+		// (EntityFactory's package):
+		assertThat(entityFactory.createBaseEntity(CatalogSensor.class, null)).isInstanceOf(CatalogSensor.class);
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/.gitignore b/org.eclipse.mdm.api.odsadapter/.gitignore
new file mode 100644
index 0000000..12a6d10
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/.gitignore
@@ -0,0 +1,18 @@
+# eclipse
+.classpath
+.project
+.settings/
+bin/
+src/gen/
+
+# gradle
+.gradle
+build/
+
+# intellij
+.idea/
+out/
+*.ipr
+*.iml
+*.iws
+/bin/
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/LICENSE.txt b/org.eclipse.mdm.api.odsadapter/LICENSE.txt
new file mode 100644
index 0000000..e48e096
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/LICENSE.txt
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0
+
+    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a) in the case of the initial Contributor, the initial content
+     Distributed under this Agreement, and
+
+  b) in the case of each subsequent Contributor:
+     i) changes to the Program, and
+     ii) additions to the Program;
+  where such changes and/or additions to the Program originate from
+  and are Distributed by that particular Contributor. A Contribution
+  "originates" from a Contributor if it was added to the Program by
+  such Contributor itself or anyone acting on such Contributor's behalf.
+  Contributions do not include changes or additions to the Program that
+  are not Modified Works.
+
+"Contributor" means any person or entity that Distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which
+are necessarily infringed by the use or sale of its Contribution alone
+or when combined with the Program.
+
+"Program" means the Contributions Distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement
+or any Secondary License (as applicable), including Contributors.
+
+"Derivative Works" shall mean any work, whether in Source Code or other
+form, that is based on (or derived from) the Program and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship.
+
+"Modified Works" shall mean any work in Source Code or other form that
+results from an addition to, deletion from, or modification of the
+contents of the Program, including, for purposes of clarity any new file
+in Source Code form that contains any contents of the Program. Modified
+Works shall not include works that contain only declarations,
+interfaces, types, classes, structures, or files of the Program solely
+in each case in order to link to, bind by name, or subclass the Program
+or Modified Works thereof.
+
+"Distribute" means the acts of a) distributing or b) making available
+in any manner that enables the transfer of a copy.
+
+"Source Code" means the form of a Program preferred for making
+modifications, including but not limited to software source code,
+documentation source, and configuration files.
+
+"Secondary License" means either the GNU General Public License,
+Version 2.0, or any later versions of that license, including any
+exceptions or additional permissions as identified by the initial
+Contributor.
+
+2. GRANT OF RIGHTS
+
+  a) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free copyright
+  license to reproduce, prepare Derivative Works of, publicly display,
+  publicly perform, Distribute and sublicense the Contribution of such
+  Contributor, if any, and such Derivative Works.
+
+  b) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free patent
+  license under Licensed Patents to make, use, sell, offer to sell,
+  import and otherwise transfer the Contribution of such Contributor,
+  if any, in Source Code or other form. This patent license shall
+  apply to the combination of the Contribution and the Program if, at
+  the time the Contribution is added by the Contributor, such addition
+  of the Contribution causes such combination to be covered by the
+  Licensed Patents. The patent license shall not apply to any other
+  combinations which include the Contribution. No hardware per se is
+  licensed hereunder.
+
+  c) Recipient understands that although each Contributor grants the
+  licenses to its Contributions set forth herein, no assurances are
+  provided by any Contributor that the Program does not infringe the
+  patent or other intellectual property rights of any other entity.
+  Each Contributor disclaims any liability to Recipient for claims
+  brought by any other entity based on infringement of intellectual
+  property rights or otherwise. As a condition to exercising the
+  rights and licenses granted hereunder, each Recipient hereby
+  assumes sole responsibility to secure any other intellectual
+  property rights needed, if any. For example, if a third party
+  patent license is required to allow Recipient to Distribute the
+  Program, it is Recipient's responsibility to acquire that license
+  before distributing the Program.
+
+  d) Each Contributor represents that to its knowledge it has
+  sufficient copyright rights in its Contribution, if any, to grant
+  the copyright license set forth in this Agreement.
+
+  e) Notwithstanding the terms of any Secondary License, no
+  Contributor makes additional grants to any Recipient (other than
+  those set forth in this Agreement) as a result of such Recipient's
+  receipt of the Program under the terms of a Secondary License
+  (if permitted under the terms of Section 3).
+
+3. REQUIREMENTS
+
+3.1 If a Contributor Distributes the Program in any form, then:
+
+  a) the Program must also be made available as Source Code, in
+  accordance with section 3.2, and the Contributor must accompany
+  the Program with a statement that the Source Code for the Program
+  is available under this Agreement, and informs Recipients how to
+  obtain it in a reasonable manner on or through a medium customarily
+  used for software exchange; and
+
+  b) the Contributor may Distribute the Program under a license
+  different than this Agreement, provided that such license:
+     i) effectively disclaims on behalf of all other Contributors all
+     warranties and conditions, express and implied, including
+     warranties or conditions of title and non-infringement, and
+     implied warranties or conditions of merchantability and fitness
+     for a particular purpose;
+
+     ii) effectively excludes on behalf of all other Contributors all
+     liability for damages, including direct, indirect, special,
+     incidental and consequential damages, such as lost profits;
+
+     iii) does not attempt to limit or alter the recipients' rights
+     in the Source Code under section 3.2; and
+
+     iv) requires any subsequent distribution of the Program by any
+     party to be under a license that satisfies the requirements
+     of this section 3.
+
+3.2 When the Program is Distributed as Source Code:
+
+  a) it must be made available under this Agreement, or if the
+  Program (i) is combined with other material in a separate file or
+  files made available under a Secondary License, and (ii) the initial
+  Contributor attached to the Source Code the notice described in
+  Exhibit A of this Agreement, then the Program may be made available
+  under the terms of such Secondary Licenses, and
+
+  b) a copy of this Agreement must be included with each copy of
+  the Program.
+
+3.3 Contributors may not remove or alter any copyright, patent,
+trademark, attribution notices, disclaimers of warranty, or limitations
+of liability ("notices") contained within the Program from any copy of
+the Program which they Distribute, provided that Contributors may add
+their own appropriate notices.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While this
+license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product
+offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes
+the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every
+other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits
+and other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program
+in a commercial product offering. The obligations in this section do not
+apply to any claims or Losses relating to any actual or alleged
+intellectual property infringement. In order to qualify, an Indemnified
+Contributor must: a) promptly notify the Commercial Contributor in
+writing of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those performance
+claims and warranties, and if a court requires any other Contributor to
+pay any damages as a result, the Commercial Contributor must pay
+those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED 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. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all
+risks associated with its exercise of rights under this Agreement,
+including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs
+or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software
+or hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted and
+may only be modified in the following manner. The Agreement Steward
+reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement
+Steward has the right to modify this Agreement. The Eclipse Foundation
+is the initial Agreement Steward. The Eclipse Foundation may assign the
+responsibility to serve as the Agreement Steward to a suitable separate
+entity. Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always be
+Distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to Distribute the Program (including its
+Contributions) under the new version.
+
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted
+under this Agreement are reserved. Nothing in this Agreement is intended
+to be enforceable by any entity that is not a Contributor or Recipient.
+No third-party beneficiary rights are created under this Agreement.
+
+Exhibit A - Form of Secondary Licenses Notice
+
+"This Source Code may also be made available under the following
+Secondary Licenses when the conditions for such availability set forth
+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+version(s), and exceptions or additional permissions here}."
+
+  Simply including a copy of this Agreement, including this Exhibit A
+  is not sufficient to license the Source Code under Secondary Licenses.
+
+  If it is not possible or desirable to put the notice in a particular
+  file, then You may include the notice in a location (such as a LICENSE
+  file in a relevant directory) where a recipient would be likely to
+  look for such a notice.
+
+  You may add additional accurate notices of copyright ownership.
diff --git a/org.eclipse.mdm.api.odsadapter/NOTICE.txt b/org.eclipse.mdm.api.odsadapter/NOTICE.txt
new file mode 100644
index 0000000..56281c6
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/NOTICE.txt
@@ -0,0 +1,382 @@
+# Notices for Eclipse MDM|BL
+
+This content is produced and maintained by the Eclipse MDM|BL project,
+it is a project of the openMDM(R) Eclipse Working Group.
+
+* Project home: https://projects.eclipse.org/projects/technology.mdmbl
+
+## Trademarks
+
+Eclipse MDM|BL, MDM|BL and Eclipse openMDM(R) logo are registered trademarks
+of the Eclipse Foundation.
+
+## Copyright
+
+All content is the property of the following respective authors or their employers.
+For more information regarding authorship of content, please consult the listed
+source code repository logs.
+
+Copyright (c) 2016-2019 Gigatronik Ingolstadt GmbH
+Copyright (c) 2016-2020 Peak Solution GmbH
+Copyright (c) 2017-2018 science + computing AG Tuebingen (ATOS SE)
+Copyright (c) 2017-2018 Canoo Engineering AG
+Copyright (c) 2017 Florian Schmitt
+Copyright (c) 2017-2020 Angelika Wittek
+Copyright (c) 2018-2019 Elektronische Fahrwerksysteme GMBH
+Copyright (c) 2018-2020 Karakun AG
+Copyright (c) 2018-2020 Alexander Nehmer
+
+## Declared Project Licenses
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v. 2.0 which is available at
+http://www.eclipse.org/legal/epl-2.0.
+
+SPDX-License-Identifier: EPL-2.0
+
+## Source Code
+
+The project maintains the following source code repositories:
+
+org.eclipse.mdm.api.base.git	    - The openMDM(R) API.
+org.eclipse.mdm.api.default.git	    - Extension of the openMDM(R) API containing default elements.
+org.eclipse.mdm.api.odsadapter.git	- ODS implementation of persistence adapter.
+org.eclipse.mdm.nucleus.git	        - Core building blocks for the openMDM Business Logic and Web Frontend.
+
+## Third-party Content
+
+The Content includes items that have been sourced from third parties as set out below.
+If you did not receive this Content directly from the Eclipse Foundation, the following
+is provided for informational purposes only, and you should look to
+the Redistributor's license for terms and conditions of use.
+
+antlr4-4.5.3.jar(2.5.3)
+    * License: New BSD license
+
+aopalliance-repackaged-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+commons-codec-1.2.jar (1.2)
+    * License: Apache License, 2.0
+
+commons-httpclient-3.1.jar  (3.1)
+    * License: Apache License, 2.0
+
+commons-lang3-3.8.1.jar (3.8.1)
+    * License: Apache License, 2.0
+
+commons-text-1.6.jar (1.6)
+    * License: Apache License, 2.0
+
+gson-2.7.jar (2.7)
+    * License: Apache License, 2.0
+
+Google Guava Version: 25.0-jre  (25.0)
+    * License: Apache License, 2.0
+
+Gradle Wrapper (4.10.2)
+    * License: Apache License, 2.0
+
+hk2-api-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL-1.1
+
+hk2-locator-2.5.0-b05.jar(2.5.0-b05)
+    * License: CDDL
+
+hk2-utils-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+jackson-annotations-2.9.0.jar  (2.9.0)
+    * License: Apache License, 2.0
+
+jackson-core-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-databind-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-base-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-json-provider-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-module-jaxb-annotations-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+javassist-3.20.0-GA.jar  (2.20.0-GA)
+    * License: Apache 2.0
+
+jcl-over-slf4j-1.7.25.jar(1.7.25)
+    * License: MIT License
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL:  https://www.slf4j.org
+    * Source URL:   https://github.com/qos-ch/slf4j
+
+jersey-client-2.23.2.jar (2.23.2)
+     * License: CDDL
+
+jersey-common-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-2.23.2.jar  (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-core-2.23.3.jar(2.23.2)
+    * License: CDDL
+
+jersey-guava-2.23.2.jar  (2.23.2)
+    * License: Apache License, 2.0
+
+jersey-media-jaxb-2.23.2.jar(2.23.2)
+    * License: CDDL
+
+jersey-media-sse-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-media-multipart-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-server-2.23.2.jar (2.23.2)
+    * License: Apache-2.0
+
+log4j-over-slf4j-1.7.25.jar (1.7.25)
+    * License: Apache-2.0
+
+logback-classic-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+logback-core-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+mimepull-1.9.6.jar (1.9.4)
+    * License: CDDL
+
+openatfx-0.7.4.jar (0.7.4)
+    * License: Apache-2.0
+
+osgi-resource-locator-1.0.1.jar(1.0.1)
+    * License: CDDL
+
+protobuf-java-3.2.0.jar (3.2.0)
+    * License: New BSD license
+
+protobuf-java-util-3.2.0.jar  (3.2.0)
+    * License: New BSD license
+
+swagger-annotations-2.0.8.jar (2.0.8)
+    * License: Apache-2.0
+
+swagger-ui-3.23.0.jar (3.23.0)
+    * License: Apache-2.0
+
+slf4j-api-1.7.25.jar  (1.7.25)
+    * License: MIT license
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL: https://github.com/qos-ch/slf4j
+    * Source URL:  https://github.com/qos-ch/slf4j/releases/tag/v_1.7.25
+
+stax2-api-3.1.4.jar (3.1.4)
+    * License: BSD-2-Clause
+
+validation-api-1.1.0.Final.jar (1.1.0.Final)
+  * License: Apache License, 2.0
+
+vavr-0.9.1-sources.jar (0.9.1)
+  * License: Apache License, 2.0
+
+vavr-match-0.9.1.jar (0.9.1)
+  * License: Apache License, 2.0
+
+woodstox-core-asl-4.4.1.jar (4.4.1)
+  * License: Apache License, 2.0
+
+
+FFAMFAMFAM Silk Icon, Version 1.3
+    * License: Creative Commons Attribution 3.0 License
+    * Licence Path: https://creativecommons.org/licenses/by/3.0/
+    * Project: http://www.famfamfam.com/lab/icons/silk/
+    * Source:  http://www.famfamfam.com/lab/icons/silk/
+
+@angular/animations:7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/animations
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/cdk:7.1.1
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api
+    * Source:  https://github.com/angular/angular/releases/tag/7.1.1
+
+
+@angular/common@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/common
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4r
+
+@angular/compiler@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/core@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/forms@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/http@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser-dynamic@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/router@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+bootstrap@4.1.3
+    * License: MIT
+    * Licence Path: https://github.com/twbs/bootstrap/raw/master/LICENSE
+    * Project: https://getbootstrap.com/
+    * Source:  https://github.com/twbs/bootstrap
+
+class-transformer@0.1.6
+    * License: MIT
+    * Licence Path: https://github.com/typestack/class-transformer/blob/master/LICENSE
+    * Project: https://github.com/pleerock/class-transformer
+    * Source:  https://github.com/pleerock/class-transformer
+
+core-js@2.6.0
+    * License: MIT
+    * Licence Path: https://github.com/zloirock/core-js/raw/master/LICENSE
+    * Project: https://github.com/zloirock/core-js
+    * Source:  https://github.com/zloirock/core-js/releases/tag/v2.6.0
+
+file-saver@1.3.3
+    * License: MIT
+    * Licence Path: https://github.com/eligrey/FileSaver.js/raw/master/LICENSE.md
+    * Project: https://github.com/eligrey/FileSaver.js
+    * Source:  https://github.com/eligrey/FileSaver.js
+
+font-awesome@4.7.0
+    * License: MIT
+    * Licence Path: https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt
+    * Project: https://fontawesome.com/
+    * Source:  https://github.com/FortAwesome/Font-Awesome
+
+ng2-split-pane@1.3.1
+    * License: MIT
+    * Licence Path: https://github.com/wannabegeek/ng2-split-pane/raw/master/LICENSE
+    * Project: https://github.com/wannabegeek/ng2-split-pane
+    * Source:  https://github.com/wannabegeek/ng2-split-pane
+
+ngx-bootstrap@3.1.2
+    * License: MIT
+    * Licence Path: https://github.com/valor-software/ngx-bootstrap/blob/v3.1.2/LICENSE
+    * Project: https://valor-software.com/ngx-bootstrap
+    * Source:  https://github.com/valor-software/ngx-bootstrap/tree/v3.1.2
+
+@ngx-translate/core@11.0.1
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/core/blob/v11.0.1/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/core
+
+@ngx-translate/http-loader@4.0.0
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/http-loader/blob/v4.0.0/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/http-loader/tree/v4.0.0
+
+primeicons:1.0.0
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeicons/blob/1.0.0/LICENSE
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeicons/tree/1.0.0
+
+primeng@7.0.1
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeng/blob/7.0.1/LICENSE.md
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeng/tree/7.0.1
+
+rxjs@6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3
+
+rxjs-compat:6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3/compat
+
+tslib@1.9.0
+    * License: Apache-2.0
+    * Project: https://github.com/Microsoft/tslib
+    * Source:  https://github.com/Microsoft/tslib/tree/1.9.0
+
+zone.js@0.8.26
+    * License: MIT
+    * Licence Path: https://github.com/angular/zone.js/raw/master/LICENSE
+    * Project: https://github.com/angular
+    * Source:  https://github.com/angular/zone.js/releases/tag/v0.8.26
+
+OMG Event Service Specification (1.2)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/EVNT/1.2/
+* Source: https://www.omg.org/spec/EVNT/1.2/pdf
+
+OMG Notification Service Specification (1.1)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/NOT/
+* Source: https://www.omg.org/spec/NOT/1.1/PDF
+
+ods530.idl
+Date: Hoehenkirchen, 06/01/2016
+"The ASAM Board of Directors releases the IDL files for use under the EPL to the Eclipse IWG openMDM.
+This is valid for all versions of ASAM ODS 5.3.x.
+This permission is valid under the conditions of Eclipse will not modify the file."
+
+AvalonEvent.idl, CorbaFileServer.idl
+Date: 08/15/2016
+"Herewith, we release the generated Client-Source-Code generated from our CORBA IDLs, namely
+* CORBANotification Service (generated from „AvalonEvent.idl”)
+* CORBAFileServer (generated from „CorbaFileServer.idl“),
+Under the Eclipse Public License (EPL). This agreement does not include the „AvalonEvent.idl“ and
+„CorbaFileServer.idl“ itself, which remain protected property of HighQSoft. "
+
+## Cryptography
+
+Content may contain encryption software. The country in which you are currently
+may have restrictions on the import, possession, and use, and/or re-export to
+another country, of encryption software. BEFORE using any encryption software,
+please check the country's laws, regulations and policies concerning the import,
+possession, or use, and re-export of encryption software, to see if this is
+permitted.
diff --git a/org.eclipse.mdm.api.odsadapter/README.md b/org.eclipse.mdm.api.odsadapter/README.md
new file mode 100644
index 0000000..80e73da
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/README.md
@@ -0,0 +1,164 @@
+# MDM5 API #
+
+
+This document describes the services defined in the MDM5 API.
+
+
+## 1. Introduction ##
+
+The MDM5 API consists of the following projects:
+
+
+-   **org.eclipse.mdm.api.base**\
+    Defines the core services and entities. Entities contained in this
+    project must be supported by all implementations.
+
+-   **org.eclipse.mdm.api.default**\
+    Extends the core API with catalog and template entities to organize
+    the storage of context data.
+
+-   **org.eclipse.mdm.api.odsadapter**\
+    Implements both org.eclipse.mdm.api.base and org.eclipse.mdm.default
+    using the query based ASAM ODS OO API.
+
+
+## 2. EntityManager ##
+
+Once a connection to a persistence (e.g. ODS server) is established, the
+entity manager allows to load entities of any kind and provides access
+to available services.
+
+
+Returned entities are always complete. This means they are loaded with
+all of their properties and related entities (as exposed by their API).
+Therefore it does not matter how entities are retrieved (e.g. entity
+manager or search service). The entity manager provides various methods
+to load instances by their id, load parent or child entities for a given
+entity or filter loaded entities with a given naming pattern. Context
+data may be loaded for TestStep or Measurement entities.
+
+
+Mass data may be loaded by defining a corresponding request. Such a
+request consists of a ChannelGroup and a subset of related Channels.
+Finally, a range is defined to loaded stored values iteratively or all at
+once. This allows a fine grained access to stored mass data.
+
+
+### 2.1. SearchService ###
+
+The search service allows to search for entities like Test, TestStep,
+Measurement and Channel across hierarchies. So one can, for example,
+search for Tests and apply filter criteria for context data of related
+TestSteps and Measurements without defining any joins. This is done by
+the internally used search queries. Each search query defines a set of
+supported entity types and hence all of its attributes may be used for
+selections or filter criteria. The search service allows to query
+possible filter values for each supported attribute.
+
+
+In addition to that a query string may be used to search for entities.
+This query string is evaluated and processed by a full text search
+which returns a result consisting of Test, TestStep or Measurement
+entities.
+
+
+### 2.2. Notification ###
+
+TODO
+
+
+### 2.3. FileService ###
+
+The file service may be used to download externally linked files, query
+their size or open a consumable download stream for a given externally
+linked file. Sequential or parallel download of multiple files is
+possible as well. A download request with multiple files may have
+multiple links to the same file. In such a case this file is downloaded
+only once and all links will point to the same local copy of the
+downloaded file. Since downloading large files may take its time to
+complete, one can pass a listener to track the overall progress.
+
+NOTE:
+```
+This service does not allow manually uploading or deleting files. Instead 
+files are automatically uploaded / deleted while entities are written 
+within a Section 2.5, "Transaction".
+```
+
+### 2.4. EntityFactory ###
+
+The entity factory is the only way to create new entities. Each entity
+returned by this service is considered to be virtual, since it does not
+have an id until it is written. Entities with informational relations
+like Quantity (references a Unit) or Unit (references a
+PhysicalDimension) may only reference already persisted entities. This
+means that a new Quantity may only be created with an already persisted
+Unit and a new Unit may only be created with an already persisted
+PhysicalDimension.
+
+
+On the other hand, it is possible to create parent / child trees
+consisting of virtual or persisted entities (parent and child entities
+are internally linked together). Within a transaction such trees are
+recursively processed, therefore it is not required to explicitly
+create, update or delete child entities, instead it is sufficient and
+highly recommended to write only the root entity of the tree(s). The
+transaction service recursively resolves such trees and executes batch
+insert-, update- or delete-statements for the children.
+
+
+### 2.5. Transaction ###
+
+The transaction service effectively modifies the stored contents.
+Entities are grouped by their type before they are processed. Each group
+is processed at once with a batch statement. Each written entity is
+scanned for externally linked files. New ones are automatically uploaded,
+while removed ones are deleted. In case of errors any changes made to the
+persistence are cancelled and hence any successfully uploaded file has to
+be deleted. Unfortunately, the removal of uploaded files cannot be
+guaranteed (e.g. a broken connection), instead a delete request for the
+uploaded files is send on a best effort basis.
+
+IMPORTANT:
+```
+Externally linked files of deleted entities are only removed if the
+entity is an instance of FilesAttachable (Test, TestStep, Measurement).
+In any other case, externally linked files are not removed since this 
+may have an impact on other entities which reference the same file.
+```
+
+Besides the modification of entities, it is possible to write mass data
+by defining write requests. A write request describes in detail how the
+mass data of a Channel is organized (e.g. values are explicit or
+generated, stored in externally linked files etc.).
+
+
+
+## 3. Connect to an ODS Server ##
+
+The ODS entity manager factory is used to connect to an ODS server. It
+takes parameters, shown in the example below, to establish a
+connection. On success an entity manager is returned.
+
+```java
+    Map<String, String> connectionParameters = new HashMap<>();
+    connectionParameters.put(ODSEntityManagerFactory.PARAM_NAMESERVICE, "corbaloc::1.2@<SERVER>:<PORT>/NameService");
+    connectionParameters.put(ODSEntityManagerFactory.PARAM_SERVICENAME, "<SERVICE>.ASAM-ODS");
+    connectionParameters.put(ODSEntityManagerFactory.PARAM_USER, "sa");
+    connectionParameters.put(ODSEntityManagerFactory.PARAM_PASSWORD, "sa");
+    EntityManager entityManager = new ODSEntityManagerFactory().connect(connectionParameters);
+    // do something useful
+    entityManager.close();
+```
+
+## 4. Copyright and License ##
+Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+
+ See the NOTICE file(s) distributed with this work for additional
+ information regarding copyright ownership.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v. 2.0 which is available at
+ http://www.eclipse.org/legal/epl-2.0.
+
+ SPDX-License-Identifier: EPL-2.0
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/build.gradle b/org.eclipse.mdm.api.odsadapter/build.gradle
new file mode 100644
index 0000000..4a95a97
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/build.gradle
@@ -0,0 +1,193 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+description = 'MDM API - ODSAdapter'
+group = 'org.eclipse.mdm'
+version = '5.2.0M1-SNAPSHOT'
+
+apply plugin: 'java'
+apply plugin: 'maven'
+apply plugin: 'eclipse'
+apply plugin: 'com.google.protobuf'
+
+buildscript {
+	repositories {
+		mavenCentral()
+	}
+	dependencies {
+		classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
+	}
+}
+
+repositories {
+	jcenter()
+	mavenLocal()
+	mavenCentral()
+}
+
+sourceSets {
+
+	generated {
+		java {
+			srcDir 'src/gen/java'
+			srcDir 'build/generated/source/proto/main/java'
+		}
+	}
+
+	main {
+		compileClasspath += generated.output
+		runtimeClasspath += generated.output
+	}
+
+	test {
+		compileClasspath += generated.output
+		runtimeClasspath += generated.output
+	}
+}
+
+configurations.all {
+	exclude group: 'javax.inject', module: 'javax.inject'
+	exclude group: 'commons-logging', module: 'commons-logging'
+	
+	// exclude guava dependencies
+	exclude group: 'com.google.code.findbugs', module: 'jsr305'
+	exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
+	exclude group: 'com.google.j2objc', module: 'j2objc-annotations'
+	exclude group: 'org.codehaus.mojo', module: 'animal-sniffer-annotations'
+	exclude group: 'org.checkerframework', module: 'checker-compat-qual'
+}
+
+dependencies {
+	compileOnly 'javax:javaee-api:7.0'
+
+	// logging
+	compile 'org.slf4j:slf4j-api:1.7.25'
+	// httpclient uses commons-logging
+	compile 'org.slf4j:jcl-over-slf4j:1.7.25'
+
+	// MDM5 API
+	compile "org.eclipse.mdm:org.eclipse.mdm.api.base:${version}"
+	compile "org.eclipse.mdm:org.eclipse.mdm.api.default:${version}"
+
+	// compile CORBA idl using JDK tools
+	generatedCompile files(System.getenv('JAVA_HOME') + '/lib/tools.jar')
+    generatedCompile files('src/main/idl/')
+    
+	// Peak notification service
+	compile 'com.google.protobuf:protobuf-java:3.2.0'
+	compile 'com.google.protobuf:protobuf-java-util:3.2.0'
+	compile 'com.google.guava:guava:25.0-jre'
+	compile 'org.glassfish.jersey.core:jersey-client:2.23.2'
+	compile 'org.glassfish.jersey.media:jersey-media-sse:2.23.2'
+	generatedCompile 'com.google.protobuf:protobuf-java:3.2.0'
+
+	// querying es
+	compile 'commons-httpclient:commons-httpclient:3.1'
+	compile 'org.apache.commons:commons-text:1.6'
+
+	// testing
+	testCompile 'junit:junit:4.12'
+	testRuntime 'org.slf4j:slf4j-simple:1.7.25'
+	testCompile 'org.mockito:mockito-core:2.13.0'
+	testCompile 'org.assertj:assertj-core:3.6.2'
+	
+	testCompile "org.elasticsearch.client:elasticsearch-rest-client:6.4.1"
+	testCompile "org.testcontainers:elasticsearch:1.12.5"
+}
+
+test {
+	if(project.hasProperty('host')) {
+		systemProperty 'host', project.property('host')
+	} else {
+		systemProperty 'host', '<host>'
+	}
+
+	if(project.hasProperty('port')) {
+		systemProperty 'port', project.property('port')
+	} else {
+		systemProperty 'port', '2809'
+	}
+	
+	if(project.hasProperty('service')) {
+		systemProperty 'service', project.property('service')
+	} else {
+		systemProperty 'service', '<service>'
+	}
+
+	jvmArgs '-Dorg.slf4j.simpleLogger.defaultLogLevel=debug'
+}
+
+protobuf {
+	protoc {
+		artifact = 'com.google.protobuf:protoc:3.2.0'
+	}
+}
+
+
+task compileIDL(type: JavaExec) {
+	classpath = configurations.generatedCompile
+
+	main = 'com.sun.tools.corba.se.idl.toJavaPortable.Compile'
+
+	// add 'fallTIE' if <Type>POA & <Type>POATie have to be generated   
+	args '-fallTIE', '-td', 'src/gen/java/', 'src/main/idl/ods530.idl'
+
+	outputs.dir("src/gen/java")
+}
+
+task compileNotificationServiceIDL(type: JavaExec) {
+	classpath = configurations.generatedCompile
+
+	main = 'com.sun.tools.corba.se.idl.toJavaPortable.Compile'
+
+	args '-emitAll', '-fallTIE', '-i', 'src/main/idl/', '-td', 'src/gen/java/', 'src/main/idl/CosNotifyChannelAdmin.idl'
+
+	outputs.dir("src/gen/java")
+	outputs.upToDateWhen { false }
+}
+
+compileGeneratedJava {
+	inputs.dir("build/generated/source")
+	inputs.dir("src/gen/java")
+}
+
+// generate classes from idl and compile them
+compileGeneratedJava.dependsOn compileIDL
+compileGeneratedJava.dependsOn compileNotificationServiceIDL
+
+compileJava.dependsOn compileGeneratedJava
+
+jar {
+	from sourceSets.generated.output
+	dependsOn generatedClasses
+
+	metaInf { from 'NOTICE.txt' }
+	metaInf { from 'LICENSE.txt' }
+}
+
+task sourcesJar(type: Jar, dependsOn: classes) {
+	classifier = 'sources'
+	from sourceSets.main.allSource
+}
+
+artifacts {
+	archives sourcesJar
+}
+
+task deleteGenerated(type: Delete) {
+	delete 'src/gen'
+	delete 'build'
+}
+
+clean.dependsOn deleteGenerated
diff --git a/org.eclipse.mdm.api.odsadapter/gradle.properties b/org.eclipse.mdm.api.odsadapter/gradle.properties
new file mode 100644
index 0000000..2ab5436
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/gradle.properties
@@ -0,0 +1,16 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+ 
+sourceCompatibility=1.8
+targetCompatibility=1.8
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/gradle/wrapper/gradle-wrapper.jar b/org.eclipse.mdm.api.odsadapter/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/org.eclipse.mdm.api.odsadapter/gradle/wrapper/gradle-wrapper.properties b/org.eclipse.mdm.api.odsadapter/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82e006
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME

+distributionPath=wrapper/dists

+zipStoreBase=GRADLE_USER_HOME

+zipStorePath=wrapper/dists

+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip

diff --git a/org.eclipse.mdm.api.odsadapter/gradlew b/org.eclipse.mdm.api.odsadapter/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/org.eclipse.mdm.api.odsadapter/gradlew.bat b/org.eclipse.mdm.api.odsadapter/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windows variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/org.eclipse.mdm.api.odsadapter/settings.gradle b/org.eclipse.mdm.api.odsadapter/settings.gradle
new file mode 100644
index 0000000..e1e8178
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/settings.gradle
@@ -0,0 +1,15 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+rootProject.name = 'org.eclipse.mdm.api.odsadapter'
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/doc/mdm5_api.adoc b/org.eclipse.mdm.api.odsadapter/src/main/doc/mdm5_api.adoc
new file mode 100644
index 0000000..ef765c3
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/doc/mdm5_api.adoc
@@ -0,0 +1,84 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+= MDM5 API
+
+This document describes the services defined in the MDM5 API.
+
+== Introduction
+The MDM5 API consists of the following projects:
+
+* *org.eclipse.mdm.api.base* +
+    Defines the core services and entities. Entities contained in this project must be supported by all implementations.
+* *org.eclipse.mdm.api.default* +
+    Extends the core API with catalog and template entities to organize the storage of context data. 
+* *org.eclipse.mdm.api.odsadapter* +
+    Implements both org.eclipse.mdm.api.base and org.eclipse.mdm.default using the query based ASAM ODS OO API.
+    
+== EntityManager
+
+Once a connection to a persistence (e.g. ODS server) is established, the entity manager allows to load entities of any kind and provides access to available services. 
+
+Returned entities are always complete. This means they are loaded with all of their properties and related entities (as exposed by their API). Therefore it does not matter how entities are retrieved (e.g. entity manager or search service). The entity manager provides various methods to load instances by their id, load parent or child entities for a given entity or filter loaded entities with a given naming pattern. Context data may be loaded for TestStep or Measurement entities.
+
+Mass data may be loaded by defining a corresponding request. Such a request consists of a ChannelGroup and a subset of related Channels. Finally a range is defined to loaded stored values iteratively or all at once. This allows a fine grained access to stored mass data.
+
+=== SearchService
+The search service allows to search for entities like Test, TestStep, Measurement and Channel across hierarchies. So one can, for example, search for Tests and apply filter criteria for context data of related TestSteps and Measurements without defining any joins. This is done by the internally used search queries. Each search query defines a set of supported entity types and hence all of its attributes may be used for selections or filter criteria. The search service allows to query possible filter values for each supported attribute.
+
+In addition to that a query string may be used to search for entities. This query string is evaluated and processed by a full text search which returns a result consisting of Test, TestStep or Measurement entities.
+
+=== Notification
+TODO
+
+=== FileService
+The file service may be used to download externally linked files, query their size or open a consumable download stream for a given externally linked file. Sequential or parallel download of multiple files is possible as well. A download request with multiple files may have multiple links to the same file. In such a case this file is downloaded only once and all links will point to the same local copy of the downloaded file. Since downloading large files may take its time to complete, one can pass a listener to track the overall progress.
+
+[NOTE]
+====
+This service does not allow manually uploading or deleting files. Instead files are automatically uploaded / deleted while entities are written within a <<Transaction>>.
+====
+
+=== EntityFactory
+The entity factory is the only way to create new entities. Each entity returned by this service is considered to be virtual, since it does not have an id until it is written. Entities with informational relations like Quantity (references a Unit) or Unit (references a PhysicalDimension) may only reference already persisted entities. This means that a new Quantity may only be created with an already persisted Unit and a new Unit may only be created with an already persisted PhysicalDimension.
+
+On the other hand it is possible to create parent / child trees consisting of virtual or persisted entities (parent and child entities are internally linked together). Within a transaction such trees are recursively processed, therefore it is not required to explicitly create, update or delete child entities, instead it is sufficient and highly recommended to write only the root entity of the tree(s). The transaction service recursively resolves such trees and executes batch insert-, update- or delete-statements for the children.
+
+=== Transaction
+The transaction service effectively modifies the stored contents. Entities are grouped by their type before they are processed. Each group is processed at once with a batch statement. Each  written entity is scanned for externally linked files. New ones are automatically uploaded, while removed ones are deleted. In case of errors any changes made to the persistence are cancelled and hence any successfully uploaded file has to be deleted. Unfortunately the removal of uploaded files cannot be guaranteed (e.g. a broken connection), instead a delete request for the uploaded files is send on a best effort basis.
+
+[IMPORTANT]
+====
+Externally linked files of deleted entities are only removed if the entity is an instance of FilesAttachable (Test, TestStep, Measurement). In any other case externally linked files are not removed, since this may have an impact on other entities which reference the same file.
+====
+
+Besides the modification of entities, it is possible to write mass data by defining write requests. A write request describes in detail how the mass data of a Channel is organized (e.g. values are explicit or generated, stored in externally linked files etc.).
+
+== Connect to an ODS Server
+The ODS entity manager factory is used to connect to an ODS server. It takes parameters, shown in the exapmple below, to establish a connection. On success an entity manager is returned.
+
+[source,java]
+----
+Map<String, String> connectionParameters = new HashMap<>();
+connectionParameters.put(ODSEntityManagerFactory.PARAM_NAMESERVICE, "corbaloc::1.2@<SERVER>:<PORT>/NameService");
+connectionParameters.put(ODSEntityManagerFactory.PARAM_SERVICENAME, "<SERVICE>.ASAM-ODS");
+connectionParameters.put(ODSEntityManagerFactory.PARAM_USER, "sa");
+connectionParameters.put(ODSEntityManagerFactory.PARAM_PASSWORD, "sa");
+
+EntityManager entityManager = new ODSEntityManagerFactory().connect(connectionParameters);
+
+// do something useful
+
+entityManager.close();
+----
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/CosEventChannelAdmin.idl b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosEventChannelAdmin.idl
new file mode 100644
index 0000000..8ddf3a3
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosEventChannelAdmin.idl
@@ -0,0 +1,59 @@
+/**

+ * This module is taken from the standard CORBA Event Service

+ * 1.2, as described in:

+ *

+ * https://www.omg.org/spec/EVNT/1.2/

+ *

+ * The idl was extracted from the following PDF:

+ * formal/04-10-02 

+ */

+

+#ifndef _COS_EVENT_CHANNEL_ADMIN_IDL_

+#define _COS_EVENT_CHANNEL_ADMIN_IDL_

+

+#include "CosEventComm.idl"
+

+#pragma prefix "omg.org"

+
+module CosEventChannelAdmin {
+
+   exception AlreadyConnected {};
+   exception TypeError {};
+
+   interface ProxyPushConsumer: CosEventComm::PushConsumer {
+      void connect_push_supplier(in CosEventComm::PushSupplier push_supplier)
+         raises(AlreadyConnected);
+   };
+
+   interface ProxyPullSupplier: CosEventComm::PullSupplier {
+      void connect_pull_consumer(in CosEventComm::PullConsumer pull_consumer)
+         raises(AlreadyConnected);
+   };
+
+   interface ProxyPullConsumer: CosEventComm::PullConsumer {
+      void connect_pull_supplier(in CosEventComm::PullSupplier pull_supplier)
+         raises(AlreadyConnected,TypeError);
+   };
+
+   interface ProxyPushSupplier: CosEventComm::PushSupplier {
+      void connect_push_consumer(in CosEventComm::PushConsumer push_consumer)
+         raises(AlreadyConnected, TypeError);
+   };
+
+   interface ConsumerAdmin {
+      ProxyPushSupplier obtain_push_supplier();
+      ProxyPullSupplier obtain_pull_supplier();
+   };
+
+   interface SupplierAdmin {
+      ProxyPushConsumer obtain_push_consumer();
+      ProxyPullConsumer obtain_pull_consumer();
+   };
+
+   interface EventChannel {
+      ConsumerAdmin for_consumers();
+      SupplierAdmin for_suppliers();
+      void destroy();
+   };
+};
+#endif /* ifndef _COS_EVENT_CHANNEL_ADMIN_IDL_ */
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/CosEventComm.idl b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosEventComm.idl
new file mode 100644
index 0000000..ed88691
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosEventComm.idl
@@ -0,0 +1,41 @@
+/**

+ * This module is taken from the standard CORBA Event Service

+ * 1.2, as described in:

+ *

+ * https://www.omg.org/spec/EVNT/1.2/

+ *

+ * The idl was extracted from the following PDF:

+ * formal/04-10-02 

+ */

+ 

+#ifndef _COS_EVENT_COMM_IDL_

+#define _COS_EVENT_COMM_IDL_

+

+#pragma prefix "omg.org"

+

+module CosEventComm {
+
+   exception Disconnected{};
+
+   interface PushConsumer {
+      void push (in any data) raises(Disconnected);
+      void disconnect_push_consumer();
+   };
+
+    interface PushSupplier {
+      void disconnect_push_supplier();
+   };
+
+   interface PullSupplier {
+      any pull () raises(Disconnected);
+      any try_pull (out boolean has_event) raises(Disconnected);
+      void disconnect_pull_supplier();
+   };
+
+   interface PullConsumer {
+      void disconnect_pull_consumer();
+   };
+
+};
+
+#endif /* ifndef _COS_EVENT_COMM_IDL_ */
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotification.idl b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotification.idl
new file mode 100644
index 0000000..a789700
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotification.idl
@@ -0,0 +1,180 @@
+/**

+ * This module is taken from the standard CORBA Notification Service

+ * 1.1, as described in:

+ *

+ * https://www.omg.org/spec/NOT/1.1/

+ *

+ * The idl was extracted from the following PDF:

+ * formal/04-10-13

+ */

+

+#ifndef _COS_NOTIFICATION_IDL_

+#define _COS_NOTIFICATION_IDL_

+

+#pragma prefix "omg.org"

+

+module CosNotification {
+
+   typedef string Istring;
+   typedef Istring PropertyName;
+   typedef any PropertyValue;
+
+   struct Property {
+      PropertyName name;
+      PropertyValue value;
+   };
+   typedef sequence<Property> PropertySeq;
+
+   // The following are the same, but serve different purposes.
+   typedef PropertySeq OptionalHeaderFields;
+   typedef PropertySeq FilterableEventBody;
+   typedef PropertySeq QoSProperties;
+   typedef PropertySeq AdminProperties;
+
+   struct _EventType {
+      string domain_name;
+      string type_name;
+   };
+   typedef sequence<_EventType> EventTypeSeq;
+
+   struct PropertyRange {
+      PropertyValue low_val;
+      PropertyValue high_val;
+   };
+
+   struct NamedPropertyRange {
+      PropertyName name;
+      PropertyRange range;
+   };
+   typedef sequence<NamedPropertyRange> NamedPropertyRangeSeq;
+
+   enum QoSError_code {
+      UNSUPPORTED_PROPERTY,
+      UNAVAILABLE_PROPERTY,
+      UNSUPPORTED_VALUE,
+      UNAVAILABLE_VALUE,
+      BAD_PROPERTY,
+      BAD_TYPE,
+      BAD_VALUE
+   };
+
+   struct PropertyError {
+      QoSError_code code;
+      PropertyName name;
+      PropertyRange available_range;
+   };
+   typedef sequence<PropertyError> PropertyErrorSeq;
+
+   exception UnsupportedQoS { PropertyErrorSeq qos_err; };
+   exception UnsupportedAdmin { PropertyErrorSeq admin_err; };
+
+   // Define the Structured Event structure
+   struct FixedEventHeader {
+      _EventType event_type;
+      string event_name;
+   };
+
+   struct EventHeader {
+      FixedEventHeader fixed_header;
+      OptionalHeaderFields variable_header;
+   };
+
+   struct StructuredEvent {
+      EventHeader header;
+      FilterableEventBody filterable_data;
+      any remainder_of_body;
+   }; // StructuredEvent
+   typedef sequence<StructuredEvent> EventBatch;
+
+   // The following constant declarations define the standard
+   // QoS property names and the associated values each property
+   // can take on. The name/value pairs for each standard property
+   // are grouped, beginning with a string constant defined for the
+   // property name, followed by the values the property can take on.
+
+   const string EventReliability = "EventReliability";
+   const short BestEffort = 0;
+   const short Persistent = 1;
+
+   const string ConnectionReliability = "ConnectionReliability";
+   // Can take on the same values as EventReliability
+
+   const string Priority = "Priority";
+   const short LowestPriority = -32767;
+   const short HighestPriority = 32767;
+   const short DefaultPriority = 0;
+
+   const string StartTime = "StartTime";
+   // StartTime takes a value of type TimeBase::UtcT.
+
+   const string StopTime = "StopTime";
+   // StopTime takes a value of type TimeBase::UtcT.
+
+   const string Timeout = "Timeout";
+   // Timeout takes on a value of type TimeBase::TimeT
+
+   const string OrderPolicy = "OrderPolicy";
+   const short AnyOrder = 0;
+   const short FifoOrder = 1;
+   const short PriorityOrder = 2;
+   const short DeadlineOrder = 3;
+
+   const string DiscardPolicy = "DiscardPolicy";
+   // DiscardPolicy takes on the same values as OrderPolicy, plus
+   const short LifoOrder = 4;
+
+   const string MaximumBatchSize = "MaximumBatchSize";
+   // MaximumBatchSize takes on a value of type long
+
+   const string PacingInterval = "PacingInterval";
+   // PacingInterval takes on a value of type TimeBase::TimeT
+
+   const string StartTimeSupported = "StartTimeSupported";
+   // StartTimeSupported takes on a boolean value
+
+   const string StopTimeSupported = "StopTimeSupported";
+   // StopTimeSupported takes on a boolean value
+
+   const string MaxEventsPerConsumer = "MaxEventsPerConsumer";
+   // MaxEventsPerConsumer takes on a value of type long
+
+   interface QoSAdmin {
+
+      QoSProperties get_qos();
+
+      void set_qos ( in QoSProperties qos) raises ( UnsupportedQoS );
+
+      void validate_qos (
+            in QoSProperties required_qos,
+            out NamedPropertyRangeSeq available_qos ) raises ( UnsupportedQoS );
+
+   }; // QosAdmin
+
+   // Admin properties are defined in similar manner as QoS
+   // properties. The only difference is that these properties
+   // are related to channel administration policies, as opposed
+   // message quality of service
+
+   const string MaxQueueLength = "MaxQueueLength";
+   // MaxQueueLength takes on a value of type long
+
+   const string MaxConsumers = "MaxConsumers";
+   // MaxConsumers takes on a value of type long
+
+   const string MaxSuppliers = "MaxSuppliers";
+   // MaxSuppliers takes on a value of type long
+
+   const string RejectNewEvents = "RejectNewEvents";
+   // RejectNewEvents takes on a value of type Boolean
+
+   interface AdminPropertiesAdmin {
+
+      AdminProperties get_admin();
+
+      void set_admin (in AdminProperties admin) raises ( UnsupportedAdmin);
+
+   }; // AdminPropertiesAdmin
+
+}; // CosNotification
+
+#endif /* _COS_NOTIFICATION_IDL_ */
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyChannelAdmin.idl b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyChannelAdmin.idl
new file mode 100644
index 0000000..524d3ea
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyChannelAdmin.idl
@@ -0,0 +1,394 @@
+/**
+ * This module is taken from the standard CORBA Notification Service
+ * 1.1, as described in:
+ *
+ * https://www.omg.org/spec/NOT/1.1/
+ *
+ * The idl was extracted from the following PDF:
+ * formal/04-10-13
+ */
+
+#ifndef _COS_NOTIFY_CHANNEL_ADMIN_IDL_
+#define _COS_NOTIFY_CHANNEL_ADMIN_IDL_
+
+#include "CosNotification.idl"
+#include "CosNotifyFilter.idl"
+#include "CosNotifyComm.idl"
+#include "CosEventChannelAdmin.idl"
+
+#pragma prefix "omg.org"
+
+module CosNotifyChannelAdmin {
+
+   exception ConnectionAlreadyActive {};
+   exception ConnectionAlreadyInactive {};
+   exception NotConnected {};
+
+   // Forward declarations
+   interface ConsumerAdmin;
+   interface SupplierAdmin;
+   interface EventChannel;
+   interface EventChannelFactory;
+
+   enum ProxyType {
+      PUSH_ANY,
+      PULL_ANY,
+      PUSH_STRUCTURED,
+      PULL_STRUCTURED,
+      PUSH_SEQUENCE,
+      PULL_SEQUENCE,
+      PUSH_TYPED,
+      PULL_TYPED
+   };
+
+   enum ObtainInfoMode {
+      ALL_NOW_UPDATES_OFF,
+      ALL_NOW_UPDATES_ON,
+      NONE_NOW_UPDATES_OFF,
+      NONE_NOW_UPDATES_ON
+   };
+
+   interface ProxyConsumer :
+         CosNotification::QoSAdmin,
+         CosNotifyFilter::FilterAdmin {
+
+      readonly attribute ProxyType MyType;
+      readonly attribute SupplierAdmin MyAdmin;
+
+      CosNotification::EventTypeSeq obtain_subscription_types(
+            in ObtainInfoMode mode );
+
+      void validate_event_qos (
+            in CosNotification::QoSProperties required_qos,
+            out CosNotification::NamedPropertyRangeSeq available_qos)
+         raises (CosNotification::UnsupportedQoS);
+
+   }; // ProxyConsumer
+
+   interface ProxySupplier :
+         CosNotification::QoSAdmin,
+         CosNotifyFilter::FilterAdmin {
+
+      readonly attribute ProxyType MyType;
+      readonly attribute ConsumerAdmin MyAdmin;
+
+      attribute CosNotifyFilter::MappingFilter priority_filter;
+      attribute CosNotifyFilter::MappingFilter lifetime_filter;
+
+      CosNotification::EventTypeSeq obtain_offered_types(
+            in ObtainInfoMode mode );
+
+      void validate_event_qos (
+            in CosNotification::QoSProperties required_qos,
+            out CosNotification::NamedPropertyRangeSeq available_qos)
+         raises (CosNotification::UnsupportedQoS);
+
+   }; // ProxySupplier
+
+   interface ProxyPushConsumer :
+         ProxyConsumer,
+         CosNotifyComm::PushConsumer {
+
+      void connect_any_push_supplier (
+            in CosEventComm::PushSupplier push_supplier)
+         raises(CosEventChannelAdmin::AlreadyConnected);
+
+   }; // ProxyPushConsumer
+
+   interface StructuredProxyPushConsumer :
+         ProxyConsumer,
+         CosNotifyComm::StructuredPushConsumer {
+
+      void connect_structured_push_supplier (
+            in CosNotifyComm::StructuredPushSupplier push_supplier)
+         raises(CosEventChannelAdmin::AlreadyConnected);
+
+   }; // StructuredProxyPushConsumer
+
+   interface SequenceProxyPushConsumer :
+         ProxyConsumer,
+         CosNotifyComm::SequencePushConsumer {
+
+      void connect_sequence_push_supplier (
+            in CosNotifyComm::SequencePushSupplier push_supplier)
+         raises(CosEventChannelAdmin::AlreadyConnected);
+
+   }; // SequenceProxyPushConsumer
+
+   interface ProxyPullSupplier :
+         ProxySupplier,
+         CosNotifyComm::PullSupplier {
+
+      void connect_any_pull_consumer (
+            in CosEventComm::PullConsumer pull_consumer)
+         raises(CosEventChannelAdmin::AlreadyConnected);
+
+   }; // ProxyPullSupplier
+
+   interface StructuredProxyPullSupplier :
+         ProxySupplier,
+         CosNotifyComm::StructuredPullSupplier {
+
+      void connect_structured_pull_consumer (
+            in CosNotifyComm::StructuredPullConsumer pull_consumer)
+         raises(CosEventChannelAdmin::AlreadyConnected);
+
+   }; // StructuredProxyPullSupplier
+
+   interface SequenceProxyPullSupplier :
+         ProxySupplier,
+         CosNotifyComm::SequencePullSupplier {
+
+      void connect_sequence_pull_consumer (
+            in CosNotifyComm::SequencePullConsumer pull_consumer)
+         raises(CosEventChannelAdmin::AlreadyConnected);
+
+   }; // SequenceProxyPullSupplier
+
+   interface ProxyPullConsumer :
+         ProxyConsumer,
+         CosNotifyComm::PullConsumer {
+
+      void connect_any_pull_supplier (
+            in CosEventComm::PullSupplier pull_supplier)
+         raises(CosEventChannelAdmin::AlreadyConnected,
+                CosEventChannelAdmin::TypeError );
+
+      void suspend_connection()
+         raises(ConnectionAlreadyInactive, NotConnected);
+
+      void resume_connection()
+         raises(ConnectionAlreadyActive, NotConnected);
+
+   }; // ProxyPullConsumer
+
+   interface StructuredProxyPullConsumer :
+         ProxyConsumer,
+         CosNotifyComm::StructuredPullConsumer {
+
+      void connect_structured_pull_supplier (
+            in CosNotifyComm::StructuredPullSupplier pull_supplier)
+         raises(CosEventChannelAdmin::AlreadyConnected,
+                CosEventChannelAdmin::TypeError );
+
+      void suspend_connection()
+         raises(ConnectionAlreadyInactive, NotConnected);
+
+      void resume_connection()
+         raises(ConnectionAlreadyActive, NotConnected);
+
+   }; // StructuredProxyPullConsumer
+
+   interface SequenceProxyPullConsumer :
+         ProxyConsumer,
+         CosNotifyComm::SequencePullConsumer {
+
+      void connect_sequence_pull_supplier (
+            in CosNotifyComm::SequencePullSupplier pull_supplier)
+         raises(CosEventChannelAdmin::AlreadyConnected,
+                CosEventChannelAdmin::TypeError );
+
+      void suspend_connection()
+         raises(ConnectionAlreadyInactive, NotConnected);
+
+      void resume_connection()
+         raises(ConnectionAlreadyActive, NotConnected);
+
+   }; // SequenceProxyPullConsumer
+
+   interface ProxyPushSupplier :
+         ProxySupplier,
+         CosNotifyComm::PushSupplier {
+
+      void connect_any_push_consumer (
+            in CosEventComm::PushConsumer push_consumer)
+         raises(CosEventChannelAdmin::AlreadyConnected,
+                CosEventChannelAdmin::TypeError );
+
+      void suspend_connection()
+         raises(ConnectionAlreadyInactive, NotConnected);
+
+      void resume_connection()
+         raises(ConnectionAlreadyActive, NotConnected);
+
+   }; // ProxyPushSupplier
+
+   interface StructuredProxyPushSupplier :
+         ProxySupplier,
+         CosNotifyComm::StructuredPushSupplier {
+
+      void connect_structured_push_consumer (
+            in CosNotifyComm::StructuredPushConsumer push_consumer)
+         raises(CosEventChannelAdmin::AlreadyConnected,
+                CosEventChannelAdmin::TypeError );
+
+      void suspend_connection()
+         raises(ConnectionAlreadyInactive, NotConnected);
+
+      void resume_connection()
+         raises(ConnectionAlreadyActive, NotConnected);
+
+   }; // StructuredProxyPushSupplier
+
+   interface SequenceProxyPushSupplier :
+         ProxySupplier,
+         CosNotifyComm::SequencePushSupplier {
+
+      void connect_sequence_push_consumer (
+            in CosNotifyComm::SequencePushConsumer push_consumer)
+         raises(CosEventChannelAdmin::AlreadyConnected,
+                CosEventChannelAdmin::TypeError );
+
+      void suspend_connection()
+         raises(ConnectionAlreadyInactive, NotConnected);
+
+      void resume_connection()
+         raises(ConnectionAlreadyActive, NotConnected);
+
+   }; // SequenceProxyPushSupplier
+
+   typedef long ProxyID;
+   typedef sequence <ProxyID> ProxyIDSeq;
+
+   enum ClientType {
+      ANY_EVENT,
+      STRUCTURED_EVENT,
+      SEQUENCE_EVENT
+   };
+
+   enum InterFilterGroupOperator { AND_OP, OR_OP };
+
+   typedef long AdminID;
+   typedef sequence<AdminID> AdminIDSeq;
+
+   exception AdminNotFound {};
+   exception ProxyNotFound {};
+
+   struct AdminLimit {
+      CosNotification::PropertyName name;
+      CosNotification::PropertyValue value;
+   };
+
+   exception AdminLimitExceeded { AdminLimit admin_property_err; };
+
+   interface ConsumerAdmin :
+         CosNotification::QoSAdmin,
+         CosNotifyComm::NotifySubscribe,
+         CosNotifyFilter::FilterAdmin,
+         CosEventChannelAdmin::ConsumerAdmin {
+
+      readonly attribute AdminID MyID;
+      readonly attribute EventChannel MyChannel;
+
+      readonly attribute InterFilterGroupOperator MyOperator;
+
+      attribute CosNotifyFilter::MappingFilter priority_filter;
+      attribute CosNotifyFilter::MappingFilter lifetime_filter;
+
+      readonly attribute ProxyIDSeq pull_suppliers;
+      readonly attribute ProxyIDSeq push_suppliers;
+
+      ProxySupplier get_proxy_supplier ( in ProxyID proxy_id )
+         raises ( ProxyNotFound );
+
+      ProxySupplier obtain_notification_pull_supplier (
+            in ClientType ctype,
+            out ProxyID proxy_id)
+         raises ( AdminLimitExceeded );
+
+      ProxySupplier obtain_notification_push_supplier (
+            in ClientType ctype,
+            out ProxyID proxy_id)
+         raises ( AdminLimitExceeded );
+
+      void destroy();
+
+   }; // ConsumerAdmin
+
+   interface SupplierAdmin :
+         CosNotification::QoSAdmin,
+         CosNotifyComm::NotifyPublish,
+         CosNotifyFilter::FilterAdmin,
+         CosEventChannelAdmin::SupplierAdmin {
+
+      readonly attribute AdminID MyID;
+      readonly attribute EventChannel MyChannel;
+
+      readonly attribute InterFilterGroupOperator MyOperator;
+
+      readonly attribute ProxyIDSeq pull_consumers;
+      readonly attribute ProxyIDSeq push_consumers;
+
+      ProxyConsumer get_proxy_consumer ( in ProxyID proxy_id )
+         raises ( ProxyNotFound );
+
+      ProxyConsumer obtain_notification_pull_consumer (
+            in ClientType ctype,
+            out ProxyID proxy_id)
+         raises ( AdminLimitExceeded );
+
+      ProxyConsumer obtain_notification_push_consumer (
+            in ClientType ctype,
+            out ProxyID proxy_id)
+         raises ( AdminLimitExceeded );
+
+      void destroy();
+
+   }; // SupplierAdmin
+
+   interface EventChannel :
+      CosNotification::QoSAdmin,
+      CosNotification::AdminPropertiesAdmin,
+      CosEventChannelAdmin::EventChannel {
+
+      readonly attribute EventChannelFactory MyFactory;
+
+      readonly attribute ConsumerAdmin default_consumer_admin;
+      readonly attribute SupplierAdmin default_supplier_admin;
+
+      readonly attribute CosNotifyFilter::FilterFactory
+                  default_filter_factory;
+
+      ConsumerAdmin new_for_consumers(
+            in InterFilterGroupOperator op,
+            out AdminID id );
+
+      SupplierAdmin new_for_suppliers(
+            in InterFilterGroupOperator op,
+            out AdminID id );
+
+      ConsumerAdmin get_consumeradmin ( in AdminID id )
+         raises (AdminNotFound);
+
+      SupplierAdmin get_supplieradmin ( in AdminID id )
+         raises (AdminNotFound);
+
+      AdminIDSeq get_all_consumeradmins();
+      AdminIDSeq get_all_supplieradmins();
+
+   }; // EventChannel
+
+   typedef long ChannelID;
+   typedef sequence<ChannelID> ChannelIDSeq;
+
+   exception ChannelNotFound {};
+
+   interface EventChannelFactory {
+
+      EventChannel create_channel (
+            in CosNotification::QoSProperties initial_qos,
+            in CosNotification::AdminProperties initial_admin,
+            out ChannelID id)
+         raises(CosNotification::UnsupportedQoS,
+                CosNotification::UnsupportedAdmin );
+
+      ChannelIDSeq get_all_channels();
+
+      EventChannel get_event_channel ( in ChannelID id )
+         raises (ChannelNotFound);
+
+   }; // EventChannelFactory
+   
+}; // CosNotifyChannelAdmin
+
+#endif /* _COS_NOTIFY_CHANNEL_ADMIN_IDL_ */
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyComm.idl b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyComm.idl
new file mode 100644
index 0000000..33df3d7
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyComm.idl
@@ -0,0 +1,135 @@
+/**
+ * This module is taken from the standard CORBA Notification Service
+ * 1.1, as described in:
+ *
+ * https://www.omg.org/spec/NOT/1.1/
+ *
+ * The idl was extracted from the following PDF:
+ * formal/04-10-13
+ */
+
+#ifndef _COS_NOTIFY_COMM_IDL_
+#define _COS_NOTIFY_COMM_IDL_
+
+#include "CosNotification.idl"
+#include "CosEventComm.idl"
+
+#pragma prefix "omg.org"
+
+module CosNotifyComm {
+
+   exception InvalidEventType { CosNotification::_EventType type; };
+
+   interface NotifyPublish {
+
+      void offer_change (
+            in CosNotification::EventTypeSeq added,
+            in CosNotification::EventTypeSeq removed )
+         raises ( InvalidEventType );
+
+   }; // NotifyPublish
+
+   interface NotifySubscribe {
+
+      void subscription_change(
+            in CosNotification::EventTypeSeq added,
+            in CosNotification::EventTypeSeq removed )
+         raises ( InvalidEventType );
+
+   }; // NotifySubscribe
+
+   interface PushConsumer :
+      NotifyPublish,
+      CosEventComm::PushConsumer {
+   }; // PushConsumer
+
+   interface PullConsumer :
+      NotifyPublish,
+      CosEventComm::PullConsumer {
+   }; // PullConsumer
+
+   interface PullSupplier :
+      NotifySubscribe,
+      CosEventComm::PullSupplier {
+   }; // PullSupplier
+
+   interface PushSupplier :
+      NotifySubscribe,
+      CosEventComm::PushSupplier {
+   };
+
+   interface StructuredPushConsumer : NotifyPublish {
+
+      void push_structured_event(
+            in CosNotification::StructuredEvent notification)
+         raises(CosEventComm::Disconnected);
+
+      void disconnect_structured_push_consumer();
+
+   }; // StructuredPushConsumer
+
+   interface StructuredPullConsumer : NotifyPublish {
+      
+      void disconnect_structured_pull_consumer();
+
+   }; // StructuredPullConsumer
+
+   interface StructuredPullSupplier : NotifySubscribe {
+
+      CosNotification::StructuredEvent pull_structured_event()
+         raises(CosEventComm::Disconnected);
+
+      CosNotification::StructuredEvent try_pull_structured_event(
+            out boolean has_event)
+         raises(CosEventComm::Disconnected);
+
+      void disconnect_structured_pull_supplier();
+
+   }; // StructuredPullSupplier
+
+   interface StructuredPushSupplier : NotifySubscribe {
+      
+      void disconnect_structured_push_supplier();
+
+   }; // StructuredPushSupplier
+
+   interface SequencePushConsumer : NotifyPublish {
+
+      void push_structured_events(
+            in CosNotification::EventBatch notifications)
+         raises(CosEventComm::Disconnected);
+
+      void disconnect_sequence_push_consumer();
+
+   }; // SequencePushConsumer
+
+   interface SequencePullConsumer : NotifyPublish {
+      
+      void disconnect_sequence_pull_consumer();
+
+   }; // SequencePullConsumer
+
+   interface SequencePullSupplier : NotifySubscribe {
+
+      CosNotification::EventBatch pull_structured_events(
+            in long max_number )
+         raises(CosEventComm::Disconnected);
+
+      CosNotification::EventBatch try_pull_structured_events(
+            in long max_number,
+            out boolean has_event)
+         raises(CosEventComm::Disconnected);
+
+      void disconnect_sequence_pull_supplier();
+
+   }; // SequencePullSupplier
+
+   interface SequencePushSupplier : NotifySubscribe {
+      
+      void disconnect_sequence_push_supplier();
+
+   }; // SequencePushSupplier
+
+}; // CosNotifyComm
+
+#endif /* _COS_NOTIFY_COMM_IDL_ */
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyFilter.idl b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyFilter.idl
new file mode 100644
index 0000000..977cc3b
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/CosNotifyFilter.idl
@@ -0,0 +1,187 @@
+/**
+ * This module is taken from the standard CORBA Notification Service
+ * 1.1, as described in:
+ *
+ * https://www.omg.org/spec/NOT/1.1/
+ *
+ * The idl was extracted from the following PDF:
+ * formal/04-10-13
+ */
+
+#ifndef _COS_NOTIFY_FILTER_IDL_
+#define _COS_NOTIFY_FILTER_IDL_
+
+#include "CosNotifyComm.idl"
+
+#pragma prefix "omg.org"
+
+module CosNotifyFilter {
+
+   typedef long ConstraintID;
+
+   struct ConstraintExp {
+      CosNotification::EventTypeSeq event_types;
+      string constraint_expr;
+   };
+
+   typedef sequence<ConstraintID> ConstraintIDSeq;
+   typedef sequence<ConstraintExp> ConstraintExpSeq;
+
+   struct ConstraintInfo {
+      ConstraintExp constraint_expression;
+      ConstraintID constraint_id;
+   };
+
+   typedef sequence<ConstraintInfo> ConstraintInfoSeq;
+
+   struct MappingConstraintPair {
+      ConstraintExp constraint_expression;
+      any result_to_set;
+   };
+
+   typedef sequence<MappingConstraintPair> MappingConstraintPairSeq;
+
+   struct MappingConstraintInfo {
+      ConstraintExp constraint_expression;
+      ConstraintID constraint_id;
+      any value;
+   };
+
+   typedef sequence<MappingConstraintInfo> MappingConstraintInfoSeq;
+
+   typedef long CallbackID;
+   typedef sequence<CallbackID> CallbackIDSeq;
+
+   exception UnsupportedFilterableData {};
+   exception InvalidGrammar {};
+   exception InvalidConstraint {ConstraintExp constr;};
+   exception DuplicateConstraintID {ConstraintID id;};
+   exception ConstraintNotFound {ConstraintID id;};
+   
+   exception CallbackNotFound {};
+
+   exception InvalidValue {ConstraintExp constr; any value;};
+
+   interface Filter {
+
+      readonly attribute string constraint_grammar;
+
+      ConstraintInfoSeq add_constraints (
+            in ConstraintExpSeq constraint_list)
+         raises (InvalidConstraint);
+
+      void modify_constraints (
+            in ConstraintIDSeq del_list,
+            in ConstraintInfoSeq modify_list)
+         raises (InvalidConstraint, ConstraintNotFound);
+
+      ConstraintInfoSeq get_constraints(
+            in ConstraintIDSeq id_list)
+         raises (ConstraintNotFound);
+
+      ConstraintInfoSeq get_all_constraints();
+
+      void remove_all_constraints();
+
+      void destroy();
+
+      boolean match ( in any filterable_data )
+         raises (UnsupportedFilterableData);
+
+      boolean match_structured (
+            in CosNotification::StructuredEvent filterable_data )
+         raises (UnsupportedFilterableData);
+
+      boolean match_typed (
+            in CosNotification::PropertySeq filterable_data )
+         raises (UnsupportedFilterableData);
+
+      CallbackID attach_callback (
+            in CosNotifyComm::NotifySubscribe callback);
+
+      void detach_callback ( in CallbackID callback)
+         raises ( CallbackNotFound );
+
+      CallbackIDSeq get_callbacks();
+
+   }; // Filter
+
+   interface MappingFilter {
+
+      readonly attribute string constraint_grammar;
+
+      readonly attribute CORBA::TypeCode value_type;
+
+      readonly attribute any default_value;
+
+      MappingConstraintInfoSeq add_mapping_constraints (
+            in MappingConstraintPairSeq pair_list)
+         raises (InvalidConstraint, InvalidValue);
+
+      void modify_mapping_constraints (
+            in ConstraintIDSeq del_list,
+            in MappingConstraintInfoSeq modify_list)
+         raises (InvalidConstraint, InvalidValue,
+                  ConstraintNotFound);
+
+      MappingConstraintInfoSeq get_mapping_constraints (
+            in ConstraintIDSeq id_list)
+         raises (ConstraintNotFound);
+
+      MappingConstraintInfoSeq get_all_mapping_constraints();
+
+      void remove_all_mapping_constraints();
+
+      void destroy();
+
+      boolean match (
+            in any filterable_data,
+            out any result_to_set )
+         raises (UnsupportedFilterableData);
+
+      boolean match_structured (
+            in CosNotification::StructuredEvent filterable_data,
+            out any result_to_set)
+         raises (UnsupportedFilterableData);
+
+      boolean match_typed (
+            in CosNotification::PropertySeq filterable_data,
+            out any result_to_set)
+         raises (UnsupportedFilterableData);
+
+   }; // MappingFilter
+
+   interface FilterFactory {
+
+      Filter create_filter ( in string constraint_grammar)
+         raises (InvalidGrammar);
+
+      MappingFilter create_mapping_filter (
+            in string constraint_grammar,
+            in any default_value)
+         raises(InvalidGrammar);
+
+   }; // FilterFactory
+
+   typedef long FilterID;
+   typedef sequence<FilterID> FilterIDSeq;
+
+   exception FilterNotFound {};
+
+   interface FilterAdmin {
+
+      FilterID add_filter ( in Filter new_filter );
+
+      void remove_filter ( in FilterID filter ) raises ( FilterNotFound );
+
+      Filter get_filter ( in FilterID filter ) raises ( FilterNotFound );
+
+      FilterIDSeq get_all_filters();
+
+      void remove_all_filters();
+
+   }; // FilterAdmin
+
+}; // CosNotifyFilter
+
+#endif /* _COS_NOTIFY_FILTER_IDL_ */
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/about.html b/org.eclipse.mdm.api.odsadapter/src/main/idl/about.html
new file mode 100644
index 0000000..399c937
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/about.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!-- saved from url=(0044)https://eclipse.org/legal/epl/longabout.html -->
+<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p><em>October 4, 2016</em></p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content").  Unless otherwise 
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL").  A copy of the EPL is available 
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was 
+provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+		
+		<h3>Third Party Content</h3>
+		<p>The Content includes items that have been sourced from third parties as set out below. If you 
+		did not receive this Content directly from the Eclipse Foundation, the following is provided 
+		for informational purposes only, and you should look to the Redistributor's license for 
+		terms and conditions of use.</p>
+		<p><em>
+		<strong>ods530.idl</strong> <br><br>
+		This file is part of the ASAM ODS standard and is not subject to modification. 
+		</em></p>
+
+
+
+</body></html>
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/idl.config b/org.eclipse.mdm.api.odsadapter/src/main/idl/idl.config
new file mode 100644
index 0000000..7c76796
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/idl.config
@@ -0,0 +1,6 @@
+PkgPrefix.CosEventComm=org.omg

+PkgPrefix.CosNotification=org.omg

+PkgPrefix.CosNotifyComm=org.omg

+PkgPrefix.CosNotifyFilter=org.omg

+PkgPrefix.CosEventChannelAdmin=org.omg

+PkgPrefix.CosNotifyChannelAdmin=org.omg
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/idl/ods530.idl b/org.eclipse.mdm.api.odsadapter/src/main/idl/ods530.idl
new file mode 100644
index 0000000..6071509
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/idl/ods530.idl
@@ -0,0 +1,10883 @@
+//    *********************************************
+//    *     ASAM ODS 5.3.0 Interface Definition     *
+//    *********************************************
+//
+//    Generated: Tue Nov 20 09:28:37 CET 2012
+//
+// More explanation for the method getInstancesEx of the interface
+// ApplElemAccess.   More details for the method setRelationType of the
+// interface ApplicationRelation.
+//
+// Method getRelationByBaseName of the interface ApplicationElement added.  
+// Method getInverseRelationName of instance BaseRelation added.   Better
+// explanation in the comments.  Removed unused error codes of the exceptions.
+//
+// 2003-12-31
+// ODS Version 5.0
+//
+// Add SelOpcode IS_NULL and IS_NOT_NULL.  Add exception AO_INVALID_DATATYPE
+// to the method setEnumerationDefinition of the interface ApplicationElement.
+//  Method getEnumerationDefinition added to the Interface BaseRelation.  Add
+// comment to methods getFormula and setFormula of interface Column.
+//
+// Add the variable CREATE_COSESSION_ALLOWED at the method newSession at the
+// interface AoFactory.   Add the methods createCoSession and getUser at the
+// interface AoSession.  Add values of localcolumn at the methods
+// getInstances, getInstancesExt and updateInstances of the interface
+// ApplElemAccess.  Comment of method setValue of the interface ValueMatrix
+// reworked.
+//
+// Correct the Method getRelationByBaseName of the interface
+// ApplicationElement to the Method getRelationsByBaseName, mistake in
+// Interface definition there are at some elements relations derived from the
+// same base relation allowed.
+//
+// Add, SUM to the AggrFunc.  Change comment of method getApplicationStructure
+// and getBaseStructure of the interface AoSession, the method
+// getApplicationStructure of the interface ApplicationElement.and the method
+// getRelation of the interface BaseStructure.  Add version string description
+// at method getInterfaceVersion of interface AoFactory.
+//
+// Add the Enumeration ValueMatrixMode.  Change the comment of the Methods
+// 13001, 13004, 13006, 14018, 14022, 16003, 21002, 24007  Add the exception
+// AO_INVALID_VALUEMATRIX_STRUCTURE for the method getValueMatrix of the
+// interface Measurement and ApplElemAccess.  Add the new method
+// getValueMatrixInMode of the interfaces Measurement (16005), SubMatrix
+// (21004) and ApplElemAccess   Add the methods getSequenceRepresentation
+// (13013), setSequenceRepresentation (13014), getGenerationParameters
+// (13015), setGenerationParameters (13016) and getRawDataType (13017) of the
+// interface Column.  Add the method getMode (22022) of the interface
+// ValueMatrix.  Little changes in description of the methods, specify which
+// object is modified, with the numbers 4008, 4009, 4010, 4011, 4012, 4013,
+// 4014, 4019, 5001, 5002, 5020, 5021, 5022, 5023, 6010, 6011, 6012, 6013,
+// 6014, 6015, 6016, 6018, 7002, 7003, 7014, 7015, 12001, 12006, 12007, 13005,
+// 14001, 14002, 14014, 14016, 14017, 22014, 22019.  Correct typing errors in
+// method 24005
+//
+// Correct the enumeration ValueMatrixMode. Correct typing errors at method
+// 13014. Extend explanation at 13015 and 13016
+//
+// Typing corrections in IDL:  Method 24005 comment changed. Change the word
+// 'calibrated' into     'recalculated' in method 4014 setUnit.
+//
+// Set the methods hasValueFlag and withValueFlag of the interface
+// ApplicationAttribute to deprecated. Change description of createAttribute
+// of interface ApplicationElement and ErrorCode AO_MISSING_VALUE.
+//
+// Add the interfaces ODSDirectory, ODSFile and ODSFileTransfer and
+// Enumeration FileOpenMode for the managed files. Add the methods
+// getODSDirectory in the interfaces ApplElemAccess and InstanceElement.
+//
+// Add the methods getEnumerationAttributes and getEnumerationStructure of the
+// interface AoSession with the required structures and sequences.
+//
+// Correct typing error's.
+//
+// Add AggrFunc DISTINCT, SelOpcode NOTLIKE and CI_NOTLIKE
+//
+// Remove ODSDirectory, change the way ODSFile is created. Change
+// FileOpenMode.
+//
+// Change the description of the method getUnit of the interface Column. 
+// Change the description of the methods of the interfaces ODSFile and
+// ODSFileTransfer.  Change the description of the enumerations
+// ValueMatrix_Mode and FileOpenMode.  Change the description of the structure
+// ApplRel.
+//
+// Remove Interface ODSFile and ODSFileTransfer and Enumeration FileOpneMode
+// with the methods which creates the ODSFile interface.
+//
+// 2009-09-25
+// Correct of some interfacaes and methods the description.   Finalize for
+// ASAM ODS version 5.2
+//
+// Add FOR_USER at auth parameter of method newSession of interface AoFactory 
+// Deprecated, solved by NVH Application model for following methods:
+// listScalingColumns, getScalingColumns, listColumnsScaledBy,
+// getColumnsScaledBy and addColumnScaledBy of interface ValueMatrix and the
+// methods isScaling and setScaling of interface Column
+//
+// Add AoSession.getId()  Add AoFactory.newSessionNameValue()  Add
+// SelOpcode.BETWEEN  Add AggrFunc.ORD  Add comment to
+// ApplElemAccess.getInstancesExt()
+//
+// Add method getODSFile at the interfaces ApplElemAccess and InstanceElement.
+//  Add the Interfaces ODSFile, ODSReadTransfer and ODSWriteTransfer.  Add
+// ErrorCode AO_FILE_LOCKED.  Add AoFile to the description of
+// AO_INVALID_BASETYPE
+//
+// Inherit ODSFile from InstanceElement. Rename method getOdsFile to
+// upcastOdsFile at interface InstanceElement. Add methods takeUnderControl
+// and removefromControl to the interface ODSFile. Method skipOctets returns
+// the real skipped number of octets.  Rename AggrFunc.ORD to AggrFunc.POINT
+//
+// Update description of the ODSFile methods and some error codes.
+//
+// Add the method getRelations at the interface BaseStructure.  Minor changes
+// in the description of some methods.  Add description for the exceptions
+// A_BAD_PARAMETER and AO_SYSTEM_PROBLEM at the method getOctetSeq of the
+// interface ODSReadTransfer.
+//
+// 2012-11-20
+// Final release ODS 5.3.0
+//
+//
+#ifndef ods_idl
+#define ods_idl
+
+module org {
+
+/**
+* ASAM services.
+*/
+module asam {
+
+/**
+* ASAM ODS service.
+*/
+module ods {
+interface AoFactory;
+interface AoSession;
+interface ApplicationAttribute;
+interface ApplicationElement;
+interface ApplicationRelation;
+interface ApplicationStructure;
+interface BaseAttribute;
+interface BaseElement;
+interface BaseRelation;
+interface BaseStructure;
+interface Blob;
+interface Column;
+interface InstanceElement;
+interface InstanceElementIterator;
+interface Measurement;
+interface NameIterator;
+interface NameValueIterator;
+interface NameValueUnitIterator;
+interface SMatLink;
+interface SubMatrix;
+interface ValueMatrix;
+interface NameValueUnitIdIterator;
+interface ApplElemAccess;
+interface QueryEvaluator;
+interface Query;
+interface NameValueUnitSequenceIterator;
+interface EnumerationDefinition;
+interface ElemResultSetExtSeqIterator;
+interface ODSFile;
+interface ODSReadTransfer;
+interface ODSWriteTransfer;
+
+/**
+* The ASAM ODS error severity flags.
+*/
+enum SeverityFlag {
+   SUCCESS,     // Ok.
+   INFORMATION, // Information.
+   WARNING,     // Warning.
+   ERROR        // Error.
+};
+
+/**
+* The ASAM ODS relation types.
+*/
+enum RelationType {
+   FATHER_CHILD, // Father-child relation.
+   INFO,         // Info relation.
+   INHERITANCE   // Inheritance relation.
+};
+
+/**
+* The ASAM ODS relationships.
+*/
+enum Relationship {
+   FATHER,    // Father.
+   CHILD,     // Child.
+   INFO_TO,   // Directed informational relationship.
+   INFO_FROM, // Directed informational relationship.
+   INFO_REL,  // Informational relationship (no direction)
+   SUPERTYPE, // Inheritance relationship: supertype.
+   SUBTYPE,   // Inheritance relationship: subtype.
+   ALL_REL    // Any of the relationships above.
+};
+
+/**
+* The ASAM ODS data types.
+*    DT_xxx  Basic data types.
+*    DS_xxx  Sequence of basic data type.
+*    ||
+*    |+- T == Type, S == Sequences.
+*    +-- D == Datatype.
+*/
+enum DataType {
+   DT_UNKNOWN,           // Unknown datatype.
+   DT_STRING,            // String.
+   DT_SHORT,             // Short value (16 bit).
+   DT_FLOAT,             // Float value (32 bit).
+   DT_BOOLEAN,           // Boolean value.
+   DT_BYTE,              // Byte value (8 bit).
+   DT_LONG,              // Long value (32 bit).
+   DT_DOUBLE,            // Double precision float value (64 bit).
+   DT_LONGLONG,          // LongLong value (64 bit).
+   DT_ID,                // LongLong value (64 bit). Not used. DT_LONGLONG is
+                         // used instead.
+   DT_DATE,              // Date. Meaning: YYYYMMDDhhmmsslllcccnnn....   -
+                         // YYYY = year, required.   - MM = month, optional.  
+                         // - DD =  day, optional.   - hh =  hour, optional.  
+                         // - mm =  minute, optional.   - ss =  second,
+                         // optional.   - lll =  millisec, optional, not
+                         // supported by Oracle timestamp.   - ccc =  microse,
+                         // optional, not supported by Oracle timestamp.   -
+                         // nnn =  nanosec, optional, not supported by Oracle
+                         // timestamp.
+   DT_BYTESTR,           // Bytestream.
+   DT_BLOB,              // Blob.
+   DT_COMPLEX,           // Complex value (32 bit each part).
+   DT_DCOMPLEX,          // Complex value (64 bit each part).
+   DS_STRING,            // String sequence.
+   DS_SHORT,             // Short sequence.
+   DS_FLOAT,             // Float sequence.
+   DS_BOOLEAN,           // Boolean sequene.
+   DS_BYTE,              // Byte sequence.
+   DS_LONG,              // Long sequence.
+   DS_DOUBLE,            // Double sequence.
+   DS_LONGLONG,          // Longlong sequence.
+   DS_COMPLEX,           // Complex sequence.
+   DS_DCOMPLEX,          // Double complex sequence.
+   DS_ID,                // LongLong sequence. Not used. DS_LONGLONG is used
+                         // instead.
+   DS_DATE,              // Date sequence.
+   DS_BYTESTR,           // Bytestream sequence.
+   DT_EXTERNALREFERENCE, // External reference.
+   DS_EXTERNALREFERENCE, // Sequence of external reference.
+   DT_ENUM,              // The enumeration datatype.
+   DS_ENUM               // The enumeration sequence datatype.
+};
+
+/**
+* The ASAM ODS build-up function codes for measurement views.
+*/
+enum BuildUpFunction {
+   BUP_JOIN,  // Join the columns
+   BUP_MERGE, // Merge the columns
+   BUP_SORT   // Sort the columns
+};
+
+/**
+* The ASAM ODS attribute type codes.
+*/
+enum AttrType {
+   APPLATTR_ONLY, // Report only application attributes.
+   INSTATTR_ONLY, // Report only instance attributes.
+   ALL            // All attributes.
+};
+
+/**
+* The ASAM ODS types for setting values.
+*/
+enum SetType {
+   APPEND, // Append data to the value matrix.
+   INSERT, // Insert data into the value matrix.
+   UPDATE, // Modify existing data of the value matrix.
+   REMOVE  // Remove the given information.
+};
+
+/**
+* The ASAM ODS error codes.
+*/
+enum ErrorCode {
+   AO_UNKNOWN_ERROR,
+   AO_ACCESS_DENIED,
+   AO_BAD_OPERATION,
+   AO_BAD_PARAMETER,
+   AO_CONNECT_FAILED,
+   AO_CONNECT_REFUSED,
+   AO_CONNECTION_LOST,
+   AO_DUPLICATE_BASE_ATTRIBUTE,
+   AO_DUPLICATE_NAME,
+   AO_DUPLICATE_VALUE,
+   AO_HAS_INSTANCES,
+   AO_HAS_REFERENCES,
+   AO_IMPLEMENTATION_PROBLEM,
+   AO_INCOMPATIBLE_UNITS,
+   AO_INVALID_ASAM_PATH,
+   AO_INVALID_ATTRIBUTE_TYPE,
+   AO_INVALID_BASE_ELEMENT,
+   AO_INVALID_BASETYPE,
+   AO_INVALID_BUILDUP_FUNCTION,
+   AO_INVALID_COLUMN,
+   AO_INVALID_COUNT,
+   AO_INVALID_DATATYPE,
+   AO_INVALID_ELEMENT,
+   AO_INVALID_LENGTH,
+   AO_INVALID_ORDINALNUMBER,
+   AO_INVALID_RELATION,
+   AO_INVALID_RELATION_RANGE,
+   AO_INVALID_RELATION_TYPE,
+   AO_INVALID_RELATIONSHIP,
+   AO_INVALID_SET_TYPE,
+   AO_INVALID_SMATLINK,
+   AO_INVALID_SUBMATRIX,
+   AO_IS_BASE_ATTRIBUTE,
+   AO_IS_BASE_RELATION,
+   AO_IS_MEASUREMENT_MATRIX,
+   AO_MATH_ERROR,
+   AO_MISSING_APPLICATION_ELEMENT,
+   AO_MISSING_ATTRIBUTE,
+   AO_MISSING_RELATION,
+   AO_MISSING_VALUE,
+   AO_NO_MEMORY,
+   AO_NO_PATH_TO_ELEMENT,
+   AO_NOT_FOUND,
+   AO_NOT_IMPLEMENTED,
+   AO_NOT_UNIQUE,
+   AO_OPEN_MODE_NOT_SUPPORTED,
+   AO_SESSION_LIMIT_REACHED,
+   AO_SESSION_NOT_ACTIVE,
+   AO_TRANSACTION_ALREADY_ACTIVE,
+   AO_TRANSACTION_NOT_ACTIVE,
+   AO_HAS_BASE_RELATION,
+   AO_HAS_BASE_ATTRIBUTE,
+   AO_UNKNOWN_UNIT,
+   AO_NO_SCALING_COLUMN,
+   AO_QUERY_TYPE_INVALID,
+   AO_QUERY_INVALID,
+   AO_QUERY_PROCESSING_ERROR,
+   AO_QUERY_TIMEOUT_EXCEEDED,
+   AO_QUERY_INCOMPLETE,
+   AO_QUERY_INVALID_RESULTTYPE,
+   AO_INVALID_VALUEMATRIX_STRUCTURE,
+   AO_FILE_LOCKED,
+   AO_SYSTEM_PROBLEM
+};
+
+/**
+* The selection operators.  SelOpcode gives query instructions like
+* "equal", "greater" etc. So far, these arguments were case sensitive.
+* There was a demand to add these arguments also for case insensitive
+* comparison operations. Therefore, the SelOpcodes for case insensitivity
+* were added. These arguments have the prefix “CI_”.
+*/
+enum SelOpcode {
+   EQ,          // Equal
+   NEQ,         // Not equal
+   LT,          // Less then
+   GT,          // Greater then
+   LTE,         // Less then equal
+   GTE,         // Greater then equal
+   INSET,       // In set, value can be a sequence.
+   NOTINSET,    // Not in set, value can be a sequence.
+   LIKE,        // like, use  pattern matching, see Pattern for the wildcard
+                // definitions.
+   CI_EQ,       // Equal. case insensitive for DT_STRING.
+   CI_NEQ,      // Not equal. case insensitive for DT_STRING.
+   CI_LT,       // Less then. case insensitive for DT_STRING.
+   CI_GT,       // Greater then. case insensitive for DT_STRING.
+   CI_LTE,      // Less then equal. case insensitive for DT_STRING.
+   CI_GTE,      // Greater then equal. case insensitive for DT_STRING.
+   CI_INSET,    // In set, value can be a sequence. case insensitive for
+                // DT_STRING.
+   CI_NOTINSET, // Not in set, value can be a sequence. case insensitive for
+                // DT_STRING.
+   CI_LIKE,     // like, use  pattern matching, see Pattern for the wildcard
+                // definitions. case insensitive for DT_STRING.
+   IS_NULL,     // Value is NULL
+   IS_NOT_NULL, // Value is not NULL
+   NOTLIKE,     // Not LIKE
+   CI_NOTLIKE,  // Not LIKE, case insensitive for DT_STRING.
+   BETWEEN      // Between; selects all instances where the value of 'attr'
+                // lies between the first two values given in 'value' (with
+                // 'attr', 'value' being elements of the SelValue structure;
+                // 'value' must be of data type S_*).
+};
+
+/**
+* Operator, bracket open and close.
+*/
+enum SelOperator {
+   AND,   // AND the two conditions.
+   OR,    // OR the two conditions.
+   NOT,   // Negate the next condition.
+   OPEN,  // Open brackets.
+   CLOSE  // Close brackets
+};
+
+/**
+* The ASAM ODS types for setting access rights.
+*/
+enum RightsSet {
+   SET_RIGHT,    // Set the given rights, overwrite the existing rights.
+   ADD_RIGHT,    // Add the given rights to the existing rights.
+   REMOVE_RIGHT  // Remove the given rights form the existing rights.
+};
+
+/**
+* Status of the query execution.
+*/
+enum QueryStatus {
+   COMPLETE,   // The execution is ready.
+   INCOMPLETE  // The execution is still running.
+};
+
+/**
+* The supported aggregate functions of the GetInstancesExt.
+*/
+enum AggrFunc {
+   NONE,     // No aggregate function is used for attribute.
+   COUNT,    // Count
+   DCOUNT,   // Distinct count
+   MIN,      // Min; only for numerical values
+   MAX,      // Max; only for numerical values
+   AVG,      // Average; only for numerical values
+   STDDEV,   // Standard deviation; only for numerical values
+   SUM,      // Sum; only for numerical values
+   DISTINCT, // Distinct
+   POINT     // The index of the values, only used by the attribute values of
+             // element AoLocalColumn
+};
+
+/**
+* The selection type.
+*/
+enum SelType {
+   SEL_VALUE_TYPE,    // Selection value.
+   SEL_OPERATOR_TYPE  // Selection logical operator.
+};
+
+/**
+* The type of the join.
+*/
+enum JoinType {
+   JTDEFAULT, // Force inner join.
+   JTOUTER    // Force outer join on destination AID.
+};
+
+/**
+* The mode of the value matrix.
+*/
+enum ValueMatrixMode {
+   CALCULATED, // The value matrix returns the calculated values.   The values
+               // of explicit columns are returned as they are stored in the
+               // physical storage.   The values of implicit columns are
+               // expanded and returned explicitly.  The values of raw columns
+               // are calculated according to the corresponding algorithm
+               // (using the calculation algorithms given by the values of the
+               // application attributes derived from the base attributes
+               // 'sequence_representation' and 'generation_parameters') and
+               // the resulting physical values are returned.  Writing to the
+               // value matrix is not allowed in this mode.
+   STORAGE     // The value matrix returns the values given in the physical
+               // storage.  The values of explicit columns are returned as
+               // they are stored in the physical storage.  The values of
+               // implicit columns are expanded and returned explicitly.  The
+               // values of raw columns are returned as they are stored
+               // (without using the calculation algorithms given by the
+               // values of the application attributes derived from the base
+               // attributes 'sequence_representation' and
+               // 'generation_parameters').  Writing to value matrix is
+               // allowed in this mode.
+};
+
+// Datatype definitions (T_xxx).
+typedef string     T_STRING;
+typedef boolean    T_BOOLEAN;
+typedef short      T_SHORT;
+typedef float      T_FLOAT;
+typedef octet      T_BYTE;
+typedef long       T_LONG;
+typedef double     T_DOUBLE;
+typedef T_STRING   Name;
+typedef T_STRING   Pattern;
+typedef T_STRING   BaseType;
+typedef T_STRING   T_DATE;
+typedef Blob       T_BLOB;
+
+// Sequence definitions (S_xxx).
+typedef sequence<T_BYTE> T_BYTESTR;
+typedef sequence<T_BOOLEAN> S_BOOLEAN;
+typedef sequence<T_BYTE> S_BYTE;
+typedef sequence<T_DOUBLE> S_DOUBLE;
+typedef sequence<T_FLOAT> S_FLOAT;
+typedef sequence<T_LONG> S_LONG;
+typedef sequence<T_SHORT> S_SHORT;
+typedef sequence<T_STRING> S_STRING;
+typedef sequence<BaseType> BaseTypeSequence;
+typedef sequence<Name> NameSequence;
+typedef sequence<Column> ColumnSequence;
+typedef sequence<SMatLink> SMatLinkSequence;
+typedef sequence<SubMatrix> SubMatrixSequence;
+typedef sequence<T_DATE> S_DATE;
+typedef sequence<T_BYTESTR> S_BYTESTR;
+typedef sequence<S_STRING> SS_STRING;
+typedef sequence<S_SHORT> SS_SHORT;
+typedef sequence<S_FLOAT> SS_FLOAT;
+typedef sequence<S_BOOLEAN> SS_BOOLEAN;
+typedef sequence<S_BYTE> SS_BYTE;
+typedef sequence<S_LONG> SS_LONG;
+typedef sequence<S_DOUBLE> SS_DOUBLE;
+typedef sequence<S_DATE> SS_DATE;
+typedef sequence<S_BYTESTR> SS_BYTESTR;
+typedef sequence<T_BLOB> S_BLOB;
+typedef sequence<ApplicationElement> ApplicationElementSequence;
+typedef sequence<ApplicationRelation> ApplicationRelationSequence;
+typedef sequence<ApplicationAttribute> ApplicationAttributeSequence;
+typedef sequence<BaseRelation> BaseRelationSequence;
+typedef sequence<BaseAttribute> BaseAttributeSequence;
+typedef sequence<BaseElement> BaseElementSequence;
+typedef sequence<InstanceElement> InstanceElementSequence;
+typedef sequence<SelOperator> SelOperatorSequence;
+
+/**
+* The ASAM ODS relation range structure.
+*/
+struct RelationRange {
+   T_SHORT min; // The minimum number in the range.
+   T_SHORT max; // The maximum number in the range. -1 means MANY without a
+                // specified maximum number.
+};
+
+/**
+* The ASAM ODS 64 bit integer structure.  This type is represented in the
+* datatype enumeration by DT_LONGLONG.
+*/
+struct T_LONGLONG {
+   T_LONG high; // The most significant 32 bits of the 64 bit value.
+   T_LONG low;  // The least significant 32 bits of the 64 bit value.
+};
+
+/**
+* The ASAM ODS complex data structure.  This type is represented in the
+* datatype enumeration by DT_COMPLEX.
+*/
+struct T_COMPLEX {
+   T_FLOAT r; // The real part of the complex number.
+   T_FLOAT i; // The imaginary part of the complex number.
+};
+
+/**
+* The ASAM ODS double-precision complex data structure. This type is
+* represented in the datatype enumeration by DT_DCOMPLEX.
+*/
+struct T_DCOMPLEX {
+   T_DOUBLE r; // The real part of the double precision complex number.
+   T_DOUBLE i; // The imaginary part of the double precision complex number.
+};
+
+/**
+* The ASAM ODS name-unit tuple structure.
+*/
+struct NameUnit {
+   Name     valName; // Attribute name or measured quantity name.
+   T_STRING unit;    // Column unit as string.
+};
+
+/**
+* The description of an reference object, the reference object can be an
+* internal ASAM ODS object or an external object. This type is
+* represented in the datatype enumeration by DT_EXTERNALREFERENCE.
+*/
+struct T_ExternalReference {
+   T_STRING description; // Description of the external reference.
+   T_STRING mimeType;    // MIME-type of the external object.
+   T_STRING location;    // Location of the external reference. (asam path or
+                         // URL)
+};
+
+/**
+* The application attribute information (metadata) definition. The same
+* information is available at the interface ApplicationAttribute
+*/
+struct ApplAttr {
+   Name       aaName;       // The application attribute name. The same name
+                            // is returned by the method getName() of the
+                            // ApplicationAttribute interface.     At the RPC
+                            // API this information was stored in the field
+                            // aAName of the structure AttrSeq and the request
+                            // AOP_GetAttr.
+   Name       baName;       // The name of the base attribute, empty ("") if
+                            // the application attribute is not derived from a
+                            // base attribute. The same name is returned by
+                            // the methods getName() of the BaseAttribute
+                            // interface. The base attribute is given by the
+                            // the method getBaseAttribute() of the interface
+                            // ApplicationAttribute.     At the RPC API this
+                            // information was stored in the field aBName of
+                            // the structure AttrSeq and the request
+                            // AOP_GetAttr.
+   DataType   dType;        // The attribute data type. The same data type is
+                            // given by the method getDataType of the
+                            // interface ApplicationAttribute.     At the RPC
+                            // API this information was stored in the field
+                            // aDataType of the structure AttrSeq and the
+                            // request AOP_GetAttr.
+   T_LONG     length;       // The maximum possible length of values. The same
+                            // length is returned by the method getLength() of
+                            // the interface ApplicationAttribute.
+   T_BOOLEAN  isObligatory; // The indicator for mandatory attributes, the
+                            // notNull indicator is set at the column of the
+                            // table in the physical storage.  The same
+                            // boolean is returned at the method
+                            // isObligatory() of the interface
+                            // ApplicationAttribute.
+   T_BOOLEAN  isUnique;     // The indicator for unique attributes. The same
+                            // boolean is returned by the method isUnique() of
+                            // the interface ApplicationAttribute.
+   T_LONGLONG unitId;       // Id of the unit if global defined. The same Id
+                            // is returned by the method getUnit() of the
+                            // interface ApplicationAttribute.     At the RPC
+                            // API this information was stored in the field
+                            // aUnit of the structure AttrSeq and the request
+                            // AOP_GetAttr.
+};
+
+/**
+* The application relation info structure. The same information is
+* available at the interface ApplicationRelation. 
+* 
+* A relation is the connection between two ASAM ODS elements; it may be
+* navigated in both
+* directions. The get- and set- methods are defined from the first
+* element, the getInverse- and
+* setInverse- methods work from the second element.
+*/
+struct ApplRel {
+   T_LONGLONG    elem1;            // The source application element Id. The
+                                   // given Id is the Id of the application
+                                   // element returned from the method
+                                   // getElem1() of the interface
+                                   // ApplicationRelation.     At the RPC API
+                                   // this information was stored in the field
+                                   // arAid1 of the structure ApplRelSeq and
+                                   // the request AOP_GetApplInf.
+   T_LONGLONG    elem2;            // The target application element Id. The
+                                   // given Id is the Id of the application
+                                   // element returned from the method
+                                   // getElem2() of the interface
+                                   // ApplicationRelation.     At the RPC API
+                                   // this information was stored in the field
+                                   // arAid2 of the structure ApplRelSeq and
+                                   // the request AOP_GetApplInf.
+   Name          arName;           // The relation name. The name is return
+                                   // with the method getName() of the
+                                   // interface ApplicationRelation.     At
+                                   // the RPC API this information was stored
+                                   // in the field arName of the structure
+                                   // ApplRelSeq and the request
+                                   // AOP_GetApplInf.
+   Name          invName;          // Name of the inverse relation. The name
+                                   // is return with the method
+                                   // getInverseName() of the interface
+                                   // ApplicationRelation. The invName is not
+                                   // available in the physical storage for
+                                   // relation databases.
+   Name          brName;           // Name of the base relation from the elem1
+                                   // to the elem2. The base relation is also
+                                   // not stored in the physical storage.
+   Name          invBrName;        // Name of the inverse base relation from
+                                   // the elem2 to the elem1. The base
+                                   // relation is also not stored in the
+                                   // physical storage.
+   RelationType  arRelationType;   // The type of the relation. Type of the
+                                   // relation is not stored in the physical
+                                   // storage. The relation type is return at
+                                   // the method getRelationType() of the
+                                   // interface ApplicationRelation.
+   RelationRange arRelationRange;  // The range of the relation. Range of the
+                                   // relation is not stored in the physical
+                                   // storage. The relation range is return at
+                                   // the method getRelationRange() of the
+                                   // interface ApplicationRelation.
+   RelationRange invRelationRange; // The inverse range of the relation. Range
+                                   // of the relation is not stored in the
+                                   // physical storage. The inverse relation
+                                   // range is return at the method
+                                   // getInverseRelationRange() of the
+                                   // interface ApplicationRelation.
+};
+
+/**
+* AID - Name pair.
+*/
+struct AIDName {
+   T_LONGLONG aid;    // The Id of the application element.
+   Name       aaName; // The attribute, or measured quantity name.
+};
+
+/**
+* Instance element Id. The unique description of an instance element.
+*/
+struct ElemId {
+   T_LONGLONG aid; // The Id of the application element.
+   T_LONGLONG iid; // The Id of the instance element.
+};
+
+/**
+* AID - Name - UnitId tuple.
+*/
+struct AIDNameUnitId {
+   AIDName    attr;   // The attribute  of the application element (aid,
+                      // name).
+   T_LONGLONG unitId; // The unit of the attribute or the column. The unitId
+                      // is the Id of instance element with the basetype
+                      // AoUnit.
+};
+
+/**
+* Order criteria.
+*/
+struct SelOrder {
+   AIDName   attr;      // Attribute specification.
+   T_BOOLEAN ascending; // ascending order, FALSE means descending.
+};
+
+/**
+* The access control list entry.
+*/
+struct ACL {
+   T_LONGLONG usergroupId; // The usergroup Id.
+   T_LONG     rights;      // The access rights of the requested object.
+};
+
+/**
+* An initial right.
+*/
+struct InitialRight {
+   T_LONG     rights;      // The initial access rights of the requested
+                           // object.
+   T_LONGLONG usergroupId; // The usergroup Id of the Initial right list.
+   T_LONGLONG refAid;      // The referencing application element.
+};
+
+/**
+* itÂ’s quite the same sequence as in the QueryStructure of GetInstances
+* with one exception. It has one new attribute called function, which is
+* of the type AggrFunc. Thereby  it is possible to define aggregate
+* functions on attribute level, without the need to parse the attribute
+* name for a known aggregate function name. The default value of that
+* attribute function is NONE, it symbolizes that no aggregate function
+* should be applied on that attribute.If an aggregate function is used,
+* it is also required to define a GroupSequence.It is also defined that a
+* ‘*’ as attribute name, delivers all attributes of an element.
+*/
+struct SelAIDNameUnitId {
+   AIDName    attr;      // The attribute  of the application element (aid,
+                         // name).
+   T_LONGLONG unitId;    // The unit of the attribute ot the column. The
+                         // unitId is the Id of instance element with the
+                         // basetype AoUnit.
+   AggrFunc   aggregate; // The aggregate function.
+};
+
+/**
+* Basically, joins can only be realized between application elements that
+* are linked via a reference defined in the model.From the definition of
+* attributes or application elements, the references for the joins are
+* determined. It is also taken into account that the application elements
+* involved are not linked directly. However, there must be an unambiguous
+* path between the application elements. The path may also include n:m
+* relations. The unambiguousness of relations between two application
+* elements no longer exists if more than one reference has been defined
+* between the application elements. In this case, these references must
+* have names and must be indicated explicitly in the request.For this
+* purpose, the request structure provides a sequence of relation
+* definitions (JoinDefSequence). The sequence in which the application
+* elements are addressed in the request also determines the sequence in
+* which the references between application elements are searched. Thus,
+* for every new application element, the server begins with the first
+* application element addressed in the request and tries to find a
+* relation from there. If no reference to the first application element
+* can be found, the search continues with the application element that
+* comes next in the request. Furthermore, the explicit relation
+* definitions (JoinDefSequence) enable an OUTER join, i.e. the result
+* also includes those records for which the join could not be
+* established.
+*/
+struct JoinDef {
+   T_LONGLONG fromAID;
+   T_LONGLONG toAID;
+   Name       refName;
+   JoinType   joiningType;
+};
+
+/**
+* The application relation with the instances to create the relation with
+* new instances.
+*/
+struct ApplicationRelationInstanceElementSeq {
+   ApplicationRelation     applRel;   // The application relation.
+   InstanceElementSequence instances; // The list with instances. The
+                                      // application element of the instances
+                                      // in the list must match one of the
+                                      // application elements of the
+                                      // application relation. All instances
+                                      // of the list must have the same
+                                      // application element.
+};
+
+/**
+* The structure with the attribute and the name of the enumeration.
+*/
+struct EnumerationAttributeStructure {
+   T_LONGLONG aid;      // The application element Id.
+   T_STRING   aaName;   // The name of the attribute
+   T_STRING   enumName; // The name of the enumeration
+};
+
+/**
+* The structure with the items of the enumeration.
+*/
+struct EnumerationItemStructure {
+   T_LONG   index;    // The index of the enuemration item.
+   T_STRING itemName; // The name of the item.
+};
+
+// Sequence definitions (S_xxx).
+typedef sequence<EnumerationAttributeStructure> EnumerationAttributeStructureSequence;
+typedef sequence<EnumerationItemStructure> EnumerationItemStructureSequence;
+typedef sequence<T_COMPLEX> S_COMPLEX;
+typedef sequence<T_DCOMPLEX> S_DCOMPLEX;
+typedef sequence<T_LONGLONG> S_LONGLONG;
+typedef sequence<S_LONGLONG> SS_LONGLONG;
+typedef sequence<S_COMPLEX> SS_COMPLEX;
+typedef sequence<S_DCOMPLEX> SS_DCOMPLEX;
+typedef sequence<T_ExternalReference> S_ExternalReference;
+typedef sequence<S_ExternalReference> SS_ExternalReference;
+typedef sequence<ApplAttr> ApplAttrSequence;
+typedef sequence<ApplRel> ApplRelSequence;
+typedef sequence<AIDName> AIDNameSequence;
+typedef sequence<AIDNameUnitId> AIDNameUnitIdSequence;
+typedef sequence<ElemId> ElemIdSequence;
+typedef sequence<SelOrder> SelOrderSequence;
+typedef sequence<ACL> ACLSequence;
+typedef sequence<InitialRight> InitialRightSequence;
+typedef sequence<SelAIDNameUnitId> SelAIDNameUnitIdSequence;
+typedef sequence<JoinDef> JoinDefSequence;
+typedef sequence<ApplicationRelationInstanceElementSeq> ApplicationRelationInstanceElementSeqSequence;
+
+/**
+* The application element definition. The same information is available
+* at the interface ApplicationElement.
+*/
+struct ApplElem {
+   T_LONGLONG       aid;        // The application element id. The id is given
+                                // also with the method getId() at the
+                                // interface ApplicationElement.     At the
+                                // RPC API this information was stored in the
+                                // field aiAId of the structure ApplInfSeq and
+                                // the request AOP_GetApplInf.
+   Name             beName;     // The base element name, all elements have a
+                                // basic element. The same name is returned by
+                                // the methods getType() of the BaseElement
+                                // interface. The base element is given with
+                                // the method getBaseElement() at the
+                                // interface ApplicationElement.     At the
+                                // RPC API this information was not delivered
+                                // but the corresponding Id of the base
+                                // element was stored in the field aiBId of
+                                // the structure ApplInfSeq and the request
+                                // AOP_GetApplInf.
+   Name             aeName;     // The application element name. The name is
+                                // given also with the method getName() at the
+                                // interface ApplicationElement.     At the
+                                // RPC API this information was stored in the
+                                // field aiName of the structure ApplInfSeq
+                                // and the request AOP_GetApplInf.
+   ApplAttrSequence attributes; // The attributes of application element. The
+                                // attributes are given with the method
+                                // getAttributes() of the interface
+                                // ApplicationElement. There are no relations
+                                // given in the this sequence.
+};
+
+/**
+* The structure with the enumeration and there items.
+*/
+struct EnumerationStructure {
+   T_STRING                         enumName; // The name of the enueration.
+   EnumerationItemStructureSequence items;    // The items of the enumeration.
+};
+
+/**
+* The union definition for all datatypes.
+*/
+union TS_Union switch (DataType) {
+   case DT_STRING:                      T_STRING                       stringVal;
+   case DT_SHORT:                       T_SHORT                        shortVal;
+   case DT_FLOAT:                       T_FLOAT                        floatVal;
+   case DT_BYTE:                        T_BYTE                         byteVal;
+   case DT_BOOLEAN:                     T_BOOLEAN                      booleanVal;
+   case DT_LONG:                        T_LONG                         longVal;
+   case DT_DOUBLE:                      T_DOUBLE                       doubleVal;
+   case DT_LONGLONG:                    T_LONGLONG                     longlongVal;
+   case DT_COMPLEX:                     T_COMPLEX                      complexVal;
+   case DT_DCOMPLEX:                    T_DCOMPLEX                     dcomplexVal;
+   case DT_DATE:                        T_DATE                         dateVal;
+   case DT_BYTESTR:                     T_BYTESTR                      bytestrVal;
+   case DT_BLOB:                        T_BLOB                         blobVal;
+   case DS_STRING:                      S_STRING                       stringSeq;
+   case DS_SHORT:                       S_SHORT                        shortSeq;
+   case DS_FLOAT:                       S_FLOAT                        floatSeq;
+   case DS_BYTE:                        S_BYTE                         byteSeq;
+   case DS_BOOLEAN:                     S_BOOLEAN                      booleanSeq;
+   case DS_LONG:                        S_LONG                         longSeq;
+   case DS_DOUBLE:                      S_DOUBLE                       doubleSeq;
+   case DS_LONGLONG:                    S_LONGLONG                     longlongSeq;
+   case DS_COMPLEX:                     S_COMPLEX                      complexSeq;
+   case DS_DCOMPLEX:                    S_DCOMPLEX                     dcomplexSeq;
+   case DS_DATE:                        S_DATE                         dateSeq;
+   case DS_BYTESTR:                     S_BYTESTR                      bytestrSeq;
+   case DT_EXTERNALREFERENCE:           T_ExternalReference            extRefVal;
+   case DS_EXTERNALREFERENCE:           S_ExternalReference            extRefSeq;
+   case DT_ENUM:                        T_LONG                         enumVal;
+   case DS_ENUM:                        S_LONG                         enumSeq;
+};
+
+/**
+* Define a union with sequences of a certain type. Using this union
+* instead of sequence <TS_Union> gives much better performance.
+*/
+union TS_UnionSeq switch (DataType) {
+   case DT_STRING:                      S_STRING                       stringVal;
+   case DT_SHORT:                       S_SHORT                        shortVal;
+   case DT_FLOAT:                       S_FLOAT                        floatVal;
+   case DT_BYTE:                        S_BYTE                         byteVal;
+   case DT_BOOLEAN:                     S_BOOLEAN                      booleanVal;
+   case DT_LONG:                        S_LONG                         longVal;
+   case DT_DOUBLE:                      S_DOUBLE                       doubleVal;
+   case DT_LONGLONG:                    S_LONGLONG                     longlongVal;
+   case DT_COMPLEX:                     S_COMPLEX                      complexVal;
+   case DT_DCOMPLEX:                    S_DCOMPLEX                     dcomplexVal;
+   case DT_DATE:                        S_DATE                         dateVal;
+   case DT_BYTESTR:                     S_BYTESTR                      bytestrVal;
+   case DT_BLOB:                        S_BLOB                         blobVal;
+   case DS_STRING:                      SS_STRING                      stringSeq;
+   case DS_SHORT:                       SS_SHORT                       shortSeq;
+   case DS_FLOAT:                       SS_FLOAT                       floatSeq;
+   case DS_BYTE:                        SS_BYTE                        byteSeq;
+   case DS_BOOLEAN:                     SS_BOOLEAN                     booleanSeq;
+   case DS_LONG:                        SS_LONG                        longSeq;
+   case DS_DOUBLE:                      SS_DOUBLE                      doubleSeq;
+   case DS_LONGLONG:                    SS_LONGLONG                    longlongSeq;
+   case DS_COMPLEX:                     SS_COMPLEX                     complexSeq;
+   case DS_DCOMPLEX:                    SS_DCOMPLEX                    dcomplexSeq;
+   case DS_DATE:                        SS_DATE                        dateSeq;
+   case DS_BYTESTR:                     SS_BYTESTR                     bytestrSeq;
+   case DT_EXTERNALREFERENCE:           S_ExternalReference            extRefVal;
+   case DS_EXTERNALREFERENCE:           SS_ExternalReference           extRefSeq;
+   case DT_ENUM:                        S_LONG                         enumVal;
+   case DS_ENUM:                        SS_LONG                        enumSeq;
+};
+
+// Sequence definitions (S_xxx).
+typedef sequence<EnumerationStructure> EnumerationStructureSequence;
+typedef sequence<ApplElem> ApplElemSequence;
+
+/**
+* The ASAM ODS value structure.  There is one flag for each value. If the
+* union (u) contains a sequence, the flag is valid for all values in that
+* sequence.
+* 
+* Meaning of flags:
+*    AO_VF_VALID(0x01)      The value is valid.
+*    AO_VF_VISIBLE(0x02)    The value has to be
+*                           visualized.
+*    AO_VF_UNMODIFIED(0x04) The value has not been
+*                           modified.
+*    AO_VF_DEFINED(0x08)    The value is defined. If
+*                           the value in a value matrix
+*                           is not available this bit
+*                           is not set.
+*   The normal value of the flag is 15.
+*/
+struct TS_Value {
+   TS_Union u;    // The value union for values of all known datatypes.
+   T_SHORT  flag; // The value flags.
+};
+
+/**
+* A structure with sequences of a certain type. Using this union instead
+* of sequence <TS_Value> gives much better performance.
+*/
+struct TS_ValueSeq {
+   TS_UnionSeq u;    // The value union for values of all known datatypes.
+   S_SHORT     flag; // See TS_Value flag.
+};
+
+/**
+* Application structure values. All values of the entire application
+* structure are stored in this structure and loaded to the Client on
+* request. 
+* 
+* At the RPC API this information delivered by the request AOP_GetApplInf
+* and AOP_GetAttr for each application element.
+*/
+struct ApplicationStructureValue {
+   ApplElemSequence applElems; // The list of application elements.
+   ApplRelSequence  applRels;  // The list of relations in the application
+                               // structure. The list of ApplRel's contains
+                               // distinct entries for relations and their
+                               // inverses. The field invName contains the
+                               // partner relation.  Both relation, the normal
+                               // and the inverse relation are given in the
+                               // sequence.
+};
+
+/**
+* The ASAM ODS name-value-unit tuple structure with a sequence of values.
+*/
+struct NameValueSeqUnit {
+   Name        valName; // Column name or measured quantity name.
+   TS_ValueSeq value;   // Column value (vector).
+   T_STRING    unit;    // Column unit as string.
+};
+
+/**
+* AID - Name - Value - UnitId quartet.
+*/
+struct AIDNameValueUnitId {
+   AIDName    attr;   // The attribute  of the application element (aid,
+                      // name).
+   T_LONGLONG unitId; // The unit of the attribute ot the column. The unitId
+                      // is the Id of instance element with the basetype
+                      // AoUnit.
+   TS_Value   values; // The attribute values with value flags.
+};
+
+/**
+* AID - Name - Value - UnitId quartet. Multiple values for on attribute.
+*/
+struct AIDNameValueSeqUnitId {
+   AIDName     attr;   // The attribute  of the application element (aid,
+                       // name).
+   T_LONGLONG  unitId; // The unit of the attribute ot the column. The unitId
+                       // is the Id of instance element with the basetype
+                       // AoUnit.
+   TS_ValueSeq values; // The column values with value flags.
+};
+
+/**
+* The ASAM ODS name-value-unitId tuple structure with a sequence of
+* values.
+*/
+struct NameValueSeqUnitId {
+   Name        valName; // Column name or measured quantity name.
+   TS_ValueSeq value;   // Column value (vector).
+   T_LONGLONG  unitId;  // Column unit as Id.
+};
+
+/**
+*  Structure for name value query or attribute search conditions.
+*/
+struct SelValue {
+   AIDNameValueUnitId attr;  // The attribute specification with unit of the
+                             // value.
+   SelOpcode          oper;  // The compare operator between the attribute and
+                             // value.
+   TS_Value           value; // Value for the condition.
+};
+
+/**
+* The ASAM ODS name-value-unitid tuple structure. This structure is
+* identical with the NameValueUnit, except the unit is given as an Id
+* insead of a string.
+*/
+struct NameValueUnitId {
+   Name       valName; // Attribute name or measured quantity name.
+   TS_Value   value;   // Attribute value or column value (vector).
+   T_LONGLONG unitId;  // Id of attribute or column unit.
+};
+
+/**
+* The attribute selection structure.
+*/
+struct SelValueExt {
+   AIDNameUnitId attr;  // The attribute specification with unit Id.
+   SelOpcode     oper;  // The compare operator between the attribute and
+                        // value.
+   TS_Value      value; // Value for the condition.
+};
+
+/**
+* Defines the sequence of selection attributes with their logical
+* operators. The Idea is to have the logical operators and the selection
+* values in one sequence. Therefore no implicit rules are necessary how
+* logical operators have to be interpreted to the corresponding selection
+* value.
+*/
+union SelItem switch (SelType) {
+   case SEL_VALUE_TYPE:                 SelValueExt                    value;
+   case SEL_OPERATOR_TYPE:              SelOperator                    operator;
+};
+
+// Sequence definitions (S_xxx).
+typedef sequence<NameValueSeqUnit> NameValueSeqUnitSequence;
+typedef sequence<AIDNameValueSeqUnitId> AIDNameValueSeqUnitIdSequence;
+typedef sequence<SelValue> SelValueSequence;
+typedef sequence<NameValueSeqUnitId> NameValueSeqUnitIdSequence;
+typedef sequence<SelItem> SelItemSequence;
+
+/**
+* The ASAM ODS name-value pair structure.
+*/
+struct NameValue {
+   Name     valName; // Attribute name or measured quantity name.
+   TS_Value value;   // Attribute value or column value (vector).
+};
+
+/**
+* The ASAM ODS name-value-unit tuple structure. This structure is
+* identical with the NameValueUnitId, except the unit is given as a
+* string insead of an Id.
+*/
+struct NameValueUnit {
+   Name     valName; // Attribute name or measured quantity name.
+   TS_Value value;   // Attribute value or column value (vector).
+   T_STRING unit;    // Attribute or column unit as string.
+};
+
+/**
+* The results for one attribute. The result set for all attributes are
+* given in the sequence of the result set.
+*/
+struct AttrResultSet {
+   NameValueSeqUnitId      attrValues; // The attribute result set of one
+                                       // element. All values have the same
+                                       // attribute (AIDName) and the same
+                                       // unit (UnitId). Only the first part
+                                       // of the possible attribute values are
+                                       // available in this result set. The
+                                       // size of the part depends on the
+                                       // parameter 'how_many' of the method
+                                       // 'getInstances' of the interface
+                                       // 'ApplElemAccess'.
+   NameValueUnitIdIterator rest;       // The rest of the results. The
+                                       // iterator provides access to the
+                                       // conseccutive
+                                       // NameValueSeqUnitId-packages of the
+                                       // result set.
+};
+
+/**
+* The query structure.
+* 
+* How to build a query.
+* 
+* A query is a search condition for instances. The instances are
+* specified by the values of the attributes. The search condition
+* represents an attribute value condition. This means the attribute value
+* specifies the selection of the instance or instance attribute. An
+* attribute is specified by the application element and the name of the
+* attribute (AIDName). The conditions are defined in the enumeration
+* SelOPCode. The values are given in the TS_Value or TS_Union structure.
+* If we like an Unit indepedent condition we needed to define the Unit at
+* the attribute, use AIDNameUnitId instead of AIDName, the server has to
+* convert the value to the proper attribute value. The attribute search
+* condition can be combined by operations defined in the enumeration
+* SelOperator. A query can be built with a sequence SelValue and
+* SelOperator.
+* 
+* How to read/write the query:
+* 
+* e.g.  SelValue1 AND SelValue2
+*   
+*          selValueSeq    = SelValue1, SelValue2
+*          selOPeratorSeq = AND  
+* 
+* e.g.  (SelValue1 AND SelValue2) OR SelValue3 
+*    
+*          selValueSeq    = SelValue1, SelValue2, SelValue3
+*          selOPeratorSeq = OPEN, AND, CLOSE, OR
+*    
+* e.g.  NOT(SelValue1 AND SelValue2) OR SelValue3 
+*    
+*          selValueSeq    = SelValue1, SelValue2, SelValue3
+*          selOPeratorSeq = NOT, OPEN, AND, CLOSE, OR
+*    
+*  e.g.  NOT(SelValue1) AND SelValue2 OR SelValue3 
+*    
+*          selValueSeq    = SelValue1, SelValue2, SelValue3
+*          selOPeratorSeq = NOT, AND, OR
+* 
+* There is no selection about the N:M relations.
+*  
+* There are no aggregate functions (MAX, MIN, COUNT etc.) defined so we
+* need no "group by" and "having" Clause. All the parts defined in the
+* "having"-clause can be defined in the select part.
+*/
+struct QueryStructure {
+   AIDNameUnitIdSequence anuSeq;  // The sequence of attributes to be
+                                  // reported. A pattern is accepted for the
+                                  // attribute name.    At the RPC API this
+                                  // information was stored in the fields
+                                  // applId and nuSeq of the structure
+                                  // GetValReq and the request AOP_GetVal. At
+                                  // the RPC API only one application element
+                                  // could be selected.
+   SelValueSequence      condSeq; // The query condition sequence.     At the
+                                  // RPC API this information was stored in
+                                  // the field nsSeq of the structure
+                                  // GetValReq and the request AOP_GetVal.
+   SelOperatorSequence   operSeq; // The query condition operator sequence.   
+                                  //  At the RPC API was the operator always
+                                  // 'AND'.
+   ElemId                relInst; // The related instance. (aid == 0 && iid ==
+                                  // 0) means no related instance specified.  
+                                  //         At the RPC API this information
+                                  // was stored in the field elemId of the
+                                  // structure GetValReq and the request
+                                  // AOP_GetVal.
+   Name                  relName; // Name of the relation.     At the RPC API
+                                  // this information was stored in the field
+                                  // refName of the structure GetValReq and
+                                  // the request AOP_GetVal.
+   SelOrderSequence      orderBy; // The order by sequence. The order of the
+                                  // result set.     At the RPC API it was not
+                                  // possiable to set the order.
+};
+
+/**
+* Restult set of one application element.
+*/
+struct ElemResultSetExt {
+   T_LONGLONG                 aid;    // The application element Id.
+   NameValueSeqUnitIdSequence values; // The attribute values of the instances
+                                      // of the given application element.
+};
+
+/**
+* The extended query structure.
+*/
+struct QueryStructureExt {
+   SelAIDNameUnitIdSequence anuSeq;  // The sequence of attributes to be
+                                     // reported. A pattern is accepted for
+                                     // the attribute name.    At the RPC API
+                                     // this information was stored in the
+                                     // fields applId and nuSeq of the
+                                     // structure GetValReq and the request
+                                     // AOP_GetVal. At the RPC API only one
+                                     // application element could be selected.
+   SelItemSequence          condSeq; // The query condition sequence.     At
+                                     // the RPC API this information was
+                                     // stored in the field nsSeq of the
+                                     // structure GetValReq and the request
+                                     // AOP_GetVal.
+   JoinDefSequence          joinSeq; // Defined the join between the
+                                     // application elements.
+   SelOrderSequence         orderBy; // The order by sequence. The order of
+                                     // the result set.     At the RPC API
+                                     // interface it was not possiable to set
+                                     // the order.
+   AIDNameSequence          groupBy; // Defines the grouping attributes for a
+                                     // request, necessary if aggregate
+                                     // functions are defined in the
+                                     // SelAIDNameUnitIdSequence.
+};
+
+// Sequence definitions (S_xxx).
+typedef sequence<NameValue> NameValueSequence;
+typedef sequence<NameValueUnit> NameValueUnitSequence;
+typedef sequence<AttrResultSet> AttrResultSetSequence;
+typedef sequence<ElemResultSetExt> ElemResultSetExtSequence;
+
+/**
+* The result set for one element. The result set for all elements are
+* given in the sequence of the result set.
+*/
+struct ElemResultSet {
+   T_LONGLONG            aid;        // The Id of the application element.
+   AttrResultSetSequence attrValues; // The selected attributes of the
+                                     // element. The number of values in each
+                                     // AttrResultSet are identical, the
+                                     // attributes of one element has always
+                                     // the position in the AttrResultSet.
+};
+
+/**
+* The Result set of the extended query. The iterator is for instance
+* oriented access.
+*/
+struct ResultSetExt {
+   ElemResultSetExtSequence    firstElems; // The sequence of the first
+                                           // how_many result elements.
+   ElemResultSetExtSeqIterator restElems;  // the iterator, which allows to
+                                           // iterate above the result values,
+                                           // the attributes of one instance
+                                           // each iteration.
+};
+
+// Sequence definitions (S_xxx).
+typedef sequence<ElemResultSet> ElemResultSetSequence;
+typedef sequence<ResultSetExt> ResultSetExtSequence;
+
+/**
+* The ASAM ODS query result types.
+*/
+interface ResultType {
+   const T_SHORT INSTELEM_ITERATOR_AS_RESULT = 0; // Iterator of instance elements as result of the query (the default).
+   const T_SHORT TABLE_ITERATOR_AS_RESULT = 1;    // Iterator for table access as result type of the query.
+   const T_SHORT TABLE_AS_RESULT = 2;             // Table as result type of the query.
+};
+
+/**
+* The lock mode of the server. The lock mode tells the way the server
+* will lock the objects as soon a modification of the server will be
+* done.
+*/
+interface LockMode {
+   const T_SHORT LOCK_INSTANCEELEMENT = 0;    // Lock the instance element. (Default LockMode)
+   const T_SHORT LOCK_APPLICATIONELEMENT = 1; // Lock the application element, all instances of the application element are locked.
+   const T_SHORT LOCK_CHILDREN = 2;           // Lock the children of the locked object. This mode can be combined with one of the upper two modi.
+};
+
+/**
+* The bits of the security rights.
+*/
+interface SecurityRights {
+   const T_LONG SEC_READ = 1;   // Read access is allowed.
+   const T_LONG SEC_UPDATE = 2; // Update access to an existing object is allowed.
+   const T_LONG SEC_INSERT = 4; // Creating new instances is allowed.
+   const T_LONG SEC_DELETE = 8; // Delete of the object is allowed.
+   const T_LONG SEC_GRANT = 16;  // Access rights may be passed on.
+};
+
+/**
+* The security level of an application element.
+*/
+interface SecurityLevel {
+   const T_LONG NO_SECURITY = 0;        // No security defined.
+   const T_LONG ELEMENT_SECURITY = 1;   // Security scaled for the application element.
+   const T_LONG INSTANCE_SECURITY = 2;  // Security scaled for instance elements.
+   const T_LONG ATTRIBUTE_SECURITY = 4; // Security scaled for appliation attributes.
+};
+
+/**
+* The ASAM ODS query constants.
+*/
+interface QueryConstants {
+   const T_LONG MaxDurationDEFAULT = 0;     // Default value of max duration parameter of the query  (no limitations).
+   const T_STRING MaxDuration = "MaxDuration";            // The ASAM ODS max duration parameter of the query.
+   const T_STRING QueryResultType = "QueryResultType";        // The ASAM ODS query result type parameter.
+   const T_LONG QueryResultTypeDEFAULT = ResultType::INSTELEM_ITERATOR_AS_RESULT; // Default value of the ASAM ODS query result type parameter.
+};
+
+/**
+* The ASAM ODS exception structure.
+*/
+exception AoException {
+   ErrorCode    errCode;
+   SeverityFlag sevFlag;
+   T_LONG       minorCode;
+   T_STRING     reason;
+};
+
+/**
+* The ASAM factory interface.
+*/
+interface AoFactory {
+
+   /** (2001)
+   * Get the description of the ASAM ODS factory. If the description is
+   * not available an empty string is returned and no exception is
+   * thrown. The server loads the description from the base attribute
+   * "description" of the instance of AoEnvironment.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *
+   * @return  The description of the ASAM ODS factory.
+   */
+   T_STRING getDescription()
+      raises (AoException);
+
+   /** (2002)
+   * Get the interface version of the ASAM ODS factory. The interface
+   * version is for each ODS version a fixed string. The string is the
+   * version of the interface implemented at the server. 
+   * 
+   * The format of the string is:
+   * V<Major Version Nr>.<Minor Version Nr>.<Revision Nr>
+   *   - Major Version Nr (numeric: [0-9]+)
+   *   - Minor Version Nr (numeric: [0-9]+)
+   *   - Revision Nr (numeric: [0-9]+)
+   * Example of the version specification is 'V5.1.0'.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *
+   * @return  The interface version of the ASAM ODS factory.
+   */
+   T_STRING getInterfaceVersion()
+      raises (AoException);
+
+   /** (2003)
+   * Get the name of the ASAM ODS factory. If the name is not available
+   * an empty string is returned and no exception is thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *
+   * @return  The name of the ASAM ODS factory.
+   */
+   T_STRING getName()
+      raises (AoException);
+
+   /** (2004)
+   * Get the type of the ASAM ODS factory. If the type is not available
+   * an empty string is returned and no exception is thrown. The server
+   * loads the type from the base attribute "Application_model_type" of
+   * the instance of AoEnvironment.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *
+   * @return  The type of the ASAM ODS factory.
+   */
+   T_STRING getType()
+      raises (AoException);
+
+   /** (2005)
+   * Establish a new session to an ASAM ODS server. The server normally
+   * checks the activity of the session and will close the session after
+   * a time period of inactivity.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECT_FAILED
+   *    AO_CONNECT_REFUSED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_OPEN_MODE_NOT_SUPPORTED
+   *    AO_SESSION_LIMIT_REACHED
+   *
+   * @param  auth  A string that may contain authentication information.
+   *               The following values are currently supported:
+   *                  USER
+   *                  PASSWORD
+   *                  CREATE_COSESSION_ALLOWED
+   *                  FOR_USER
+   *                The values may be specified in any order and have to
+   *               be separated by comma.
+   *               The variable CREATE_COSESSION_ALLOWED
+   *                       Value (DT_STRING) TRUE or FALSE
+   *                       Default for CREATE_COSESSION_ALLOWED =
+   *               FALSE.
+   *                      The variable CREATE_COSESSION_ALLOWED is a
+   *               read-only variable in the session.
+   *               The variable FOR_USER is the name of the user for
+   *               which this session shall be created. If this value is
+   *               given, USER must be a superuser. Otherwise the
+   *               exception AO_CONNECT_REFUSED will be thrown.
+   *               Example:
+   *               "USER=hans, PASSWORD=secret, CREATE_COSESSION_ALLOWED
+   *               = TRUE"
+   *
+   * @return  The new created ASAM ODS session.
+   */
+   AoSession newSession(
+      in T_STRING auth)
+      raises (AoException);
+
+   /** (2006)
+   * Establish a new session to an ASAM ODS server. The server normally
+   * checks the activity of the session and will close the session after
+   * a time period of inactivity. The authentication is a list of
+   * NameValue which is an argument of the method.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECT_FAILED
+   *    AO_CONNECT_REFUSED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_OPEN_MODE_NOT_SUPPORTED
+   *    AO_SESSION_LIMIT_REACHED
+   *
+   * @param  auth  A list of NameValue with the parameters for the
+   *               authentication, the parameter is stored in the Name of
+   *               the NameValue and the value of the aprameter is stored
+   *               in the Value. Each entry in the list represent exact
+   *               one parameter. With this argument the values of the
+   *               parameters can contain also comma because these are
+   *               not used as separater.
+   *
+   * @return  The new created ASAM ODS session.
+   */
+   AoSession newSessionNameValue(
+      in NameValueSequence auth)
+      raises (AoException);
+
+}; // Interface AoFactory.
+
+/**
+* The ASAM ODS session interface.
+*/
+interface AoSession {
+
+   /** (3001)
+   * Abort (rollback) a transaction. The changes made in the transaction
+   * are lost.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   */
+   void abortTransaction()
+      raises (AoException);
+
+   /** (3002)
+   * Close session to an ASAM ODS server. Active transactions are
+   * committed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void close()
+      raises (AoException);
+
+   /** (3003)
+   * Commit a transaction. The changes made in the transaction become
+   * permanent.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   */
+   void commitTransaction()
+      raises (AoException);
+
+   /** (3004)
+   * Get the application model from the current session by returning an
+   * object with the interface ApplicationStructure. The complete
+   * information on the application model is available through that
+   * interface.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The application structure.
+   */
+   ApplicationStructure getApplicationStructure()
+      raises (AoException);
+
+   /** (3005)
+   * Get the application model as values from the current session.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The application structure as value.
+   */
+   ApplicationStructureValue getApplicationStructureValue()
+      raises (AoException);
+
+   /** (3006)
+   * Get the ASAM ODS base model from the current session by returning an
+   * object with the interface BaseStructure. The complete information on
+   * the base model is available through that interface; it includes all
+   * possible base elements with all possible base attributes as
+   * specified by ASAM ODS.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The base structure.
+   */
+   BaseStructure getBaseStructure()
+      raises (AoException);
+
+   /** (3007)
+   * Get context variables from the session. A pattern string can be
+   * specified to select groups of variables.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  varPattern  The name or the search pattern for the context
+   *                     variable(s).
+   *
+   * @return  A list of context variables.
+   */
+   NameValueIterator getContext(
+      in Pattern varPattern)
+      raises (AoException);
+
+   /** (3008)
+   * Get a context variable by its name from the session.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  varName  The name of the requested context variable.
+   *
+   * @return  The requested context variable.
+   */
+   NameValue getContextByName(
+      in Name varName)
+      raises (AoException);
+
+   /** (3009)
+   * List the names of context variables from the session. A pattern
+   * string can be specified to select groups of variables.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NOT_FOUND
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  varPattern  The name or the search pattern for the context
+   *                     variable(s).
+   *
+   * @return  A list of context variable names.
+   */
+   NameIterator listContext(
+      in Pattern varPattern)
+      raises (AoException);
+
+   /** (3010)
+   * Remove context variables from the session. A pattern string can be
+   * specified to remove groups of variables.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NOT_FOUND
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  varPattern  The name or the search pattern for the context
+   *                     variable(s) to be removed.
+   */
+   void removeContext(
+      in Pattern varPattern)
+      raises (AoException);
+
+   /** (3011)
+   * Set/modify a known context variable or add a new context variable to
+   * the session.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  contextVariable  The context variable.
+   */
+   void setContext(
+      in NameValue contextVariable)
+      raises (AoException);
+
+   /** (3012)
+   * Set/modify a known context variable or add a new context variable to
+   * the session. This is a convenience method for the frequently used
+   * string variable type. It uses setContext  internally.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  varName  The name of the context variable.
+   *
+   * @param  value  The value of the context variable.
+   */
+   void setContextString(
+      in Name varName,
+      in T_STRING value)
+      raises (AoException);
+
+   /** (3013)
+   * Start a transaction on the physical storage system (e.g. database
+   * system). Only when a transaction is started it is allowed to create
+   * or modify instances or measurement data. The changes get permanent
+   * with a commit of the transaction or will be lost with an abort of
+   * the transaction. If the session is closed the transaction will be
+   * committed automatically. If a transaction is already active an
+   * exception is thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_ALREADY_ACTIVE
+   */
+   void startTransaction()
+      raises (AoException);
+
+   /** (3014)
+   * Make the changes permanent.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   */
+   void flush()
+      raises (AoException);
+
+   /** (3015)
+   * Every new created instance will set its initial rights to <acl> .
+   * This method overrides the default-methods for applying initial
+   * rights. The initial rights are only valid for the current session.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  irlEntries  The current initial rights.
+   *
+   * @param  set  Set (1) or remove (0) the current initial rights. The
+   *              previous initial rights get lost. If the parameter set
+   *              is 0 (remove) the parameter irlEntries will be ignored.
+   */
+   void setCurrentInitialRights(
+      in InitialRightSequence irlEntries,
+      in T_BOOLEAN set)
+      raises (AoException);
+
+   /** (3016)
+   * Get the current lock mode. The lock mode tells the server which
+   * objects to lock for upcoming changes. Application elements, instance
+   * elements or children of elements can be locked.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The current lock mode. The lock mode constants are defined
+   *          in the interface LockMode. The interface definition
+   *          language IDL does not allow to set the values of
+   *          enumerations thus the constant definitions had to be done
+   *          in an interface.
+   */
+   T_SHORT getLockMode()
+      raises (AoException);
+
+   /** (3017)
+   * Set the new lock mode. The lock mode tells the server which objects
+   * to lock for upcoming changes. Application elements, instance
+   * elements or children of elements can be locked.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  lockMode  The new lock mode. The lock mode constants are
+   *                   defined in the interface LockMode. The interface
+   *                   definition language IDL does not allow to set the
+   *                   values of enumerations thus the constant
+   *                   definitions had to be done in an interface.
+   */
+   void setLockMode(
+      in T_SHORT lockMode)
+      raises (AoException);
+
+   /** (3018)
+   * Get the application element access object from the current session.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The application element access object.
+   */
+   ApplElemAccess getApplElemAccess()
+      raises (AoException);
+
+   /** (3019)
+   * Change the password for user defined by <username> to <newPassword>.
+   * A normal user must supply his current password <oldPassword>. The
+   * super user can change the password without supplying the current
+   * password <oldPassword>. If no username is given the password of the
+   * user of the current session will be changed. The password is
+   * normally encrypted in the attribute of the user instance element.
+   * Creating a new user can be done by creating a new instance,
+   * afterwards the password must be set by the super user.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_WRONG_PASSWORD
+   *
+   * @param  username  The name of the user for which the password will
+   *                   be changed. If no username is given the password
+   *                   of the current user will be changed. If the
+   *                   username differs from the current user the current
+   *                   user must be a super user.
+   *
+   * @param  oldPassword  The current password of the user. A normal user
+   *                      must supply his current password. The super
+   *                      user can change the password without supplying
+   *                      the current password.
+   *
+   * @param  newPassword  The new password of the user.
+   */
+   void setPassword(
+      in T_STRING username,
+      in T_STRING oldPassword,
+      in T_STRING newPassword)
+      raises (AoException);
+
+   /** (3020)
+   * Get the description of the ASAM ODS session. The description of the
+   * session is identical with description of the ASAM ODS factory. If
+   * the description is not available an empty string is returned and no
+   * exception is thrown. The server loads the description from the base
+   * attribute "description" of the instance of AoEnvironment.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_CONNECTION_LOST
+   *
+   * @return  The description of the ASAM ODS session.
+   */
+   T_STRING getDescription()
+      raises (AoException);
+
+   /** (3021)
+   * Get the name of the ASAM ODS session. The name of the session is
+   * identical with the name of the ASAM ODS factory. If the name is not
+   * available an empty string is returned and no exception is thrown.
+   * The server loads the name from the base attribute "name" of the
+   * instance of AoEnvironment.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_CONNECTION_LOST
+   *
+   * @return  The name of the ASAM ODS session.
+   */
+   Name getName()
+      raises (AoException);
+
+   /** (3022)
+   * Get the type of the ASAM ODS session. The type of the session is
+   * identical with the type of the ASAM ODS factory. If the type is not
+   * available an empty string is returned and no exception is thrown.
+   * The server loads the type from the base attribute
+   * "Application_model_type" of the instance of AoEnvironment.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_CONNECTION_LOST
+   *
+   * @return  The type of the ASAM ODS session.
+   */
+   T_STRING getType()
+      raises (AoException);
+
+   /** (3023)
+   * Create a QueryEvaluator object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_ACCESS_DENIED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The new created query evaluator object
+   */
+   QueryEvaluator createQueryEvaluator()
+      raises (AoException);
+
+   /** (3024)
+   * Create a new object with the Interface Blob on the server. This
+   * object can be used to create an attribute value of the data type
+   * DT_BLOB.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The reference of the blob object which is generated at the
+   *          server.
+   */
+   Blob createBlob()
+      raises (AoException);
+
+   /** (3025)
+   * Create a co session. The co session session is the same session as
+   * the original session was at login time.
+   * The co session has no relation to the original session except that
+   * the same authentication is used.
+   * A client application with components can give all components his own
+   * session to the ASAM ODS Server. So the component can close the
+   * session when it is ready, the component can start his own
+   * transaction without any conflict with other components. 
+   * Only when the variable CREATE_COSESSION_ALLOWED=TRUE is given in the
+   * 'auth' parameter of the method newSession at the interface AoFactory
+   * an new session will be created otherwise the exception
+   * AO_ACCESS_DENIED is thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_ACCESS_DENIED
+   *
+   * @return  The co session.
+   */
+   AoSession createCoSession()
+      raises (AoException);
+
+   /** (3026)
+   * Returns the instance element of the user logged in, this is the
+   * instance element from the application element derived from AoUser,
+   * with the name given in s given in the 'auth' parameter of the method
+   * newSession at the interface AoFactory (variable USER). 
+   * 
+   * When the client settings of the user are stored in the ASAM ODS
+   * application model, this methods helps the client  to get his
+   * settings.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *
+   * @return  The instance element of the logged in user.
+   */
+   InstanceElement getUser()
+      raises (AoException);
+
+   /** (3027)
+   * Get the list with the attributes of all elements and the enumeration
+   * name which has an enumeration.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NOT_FOUND
+   *
+   * @return  The list with attribute and there enumeration.
+   */
+   EnumerationAttributeStructureSequence getEnumerationAttributes()
+      raises (AoException);
+
+   /** (3028)
+   * Get all enumerations used in the application model. The enumerations
+   * and all items of the enumerations are returned to the client.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The enumeration with there Items.
+   */
+   EnumerationStructureSequence getEnumerationStructure()
+      raises (AoException);
+
+   /** (3029)
+   * Returns the Id of the session, the ODS server will give each session
+   * an unique Id. The ODS server returns this Id to the client.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *
+   * @return  The Id of the session.
+   */
+   T_LONG getId()
+      raises (AoException);
+
+}; // Interface AoSession.
+
+/**
+* The ASAM ODS application attribute interface.
+*/
+interface ApplicationAttribute {
+
+   /** (4001)
+   * Get the base attribute of the application attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The base attribute of the application attribute. A 'null'
+   *          is returned if the application attribute has no base
+   *          attribute.
+   */
+   BaseAttribute getBaseAttribute()
+      raises (AoException);
+
+   /** (4002)
+   * Get the data type of the application attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The data type of the application attribute.
+   */
+   DataType getDataType()
+      raises (AoException);
+
+   /** (4003)
+   * Get the maximum allowed length of the value of the application
+   * attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The maximum allowed length of the application attribute.
+   */
+   T_LONG getLength()
+      raises (AoException);
+
+   /** (4004)
+   * Get the name of the application attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The name of the application attribute.
+   */
+   Name getName()
+      raises (AoException);
+
+   /** (4005)
+   * Get the unit Id of the application attribute. The unit Id is only
+   * valid for the current server.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The unit Id of the application attribute.
+   */
+   T_LONGLONG getUnit()
+      raises (AoException);
+
+   /** (4006)
+   * Get the obligatory flag of the application attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The obligatory flag of the application attribute.
+   */
+   T_BOOLEAN isObligatory()
+      raises (AoException);
+
+   /** (4007)
+   * Get the unique flag of the application attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The unique flag of the application attribute.
+   */
+   T_BOOLEAN isUnique()
+      raises (AoException);
+
+   /** (4008)
+   * Set the base attribute of the application attribute. This allows the
+   * client to declare the application attribute (new or existing)
+   * additional to a base attribute. The application attribute will
+   * become the derived attribute of the given base attribute.
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The base attribute must be unique within the application element
+   * otherwise the exception AO_DUPLICATE_BASE_ATTRIBUTE is thrown.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   * 
+   * If this method is called before the first commit it will not throw
+   * the following exceptions:
+   *    AO_INVALID_DATATYPE
+   *    AO_MISSING_VALUE
+   *    AO_NOT_UNIQUE.
+   * 
+   * After the first commit, there may be instances of the application
+   * attribute. These instances may cause the following problems:
+   * 
+   * AO_INVALID_DATATYPE: The data type of the base attribute is not the
+   * same as the data type of the instantiated attributes.
+   * 
+   * AO_MISSING_VALUE: The obligatory flag of the base attribute is set
+   * but there are one or more empty values in the instances.
+   * 
+   * AO_NOT_UNIQUE: The unique flag of the base attribute is set but the
+   * values of the instances are not unique.
+   * 
+   * The length, the name and the unit of the application attribute are
+   * not affected by this call.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_BASE_ATTRIBUTE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_DATATYPE
+   *    AO_MISSING_VALUE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NOT_UNIQUE
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  baseAttr  The base attribute.
+   */
+   void setBaseAttribute(
+      in BaseAttribute baseAttr)
+      raises (AoException);
+
+   /** (4009)
+   * Set the data type of the application attribute. 
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * It is not allowed to set the data type of application attributes
+   * that represent base attributes. An attempt to set the data type of
+   * such an application attribute will result in the exception
+   * AO_IS_BASE_ATTRIBUTE.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   * 
+   * If this method is called before the first commit it will not throw
+   * the following exception:
+   *    AO_INVALID_DATATYPE
+   * 
+   * After the first commit, there may be instances of the application
+   * attribute. These instances may cause the following problem:
+   * 
+   * AO_INVALID_DATATYPE: The data type of the base attribute is not the
+   * same as the data type of the instantiated attributes.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_BASE_ATTRIBUTE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_DATATYPE
+   *    AO_IS_BASE_ATTRIBUTE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaDataType  The data type.
+   */
+   void setDataType(
+      in DataType aaDataType)
+      raises (AoException);
+
+   /** (4010)
+   * Set the obligatory flag of the application attribute.
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * It is not allowed to set the obligatory flag of application
+   * attributes
+   * that represent base attributes. An attempt to set the obligatory
+   * flag of such an application attribute will result in the exception
+   * AO_IS_BASE_ATTRIBUTE.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   * 
+   * If this method is called before the first commit it will not throw
+   * the following exception:
+   *    AO_MISSING_VALUE
+   * 
+   * After the first commit, there may be instances of the application
+   * attribute. These instances may cause the following problem:
+   * 
+   * AO_MISSING_VALUE: The obligatory flag of the base attribute is set
+   * but there are one or more empty values in the instances.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_BASE_ATTRIBUTE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_IS_BASE_ATTRIBUTE
+   *    AO_MISSING_VALUE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaIsObligatory  The obligatory flag.
+   */
+   void setIsObligatory(
+      in T_BOOLEAN aaIsObligatory)
+      raises (AoException);
+
+   /** (4011)
+   * Set the unique flag of the application attribute. 
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The server will check if the values of the instance attributes are
+   * unique. If this flag is set and the values of an attribute are not
+   * unique when using the method setValue an exception is thrown. If
+   * instances of the application element already exist that contain
+   * non-unique values and the flag shall be set this method throws an
+   * exception.
+   * 
+   * It is not allowed to set the unique flag of application attributes
+   * that represent base attributes. An attempt to set the unique flag of
+   * such an application attribute will result in the exception
+   * AO_IS_BASE_ATTRIBUTE.
+   * 
+   * If the unique flag is set to TRUE the obligatory flag is also set to
+   * TRUE. The previous values of both flag do not matter in this case.
+   * Setting the unique flag to FALSE does not affect the obligatory
+   * flag.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   * 
+   * If this method is called before the first commit it will not throw
+   * the following exception:
+   *    AO_MISSING_VALUE
+   *    AO_NOT_UNIQUE
+   * 
+   * After the first commit, there may be instances of the application
+   * attribute. These instances may cause the following problem:
+   * 
+   * AO_MISSING_VALUE: The obligatory flag of the base attribute is set
+   * but there are one or more empty values in the instances.
+   * 
+   * AO_NOT_UNIQUE: The unique flag of the base attribute is set but the
+   * values of the instances are not unique.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_BASE_ATTRIBUTE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_IS_BASE_ATTRIBUTE
+   *    AO_MISSING_VALUE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NOT_UNIQUE
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaIsUnique  The unique flag.
+   */
+   void setIsUnique(
+      in T_BOOLEAN aaIsUnique)
+      raises (AoException);
+
+   /** (4012)
+   * Set the maximum allowed length of the application attribute. The
+   * maximum value  accepted by the ASAM ODS server for this length
+   * information depends on the underlying physical storage. For the
+   * physical storage specified in chapter 3 the maximum allowed length
+   * will be stored in the AFLEN value in SVCATTR, and it is restricted
+   * by the maximum length of string type database fields. If a length is
+   * specified that exceeds the capabilities of the underlying physical
+   * storage the server will throw the exception AO_INVALID_LENGTH. 
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction. 
+   * 
+   * This method is useful for ODS database design tools. Negative length
+   * values are not allowed.
+   * 
+   * This method provides only a hint to a database server in the design
+   * phase which size the data entries may have. The length is only
+   * relevant for is ignored for all attribute values with the data type
+   * other datatypes than DT_STRING, DS_STRING, DT_DATE, DS_DATE, all
+   * components of DT_EXTERNALREFERENCE and of DS_EXTERNALREFERENCE, and
+   * the header portion of DT_BLOB.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   * 
+   * If this method is called before the first commit it will not throw
+   * the following exception:
+   *    AO_HAS_INSTANCES
+   * 
+   * After the first commit, there may be instances of the application
+   * attribute. These instances may cause the exception AO_HAS_INSTANCES
+   * if the instances of the application attribute are not empty.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_INSTANCES
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_LENGTH
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaLength  The maximum attribute length.
+   */
+   void setLength(
+      in T_LONG aaLength)
+      raises (AoException);
+
+   /** (4013)
+   * Set the name of an application attribute. 
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The name must be unique.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   * 
+   * The name of an application attribute must not exceed the maximum
+   * name length of the underlying physical storage. Current server
+   * implementations typically restrict it to 30 characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_NAME
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaName  The application attribute name.
+   */
+   void setName(
+      in Name aaName)
+      raises (AoException);
+
+   /** (4014)
+   * Set the unit Id of an application attribute. 
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The unit Id is only valid for the current server. If instances of
+   * the application attribute exist, the respective values are
+   * automatically converted to the new unit. If there is no known
+   * conversion an exception is thrown.
+   * 
+   * The automatic conversion can be avoided if the unit is set to zero.
+   * After that the transaction must be committed. In the next step the
+   * new unit may be set in another transaction.
+   * 
+   * The automatic conversion is done only for the following data
+   * types:
+   *    DT_BYTE
+   *    DT_COMPLEX
+   *    DT_DCOMPLEX
+   *    DT_DOUBLE
+   *    DT_FLOAT
+   *    DT_LONG
+   *    DT_LONGLONG
+   *    DT_SHORT
+   * as well as for the corresponding sequence data types. For complex
+   * data types the real and imaginary part are converted separately.
+   * 
+   * If the unit of an attribute is set the unit is constant. If the
+   * value of the attribute has another unit the value is recalculated to
+   * the unit of the application attribute. If there is no unit at the
+   * application attribute the unit at the attribute value is stored and
+   * reported on request at the instance.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   * 
+   * If this method is called before the first commit it will not throw
+   * the following exceptions:
+   *    AO_INCOMPATIBLE_UNITS
+   *    AO_MATH_ERROR
+   * 
+   * After the first commit, there may be instances of the application
+   * attribute. These instances may cause the following problems:
+   * 
+   * AO_INCOMPATIBLE_UNITS: No conversion rules is known to convert the
+   * unit.
+   * 
+   * AO_MATH_ERROR: Converting the values to the new unit results in data
+   * overflow or underflow or a division by zero is detected.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INCOMPATIBLE_UNITS
+   *    AO_MATH_ERROR
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_UNKNOWN_UNIT
+   *
+   * @param  aaUnit  The unit Id.
+   */
+   void setUnit(
+      in T_LONGLONG aaUnit)
+      raises (AoException);
+
+   /** (4015)
+   * The given user group the rights should be set for. <rights> defines
+   * the rights to set or to clear. If the parameter <set> is set to
+   * 'set', the rights in <rights> are set all others are cleared. If the
+   * parameter <set> is set to 'add', the rights in <rights> are added to
+   * the existing rights. If the parameter <set> is set to 'remove', the
+   * rights in <rights> are removed from the existing rights.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  usergroup  The user group for which the rights will be
+   *                    modified.
+   *
+   * @param  rights  The new right for the user group. The rights
+   *                 constants are defined in the interface
+   *                 SecurityRights. The interface definition language
+   *                 IDL does not allow to set the values of enumerations
+   *                 thus the constant definitions had to be done in an
+   *                 interface.
+   *
+   * @param  set  What to do with the new right.
+   */
+   void setRights(
+      in InstanceElement usergroup,
+      in T_LONG rights,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (4016)
+   * Retrieve access control list information of the given object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The access control list entries of the given application
+   *          element.
+   */
+   ACLSequence getRights()
+      raises (AoException);
+
+   /** (4017)
+   * Return the application element to which the attribute belongs.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The application element of the attribute.
+   */
+   ApplicationElement getApplicationElement()
+      raises (AoException);
+
+   /** (4018)
+   * Get the auto generate flag of the application attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The auto generate flag of the application attribute.
+   */
+   T_BOOLEAN isAutogenerated()
+      raises (AoException);
+
+   /** (4019)
+   * Set the auto generate flag of the application attribute.
+   * 
+   * It is allowed to modify the application attribute outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * For performance and flexibility reasons this set-method should be
+   * used before the new application attribute is committed the first
+   * time.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_BASE_ATTRIBUTE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_IS_BASE_ATTRIBUTE
+   *    AO_MISSING_VALUE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  isAutogenerated  The auto generate flag.
+   */
+   void setIsAutogenerated(
+      in T_BOOLEAN isAutogenerated)
+      raises (AoException);
+
+   /** (4020)
+   * Get the definition of the enumeration.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_DATATYPE
+   *
+   * @return  The ASAM ODS enumeration.
+   */
+   EnumerationDefinition getEnumerationDefinition()
+      raises (AoException);
+
+   /** (4021)
+   * Set the definition of the enumeration. This method modifies the
+   * application model, only the super user can use this method.
+   * 
+   * The AoException AO_INVALID_DATATYPE is thrown when the data type of
+   * the attribute is not DT_ENUM.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_ACCESS_DENIED
+   *    AO_INVALID_DATATYPE
+   *
+   * @param  enumDef  The new enumeration definition.
+   */
+   void setEnumerationDefinition(
+      in EnumerationDefinition enumDef)
+      raises (AoException);
+
+   /** (4022)
+   * Has the attribute an unit. If this flag is set, all the attributes
+   * of the instances derived from this attribute will has an unit.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The flag if the attribute has an unit.
+   */
+   T_BOOLEAN hasUnit()
+      raises (AoException);
+
+   /** (4023)
+   * Set whether the attribute becomes an unit or not. A call to the
+   * method setUnit() will automatically set the withUnit(TRUE).
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  withUnit  The flag if the attribute becomes an unit.
+   */
+   void withUnit(
+      in T_BOOLEAN withUnit)
+      raises (AoException);
+
+   /** (4024)
+   * Deprecated, not used any more since ASAM ODS 5.2. 
+   * Has the attribute a value flag. If this flag is set, all the
+   * attributes of the instances derived from this attribute will has a
+   * value flag. If this flag is not set the flag in the TS_Value
+   * structure can be ignored.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The flag if the attribute has a value flag.
+   */
+   T_BOOLEAN hasValueFlag()
+      raises (AoException);
+
+   /** (4025)
+   * Deprecated, not used any more since ASAM ODS 5.2. 
+   * Set whether the attribute becomes a value flag or not. If this flag
+   * isn't set the flag of the TS_Value will be ignored by the server.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  withValueFlag  The flag if the attribute becomes a value
+   *                        flag.
+   */
+   void withValueFlag(
+      in T_BOOLEAN withValueFlag)
+      raises (AoException);
+
+}; // Interface ApplicationAttribute.
+
+/**
+* The ASAM ODS application element interface.
+*/
+interface ApplicationElement {
+
+   /** (5001)
+   * Create a new application attribute on the server. 
+   * 
+   * It is allowed to modify the application element outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The properties of the new application attribute may be changed via
+   * the set-methods of the ApplicationAttribute interface.
+   * 
+   * For performance reasons it is recommended to set all required
+   * properties of an application attribute before it is committed the
+   * first time. This avoids database cross-checks for each attribute.
+   * 
+   * The default properties of a new application attribute are:
+   *    BaseAttribute   NULL
+   *    DataType        DT_UNKNOWN
+   *    IsObligatory    0
+   *    IsUnique        0
+   *    Length          0
+   *    Name            "AUTOGEN"
+   *    Unit            NULL
+   * 
+   * If there are already instances of the application element the values
+   * of the existing instances of the new attribute are set to
+   * undefined.
+   * 
+   * The exception AO_DUPLICATE_NAME name occurs if there is already
+   * another application attribute with the name "AUTOGEN".
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_NAME
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @return  The new application attribute.
+   */
+   ApplicationAttribute createAttribute()
+      raises (AoException);
+
+   /** (5002)
+   * Create an instance of the application element. 
+   * 
+   * It is allowed to create an instance outside a transaction but it is
+   * recommended to activate a transaction.
+   * 
+   * The instance gets permanent when the  transaction is committed.  All
+   * attributes connected to the application element are automatically
+   * created and connected to the instance. The values of the attributes
+   * can be set by the method setValue of the interface InstanceElement.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  ieName  The instance name.
+   *
+   * @return  The new instance.
+   */
+   InstanceElement createInstance(
+      in Name ieName)
+      raises (AoException);
+
+   /** (5003)
+   * Get a list of all related application elements connected to this
+   * application element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The related application elements.
+   */
+   ApplicationElementSequence getAllRelatedElements()
+      raises (AoException);
+
+   /** (5004)
+   * Get a list of all application relations connected to this
+   * application element. The inverse relation of relations connected to
+   * other application elements pointing to the given application
+   * elements are not returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The application relations of the application element.
+   */
+   ApplicationRelationSequence getAllRelations()
+      raises (AoException);
+
+   /** (5005)
+   * Get the application attribute of an application element which is
+   * inherited from the base attribute with the given name. The base name
+   * is case insensitive and may not contain wildcard characters. 
+   * 
+   * Note: The base model is case blind,  e.g. Id, ID and id is all the
+   * same base attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  baName  The base attribute name.
+   *
+   * @return  The application attribute.
+   */
+   ApplicationAttribute getAttributeByBaseName(
+      in Name baName)
+      raises (AoException);
+
+   /** (5006)
+   * Get the application attribute of an application element which has
+   * the given name. The name is case sensitive and may not contain
+   * wildcard characters.
+   * 
+   * Note: The application model is case sensitive, e.g. Id and ID are
+   * different application attributes, don't use this misleading
+   * attribute name.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaName  The application attribute name.
+   *
+   * @return  The application attribute.
+   */
+   ApplicationAttribute getAttributeByName(
+      in Name aaName)
+      raises (AoException);
+
+   /** (5007)
+   * Get a list of the application attributes of an application element.
+   * The reference attributes are not returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaPattern  The name or the search pattern for the
+   *                    application attribute name.
+   *
+   * @return  The application attributes.
+   */
+   ApplicationAttributeSequence getAttributes(
+      in Pattern aaPattern)
+      raises (AoException);
+
+   /** (5008)
+   * Get the base element of an application element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The base element.
+   */
+   BaseElement getBaseElement()
+      raises (AoException);
+
+   /** (5009)
+   * Get the Id of an application element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The Id of the application element.
+   */
+   T_LONGLONG getId()
+      raises (AoException);
+
+   /** (5010)
+   * Get the instance element specified by the given Id. If the Id of the
+   * instance is not unique an exception is thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  ieId  The instance element Id.
+   *
+   * @return  The instance element.
+   */
+   InstanceElement getInstanceById(
+      in T_LONGLONG ieId)
+      raises (AoException);
+
+   /** (5011)
+   * Get the instance element specified by the given name. If the name of
+   * the instance is not unique an exception is thrown.
+   * 
+   * This is a convenience method for instance elements with unique
+   * names. If there are duplicate names for instance use the method
+   * getInstances instead and specify the requested name as pattern
+   * parameter.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_NAME
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  ieName  The instance element name.
+   *
+   * @return  The instance element.
+   */
+   InstanceElement getInstanceByName(
+      in Name ieName)
+      raises (AoException);
+
+   /** (5012)
+   * Get the instances whose names match the pattern. The pattern is case
+   * sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  iePattern  The name or the search pattern for the instance
+   *                    element name.
+   *
+   * @return  The instance elements.
+   */
+   InstanceElementIterator getInstances(
+      in Pattern iePattern)
+      raises (AoException);
+
+   /** (5013)
+   * Get the name of an application element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The name of the application element.
+   */
+   Name getName()
+      raises (AoException);
+
+   /** (5014)
+   * Get related application elements connected via the specified
+   * relationship.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATIONSHIP
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeRelationship  The requested relationship.
+   *
+   * @return  The related application elements.
+   */
+   ApplicationElementSequence getRelatedElementsByRelationship(
+      in Relationship aeRelationship)
+      raises (AoException);
+
+   /** (5015)
+   * Get application relations of the requested type connected from this
+   * application element. The inverse relations are not returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION_TYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeRelationType  The requested relation type.
+   *
+   * @return  The application relations.
+   */
+   ApplicationRelationSequence getRelationsByType(
+      in RelationType aeRelationType)
+      raises (AoException);
+
+   /** (5016)
+   * Get the names of all related application elements.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The names of the related application elements.
+   */
+   NameSequence listAllRelatedElements()
+      raises (AoException);
+
+   /** (5017)
+   * Get the application attribute names of the application element.
+   * There are no attribute names returned in the result list that
+   * contain a reference to another application element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaPattern  The name or the search pattern for the
+   *                    application attribute name.
+   *
+   * @return  The names of the application attributes.
+   */
+   NameSequence listAttributes(
+      in Pattern aaPattern)
+      raises (AoException);
+
+   /** (5018)
+   * Get the names of the instances whose names match the pattern. The
+   * pattern is case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aaPattern  The name or the search pattern for the
+   *                    application attribute name.
+   *
+   * @return  The names of the instances.
+   */
+   NameIterator listInstances(
+      in Pattern aaPattern)
+      raises (AoException);
+
+   /** (5019)
+   * Get the names of related application elements connected via the
+   * specified relationship.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATIONSHIP
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeRelationship  The requested relationship.
+   *
+   * @return  The names of the related application elements.
+   */
+   NameSequence listRelatedElementsByRelationship(
+      in Relationship aeRelationship)
+      raises (AoException);
+
+   /** (5020)
+   * Remove an application attribute from an application element. If
+   * there are instances of the application element the attribute of the
+   * existing instances change from application to instance attributes.
+   * 
+   * 
+   * It is allowed to modify the application element outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  applAttr  The application attribute to remove.
+   */
+   void removeAttribute(
+      in ApplicationAttribute applAttr)
+      raises (AoException);
+
+   /** (5021)
+   * Remove an instance from the application element. 
+   * 
+   * It is allowed to remove an instance outside a transaction but it is
+   * recommended to activate a transaction.
+   * 
+   * The instance is removed from the server when the transaction is
+   * committed. If the recursive flag is set all children of the instance
+   * are also deleted. Removing instances is allowed only if there are no
+   * references(relations) to this instance. If the recursive flag is set
+   * a reference to one of the children is not allowed and will cause an
+   * exception.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_REFERENCES
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  ieId  The instance Id.
+   *
+   * @param  recursive  The recursive flag.
+   */
+   void removeInstance(
+      in T_LONGLONG ieId,
+      in T_BOOLEAN recursive)
+      raises (AoException);
+
+   /** (5022)
+   * Set the base element of the application element. 
+   * 
+   * It is allowed to modify the application element outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The assignment to the current base element is overwritten. If there
+   * are instances of the application element or references to the
+   * application element an exception is thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_INSTANCES
+   *    AO_HAS_REFERENCES
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  baseElem  The base element.
+   */
+   void setBaseElement(
+      in BaseElement baseElem)
+      raises (AoException);
+
+   /** (5023)
+   * Set the name of the application element.
+   *  
+   * It is allowed to modify the application element outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The name of the application element must be unique.
+   * 
+   * The name of an application element must not exceed the maximum name
+   * length of the underlying physical storage. Current server
+   * implementations restrict it to 30 characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_NAME
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  aeName  The application element name.
+   */
+   void setName(
+      in Name aeName)
+      raises (AoException);
+
+   /** (5024)
+   * The given user group the rights should be set for. <rights> defines
+   * the rights to set or to clear. If the parameter <set> is set to
+   * 'set', the rights in <rights> are set all others are cleared. If the
+   * parameter <set> is set to 'add', the rights in <rights> are added to
+   * the existing rights. If the parameter <set> is set to 'remove', the
+   * rights in <rights> are removed from the existing rights.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  usergroup  The user group for which the rights will be
+   *                    modified.
+   *
+   * @param  rights  The new right for the user group. The rights
+   *                 constants are defined in the interface
+   *                 SecurityRights. The interface definition language
+   *                 IDL does not allow to set the values of enumerations
+   *                 thus the constant definitions had to be done in an
+   *                 interface.
+   *
+   * @param  set  What to do with the new right.
+   */
+   void setRights(
+      in InstanceElement usergroup,
+      in T_LONG rights,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (5025)
+   * Retrieve access control list information of the given object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The access control list entries of the given application
+   *          element.
+   */
+   ACLSequence getRights()
+      raises (AoException);
+
+   /** (5026)
+   * Retrieve access control list information for the initial rights of
+   * the given object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The access control list entries with the initial rights of
+   *          the given application element.
+   */
+   InitialRightSequence getInitialRights()
+      raises (AoException);
+
+   /** (5027)
+   * The given user group the initial rights should be set for. <rights>
+   * defines the rights to set or to clear. If the parameter <set> is set
+   * to 'set', the rights in <rights> are set all others are cleared. If
+   * the parameter <set> is set to 'add', the rights in <rights> are
+   * added to the existing rights. If the parameter <set> is set to
+   * 'remove', the rights in <rights> are removed from the existing
+   * rights.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  usergroup  The user group for which the initial rights will
+   *                    be modified.
+   *
+   * @param  rights  The new initial rights for the user group. The
+   *                 rights constants are defined in the interface
+   *                 SecurityRights. The interface definition language
+   *                 IDL does not allow to set the values of enumerations
+   *                 thus the constant definitions had to be done in an
+   *                 interface.
+   *
+   * @param  refAid  The Id of referencing application element for which
+   *                 the initial rights will be used. If no refAid is set
+   *                 the initial rights will be used for each new
+   *                 instance element independent of the application
+   *                 element.
+   *
+   * @param  set  What to do with the new initial rights.
+   */
+   void setInitialRights(
+      in InstanceElement usergroup,
+      in T_LONG rights,
+      in T_LONGLONG refAid,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (5028)
+   * Set for the given application element, which relation will be used
+   * to determine the initial rights for the new created instances.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  applRel  The application relation which will be used to
+   *                  determine the initial rights. The relation range of
+   *                  the application relation must be [1:1] otherwise
+   *                  the server can not find an unique instance element
+   *                  to retrieve the initial rights.
+   *
+   * @param  set  Set or remove the relation for the initial rights. If
+   *              this parameter is true the relation will be set
+   *              otherwise removed.
+   */
+   void setInitialRightRelation(
+      in ApplicationRelation applRel,
+      in T_BOOLEAN set)
+      raises (AoException);
+
+   /** (5029)
+   * Get all relations which are used to retrieve the instances to create
+   * the initial rights of the new created instance element. If there are
+   * more then one application relation the initial rights of each
+   * related instance are 'ored' to the list of the initial rights.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The sequence with the application relations which will be
+   *          used to create the initial rights of the new created
+   *          instance element.
+   */
+   ApplicationRelationSequence getInitialRightRelations()
+      raises (AoException);
+
+   /** (5030)
+   * Get the security level of the application element. The security
+   * level tells if there is a security check for both application
+   * element and instance elements or only for the application
+   * attributes, the instance elements or none at all.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The current security level. The security level constants
+   *          are defined in the interface SecurityLevel. The interface
+   *          definition language IDL does not allow to set the values of
+   *          enumerations thus the constant definitions had to be done
+   *          in an interface.
+   */
+   T_LONG getSecurityLevel()
+      raises (AoException);
+
+   /** (5031)
+   * Set the security level for the given application element. If the
+   * security level is added the client is responsible for the access
+   * control list entries of the existing objects.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  secLevel  The new security level. The security level
+   *                   constants are defined in the interface
+   *                   SecurityLevel. The interface definition language
+   *                   IDL does not allow to set the values of
+   *                   enumerations thus the constant definitions had to
+   *                   be done in an interface.
+   *
+   * @param  set  What to do with the new security level.
+   */
+   void setSecurityLevel(
+      in T_LONG secLevel,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (5032)
+   * Get the application model to which the application element belongs
+   * by returning an object with the interface ApplicationStructure. The
+   * application model provided is the same as that provided from the
+   * method getApplicationStructure of the Interface AoSession. This
+   * method guarantees that the client software is able to return to the
+   * session in case the session object is not available.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The application structure to which the application element
+   *          belongs.
+   */
+   ApplicationStructure getApplicationStructure()
+      raises (AoException);
+
+   /** (5033)
+   * Create a list with instances. The attribute are given with the name
+   * of the sequence. The values of the attributes are given in the value
+   * sequence. The index in the different value sequences match for one
+   * instance element. The index in the instance element sequence of the
+   * related instances match for the instance with the same index in the
+   * value sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_INVALID_REQUEST
+   *
+   * @param  attributes  The attributes of the new created instances.
+   *
+   * @param  relatedInstances  The list with related instances for
+   *                           different application relations.
+   *
+   * @return  The list with the new created instances.
+   */
+   InstanceElementSequence createInstances(
+      in NameValueSeqUnitSequence attributes,
+      in ApplicationRelationInstanceElementSeqSequence relatedInstances)
+      raises (AoException);
+
+   /** (5034)
+   * Return the basic application relations derived from the base
+   * relation with the given relation name.
+   * Take care at most elements only one application relation can be
+   * derived from a base relation, there are some well defined
+   * exceptions, so the method can return more then one application
+   * relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  baseRelName  The name of the base relation.
+   *
+   * @return  The application relation sequence, if no relation is found
+   *          an empty sequence is returned.
+   */
+   ApplicationRelationSequence getRelationsByBaseName(
+      in Name baseRelName)
+      raises (AoException);
+
+}; // Interface ApplicationElement.
+
+/**
+* The ASAM ODS application relation interface.
+* 
+* A relation is the connection between two ASAM ODS elements; it may be
+* navigated in both
+* directions. The get- and set- methods are defined from the first
+* element, the getInverse- and
+* setInverse- methods work from the second element.
+*/
+interface ApplicationRelation {
+
+   /** (6001)
+   * Get the base relation of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The base relation of the application relation. A 'null' is
+   *          returned if the application relation has no base relation.
+   */
+   BaseRelation getBaseRelation()
+      raises (AoException);
+
+   /** (6002)
+   * Get the first application element of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The first application element of the application relation.
+   */
+   ApplicationElement getElem1()
+      raises (AoException);
+
+   /** (6003)
+   * Get the second application element of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The second application element of the application relation.
+   */
+   ApplicationElement getElem2()
+      raises (AoException);
+
+   /** (6004)
+   * Get the inverse relation range of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The inverse relation range of the application relation.
+   */
+   RelationRange getInverseRelationRange()
+      raises (AoException);
+
+   /** (6005)
+   * Get the inverse relationship of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The inverse relationship of the application relation.
+   */
+   Relationship getInverseRelationship()
+      raises (AoException);
+
+   /** (6006)
+   * Get the name of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The name of the application relation.
+   */
+   Name getRelationName()
+      raises (AoException);
+
+   /** (6007)
+   * Get the relation range of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The relation range of the application relation.
+   */
+   RelationRange getRelationRange()
+      raises (AoException);
+
+   /** (6008)
+   * Get the relationship of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The relationship of the application relation.
+   */
+   Relationship getRelationship()
+      raises (AoException);
+
+   /** (6009)
+   * Get the relation type of the application relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The relation type of the application relation.
+   */
+   RelationType getRelationType()
+      raises (AoException);
+
+   /** (6010)
+   * Set the base relation of the application relation. 
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The relation type and relation range is copied from the base
+   * relation. The previous values get lost.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  baseRel  The base relation.
+   */
+   void setBaseRelation(
+      in BaseRelation baseRel)
+      raises (AoException);
+
+   /** (6011)
+   * Set the first application element of the application relation. 
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_ELEMENT
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  applElem  The application element.
+   */
+   void setElem1(
+      in ApplicationElement applElem)
+      raises (AoException);
+
+   /** (6012)
+   * Set the second application element of the application relation. 
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_ELEMENT
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  applElem  The application element.
+   */
+   void setElem2(
+      in ApplicationElement applElem)
+      raises (AoException);
+
+   /** (6013)
+   * Set the relation range of an application relation. 
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * It is only allowed to set the relation type if no base relation is
+   * defined.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_BASE_RELATION
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION_RANGE
+   *    AO_IS_BASE_RELATION
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  arRelationRange  The inverse relation range.
+   */
+   void setInverseRelationRange(
+      in RelationRange arRelationRange)
+      raises (AoException);
+
+   /** (6014)
+   * Set the name of an application relation.
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The name of an application attribute must not exceed the maximum
+   * name length of the underlying physical storage. Current server
+   * typically implementations restrict it to 30 characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  arName  The application relation name.
+   */
+   void setRelationName(
+      in Name arName)
+      raises (AoException);
+
+   /** (6015)
+   * Set the relation range of an application relation. 
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * It is only allowed to set the relation type if no base relation is
+   * defined.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_BASE_RELATION
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION_RANGE
+   *    AO_IS_BASE_RELATION
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  arRelationRange  The relation range.
+   */
+   void setRelationRange(
+      in RelationRange arRelationRange)
+      raises (AoException);
+
+   /** (6016)
+   * Set the relation type of an application relation. 
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The relationship is automatically set when the relation type is set.
+   * It is only allowed to set the relation type if no base relation is
+   * defined.
+   * 
+   * It is only allowed to modify a relation type when no base relation
+   * is given, otherwise the exception AO_HAS_BASE_RELATION is thrown.
+   * 
+   * It is not allowed to set the relation type FATHER_CHILD, these
+   * relation type is reserved for the base model. The two relation types
+   * which can be set are  INFO or INHERITANCE. 
+   * 
+   * The relationship is set automatic when the relation type is set, the
+   * maximum of the relation range determines the relationship between
+   * the elements of the relation.
+   * 
+   * R.Type      | max R.Range | max inv. R.Range | Relationship         
+   *               
+   * ------------+-------------+------------------+-------------         
+   *              
+   * INFO        | 1           | 1                | exception,
+   * AO_INVALID_RELATION_TYPE 
+   * ------------+-------------+------------------+-------------         
+   *        
+   * INFO        | 1           | MANY             | INFO_TO              
+   *               
+   * ------------+-------------+------------------+-------------         
+   *              
+   * INFO        | MANY        | 1                | INFO_FROM            
+   *               
+   * ------------+-------------+------------------+-------------         
+   *              
+   * INFO        | MANY        | MANY             | INFO                 
+   *               
+   * ------------+-------------+------------------+-------------         
+   *              
+   * INHERITANCE | 1           | 1                | exception,
+   * AO_INVALID_RELATION_TYPE 
+   * ------------+-------------+------------------+-------------         
+   *              
+   * INHERITANCE | 1           | MANY             | SUPERTYPE            
+   *               
+   * ------------+-------------+------------------+-------------         
+   *              
+   * INHERITANCE | MANY        | 1                | SUBTYPE              
+   *               
+   * ------------+-------------+------------------+-------------         
+   *              
+   * INHERITANCE | MANY        | MANY             | exception,
+   * AO_INVALID_RELATION_TYPE
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_BASE_RELATION
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION_TYPE
+   *    AO_IS_BASE_RELATION
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  arRelationType  The relation type.
+   */
+   void setRelationType(
+      in RelationType arRelationType)
+      raises (AoException);
+
+   /** (6017)
+   * Get the inverse name of the application relation. The inverse name
+   * of an application relation is the name of the relation seen from the
+   * other application element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The inverse name of the application relation.
+   */
+   Name getInverseRelationName()
+      raises (AoException);
+
+   /** (6018)
+   * Set the name of an application relation.
+   * 
+   * It is allowed to modify the application relation outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  arInvName  The inverse application relation name.
+   */
+   void setInverseRelationName(
+      in Name arInvName)
+      raises (AoException);
+
+}; // Interface ApplicationRelation.
+
+/**
+* The ASAM ODS application structure interface.
+*/
+interface ApplicationStructure {
+
+   /** (7001)
+   * Check the application model for ASAM ODS conformity. The first error
+   * found is reported by an exception. The following checks are
+   * performed:
+   * 
+   *  - Each application element must be derived from a valid base
+   * element.
+   *  - An application attribute is derived from one base attribute. It
+   * is not allowed to derive more the one application attribute from the
+   * same base attribute. It is allowed that application attributes are
+   * not derived from any base attribute.
+   *  - All application elements must have at least the mandatory
+   * attributes.
+   *  - Each application elements must be identified by a unique Asam
+   * path. No "floating" application elements are allowed.
+   *  - All relations required by the base model must be present.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_BASE_ATTRIBUTE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION
+   *    AO_MISSING_ATTRIBUTE
+   *    AO_MISSING_RELATION
+   *    AO_MISSING_APPLICATION_ELEMENT
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_PATH_TO_ELEMENT
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void check()
+      raises (AoException);
+
+   /** (7002)
+   * Create a new application element in the application model. 
+   * 
+   * It is allowed to modify the application model outside a transaction
+   * but it is recommended to activate a transaction.
+   * 
+   * The information whether or not the new application element is a top
+   * level element is taken from the specified base element. The Id of
+   * the application element is set automatically. The mandatory base
+   * attributes are created automatically. Optional attributes have to be
+   * created by the calling program. The application attribute interface
+   * methods may be used to modify the attributes.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  baseElem  The base element from which the application
+   *                   element is derived.
+   *
+   * @return  The new application element.
+   */
+   ApplicationElement createElement(
+      in BaseElement baseElem)
+      raises (AoException);
+
+   /** (7003)
+   * Create a new relation. 
+   * 
+   * It is allowed to modify the application model outside a transaction
+   * but it is recommended to activate a transaction.
+   * 
+   * The relation is part of the application model. The application
+   * relation interface methods may be used to modify the relation.
+   * 
+   * The default properties of a new application relation are:
+   *    BaseRelation   NULL
+   *    Element1       NULL
+   *    Element2       NULL
+   *    Range          -2, -2
+   *    Name           NULL
+   *    Type           INFO
+   * When element 1 or element 2 is set before the name of the relation
+   * is specified, the name of the application relation is set to
+   * "AUTOGEN".
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @return  The new application relation.
+   */
+   ApplicationRelation createRelation()
+      raises (AoException);
+
+   /** (7004)
+   * Get the application element with the requested Id.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeId  The Id of the requested application element.
+   *
+   * @return  The requested application element.
+   */
+   ApplicationElement getElementById(
+      in T_LONGLONG aeId)
+      raises (AoException);
+
+   /** (7005)
+   * Get the application element with the requested name.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeName  The name of the requested application element.
+   *
+   * @return  The requested application element.
+   */
+   ApplicationElement getElementByName(
+      in Name aeName)
+      raises (AoException);
+
+   /** (7006)
+   * Get the application elements whose names match the pattern. The
+   * pattern is case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aePattern  The name or the search pattern for the requested
+   *                    application elements.
+   *
+   * @return  The requested application elements.
+   */
+   ApplicationElementSequence getElements(
+      in Pattern aePattern)
+      raises (AoException);
+
+   /** (7007)
+   * Get the names of application elements that are derived from the
+   * specified base element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_BASETYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeType  The requested base element type. The base element
+   *                 type can be a pattern.
+   *
+   * @return  The requested application element names.
+   */
+   ApplicationElementSequence getElementsByBaseType(
+      in BaseType aeType)
+      raises (AoException);
+
+   /** (7008)
+   * Get the instance element specified by the ASAM path.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_ASAM_PATH
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  asamPath  The ASAM path of the requested instance element.
+   *
+   * @return  The requested instance element.
+   */
+   InstanceElement getInstanceByAsamPath(
+      in Name asamPath)
+      raises (AoException);
+
+   /** (7009)
+   * Returns the relations between two application elements.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  applElem1  The first application element.
+   *
+   * @param  applElem2  The second application element.
+   *
+   * @return  The relations between the specified application elements.
+   */
+   ApplicationRelationSequence getRelations(
+      in ApplicationElement applElem1,
+      in ApplicationElement applElem2)
+      raises (AoException);
+
+   /** (7010)
+   * Get the top level application elements which are inherited from the
+   * base element that matches the base type. If the given base type is
+   * no top level base element an exception is thrown. A top level
+   * application element is an application element without a father.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_BASETYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeType  The requested base type. The base element type can
+   *                 be a pattern.
+   *
+   * @return  The top level application elements.
+   */
+   ApplicationElementSequence getTopLevelElements(
+      in BaseType aeType)
+      raises (AoException);
+
+   /** (7011)
+   * Get the names of the application elements that  match the pattern.
+   * The pattern is case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aePattern  The name or the search pattern for the requested
+   *                    base elements.
+   *
+   * @return  The names of the application elements.
+   */
+   NameSequence listElements(
+      in Pattern aePattern)
+      raises (AoException);
+
+   /** (7012)
+   * Get the names of application elements that are  derived from the
+   * given base type.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_BASETYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeType  The requested base type. The base element type can
+   *                 be a pattern.
+   *
+   * @return  The names of the application elements.
+   */
+   NameSequence listElementsByBaseType(
+      in BaseType aeType)
+      raises (AoException);
+
+   /** (7013)
+   * Get the names of the top level application elements that are derived
+   * from the given base type. If the given base type is not a top level
+   * base element an exception is thrown. A top level application element
+   * is an application element without a father.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_BASETYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aeType  The requested base type.
+   *
+   * @return  The names of the application elements.
+   */
+   NameSequence listTopLevelElements(
+      in BaseType aeType)
+      raises (AoException);
+
+   /** (7014)
+   * Remove an application element from the application model. 
+   * 
+   * It is allowed to modify the application model outside a transaction
+   * but it is recommended to activate a transaction.
+   * 
+   *   - Only allowed:
+   *       - if the application element is empty
+   *         (has no instances).
+   *       - no relations with other application elements.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_INSTANCES
+   *    AO_HAS_REFERENCES
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  applElem  The application element to be removed.
+   */
+   void removeElement(
+      in ApplicationElement applElem)
+      raises (AoException);
+
+   /** (7015)
+   * This method removes an application relation from the model. 
+   * 
+   * It is allowed to modify the application model outside a transaction
+   * but it is recommended to activate a transaction.
+   * 
+   * The elements of the relation are still part of the application
+   * model. If there are instances of the relation they are also removed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_HAS_INSTANCES
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  applRel  The application relation to be removed.
+   */
+   void removeRelation(
+      in ApplicationRelation applRel)
+      raises (AoException);
+
+   /** (7016)
+   * Get the instance elements specified by the element id.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_ASAM_PATH
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  ieIds  The sequence with the element id.
+   *
+   * @return  The requested instance element sequence.
+   */
+   InstanceElementSequence getInstancesById(
+      in ElemIdSequence ieIds)
+      raises (AoException);
+
+   /** (7017)
+   * Get the current client session in which the application model is
+   * created.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The current client session.
+   */
+   AoSession getSession()
+      raises (AoException);
+
+   /** (7018)
+   * Create a new enumeration definition. This method modifies the
+   * application model and is only allowed for the super user.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_ACCESS_DENIED
+   *
+   * @param  enumName  Name of the enumeration
+   *
+   * @return  The new created enumeration
+   */
+   EnumerationDefinition createEnumerationDefinition(
+      in T_STRING enumName)
+      raises (AoException);
+
+   /** (7019)
+   * Remove the enumeration definition. The server checks if the
+   * enumeration is still in use by one of the attributes. This method
+   * modifies the application model and is only allowed for the super
+   * user.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_ACCESS_DENIED
+   *
+   * @param  enumName  Name of the enumeration to remove.
+   */
+   void removeEnumerationDefinition(
+      in T_STRING enumName)
+      raises (AoException);
+
+   /** (7020)
+   * Get the list of all enumeration names.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  List with all enumeration names.
+   */
+   NameSequence listEnumerations()
+      raises (AoException);
+
+   /** (7021)
+   * Get the specified enumeration definition.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  enumName  Name of the requested enumeration.
+   *
+   * @return  The enumeration definition.
+   */
+   EnumerationDefinition getEnumerationDefinition(
+      in T_STRING enumName)
+      raises (AoException);
+
+   /** (7022)
+   * Create the relation between a list of instances. The number of
+   * instances in both list must be identical. The application element of
+   * the instances in each list must be identical. The application
+   * elements must match the application elements of the application
+   * relation. The index in the list of the instances defines related
+   * instances.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_INVALID_REQUEST
+   *
+   * @param  applRel  The application relation.
+   *
+   * @param  elemList1  The list with the instances of one application
+   *                    element for which the relation will be created.
+   *
+   * @param  elemList2  The list with the related instances.
+   */
+   void createInstanceRelations(
+      in ApplicationRelation applRel,
+      in InstanceElementSequence elemList1,
+      in InstanceElementSequence elemList2)
+      raises (AoException);
+
+}; // Interface ApplicationStructure.
+
+/**
+* The ASAM ODS base attribute interface.
+*/
+interface BaseAttribute {
+
+   /** (8001)
+   * Get the data type of the base attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The data type of the base attribute.
+   */
+   DataType getDataType()
+      raises (AoException);
+
+   /** (8002)
+   * Get the name of the base attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The name of the base attribute.
+   */
+   Name getName()
+      raises (AoException);
+
+   /** (8003)
+   * Get the obligatory flag of the base attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The obligatory flag of the base attribute.
+   */
+   T_BOOLEAN isObligatory()
+      raises (AoException);
+
+   /** (8004)
+   * Get the unique flag of the base attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The unique flag of the base attribute.
+   */
+   T_BOOLEAN isUnique()
+      raises (AoException);
+
+   /** (8005)
+   * Return the base element to which the attribute belongs..
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The base element of the attribute.
+   */
+   BaseElement getBaseElement()
+      raises (AoException);
+
+   /** (8006)
+   * Get the definition of the enumeration of the base attribute.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_DATATYPE
+   *
+   * @return  The ASAM ODS enumeration.
+   */
+   EnumerationDefinition getEnumerationDefinition()
+      raises (AoException);
+
+}; // Interface BaseAttribute.
+
+/**
+* The ASAM ODS base element interface.
+*/
+interface BaseElement {
+
+   /** (9001)
+   * Get all known relations of the base element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  All known relations of the base element.
+   */
+   BaseRelationSequence getAllRelations()
+      raises (AoException);
+
+   /** (9002)
+   * Get attributes of the base element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  baPattern  The name or the search pattern for the requested
+   *                    base attributes.
+   *
+   * @return  The requested attributes of the base element.
+   */
+   BaseAttributeSequence getAttributes(
+      in Pattern baPattern)
+      raises (AoException);
+
+   /** (9003)
+   * Get the related elements of a base element defined by the
+   * relationship.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATIONSHIP
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  brRelationship  The requested relationship.
+   *
+   * @return  The related elements of a base element.
+   */
+   BaseElementSequence getRelatedElementsByRelationship(
+      in Relationship brRelationship)
+      raises (AoException);
+
+   /** (9004)
+   * Get the base element's relations of the requested relation type.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION_TYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  brRelationType  The requested relation type.
+   *
+   * @return  The base element's relations of the requested type.
+   */
+   BaseRelationSequence getRelationsByType(
+      in RelationType brRelationType)
+      raises (AoException);
+
+   /** (9005)
+   * Get the type of the base element. The type of the base element is
+   * identical with the name of the base element. The type of the base
+   * element is a string.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The type of the base element.
+   */
+   BaseType getType()
+      raises (AoException);
+
+   /** (9006)
+   * Get whether or not the base element is a top level element. Top
+   * level elements are elements without a father.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  Boolean whether or not the base element is a top level
+   *          element.
+   */
+   T_BOOLEAN isTopLevel()
+      raises (AoException);
+
+   /** (9007)
+   * Get attribute names of the base element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  baPattern  The name or the search pattern for the requested
+   *                    base attribute names.
+   *
+   * @return  The requested attribute names of the base element.
+   */
+   NameSequence listAttributes(
+      in Pattern baPattern)
+      raises (AoException);
+
+   /** (9008)
+   * Get the related element names of the base element defined by the
+   * relationship.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATIONSHIP
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  brRelationship  The requested relationship.
+   *
+   * @return  The related element names of the base element.
+   */
+   BaseTypeSequence listRelatedElementsByRelationship(
+      in Relationship brRelationship)
+      raises (AoException);
+
+}; // Interface BaseElement.
+
+/**
+* The ASAM ODS base relation interface.
+*/
+interface BaseRelation {
+
+   /** (10001)
+   * Get the first base element of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The first base element of the base relation.
+   */
+   BaseElement getElem1()
+      raises (AoException);
+
+   /** (10002)
+   * Get the second base element of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The second base element of the base relation.
+   */
+   BaseElement getElem2()
+      raises (AoException);
+
+   /** (10003)
+   * Get the inverse relation range of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The inverse relation range of the base relation.
+   */
+   RelationRange getInverseRelationRange()
+      raises (AoException);
+
+   /** (10004)
+   * Get the inverse relationship of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The inverse relationship of the base relation.
+   */
+   Relationship getInverseRelationship()
+      raises (AoException);
+
+   /** (10005)
+   * Get the relation name of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The relation name of the base relation.
+   */
+   Name getRelationName()
+      raises (AoException);
+
+   /** (10006)
+   * Get the relation range of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The relation range of the base relation.
+   */
+   RelationRange getRelationRange()
+      raises (AoException);
+
+   /** (10007)
+   * Get the relationship of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The relationship of the base relation.
+   */
+   Relationship getRelationship()
+      raises (AoException);
+
+   /** (10008)
+   * Get the relation type of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The relation type of the base relation.
+   */
+   RelationType getRelationType()
+      raises (AoException);
+
+   /** (10009)
+   * Return the inverse name of the base relation.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The name of the inverse relation.
+   */
+   Name getInverseRelationName()
+      raises (AoException);
+
+}; // Interface BaseRelation.
+
+/**
+* The ASAM ODS base structure interface.
+*/
+interface BaseStructure {
+
+   /** (11001)
+   * Get the base element that matches the requested type. The type of a
+   * base element is identical with the name of the base element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_BASETYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  beType  The name of the requested base element.
+   *
+   * @return  The requested base element.
+   */
+   BaseElement getElementByType(
+      in BaseType beType)
+      raises (AoException);
+
+   /** (11002)
+   * Get the base elements that match the pattern. The pattern is case
+   * sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  bePattern  The name or the search pattern for the requested
+   *                    base elements.
+   *
+   * @return  The requested base elements.
+   */
+   BaseElementSequence getElements(
+      in Pattern bePattern)
+      raises (AoException);
+
+   /** (11003)
+   * Get the base relation between two base elements. The base relation
+   * is given from the first element (parameter elem1) to the second
+   * element (parameter elem2), the inverse relation is not given.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NOT_FOUND
+   *
+   * @param  elem1  The base element from which the relation starts.
+   *
+   * @param  elem2  The base element to which the relation points.
+   *
+   * @return  The base relation between the two base elements.
+   */
+   BaseRelation getRelation(
+      in BaseElement elem1,
+      in BaseElement elem2)
+      raises (AoException);
+
+   /** (11004)
+   * Get the top level base elements that match the pattern. The pattern
+   * is case sensitive and may contain wildcard characters. A top level
+   * base element is a base element without a father.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  bePattern  The name or the search pattern for the requested
+   *                    top level base elements.
+   *
+   * @return  The requested top level base elements.
+   */
+   BaseElementSequence getTopLevelElements(
+      in Pattern bePattern)
+      raises (AoException);
+
+   /** (11005)
+   * Get the version of the base model. The version of the base model is
+   * the version of the ASAM ODS base model.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The version of the ASAM ODS base model.
+   */
+   T_STRING getVersion()
+      raises (AoException);
+
+   /** (11006)
+   * Get the base element names that match the pattern. The pattern is
+   * case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  bePattern  The name or the search pattern for the requested
+   *                    base element names.
+   *
+   * @return  The requested base element names.
+   */
+   BaseTypeSequence listElements(
+      in Pattern bePattern)
+      raises (AoException);
+
+   /** (11007)
+   * Get the top level base element names that match the pattern. The
+   * pattern is case sensitive and may contain wildcard characters. A top
+   * level base element is a base element without a father.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  bePattern  The name or the search pattern for the requested
+   *                    top level base element names.
+   *
+   * @return  The requested top level base element names.
+   */
+   BaseTypeSequence listTopLevelElements(
+      in Pattern bePattern)
+      raises (AoException);
+
+   /** (11008)
+   * Get the base relations between two base elements. The base relation
+   * is given from the first element (parameter elem1) to the second
+   * element (parameter elem2), the inverse relation is not given.
+   * When there are no base relation between the two elements the server
+   * will throw the exception AO_NOT_FOUND
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NOT_FOUND
+   *
+   * @param  elem1  The base element from which the relation starts.
+   *
+   * @param  elem2  The base element to which the relation points.
+   *
+   * @return  The list with base relations between the two elements.
+   */
+   BaseRelationSequence getRelations(
+      in BaseElement elem1,
+      in BaseElement elem2)
+      raises (AoException);
+
+}; // Interface BaseStructure.
+
+/**
+* The ASAM ODS blob interface.
+*/
+interface Blob {
+
+   /** (12001)
+   * Append a byte sequence to the binary large object. 
+   * 
+   * It is allowed to modify the binary large object outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  value  The byte sequence.
+   */
+   void append(
+      in S_BYTE value)
+      raises (AoException);
+
+   /** (12002)
+   * Compares the content of the binary large object. The headers are not
+   * compared.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aBlob  The blob to compare.
+   *
+   * @return  A flag whether or not the compared blobs are equal.
+   */
+   T_BOOLEAN compare(
+      in T_BLOB aBlob)
+      raises (AoException);
+
+   /** (12003)
+   * Get a part of the binary large object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  offset  The starting position of the data in the blob.
+   *
+   * @param  length  The number of bytes requested from the blob.
+   *
+   * @return  The request part of the blob data.
+   */
+   S_BYTE get(
+      in T_LONG offset,
+      in T_LONG length)
+      raises (AoException);
+
+   /** (12004)
+   * Get the header of the binary large object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The blob header.
+   */
+   T_STRING getHeader()
+      raises (AoException);
+
+   /** (12005)
+   * Get the length of the binary large object without loading it.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The blob length.
+   */
+   T_LONG getLength()
+      raises (AoException);
+
+   /** (12006)
+   * Clear the binary large object and set the new data. 
+   * 
+   * It is allowed to modify the binary large object outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  value  The new blob data.
+   */
+   void set(
+      in S_BYTE value)
+      raises (AoException);
+
+   /** (12007)
+   * Set the header of a binary large object. 
+   * 
+   * It is allowed to modify the binary large object outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  header  The blob header.
+   */
+   void setHeader(
+      in T_STRING header)
+      raises (AoException);
+
+   /** (12008)
+   * Destroy the object on the server. The destructor of the client, so
+   * the server knows this object is not used anymore by the client.
+   * Access to this object after the destroy method will lead to an
+   * exception.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+}; // Interface Blob.
+
+/**
+* The ASAM ODS column interface. It is not inherited from
+* InstanceElement. Via the method getColumn of the interface SubMatrix
+* the column is accessed. The column is only used for read access. With
+* the creation of instances at the application element of type
+* AoLocalColumn and the relation to the instances of the application
+* element of type AoSubMatrix a local column can be created. The column
+* name is used for the SMatLink and the column is used to store a formula
+* for the calculation of the values of the column. There is no definition
+* of the formula language at the moment.
+*/
+interface Column {
+
+   /** (13001)
+   * Get the formula of the column.
+   * 
+   * There is no formula defined in ASAM ODS, so there is nothing to
+   * return.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The formula of the column.
+   */
+   T_STRING getFormula()
+      raises (AoException);
+
+   /** (13002)
+   * Get the name of the column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The name of the column.
+   */
+   Name getName()
+      raises (AoException);
+
+   /** (13003)
+   * Get the source measurement quantity.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The source measurement quantity.
+   */
+   InstanceElement getSourceMQ()
+      raises (AoException);
+
+   /** (13004)
+   * Get the unit of the column.
+   * 
+   * The method returns the unit of the values according the current
+   * setting. Initially within a session this is the unit as given in the
+   * storage. After setUnit() is called, the unit as specified by
+   * setUnit() will be
+   * returned for the particular column. Thus the unit returned will be
+   * retrieved by the ODS server according to following strategy:
+   * 1) if a unit has already been set for the paricular column by
+   * setUnit(..) prior; that unit is returned, else
+   * 2) if the related measurement quantity has a unit (i.e. it has a
+   * relation derived from the base relation 'unit' referencing an
+   * instance of base type AoUnit), that unit's name is returned, else
+   * 3) if the related measurement quantity has a relation to a quantity
+   * (i.e. its relation derived from the base relation 'quantity' is
+   * referencing an instance of base type AoQuantity), and this quantity
+   * has
+   * a default unit (i.e. it has a relation derived from the base
+   * relation 'default_unit' referencing an instance of base type
+   * AoUnit), that unit's name is returned, else
+   * 4) an empty string is returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The unit of the column.
+   */
+   T_STRING getUnit()
+      raises (AoException);
+
+   /** (13005)
+   * Set the formula of the column. 
+   * 
+   * It is allowed to modify the column outside a transaction but it is
+   * recommended to activate a transaction.
+   * 
+   * There is no formula in ASAM ODS so don't try to set the formula.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  formula  The formula.
+   */
+   void setFormula(
+      in T_STRING formula)
+      raises (AoException);
+
+   /** (13006)
+   * Set the unit of the column. This is only a temporary unit for
+   * getting the values of a column. This unit is not stored in the
+   * storage. 
+   * When an empty string is given the unit is returned to the original
+   * setting.
+   * When the value matrix where the column belongs to is in the STORAGE
+   * mode this method have no influence on the values returned from the
+   * value matrix.
+   * To change the unit permanent in the storage the relation at the
+   * measurement quantity must be changed by the client.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  unit  The physical unit.
+   */
+   void setUnit(
+      in T_STRING unit)
+      raises (AoException);
+
+   /** (13007)
+   * Is the column an independent column
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The independent flag of the column.
+   */
+   T_BOOLEAN isIndependent()
+      raises (AoException);
+
+   /** (13008)
+   * Deprecated, solved by NVH Application model.
+   * 
+   * Is the column an scaling column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  Tells if the column is a scaling column.
+   */
+   T_BOOLEAN isScaling()
+      raises (AoException);
+
+   /** (13009)
+   * Set the column as an independent column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  independent  The new value of the independent flag.
+   */
+   void setIndependent(
+      in T_BOOLEAN independent)
+      raises (AoException);
+
+   /** (13010)
+   * Deprecated, solved by NVH Application model.
+   * 
+   * Set the column to a scaling column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  scaling  The new value of the scaling flag.
+   */
+   void setScaling(
+      in T_BOOLEAN scaling)
+      raises (AoException);
+
+   /** (13011)
+   * Get the data type of the column.
+   * The data type of the measurement quantity is always returned,
+   * independent of the mode of the values matrix where the column
+   * belongs to neither the sequence representation of the column.
+   * 
+   * This method always returns the data type of the measurement quantity
+   * to which this local column belongs, independent of 
+   * - the value matrix mode of the value matrices this local column
+   * belongs to
+   * - the sequence representation of this local column
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The data type of the column.
+   */
+   DataType getDataType()
+      raises (AoException);
+
+   /** (13012)
+   * Destroy the object on the server. The destructor of the client so
+   * the server knows this object is not used anymore by the client.
+   * Access to this object after the destroy method will lead to an
+   * exception.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (13013)
+   * Get the sequence representation of the column. 
+   * 
+   * When the value matrix to which the column belongs is in CALCULATED
+   * mode the sequence_representation is always explicit.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The sequence representation of the column. This is the
+   *          integer value according the enumeration seq_rep_enum of the
+   *          base model.
+   */
+   T_LONG getSequenceRepresentation()
+      raises (AoException);
+
+   /** (13014)
+   * Set the sequence representation of a new column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_BAD_PARAMETER
+   *    AO_TRANSACTION_NOT_ACTVIE
+   *
+   * @param  sequenceRepresentation  The sequence representation.  This
+   *                                 is the integer value according the
+   *                                 enumeration seq_rep_enum of the base
+   *                                 model.
+   */
+   void setSequenceRepresentation(
+      in T_LONG sequenceRepresentation)
+      raises (AoException);
+
+   /** (13015)
+   * Get the generation parameters of the Column. 
+   * 
+   * If no generation parameters exist an empty sequence is returned, its
+   * type is double, its length is 0.
+   * When the value matrix to which the column belongs is in CALCULATED
+   * mode an empty sequence is returned, its type is double, its length
+   * is 0.
+   * 
+   * The data type of the generation parameter for the implicit columns
+   * is the data type given at the measurement quantity. The data type of
+   * the generation parameters for raw data is always T_DOUBLE.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The generation parameters.
+   */
+   TS_Union getGenerationParameters()
+      raises (AoException);
+
+   /** (13016)
+   * Set the generation parameters.
+   * 
+   * The data type of the generation parameter for the implicit columns
+   * must be the data type given at the measurement quantity. The data
+   * type of the generation parameters for raw data must be always
+   * T_DOUBLE.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_BAD_PARAMETER
+   *    AO_TRANSACTION_NOT_ACTVIE
+   *
+   * @param  generationParameters  The generation parameters.
+   */
+   void setGenerationParameters(
+      in TS_Union generationParameters)
+      raises (AoException);
+
+   /** (13017)
+   * Get the data type of the raw values.
+   * 
+   * When the column has no raw values the data type of the measurement
+   * quantity is returned. 
+   * When the value matrix to which the column belongs is in CALCULATED
+   * mode the data type of the measurement quantity returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The data type of the raw values.
+   */
+   DataType getRawDataType()
+      raises (AoException);
+
+}; // Interface Column.
+
+/**
+* The ASAM ODS instance element interface. It is allowed to modify the
+* instances outside a transaction but recommended to activate a
+* transaction before the instances are modified. The modifications to
+* instances get permanent when the transaction is committed.
+*/
+interface InstanceElement {
+
+   /** (14001)
+   * Add an instance attribute to the instance. The instance attribute is
+   * built as a Name/Value/Unit tuple on the client. This method has to
+   * copy the data from the client to the server. The name of the
+   * attribute must be unique. 
+   * 
+   * It is allowed to add an instance attribute outside a transaction but
+   * it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  instAttr  The instance attribute to be added.
+   */
+   void addInstanceAttribute(
+      in NameValueUnit instAttr)
+      raises (AoException);
+
+   /** (14002)
+   * Create a relation between the current and the given instance. Check
+   * if the application elements of the relation matches the application
+   * elements of the instances. 
+   * 
+   * It is allowed to modify the instance element outside a transaction
+   * but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  relation  The application relation.
+   *
+   * @param  instElem  The instance element.
+   */
+   void createRelation(
+      in ApplicationRelation relation,
+      in InstanceElement instElem)
+      raises (AoException);
+
+   /** (14003)
+   * Get the application element of the instance element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The application element from which the instance element is
+   *          derived.
+   */
+   ApplicationElement getApplicationElement()
+      raises (AoException);
+
+   /** (14004)
+   * Get the ASAM-Path of the instance element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The ASAM path to the instance element.
+   */
+   Name getAsamPath()
+      raises (AoException);
+
+   /** (14005)
+   * Get the Id of the instance element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The Id of the instance element.
+   */
+   T_LONGLONG getId()
+      raises (AoException);
+
+   /** (14006)
+   * Get the name of the instance element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The name of the instance element.
+   */
+   Name getName()
+      raises (AoException);
+
+   /** (14007)
+   * Get the related instances. The application relation and the name of
+   * the related  instances specify the listed instances. The pattern is
+   * case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  applRel  The application relation.
+   *
+   * @param  iePattern  The name or the search pattern for the related
+   *                    instance names.
+   *
+   * @return  The related instances.
+   */
+   InstanceElementIterator getRelatedInstances(
+      in ApplicationRelation applRel,
+      in Pattern iePattern)
+      raises (AoException);
+
+   /** (14008)
+   * Get the list of related instances. The relationship and the name of
+   * the related instances specify the listed instances. The pattern is
+   * case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATIONSHIP
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  ieRelationship  The requested relationship.
+   *
+   * @param  iePattern  The name or the search pattern for the related
+   *                    instance names.
+   *
+   * @return  The related instances.
+   */
+   InstanceElementIterator getRelatedInstancesByRelationship(
+      in Relationship ieRelationship,
+      in Pattern iePattern)
+      raises (AoException);
+
+   /** (14009)
+   * Get the attribute value (name, value and unit) of the given
+   * attribute of the instance element. This method will not return the
+   * value of relation attributes, use the method getRelatedInstances.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  attrName  The name of the requested attribute.
+   *
+   * @return  The attribute value.
+   */
+   NameValueUnit getValue(
+      in Name attrName)
+      raises (AoException);
+
+   /** (14010)
+   * Get the attribute value (value and unit) of the attribute inherited
+   * from the given base attribute of the instance element. The base name
+   * is case insensitive and may not contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  baseAttrName  The base name of the requested attribute.
+   *
+   * @return  The attribute value.
+   */
+   NameValueUnit getValueByBaseName(
+      in Name baseAttrName)
+      raises (AoException);
+
+   /** (14011)
+   * Get the attribute names from the instance element. The  attributes
+   * reserved for a relation are not listed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_ATTRIBUTE_TYPE
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  iaPattern  The name or the search pattern for the attribute
+   *                    names.
+   *
+   * @param  aType  The requested attribute type.
+   *
+   * @return  The names of the attributes.
+   */
+   NameSequence listAttributes(
+      in Pattern iaPattern,
+      in AttrType aType)
+      raises (AoException);
+
+   /** (14012)
+   * Get the names of the related instances. The application relation and
+   * the name of the related instances specifies the listed names. The
+   * pattern is case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  ieRelation  The application relation.
+   *
+   * @param  iePattern  The name or the search pattern for the related
+   *                    instance names.
+   *
+   * @return  The names of the related instances.
+   */
+   NameIterator listRelatedInstances(
+      in ApplicationRelation ieRelation,
+      in Pattern iePattern)
+      raises (AoException);
+
+   /** (14013)
+   * Get the names of the related instances. The relationship and the
+   * name of the related instances specify the listed names. The pattern
+   * is case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATIONSHIP
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  ieRelationship  The requested relationship.
+   *
+   * @param  iePattern  The name or the search pattern for the related
+   *                    instance names.
+   *
+   * @return  The names of the related instances.
+   */
+   NameIterator listRelatedInstancesByRelationship(
+      in Relationship ieRelationship,
+      in Pattern iePattern)
+      raises (AoException);
+
+   /** (14014)
+   * Remove an instance attribute.
+   * 
+   * It is allowed to remove the instance attribute outside a transaction
+   * but it is recommended to activate a transaction.
+   * 
+   * The application attributes can't be removed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  attrName  The name of the attribute to be removed.
+   */
+   void removeInstanceAttribute(
+      in Name attrName)
+      raises (AoException);
+
+   /** (14015)
+   * Remove the relation between the current instance and the given
+   * instance. It is necessary to specify the instance element in case of
+   * n:m relations if not all relations shall be deleted. 
+   * 
+   * It is allowed to modify the instance element outside a transaction
+   * but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_RELATION
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  applRel  The relation to be removed.
+   *
+   * @param  instElem_nm  The instance element for specific delete from
+   *                      n:m relations.
+   */
+   void removeRelation(
+      in ApplicationRelation applRel,
+      in InstanceElement instElem_nm)
+      raises (AoException);
+
+   /** (14016)
+   * Rename the instance attribute. The application attributes can't be
+   * renamed. 
+   * 
+   * It is allowed to rename the instance attribute outside a transaction
+   * but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_NAME
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  oldName  The old instance attribute name.
+   *
+   * @param  newName  The new instance attribute name.
+   */
+   void renameInstanceAttribute(
+      in Name oldName,
+      in Name newName)
+      raises (AoException);
+
+   /** (14017)
+   * Set the name of an instance element. 
+   * 
+   * It is allowed to modify the name of the instance element outside a
+   * transaction but it is recommended to activate a transaction.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  iaName  The instance attribute name.
+   */
+   void setName(
+      in Name iaName)
+      raises (AoException);
+
+   /** (14018)
+   * Set the value of an application attribute or of an existing instance
+   * attribute, but is doesn't create a new instance attribute; for this
+   * purpose use the method addInstancesAttribute of this interface.
+   * 
+   * It is allowed to modify the attribute value outside a transaction
+   * but it is recommended to activate a transaction.
+   * 
+   * The name of the attribute is specified by the name of the
+   * NameValueUnit tuple. If the application attribute flag unique is
+   * set, the uniqueness of the new value is checked.
+   * 
+   * This method can not be used to set the value of a relation
+   * attribute, use the method createRelation of this interface .
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_VALUE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  value  The value to be set in the instance element.
+   */
+   void setValue(
+      in NameValueUnit value)
+      raises (AoException);
+
+   /** (14019)
+   * Cast an instance element to a measurement. There are some
+   * object-oriented languages which do not allow this cast.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_BASETYPE
+   *
+   * @return  The instance of type measurement.
+   */
+   Measurement upcastMeasurement()
+      raises (AoException);
+
+   /** (14020)
+   * Cast an instance element to a submatrix. There are some
+   * object-oriented languages which do not allow this cast.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_BASETYPE
+   *
+   * @return  The instance of type submatrix.
+   */
+   SubMatrix upcastSubMatrix()
+      raises (AoException);
+
+   /** (14021)
+   * Get the attribute value (name, value and unit) of the given
+   * attribute of the instance element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_INCOMPATIBLE_UNITS
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  attr  The name of the requested attribute and the unit of
+   *               the attribute value.
+   *
+   * @return  The attribute value, value converted to the requested unit.
+   */
+   NameValueUnit getValueInUnit(
+      in NameUnit attr)
+      raises (AoException);
+
+   /** (14022)
+   * Set a sequences of values of an application attributes but no
+   * instances attributes.
+   * 
+   * It is allowed to modify the values of the attributes outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The name of the attribute is specified by the name of the
+   * NameValueUnit tuple. If the application attribute flag unique is
+   * set, the uniqueness of the new value is checked.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_DUPLICATE_VALUE
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  values  The sequence of the values to be set at the instance
+   *                 element.
+   */
+   void setValueSeq(
+      in NameValueUnitSequence values)
+      raises (AoException);
+
+   /** (14023)
+   * The given user group the rights should be set for. <rights> defines
+   * the rights to set or to clear. If the parameter <set> is set to
+   * 'set', the rights in <rights> are set all others are cleared. If the
+   * parameter <set> is set to 'add', the rights in <rights> are added to
+   * the existing rights. If the parameter <set> is set to 'remove', the
+   * rights in <rights> are removed from the existing rights.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  usergroup  The user group for which the rights will be
+   *                    modified.
+   *
+   * @param  rights  The new right for the user group. The rights
+   *                 constants are defined in the interface
+   *                 SecurityRights. The interface definition language
+   *                 IDL does not allow to set the values of enumerations
+   *                 thus the constant definitions had to be done in an
+   *                 interface.
+   *
+   * @param  set  What to do with the new right.
+   */
+   void setRights(
+      in InstanceElement usergroup,
+      in T_LONG rights,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (14024)
+   * Retrieve access control list information of the given object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The access control list entries of the given application
+   *          element.
+   */
+   ACLSequence getRights()
+      raises (AoException);
+
+   /** (14025)
+   * Retrieve access control list information for the initial rights of
+   * the given object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The access control list entries with the initial rights of
+   *          the given application element.
+   */
+   InitialRightSequence getInitialRights()
+      raises (AoException);
+
+   /** (14026)
+   * The given user group the initial rights should be set for. <rights>
+   * defines the rights to set or to clear. If the parameter <set> is set
+   * to 'set', the rights in <rights> are set all others are cleared. If
+   * the parameter <set> is set to 'add', the rights in <rights> are
+   * added to the existing rights. If the parameter <set> is set to
+   * 'remove', the rights in <rights> are removed from the existing
+   * rights.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  usergroup  The user group for which the initial rights will
+   *                    be modified.
+   *
+   * @param  rights  The new initial rights for the user group. The
+   *                 rights constants are defined in the interface
+   *                 SecurityRights. The interface definition language
+   *                 IDL does not allow to set the values of enumerations
+   *                 thus the constant definitions have to be done in the
+   *                 interface.
+   *
+   * @param  refAid  The Id of referencing application element for which
+   *                 the initial rights will be used. If no refAid is set
+   *                 the initial rights will be used for each new
+   *                 instance element independent of the application
+   *                 element.
+   *
+   * @param  set  What to do with the new initial rights.
+   */
+   void setInitialRights(
+      in InstanceElement usergroup,
+      in T_LONG rights,
+      in T_LONGLONG refAid,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (14027)
+   * Provides an easy-to-use and effective copy mechanism for instance
+   * elements inside the server. The new instance elements gets a copy of
+   * all attribute values and informational relations that are available
+   * in the original instance element. The new instance element has the
+   * same parent as the original instance element but it does not have
+   * references to any children of the original instance element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  newName  The name of the new instance element. If a new
+   *                  version shall be created this parameter may be NULL
+   *                  to use the same name for the copy. In this case a
+   *                  new version must be provided.
+   *
+   * @param  newVersion  The version of the new instance element. This
+   *                     parameter may be NULL if a new name is provided.
+   *
+   * @return  The reference to the copied instance element.
+   */
+   InstanceElement shallowCopy(
+      in T_STRING newName,
+      in T_STRING newVersion)
+      raises (AoException);
+
+   /** (14028)
+   * Provides an easy-to-use and effective copy mechanism for instance
+   * element hierarchies inside the server (e.g. copy a project with all
+   * tests or copy a test with all measurements). The deep copy follows
+   * only the child references but not the informational references.
+   * Example: Copying elements of type AoMeasurement does not include
+   * copying the referenced elements of type AoMeasurementQuantity. The
+   * copied instance elements of type AoMeasurement will reference the
+   * same measurement quantities as the original. An application that
+   * wants to copy the measurement quantity also must do this (including
+   * setting the proper references) by itself e.g. with another call to
+   * shallowCopy; deepCopy is not necessary in this case because
+   * AoMeasurementQuantity has no children.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  newName  The name of the new instance element. If a new
+   *                  version shall be created this parameter may be NULL
+   *                  to use the same name for the copy. In this case a
+   *                  new version must be provided.
+   *
+   * @param  newVersion  The version of the new instance element. This
+   *                     parameter may be NULL if a new name is provided.
+   *
+   * @return  The reference to the copied instance element hierarchy.
+   */
+   InstanceElement deepCopy(
+      in T_STRING newName,
+      in T_STRING newVersion)
+      raises (AoException);
+
+   /** (14029)
+   * Get the sequence of the values of the application or instance
+   * attributes, specified by their names.  The name sequence can use a
+   * pattern (*) for all attributes of the instance element. This means
+   * that application as well as   instance attributes will be delivered.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  attrNames  The names of the attributes to be reported.
+   *
+   * @return  The sequence of the attribute values.
+   */
+   NameValueUnitSequence getValueSeq(
+      in NameSequence attrNames)
+      raises (AoException);
+
+   /** (14030)
+   * Destroy the object on the server. The destructor of the client so
+   * the server knows this object is not used anymore by the client.
+   * Access to this object after the destroy method will lead to an
+   * exception.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (14031)
+   * Compare two instance elements. The Id's of the application elements
+   * and the Id's of the instance elements are compared. The Id's of the
+   * application elements will be compare first.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  compIeObj  The instance element to compare with.
+   *
+   * @return  The difference of the Id's. Meaning:
+   *          diff < 0 ElemId of instance is smaller then instance to
+   *          compare with.
+   *          diff == 0 ElemId is identical.
+   *          diff > 0 ElemId of instance is greater then instance to
+   *          compare with.
+   */
+   T_LONGLONG compare(
+      in InstanceElement compIeObj)
+      raises (AoException);
+
+   /** (14032)
+   * Create a list with instances which are related to the actual
+   * instance element. The attribute are given with the name of the
+   * sequence. The values of the attributes are given in the value
+   * sequence. The index in the different value sequences match for one
+   * instance element. The index in the instance element sequence of the
+   * related instances match for the instance with the same index in the
+   * value sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_INVALID_REQUEST
+   *
+   * @param  applRel  The application relation for witch the related
+   *                  instances will be created.
+   *
+   * @param  attributes  The attributes of the new created instances.
+   *
+   * @param  relatedInstances  The list with related instances for
+   *                           different application relations.
+   *
+   * @return  The list with the new created instances.
+   */
+   InstanceElementSequence createRelatedInstances(
+      in ApplicationRelation applRel,
+      in NameValueSeqUnitSequence attributes,
+      in ApplicationRelationInstanceElementSeqSequence relatedInstances)
+      raises (AoException);
+
+   /** (14033)
+   * Upcast the InstanceElement object to the corresponding ODSFile
+   * interface for an instance. 
+   * 
+   * This method may only be invoked for instances of an application
+   * element derived from
+   * the base element AoFile and returns an ODSFile interface.
+   * 
+   * An exception with the error code AO_INVALID_BASETYPE is thrown when
+   * the instance is not an instance of an application element derived
+   * from the base element AoFile.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_INVALID_BASETYPE
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The ODSFile interface to access the desired file.
+   */
+   ODSFile upcastODSFile()
+      raises (AoException);
+
+}; // Interface InstanceElement.
+
+/**
+* The ASAM ODS instance element iterator interface.
+*/
+interface InstanceElementIterator {
+
+   /** (15001)
+   * Destroy the iterator and free the associated memory.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (15002)
+   * Get the total number of elements accessible by the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of elements accessible by the iterator.
+   */
+   T_LONG getCount()
+      raises (AoException);
+
+   /** (15003)
+   * Get the next n elements from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  how_many  The number of requested elements.
+   *
+   * @return  The next n instance elements from the instance sequence.
+   */
+   InstanceElementSequence nextN(
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (15004)
+   * Get the next element from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The next instance element from the instance sequence.
+   */
+   InstanceElement nextOne()
+      raises (AoException);
+
+   /** (15005)
+   * Reset the pointer in the element sequence to the first element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void reset()
+      raises (AoException);
+
+}; // Interface InstanceElementIterator.
+
+/**
+* The ASAM ODS measurement interface.The interface Measurement extends
+* the interface InstanceElement. Thus alll methods of the interface
+* InstanceElement do also work here.
+*/
+interface Measurement : InstanceElement {
+
+   /** (16001)
+   * Create a submatrix link. The submatrix link is only valid in the
+   * current session. When the session is closed the submatrix link will
+   * be destroyed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The new submatrix link.
+   */
+   SMatLink createSMatLink()
+      raises (AoException);
+
+   /** (16002)
+   * Get the list of the submatrix links .
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The available submatrix links.
+   */
+   SMatLinkSequence getSMatLinks()
+      raises (AoException);
+
+   /** (16003)
+   * Get the value matrix of a measurement. 
+   * By calling this method, the value matrix mode of the returned value
+   * matrix will be taken from the context variable 'VALUEMATRIX_MODE'.
+   * For more information especially on different modes of the value
+   * matrix, see description at the method getValueMatrixInMode() of this
+   * interface.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_VALUEMATRIX_STRUCTURE
+   *
+   * @return  The value matrix.
+   */
+   ValueMatrix getValueMatrix()
+      raises (AoException);
+
+   /** (16004)
+   * Remove a submatrix link.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  smLink  The sub matrix link to be removed.
+   */
+   void removeSMatLink(
+      in SMatLink smLink)
+      raises (AoException);
+
+   /** (16005)
+   * Get the value matrix of a measurement in the requested mode.
+   * 
+   * The server checks the independent column, if there is more than one
+   * submatrix at the measurement there must be exactly one independent
+   * column with the same measurement quantity in each submatrix,
+   * otherwise the exception AO_INVALID_VALUEMATRIX_STRUCTURE is
+   * thrown.
+   * 
+   * The server throws the exception AO_INVALID_VALUEMATRIX_STRUCTURE
+   * when it is unable to create the value matrix due to the data of the
+   * measurement
+   * - if there are no independent column
+   * - if there are different independent columns
+   * - if there are sub matrices with more than one independent column.
+   * 
+   * The server orders the values according to the values of the
+   * independent localcolumn. (in ascending order) It is up to the server
+   * what value is returned when a measurement quantity has two different
+   * values at the same independent point. The gaps are marked with Flags
+   * in TS_ValueSeq (flagvalue = 0).
+   * 
+   * In the CALCULATED mode the server returns the calculated values for
+   * implicit and raw values. The server returns at each measurement
+   * point the explicit value as the value for the implicit channels. The
+   * raw values are calculated to the explicit values.
+   * 
+   * In the STORAGE mode the server handles the values of the localcolumn
+   * as they are in the storage. Write is only allowed when the value
+   * matrix is in the STROAGE mode.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_VALUEMATRIX_STRUCTURE
+   *
+   * @param  vmMode  The requested mode of the value matrix.
+   *
+   * @return  The value matrix.
+   */
+   ValueMatrix getValueMatrixInMode(
+      in ValueMatrixMode vmMode)
+      raises (AoException);
+
+}; // Interface Measurement.
+
+/**
+* The ASAM ODS name iterator interface.
+*/
+interface NameIterator {
+
+   /** (17001)
+   * Destroy the iterator and free the associated memory.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (17002)
+   * Get the total number of elements accessible by the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of elements accessible by the iterator.
+   */
+   T_LONG getCount()
+      raises (AoException);
+
+   /** (17003)
+   * Get the next n elements from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  how_many  The number of requested elements.
+   *
+   * @return  The next n names from the name sequence.
+   */
+   NameSequence nextN(
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (17004)
+   * Get the next element from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The next name from the name sequence.
+   */
+   Name nextOne()
+      raises (AoException);
+
+   /** (17005)
+   * Reset the pointer in the element sequence to the first element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void reset()
+      raises (AoException);
+
+}; // Interface NameIterator.
+
+/**
+* The ASAM ODS name-value iterator interface.
+*/
+interface NameValueIterator {
+
+   /** (18001)
+   * Destroy the iterator and free the associated memory.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (18002)
+   * Get the total number of elements accessible by the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of elements accessible by the iterator.
+   */
+   T_LONG getCount()
+      raises (AoException);
+
+   /** (18003)
+   * Get the next n elements from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  how_many  The number of requested elements.
+   *
+   * @return  The next n name-value pairs from the name-value pair
+   *          sequence.
+   */
+   NameValueSequence nextN(
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (18004)
+   * Get the next element from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The next name-value pair from the name-value pair sequence.
+   */
+   NameValue nextOne()
+      raises (AoException);
+
+   /** (18005)
+   * Reset the pointer in the element sequence to the first element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void reset()
+      raises (AoException);
+
+}; // Interface NameValueIterator.
+
+/**
+* The ASAM ODS name-value-unit iterator interface. This interface is
+* identical with the NameValueUnitIdIterator, except the unit is given as
+* a string insead of an Id.
+*/
+interface NameValueUnitIterator {
+
+   /** (19001)
+   * Destroy the iterator and free the associated memory.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (19002)
+   * Get the total number of elements accessible by the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of elements accessible by the iterator.
+   */
+   T_LONG getCount()
+      raises (AoException);
+
+   /** (19003)
+   * Get the next n elements from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  how_many  The number of requested elements.
+   *
+   * @return  The next n name-value-unit tuples from the name-value-unit
+   *          tuple sequence.
+   */
+   NameValueUnitSequence nextN(
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (19004)
+   * Get the next element from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The next name-value-unit tuple from the name-value-unit
+   *          tuple sequence.
+   */
+   NameValueUnit nextOne()
+      raises (AoException);
+
+   /** (19005)
+   * Reset the pointer in the element sequence to the first element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void reset()
+      raises (AoException);
+
+}; // Interface NameValueUnitIterator.
+
+/**
+* The ASAM ODS submatrix link interface.
+*/
+interface SMatLink {
+
+   /** (20001)
+   * Get the link or build type.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The link type.
+   */
+   BuildUpFunction getLinkType()
+      raises (AoException);
+
+   /** (20002)
+   * Get the ordinal or sequence number
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The sequence number.
+   */
+   T_LONG getOrdinalNumber()
+      raises (AoException);
+
+   /** (20003)
+   * Get the first submatrix of the link.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The first submatrix of the link.
+   */
+   SubMatrix getSMat1()
+      raises (AoException);
+
+   /** (20004)
+   * Get the bind columns of the first submatrix used in the link (e.g.
+   * Time).
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The columns of the first submatrix.
+   */
+   ColumnSequence getSMat1Columns()
+      raises (AoException);
+
+   /** (20005)
+   * Get the second submatrix of the link.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The second submatrix of the link.
+   */
+   SubMatrix getSMat2()
+      raises (AoException);
+
+   /** (20006)
+   * Get the bind columns of the second submatrix used in the link (e.g.
+   * Time).
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The columns of the second submatrix.
+   */
+   ColumnSequence getSMat2Columns()
+      raises (AoException);
+
+   /** (20007)
+   * Set the build or link type.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_BUILDUP_FUNCTION
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  linkType  The requested build-up function.
+   */
+   void setLinkType(
+      in BuildUpFunction linkType)
+      raises (AoException);
+
+   /** (20008)
+   * Set the ordinal or sequence number.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_ORDINALNUMBER
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  ordinalNumber  The sequence number.
+   */
+   void setOrdinalNumber(
+      in T_LONG ordinalNumber)
+      raises (AoException);
+
+   /** (20009)
+   * Set the first submatrix of the link.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_SUBMATRIX
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  subMat1  The first sub matrix of the sub matrix link.
+   */
+   void setSMat1(
+      in SubMatrix subMat1)
+      raises (AoException);
+
+   /** (20010)
+   * Set the bind columns of the first submatrix used in the link (e.g.
+   * Time).
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_COLUMN
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  columns  The column sequence of the sub matrix.
+   */
+   void setSMat1Columns(
+      in ColumnSequence columns)
+      raises (AoException);
+
+   /** (20011)
+   * Set the second submatrix of the link.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_INVALID_SUBMATRIX
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  subMat2  The second sub matrix of the sub matrix link.
+   */
+   void setSMat2(
+      in SubMatrix subMat2)
+      raises (AoException);
+
+   /** (20012)
+   * Set the bind columns of the second submatrix used in the link (e.g.
+   * Time). If there is more than one column bound the column sequence
+   * must be identical with the column sequence of the first submatrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_INVALID_COLUMN
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  columns  The column sequence of the sub matrix.
+   */
+   void setSMat2Columns(
+      in ColumnSequence columns)
+      raises (AoException);
+
+}; // Interface SMatLink.
+
+/**
+* The ASAM ODS submatrix interface. The instances of the submatrix can be
+* accessed via the method getRelatedInstances of the interface
+* Measurement. The interface SubMatrix extends the interface
+* InstanceElement. Thus alll methods of the interface InstanceElement do
+* also work here.
+*/
+interface SubMatrix : InstanceElement {
+
+   /** (21001)
+   * Get the columns of the submatrix. The column is not inherited from
+   * the InstanceElement interface. This is the only way to get a column.
+   * The columns are used in the SMatLink interface to build the value
+   * matrix. The pattern is case sensitive and may contain wildcard
+   * characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the column
+   *                     names.
+   *
+   * @return  The columns of the submatrix.
+   */
+   ColumnSequence getColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (21002)
+   * Get a value matrix of the submatrix.
+   * By calling this method, the value matrix mode of the returned value
+   * matrix will be taken from the context variable 'VALUEMATRIX_MODE'.
+   * For more information especially on different modes of the value
+   * matrix, see description at the method getValueMatrixInMode() of this
+   * interface.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_SMATLINK
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The value matrix.
+   */
+   ValueMatrix getValueMatrix()
+      raises (AoException);
+
+   /** (21003)
+   * Get the names of the columns of the submatrix. The name sequence is
+   * identical with the names of the related instances. The pattern is
+   * case sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the column
+   *                     names.
+   *
+   * @return  The column names of the submatrix.
+   */
+   NameSequence listColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (21004)
+   * Get the value matrix of a submatrix in the requested mode.
+   * 
+   * The server doesn't check any independent columns. The columns are
+   * only the local columns from this submatrix. The flags in the
+   * TS_ValueSeq are the flags of the localcolumn. If no flags are given
+   * there are no flags available, the client have to check the
+   * global_flag.
+   * 
+   * In the CALCULATED mode the server returns the calculated values for
+   * implicit and raw values. The server returns at each measurement
+   * point the explicit value as the value for the implicit channels. The
+   * raw values are calculated to the explicit values.
+   * 
+   * In the STORAGE mode the server handles the values of the localcolumn
+   * as they are in the storage. Write is only allowed when the value
+   * matrix is in the STROAGE mode. The values are exactly from this
+   * submatrix. The raw / implicit values are returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  vmMode  The requested mode of the value matrix.
+   *
+   * @return  The value matrix.
+   */
+   ValueMatrix getValueMatrixInMode(
+      in ValueMatrixMode vmMode)
+      raises (AoException);
+
+}; // Interface SubMatrix.
+
+/**
+* The ASAM ODS value matrix interface. Value matrix is an interface used
+* by Measurement and SubMatrix to handle vectors of values.
+*/
+interface ValueMatrix {
+
+   /** (22001)
+   * Get the columns of the value matrix no matter whether the column is
+   * dependent or independent. The pattern is case sensitive and may
+   * contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the column
+   *                     names.
+   *
+   * @return  The columns of the value matrix, no matter whether the
+   *          column is dependent, independent or scaling
+   */
+   ColumnSequence getColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (22002)
+   * Get the column count of the value matrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of columns of the value matrix.
+   */
+   T_LONG getColumnCount()
+      raises (AoException);
+
+   /** (22003)
+   * Get the independent columns of the value matrix. The independent
+   * columns are the columns used to build the value matrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the
+   *                     independent column name.
+   *
+   * @return  The independent column of the value matrix.
+   */
+   ColumnSequence getIndependentColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (22004)
+   * Get the row count of the value matrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of rows of the value matrix.
+   */
+   T_LONG getRowCount()
+      raises (AoException);
+
+   /** (22005)
+   * Get a measurement point of the value matrix. The parameter meaPoint
+   * specifies the row of the matrix. The iterator allows to access all
+   * elements in the row.
+   * 
+   * The server behavior depends on the mode of the value matrix.
+   * Value matrix mode 'CALCULATED':
+   * In case 'sequence_representation' of the corresponding local column
+   * is one of the entries 'raw_linear', raw_polynomial',
+   * 'raw_linear_external', 'raw_polynomial_external',
+   * 'raw_linear_calibrated', or 'raw_linear_calibrated_external', the
+   * server will first calculate the physical values from raw values and
+   * generation parameters, before it returns them to the requesting
+   * client.
+   * Value matrix mode 'STORAGE':
+   * In case 'sequence_representation' of the corresponding local column
+   * is one of the entries 'raw_linear', raw_polynomial',
+   * 'raw_linear_external', 'raw_polynomial_external',
+   * 'raw_linear_calibrated', or 'raw_linear_calibrated_external', the
+   * server will return the raw values of the local column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  meaPoint  The measurement point.
+   *
+   * @return  The requested measurement point.
+   */
+   NameValueUnitIterator getValueMeaPoint(
+      in T_LONG meaPoint)
+      raises (AoException);
+
+   /** (22006)
+   * Get the values or a part of values of the column from the value
+   * matrix. The parameter column specifies from which column the values
+   * will be returned. The startPoint and count specify the part of the
+   * vector. A startPoint = 0 and count = rowCount will return the entire
+   * vector. When startPoint >= rowCount an exception is thrown. If
+   * startPoint + count > rowCount only the remaining values of the
+   * vector are returned and no exception is thrown. Use the getName and
+   * getUnit method of the interface column for the name and the unit of
+   * the column. The name and the value are not stored at each element of
+   * the vector. The return type TS_ValueSeq is not a sequence of
+   * TS_Value but a special structure.
+   * 
+   * The server behavior depends on the mode of the value matrix.
+   * Value matrix mode 'CALCULATED':
+   * In case 'sequence_representation' of the corresponding local column
+   * is one of the entries 'raw_linear', raw_polynomial',
+   * 'raw_linear_external', 'raw_polynomial_external',
+   * 'raw_linear_calibrated', or 'raw_linear_calibrated_external', the
+   * server will first calculate the physical values from raw values and
+   * generation parameters, before it returns them to the requesting
+   * client.
+   * Value matrix mode 'STORAGE':
+   * In case 'sequence_representation' of the corresponding local column
+   * is one of the entries 'raw_linear', raw_polynomial',
+   * 'raw_linear_external', 'raw_polynomial_external',
+   * 'raw_linear_calibrated', or 'raw_linear_calibrated_external', the
+   * server will return the raw values of the local column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_COLUMN
+   *    AO_INVLAID_COUNT
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  col  The column to retrieve the values from.
+   *
+   * @param  startPoint  The starting point in the column.
+   *
+   * @param  count  The number of points to be retrieved.
+   *
+   * @return  The requested column values of the value matrix.
+   */
+   TS_ValueSeq getValueVector(
+      in Column col,
+      in T_LONG startPoint,
+      in T_LONG count)
+      raises (AoException);
+
+   /** (22007)
+   * Get the names of the columns of the value matrix no matter whether
+   * the column is dependent or independent. The pattern is case
+   * sensitive and may contain wildcard characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the column
+   *                     names.
+   *
+   * @return  The column names of the value matrix, no matter whether the
+   *          column is dependent, independent or scaled by another one.
+   */
+   NameSequence listColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (22008)
+   * Get the names of the independent columns of the value matrix. The
+   * independent columns are the columns used to build the value matrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the
+   *                     independent column name.
+   *
+   * @return  The names of the independent columns of the value matrix.
+   */
+   NameSequence listIndependentColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (22009)
+   * Remove the values of the columns at a given measurement point.
+   * Remove the number of points of the given column. If the count is 0
+   * all points until the end of the column are removed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_COUNT
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  columnNames  The columns from which the measurement points
+   *                      are to be removed.
+   *
+   * @param  meaPoint  The measurement point to be removed.
+   *
+   * @param  count  The number of points to be removed from each column.
+   */
+   void removeValueMeaPoint(
+      in NameSequence columnNames,
+      in T_LONG meaPoint,
+      in T_LONG count)
+      raises (AoException);
+
+   /** (22010)
+   * Remove the values from a value vector. Beginning at startPoint the
+   * number of values specified in count are removed. If count is 0 all
+   * values from  the startPoint until the end of the vector are removed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_COLUMN
+   *    AO_INVALID_COUNT
+   *    AO_NOT_FOUND
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  col  The column from which the values are to be removed.
+   *
+   * @param  startPoint  The starting point for the value removal.
+   *
+   * @param  count  The number of points to be removed from the column.
+   */
+   void removeValueVector(
+      in Column col,
+      in T_LONG startPoint,
+      in T_LONG count)
+      raises (AoException);
+
+   /** (22011)
+   * Create or modify a measurement point of a value matrix. 
+   * The sequence of name values specifies the names of the column with
+   * the new values. 
+   * The meaning of the parameter setType is:
+   * 
+   *    INSERT   Insert the values at meaPoint, the current values at
+   * meaPoint    are moved to the end of  the new inserted values.
+   * 
+   *    APPEND   The value of meaPoint is ignored, the values are
+   * appended at the end of the current values.
+   * 
+   *    UPDATE   Update or modify the values at meaPoint, the current
+   * values are overwritten. If meaPoint is bigger than the number of
+   * values in the          vector, the measurement point is
+   * automatically appended.
+   * 
+   * The names of the columns have to exist.
+   * 
+   * When a client creates a ValueMatrix based on AoMeasurement this
+   * methods behaves as follows:
+   * The server checks the sub matrices and creates all necessary
+   * instances of AoSubmatrix, AoLocalColumn and AoMeasurementQuantity. 
+   * The values of the name attribute of AoSubmatrix must be generated by
+   * the server. The value will be equal to the value of the attribute ID
+   * (converted to DT_STRING). Missing instances of AoMeasurementQuantity
+   * will be created by the server, too. 
+   * 
+   * The mandatory attributes will get the following default values:
+   * Name supplied by client 
+   * Datatype copied from AoQuantity.default_datatype
+   * Typesize copied from AoQuantity.default_typesize
+   * Interpolation no interpolation
+   * Rank copied from AoQuantity.default_rank
+   * Dimension copied from AoQuantity.default_dimension
+   * 
+   * The server takes the value of the channel (supplied by client) and
+   * looks up the corresponding instance in AoQuantity using the
+   * attribute default_meq_name.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_IS_MEASUREMENT_MATRIX
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  set  The set type.
+   *
+   * @param  meaPoint  The measurement point.
+   *
+   * @param  value  The values to be inserted.
+   */
+   void setValueMeaPoint(
+      in SetType set,
+      in T_LONG meaPoint,
+      in NameValueSequence value)
+      raises (AoException);
+
+   /** (22012)
+   * Create or modify a value vector in a value matrix. 
+   * 
+   * It is allowed to modify the values of the value matrix outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The data is made permanent on transaction commit. Until the
+   * transaction is committed or until the access to the measurement
+   * point of the value matrix, it is allowed to have different number of
+   * values in the different value vectors.
+   * 
+   * The meaning of the parameter setType is:
+   * 
+   *    INSERT   Insert the values from startPoint, the current available
+   * values from startPoint are moved to the end of the new inserted
+   * values.
+   * 
+   *    APPEND   The value of startPoint is ignored,  the values are
+   * appended at the end of the current values.
+   * 
+   *    UPDATE   Update or modify the values from startPoint, the current
+   * values are overwritten. If the number of values in the parameter
+   * values is too big    the values are automatically appended.
+   * 
+   * When a client creates a ValueMatrix based on AoMeasurement this
+   * methods 
+   * behaves as follows:
+   * The server checks the sub matrices and creates all necessary
+   * instances of AoSubmatrix, AoLocalColumn and AoMeasurementQuantity. 
+   * The values of the name attribute of AoSubmatrix must be generated by
+   * the server. The value will be equal to the value of the attribute ID
+   * (converted to DT_STRING). Missing instances of AoMeasurementQuantity
+   * will be created by the server, 
+   * too. 
+   * 
+   * The mandatory attributes will get the following default values:
+   * Name supplied by client 
+   * Datatype copied from AoQuantity.default_datatype
+   * Typesize copied from AoQuantity.default_typesize
+   * Interpolation no interpolation
+   * Rank copied from AoQuantity.default_rank
+   * Dimension copied from AoQuantity.default_dimension
+   * 
+   * The server takes the value of the channel (supplied by client) and
+   * looks up the corresponding instance in AoQuantity using the
+   * attribute default_meq_name.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_COLUMN
+   *    AO_INVALID_SET_TYPE
+   *    AO_IS_MEASUREMENT_MATRIX
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  col  The column whose values are to be set.
+   *
+   * @param  set  The set type.
+   *
+   * @param  startPoint  The starting point for the new values.
+   *
+   * @param  value  The values to be inserted.
+   */
+   void setValueVector(
+      in Column col,
+      in SetType set,
+      in T_LONG startPoint,
+      in TS_ValueSeq value)
+      raises (AoException);
+
+   /** (22013)
+   * Create or modify a number of value vectors in a value matrix. 
+   * 
+   * It is allowed to modify the values of the value matrix outside a
+   * transaction but it is recommended to activate a transaction.
+   * 
+   * The data is made permanent on transaction commit. Until the
+   * transaction is committed or until the access to the measurement
+   * point of the value matrix it is allowed to have different numbers of
+   * values in the different value vectors.
+   * 
+   * The names of the parameter values are the names of the columns. The
+   * values are the new values of the column. (setValueMeaPoint allows
+   * only one point, the TS_ValueSeq allows more then one point) There is
+   * a sequence of name value pairs (setValueVector allows only one
+   * column), so a block of values can be modified.
+   * 
+   * The meaning of the parameter setType is:
+   * 
+   *    INSERT   Insert the values from startPoint,  the current
+   * available values from  startPoint are moved to the end of  the new
+   * inserted values.
+   * 
+   *    APPEND   The value of startPoint is ignored, the values are
+   * appended at the end of the current values.
+   * 
+   *    UPDATE   Update or modify the values from startPoint, the current
+   * values are overwritten. If the number of values is greater than the
+   * number of values in the  vector, the measurement point is 
+   * automatically appended.
+   * 
+   *    REMOVE  Remove the number of values from each column, starting
+   * with startPoint. The name of the column is given as the name of the
+   * NameValueseqUnit, the  number of values to remove is given  in the
+   * number of the values in the   value.
+   * 
+   * When a client creates a ValueMatrix based on AoMeasurement this
+   * methods behaves as follows:
+   * The server checks the sub matrices and creates all necessary
+   * instances of AoSubmatrix, AoLocalColumn and AoMeasurementQuantity. 
+   * The values of the name attribute of AoSubmatrix must be generated by
+   * the server. The value will be equal to the value of the attribute ID
+   * (converted to DT_STRING). Missing instances of AoMeasurementQuantity
+   * will be created by the server, too. 
+   * 
+   * The mandatory attributes will get the following default values:
+   * Name supplied by client 
+   * Datatype copied from AoQuantity.default_datatype
+   * Typesize copied from AoQuantity.default_typesize
+   * Interpolation no interpolation
+   * Rank copied from AoQuantity.default_rank
+   * Dimension copied from AoQuantity.default_dimension
+   * 
+   * The server takes the value of the channel (supplied by client) and
+   * looks up the corresponding instance in AoQuantity using the
+   * attribute default_meq_name.
+   * 
+   * The ValueMatrix interface handles the values but not the raw values,
+   * to modify the raw values the instances of localcolumn must be
+   * created, the base attribute sequence_representation, raw_datatype
+   * and the generation_parameter must be created before the values are
+   * modified. The values must have the data type identical with the
+   * raw_datatype, any other data type will cause an AO_INVALID_DATATYPE
+   * exception.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_COLUMN
+   *    AO_INVALID_SET_TYPE
+   *    AO_INVALID_DATATYPE
+   *    AO_IS_MEASUREMENT_MATRIX
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  set  The set type.
+   *
+   * @param  startPoint  The measurement point.
+   *
+   * @param  value  The values to be inserted.
+   */
+   void setValue(
+      in SetType set,
+      in T_LONG startPoint,
+      in NameValueSeqUnitSequence value)
+      raises (AoException);
+
+   /** (22014)
+   * Add a column to the value matrix. It is only allowed to create a
+   * value vector if the value matrix is created from a submatrix. 
+   * 
+   * It is allowed to add a column outside a transaction but it is
+   * recommended to activate a transaction.
+   * 
+   * The data is made permanent on transaction commit. Until the
+   * transaction is committed or until the access to the measurement
+   * point of the value matrix it is allowed to have different number of
+   * values in the different value vectors. After the new column is
+   * added, it is possible to set the values of the column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_NAME
+   *    AO_INVALID_SET_TYPE
+   *    AO_IS_MEASUREMENT_MATRIX
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  newColumn  The name and unit of the column to add.
+   *
+   * @return  The new column.
+   */
+   Column addColumn(
+      in NameUnit newColumn)
+      raises (AoException);
+
+   /** (22015)
+   * Deprecated, solved by NVH Application model.
+   * 
+   * Get the names of the scaling columns of the value matrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the scaling
+   *                     column name.
+   *
+   * @return  The names of the scaling columns of the value matrix.
+   */
+   NameSequence listScalingColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (22016)
+   * Deprecated, solved by NVH Application model.
+   * 
+   * Get the scaling column of the value matrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  colPattern  The name or the search pattern for the scaling
+   *                     column name.
+   *
+   * @return  The scaling columns of the value matrix.
+   */
+   ColumnSequence getScalingColumns(
+      in Pattern colPattern)
+      raises (AoException);
+
+   /** (22017)
+   * Deprecated, solved by NVH Application model.
+   * 
+   * List the names of the columns, which are scaled by the given column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NO_SCALING_COLUMN
+   *
+   * @param  scalingColumn  The scaling column.
+   *
+   * @return  The names of the columns which are scaled by the given
+   *          input column.
+   */
+   NameSequence listColumnsScaledBy(
+      in Column scalingColumn)
+      raises (AoException);
+
+   /** (22018)
+   * Deprecated, solved by NVH Application model.
+   * 
+   * Get the columns which are scaled by the given column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NO_SCALING_COLUMN
+   *
+   * @param  scalingColumn  The scaling column.
+   *
+   * @return  The columns which are scaled by the given input column.
+   */
+   ColumnSequence getColumnsScaledBy(
+      in Column scalingColumn)
+      raises (AoException);
+
+   /** (22019)
+   * Deprecated, solved by NVH Application model.
+   * 
+   * Add a column to the value matrix. It is only allowed to create a
+   * value vector if the value matrix is created from a submatrix. The
+   * column will be scaled by the given scaling column.
+   * 
+   * It is allowed to add a column outside a transaction but it is
+   * recommended to activate a transaction.
+   * 
+   * The data is made permanent on transaction commit. Until the
+   * transaction is committed or until the access to the measurement
+   * point of the value matrix it is allowed to have different number of
+   * values in the different value vectors. After the new column is
+   * added, it is possible to set the values of the column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_INVALID_NAME
+   *    AO_INVALID_SET_TYPE
+   *    AO_IS_MEASUREMENT_MATRIX
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NO_SCALING_COLUMN
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  newColumn  The name and unit of the column to add.
+   *
+   * @param  scalingColumn  The scaling column.
+   *
+   * @return  The new column.
+   */
+   Column addColumnScaledBy(
+      in NameUnit newColumn,
+      in Column scalingColumn)
+      raises (AoException);
+
+   /** (22020)
+   * Destroy the object on the server. The destructor of the client, so
+   * the server knows this object is not used anymore by the client.
+   * Access to this object after the destroy method will lead to an
+   * exception.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (22021)
+   * Get the values of different columns of the value matrix.
+   * 
+   * The server behavior depends on the mode of the value matrix.
+   * Value matrix mode 'CALCULATED':
+   * In case 'sequence_representation' of the corresponding local column
+   * is one of the entries 'raw_linear', raw_polynomial',
+   * 'raw_linear_external', 'raw_polynomial_external',
+   * 'raw_linear_calibrated', or 'raw_linear_calibrated_external', the
+   * server will first calculate the physical values from raw values and
+   * generation parameters, before it returns them to the requesting
+   * client.
+   * Value matrix mode 'STORAGE':
+   * In case 'sequence_representation' of the corresponding local column
+   * is one of the entries 'raw_linear', raw_polynomial',
+   * 'raw_linear_external', 'raw_polynomial_external',
+   * 'raw_linear_calibrated', or 'raw_linear_calibrated_external', the
+   * server will return the raw values of the local column.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  columns  The requested columns.
+   *
+   * @param  startPoint  The starting point in the column.
+   *
+   * @param  count  The number of points to be retrieved. 0 mean until
+   *                end of column.
+   *
+   * @return  The values of the different columns. The name of the return
+   *          structure corresponds with the name of the column. The unit
+   *          corresponds with the unit of the column. The order of the
+   *          results might not match the order in the requested
+   *          sequence.
+   */
+   NameValueSeqUnitSequence getValue(
+      in ColumnSequence columns,
+      in T_LONG startPoint,
+      in T_LONG count)
+      raises (AoException);
+
+   /** (22022)
+   * Get the current mode of the value matrix.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The mode of the value matrix
+   */
+   ValueMatrixMode getMode()
+      raises (AoException);
+
+}; // Interface ValueMatrix.
+
+/**
+* The ASAM ODS name-value-unitId iterator interface. This interface is
+* identical with the NameValueUnitIterator, except the unit is given as
+* an Id insead of a string.
+*/
+interface NameValueUnitIdIterator {
+
+   /** (23001)
+   * Destroy the iterator and free the associated memory.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (23002)
+   * Get the total number of elements accessible by the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of elements accessible by the iterator.
+   */
+   T_LONG getCount()
+      raises (AoException);
+
+   /** (23003)
+   * Get the next n elements from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  how_many  The number of requested elements.
+   *
+   * @return  The next n name-value-unit tuples from the name-value-unit
+   *          tuple sequence.
+   */
+   NameValueSeqUnitId nextN(
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (23004)
+   * Get the next element from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The next name-value-unitId tuple from the name-value-unitId
+   *          tuple sequence.
+   */
+   NameValueUnitId nextOne()
+      raises (AoException);
+
+   /** (23005)
+   * Reset the pointer in the element sequence to the first element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void reset()
+      raises (AoException);
+
+}; // Interface NameValueUnitIdIterator.
+
+/**
+* The application element access.  The ApplElemAccess interface (RPC API
+* GetVal, PutVal, GetInstRef, ...) is responsible to retrieve instances
+* of application elements. Currently available query methods are:
+* - query with attribute and value
+* - query with attribute and values (not)in set
+* - sorted results
+* - grouped results including having condition
+*/
+interface ApplElemAccess {
+
+   /** (24001)
+   * Perform the Query.
+   * 
+   * The number of different application elements which are requested are
+   * exactly defined by the definition of the query given in the field
+   * anuSeq of the QueryStructure. The number of attributes for each
+   * application element is also given in the definition. The number of
+   * matching instances (their attributes) is not defined by the query
+   * and can be a large amount. Therefore only one iterator for the
+   * attribute values are defined.
+   * 
+   * The values of the localcolumn instances is part of the resultset
+   * when the following criteria all fit:
+   * 
+   * - Only when the attributes id, generation_parameters, values, flags
+   * are requested, as soon as any other attributes is requested the
+   * values are not reported.
+   * - The values of the localcolumn must all belong to exactly one
+   * instances of AoMeasurement
+   * - The server have a limitation of the memory, not the system memory
+   * limitation, as soon as the result set will break the limitation an
+   * exception will be thrown.
+   * 
+   * - No iterator for the rest is required.
+   * 
+   * In case an attribute of blob type is among the requested attributes,
+   * the content of the return structure will depend on the number of
+   * instances that are returned:
+   * - In case attributes of only one instance are returned (either
+   * because 'how_many' was set to 1 or there is only one instance
+   * available at the server), the return structure contains the blob
+   * itself.
+   * -In case attributes of more than one instance are returned, the
+   * return structure does not contain the blobs; instead it contains the
+   * headers of the respective blobs.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aoq  The query definition.
+   *
+   * @param  how_many  Maximum number of values in each result set. Valid
+   *                   arguments are: 
+   *                   how_many = 0 : report all found values,
+   *                   how_many > 0 : report a maximum number of values.
+   *
+   * @return  The result set with the requested attribute values.
+   */
+   ElemResultSetSequence getInstances(
+      in QueryStructure aoq,
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (24002)
+   * Get related instances (Id). This method returns a sequence of
+   * related instances. 
+   * 
+   * The relation name specifies the relation given in the
+   * ApplStructValue. The aid of the ElemId and the relName defines the
+   * unique relation and the target application element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  elem  Original instance. 
+   *               
+   *               At the RPC API this information was stored in the
+   *               field elemId of the structure GetInstRefReq and the
+   *               request AOP_GetInstRef.
+   *
+   * @param  relName  The relation name. 
+   *                  
+   *                  At the RPC API this information was stored in the
+   *                  field refName of the structure GetInstRefReq   and
+   *                  the request AOP_GetInstRef.
+   *
+   * @return  The list of the Id of the related instances.
+   */
+   S_LONGLONG getRelInst(
+      in ElemId elem,
+      in Name relName)
+      raises (AoException);
+
+   /** (24003)
+   * Set the instance reference.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  elem  The instance to add the related instances.
+   *               
+   *               At the RPC API this information was stored in the
+   *               field elemId1 of the structure SetInstRefReq  and the
+   *               request AOP_SetInstRef.
+   *
+   * @param  relName  The name of relation. 
+   *                  
+   *                  At the RPC API this information was stored in the
+   *                  field refName of the structure SetInstRefReq and
+   *                  the request AOP_SetInstRef.
+   *
+   * @param  instIds  Sequence of instance id's. 
+   *                  
+   *                  At the RPC API this information was stored in the
+   *                  field elemId2 of the structure SetInstRefReq and
+   *                  the request AOP_SetInstRef. It was not possible to
+   *                  set more then one relation.
+   *
+   * @param  type  The type of the modification, insert, update or
+   *               remove. 
+   *               
+   *               At the RPC API this information was stored in the
+   *               field on off of the structure SetInstRefReq and the
+   *               request AOP_SetInstRef.
+   */
+   void setRelInst(
+      in ElemId elem,
+      in Name relName,
+      in S_LONGLONG instIds,
+      in SetType type)
+      raises (AoException);
+
+   /** (24004)
+   * Create instance elements of an application element. 
+   * The application element is specified by the AID of input structure.
+   * 
+   * The attribute names are specified by the name of the input
+   * structure.
+   * The values of one instance element are specified in the valueseq of
+   * the input structure.
+   * You can create several instance elements in one call by filling the
+   * valueseq of the input structure.
+   * The same index in the valueseq corresponds to the attributes values
+   * of one instance element. This method returns a sequence of Id's, the
+   * order is related to the order of instance element specified in the
+   * input structure. In case of inheritance, the method supports only
+   * instances of same subtype per call. The returned Id's are the Id's
+   * of the related super type instances.
+   * 
+   * The client must supply all mandatory attributes and references
+   * within one single method call; otherwise the object cannot be made
+   * persistent by the server in the database without the risk of
+   * violating any database constraint.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  val  The sequence of attributes and their values. 
+   *              
+   *              At the RPC API this information was stored in the
+   *              fields elemId and nvSeq of the structure PutValReq and
+   *              the request AOP_PutValReq.
+   *
+   * @return  List with the Id's of the new created instances.
+   */
+   ElemIdSequence insertInstances(
+      in AIDNameValueSeqUnitIdSequence val)
+      raises (AoException);
+
+   /** (24005)
+   * Update one or more attributes of one or more instance elements. It's
+   * necessary that the input structure includes also the Id attribute,
+   * the Id attribute will be used to select the instance elements. In
+   * case of inherited application elements the super type Id has to be
+   * included. The values of one instance element are specified in the
+   * valueseq of the input structure. The same index in the valueseq
+   * corresponds to the attributes values of one instance element. 
+   * 
+   * The server will update the values of the localcolumn instances when
+   * the following criteria all fit:
+   * 
+   * - Only when the attributes id, generation_parameters, values, flags
+   * are given, as soon as any other attributes is given an exception is
+   * thrown.
+   * - The values of the localcolumn must all belong to exactly one
+   * instances of AoMeasurement
+   * - The server have a limitation of the memory, not the system memory
+   * limitation, as soon as the given values breaks the limitation an
+   * exception will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  val  The sequence of attributes and their values. At least
+   *              one of the attribute values sequence must be a sequence
+   *              with the Id. 
+   *              
+   *              At the RPC API this information was stored in the
+   *              fields elemId and nvSeq of the structure PutValReq and
+   *              the request AOP_PutValReq.
+   */
+   void updateInstances(
+      in AIDNameValueSeqUnitIdSequence val)
+      raises (AoException);
+
+   /** (24006)
+   * Delete instances from an application element. In case of inherited
+   * application elements the Id of the super type has to be specified.
+   * 
+   * This method can be used to delete several instances of the same
+   * application element, the method removeInstance of the interface
+   * ApplicationElement to remove one instance of an application element
+   * with the children of the instance element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The application element Id.
+   *
+   * @param  instIds  The sequence of instance Id's. 
+   *                  
+   *                  At the RPC API this information was stored in the
+   *                  fields elemId and nvSeq of the structure PutValReq
+   *                  and the request AOP_PutValReq.
+   */
+   void deleteInstances(
+      in T_LONGLONG aid,
+      in S_LONGLONG instIds)
+      raises (AoException);
+
+   /** (24007)
+   * Get the value matrix of a measurement or a submatrix. If the value
+   * matrix will be built up with special submatrix link, use the
+   * interface Measurement.
+   * By calling this method, the value matrix mode of the returned value
+   * matrix will be taken from the context variable 'VALUEMATRIX_MODE'.
+   * For more information especially on different modes of the value
+   * matrix, see description at the method getValueMatrixInMode() of the
+   * interfaces 'Measurement' and 'SubMatrix'.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_BASETYPE
+   *
+   * @param  elem  The element id. The aid has to be the application
+   *               element Id of the AoMeasurement or AoSubmatrix.
+   *
+   * @return  The value matrix
+   */
+   ValueMatrix getValueMatrix(
+      in ElemId elem)
+      raises (AoException);
+
+   /** (24008)
+   * Set the ACL information on some application element-attribute
+   * defined by <aid> and <attr_name>. The <usergroup_id> defines the
+   * user group the rights should be set for. <rights> defines the rights
+   * to set or to clear. If the parameter <set> is set to 'set', the
+   * rights in <rights> are set all others are cleared. If the parameter
+   * <set> is set to 'add', the rights in <rights> are added to the
+   * existing rights. If the parameter <set> is set to 'remove', the
+   * rights in <rights> are removed from the existing rights. Restriction
+   * for the model: only one application element of the type AoUserGroup
+   * is allowed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  attrName  The name of the attribute.
+   *
+   * @param  usergroupId  The user group to set the rights for.
+   *
+   * @param  rights  The new right for the user group.
+   *
+   * @param  set  What to do with the new right.
+   */
+   void setAttributeRights(
+      in T_LONGLONG aid,
+      in T_STRING attrName,
+      in T_LONGLONG usergroupId,
+      in T_LONG rights,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (24009)
+   * Set the ACL information on some application element defined by
+   * <aid>. The <usergroup_id> defines the user group the rights should
+   * be set for. <rights> defines the rights to set or to clear. If the
+   * parameter <set> is set to 'set', the rights in <rights> are set all
+   * others are cleared. If the parameter <set> is set to 'add', the
+   * rights in <rights> are added to the existing rights. If the
+   * parameter <set> is set to 'remove', the rights in <rights> are
+   * removed from the existing rights.  Restriction for the model: only
+   * one application element of the type AoUserGroup is allowed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  usergroupId  The user group to set the rights for.
+   *
+   * @param  rights  The new rights for the user group. The rights
+   *                 constants are defined in the interface
+   *                 SecurityRights. The interface definition language
+   *                 IDL does not allow to set the values of enumerations
+   *                 thus the constant definitions had to be done in an
+   *                 interface.
+   *
+   * @param  set  What to do with the new right.
+   */
+   void setElementRights(
+      in T_LONGLONG aid,
+      in T_LONGLONG usergroupId,
+      in T_LONG rights,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (24010)
+   * Set the ACL information on some instance defined by the application
+   * element id <aid> and a sequence of instance defined by the id <iid>.
+   * The <usergroup_id> defines the user group the rights should be set
+   * for. <rights> defines the rights to set or to clear. If the
+   * parameter <set> is set to 'set', the rights in <rights> are set all
+   * others are cleared. If the parameter <set> is set to 'add', the
+   * rights in <rights> are added to the existing rights. If the
+   * parameter <set> is set to 'remove', the rights in <rights> are
+   * removed from the existing rights.  Restriction for the model: only
+   * one application element of the type AoUserGroup is allowed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  instIds  The sequence of instance Id's.
+   *
+   * @param  usergroupId  The user group to set the rights for.
+   *
+   * @param  rights  The new right for the user group.
+   *
+   * @param  set  What to do with the new right.
+   */
+   void setInstanceRights(
+      in T_LONGLONG aid,
+      in S_LONGLONG instIds,
+      in T_LONGLONG usergroupId,
+      in T_LONG rights,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (24011)
+   * Retrieve access control list information for the given application
+   * attribute <aid>/<attr_name>.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  attrName  The name of the attribute.
+   *
+   * @return  The access control list entries of the give application
+   *          attribute.
+   */
+   ACLSequence getAttributeRights(
+      in T_LONGLONG aid,
+      in T_STRING attrName)
+      raises (AoException);
+
+   /** (24012)
+   * Retrieve access control list information for the requested
+   * application element <aid>.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @return  The access control list entries of the given application
+   *          element.
+   */
+   ACLSequence getElementRights(
+      in T_LONGLONG aid)
+      raises (AoException);
+
+   /** (24013)
+   * Retrieve access control list information for the requested instance
+   * <aid>/<iid>.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  iid  The Id of the instance.
+   *
+   * @return  The access control list entries of the given instance.
+   */
+   ACLSequence getInstanceRights(
+      in T_LONGLONG aid,
+      in T_LONGLONG iid)
+      raises (AoException);
+
+   /** (24014)
+   * Set the access control list information for the initial rights on
+   * some application element defined by <aid>. The <usergroup_id>
+   * defines the user group the rights should be set for. <rights>
+   * defines the rights to set or to clear. If the parameter <set> is set
+   * to 'set', the rights in <rights> are set all others are cleared. If
+   * the parameter <set> is set to 'add', the rights in <rights> are
+   * added to the existing rights. If the parameter <set> is set to
+   * 'remove', the rights in <rights> are removed from the existing
+   * rights.  Restriction for the model: only one application element of
+   * the type AoUserGroup is allowed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  usergroupId  The user group to set the initial rights for.
+   *
+   * @param  rights  The new initial rights for the user group. The
+   *                 rights constants are defined in the interface
+   *                 SecurityRights. The interface definition language
+   *                 IDL does not allow to set the values of enumerations
+   *                 thus the constant definitions had to be done in an
+   *                 interface.
+   *
+   * @param  refAid  The Id of referencing application element for which
+   *                 the initial rights will be used. If no refAid is set
+   *                 the initial rights will be used for each new
+   *                 instance element independent of the application
+   *                 element.
+   *
+   * @param  set  What to do with the new initial rights.
+   */
+   void setElementInitialRights(
+      in T_LONGLONG aid,
+      in T_LONGLONG usergroupId,
+      in T_LONG rights,
+      in T_LONGLONG refAid,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (24015)
+   * Set the access control list information for the initial rights on
+   * some instance defined by the application element id <aid> and a
+   * sequence of instance defined by the id <iid>. The <usergroup_id>
+   * defines the user group the rights should be set for. <rights>
+   * defines the rights to set or to clear. If the parameter <set> is set
+   * to 'set', the rights in <rights> are set all others are cleared. If
+   * the parameter <set> is set to 'add', the rights in <rights> are
+   * added to the existing rights. If the parameter <set> is set to
+   * 'remove', the rights in <rights> are removed from the existing
+   * rights.  Restriction for the model: only one application element of
+   * the type AoUserGroup is allowed.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  instIds  The sequence of instance Id's.
+   *
+   * @param  usergroupId  The user group to set the initial rights for.
+   *
+   * @param  rights  The new initial right for the user group.
+   *
+   * @param  refAid  The Id of referencing application element for which
+   *                 the initial rights will be used. If no refAid is set
+   *                 the initial rights will be used for each new
+   *                 instance element independent of the application
+   *                 element.
+   *
+   * @param  set  What to do with the new initial rights.
+   */
+   void setInstanceInitialRights(
+      in T_LONGLONG aid,
+      in S_LONGLONG instIds,
+      in T_LONGLONG usergroupId,
+      in T_LONG rights,
+      in T_LONGLONG refAid,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (24016)
+   * Set the flag <set> in svcattr, if this reference will be used (or
+   * not) to retrieve the Initial Rights. If more than one reference is
+   * set to true, the union (or-function) of all rights are used.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *
+   * @param  aid  The application element Id.
+   *
+   * @param  refName  The name of the reference.
+   *
+   * @param  set  What to do with the given reference.
+   */
+   void setInitialRightReference(
+      in T_LONGLONG aid,
+      in T_STRING refName,
+      in RightsSet set)
+      raises (AoException);
+
+   /** (24017)
+   * Get all attribute names (references) which are used to retrieve the
+   * Initial Rights.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The application element Id.
+   *
+   * @return  The names of the references which will be used for the
+   *          initial rights determination.
+   */
+   NameSequence getInitialRightReference(
+      in T_LONGLONG aid)
+      raises (AoException);
+
+   /** (24018)
+   * Retrieve access control list information of the initial rights for
+   * the requested application element <aid>.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @return  The access control list entries of the given application
+   *          element for the initial rights.
+   */
+   InitialRightSequence getElementInitialRights(
+      in T_LONGLONG aid)
+      raises (AoException);
+
+   /** (24019)
+   * Retrieve access control list information of the initial rights for
+   * the requested instance <aid>/<iid>.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aid  The Id of the application element.
+   *
+   * @param  iid  The Id of the instance.
+   *
+   * @return  The access control list entries of the given instance for
+   *          the initial rights.
+   */
+   InitialRightSequence getInstanceInitialRights(
+      in T_LONGLONG aid,
+      in T_LONGLONG iid)
+      raises (AoException);
+
+   /** (24020)
+   * Perform the Query. This method can be used for a more powerful query
+   * compared to the method getInstances of this interface, with join
+   * definitions and aggregate functions.
+   * 
+   * The number of different application elements which are requested are
+   * exactly defined by the definition of the query given in the field
+   * anuSeq of the QueryStructureExt. The number of attributes for each
+   * application element is also given in the definition. The number of
+   * matching instances (their attributes) is not defined by the query
+   * and can be a large amount. Therefore only one iterator for the
+   * attribute values are defined.
+   * 
+   * The return is a sequence of the structure ResultSetExt . This
+   * sequence will always have the length of 1. This
+   * element in the structure have two fields 
+   *   - firstElems of type ElemResultSetExtSequence
+   *   - restElems of type ElemResultSetExtSeqIterator
+   * 
+   * firstElems
+   * The firstElems is a sequence of ElemResultSetExt, the length of the
+   * sequence corresponds with the number of different application
+   * elements requested in the anuSeq of the QueryStructrueExt. The
+   * structure ElemResultSetExt has the fields aid and values. The aid is
+   * the Id of the application element, the values, a sequence of the
+   * structure NameValueSeqUnitId are the values of the attributes. For
+   * each reported attribute an entry is given in the sequence, the name
+   * of the attribute is given in the field valName. The Id of the unit
+   * is given in the field unitId, this is the Id of the instance of the
+   * application element derived from the base element AoUnit. The values
+   * are given in the field value with the type TS_ValueSeq. Each value
+   * sequence has the same length, this length is maximum how_many the
+   * parameter of the method. If no values are found the length of the
+   * sequence is 0. The values with the same index in the different
+   * sequences of the entry in the NameValueSeqUnitIdSequence belongs to
+   * the same instance element. 
+   * 
+   * restElems
+   * The restElems is an iterator for the remaining sequence of
+   * ElemResultSetExt. This iterator allows to load the next N values
+   * from the ResultSet. The result of the element is the same way stored
+   * as at the field firstElems, the next N is the length of the sequence
+   * of the field value of the NameValueSeqUnitId. The method nextOne is
+   * wrong specified and should not be used, use instead the method nextN
+   * with n=1. The method getCount return the total number of found
+   * element, also the number already returned in firstElems. The method
+   * reset set the iterator the beginning of the ResultSet, this is the
+   * beginning of the firstElems.
+   * 
+   * The values of the localcolumn instances is part of the resultset
+   * when the following criteria all fit:
+   * 
+   * - Only when the attributes id, generation_parameters, values, flags
+   * are requested, as soon as any other attributes is requested the
+   * values are not reported.
+   * - The values of the localcolumn must all belong to exactly one
+   * instances of AoMeasurement
+   * - The server have a limitation of the memory, not the system memory
+   * limitation, as soon as the result set will break the limitation an
+   * exception will be thrown.
+   * - No iterator for the rest is required.
+   * 
+   * In case an attribute of blob type is among the requested attributes,
+   * the content of the return structure will depend on the number of
+   * instances that are returned:
+   * - In case attributes of only one instance are returned (either
+   * because 'how_many' was set to 1 or there is only one instance
+   * available at the server), the return structure contains the blob
+   * itself.
+   * - In case attributes of more than one instance are returned, the
+   * return structure does not contain the blobs; instead it contains the
+   * headers of the respective blobs.
+   * 
+   * The value of valName of query result values shall be the aaName in
+   * case AggrFunc='NONE' and shall be constructed for all other AggrFunc
+   * values as string concatenation of the AggrFunc value followed by a
+   * '(' character, followed by the name of attribute (aaName) followed
+   * by a ')' character.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  aoq  The query definition.
+   *
+   * @param  how_many  Maximum number of values in each result set. Valid
+   *                   arguments are: 
+   *                   how_many = 0 : report all found values,
+   *                   how_many > 0 : report a maximum number of values.
+   *
+   * @return  The result set with the requested attribute values.
+   */
+   ResultSetExtSequence getInstancesExt(
+      in QueryStructureExt aoq,
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (24021)
+   * Get the value matrix of a measurement or a submatrix. If the value
+   * matrix will be built up with special submatrix link, use the
+   * interface Measurement.
+   * The behavior of the ASAM ODS server depends on whether the
+   * referenced element is a submatrix or a measurement. For more
+   * information on the server behavior see description at the method
+   * getValueMatrixInMode() of the interfaces 'Measurement' and
+   * 'SubMatrix'.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_INVALID_BASETYPE
+   *    AO_INVALID_VALUEMATRIX_STRUCTURE
+   *
+   * @param  elem  The element id. The aid has to be the application
+   *               element Id of the AoMeasurement or AoSubmatrix.
+   *
+   * @param  vmMode  The requested mode of the value matrix.
+   *
+   * @return  The value matrix.
+   */
+   ValueMatrix getValueMatrixInMode(
+      in ElemId elem,
+      in ValueMatrixMode vmMode)
+      raises (AoException);
+
+   /** (24022)
+   * Get the ODSFile interface for an instance of an application element
+   * derived from AoFile.
+   * 
+   * This method returns an ODSFile interface.
+   * 
+   * One parameter controls the behavior of this method:
+   * The value of the parameter 'elem' (with its components 'aid' and
+   * 'iid') uniquely identifies
+   * an instance within the ODS storage. If no such instance exists, or
+   * if the instance is not
+   * an instance of an application element derived from AoFile, the
+   * exception
+   * AO_INVALID_BASETYPE is thrown.
+   * 
+   * Note that an ODS server may be set up to support the ODS security
+   * concepts and that in
+   * such case access to a file is only allowed if the access rights of
+   * the accessing user are
+   * sufficient. If the user does not have at least READ rights for the
+   * instance specified by
+   * 'elem' an exception AO_ACCESS_DENIED will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_INVALID_BASETYPE
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_ACCESS_DENIED
+   *
+   * @param  elem  The instance to which the file belongs, whose access
+   *               is intended.
+   *
+   * @return  The ODSFile interface to access the desired file.
+   */
+   ODSFile getODSFile(
+      in ElemId elem)
+      raises (AoException);
+
+}; // Interface ApplElemAccess.
+
+/**
+* The ASAM ODS query evaluator interface allows to perform queries in
+* synchronous mode and to create Query objects for asynchronous
+* execution.
+*/
+interface QueryEvaluator {
+
+   /** (25000)
+   * Evaluate a query in synchronous mode.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_QUERY_TYPE_INVALID
+   *    AO_QUERY_INVALID
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_TIMEOUT_EXCEEDED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  queryStr  The query string.
+   *
+   * @param  params  Sequence of parameter names and values. The
+   *                 following parameters should be passed:
+   *                 
+   *                 Name: "MaxDuration"; 
+   *                 Type: T_LONG
+   *                 Comment: Can be used to restrict the processing
+   *                 time. The time is given in  milliseconds,
+   *                 Default value: 0 (no restriction)
+   *
+   * @return  The result of the query as an instance element iterator.
+   */
+   InstanceElementIterator getInstances(
+      in T_STRING queryStr,
+      in NameValueSequence params)
+      raises (AoException);
+
+   /** (25001)
+   * Evaluate a query in synchronous mode.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_QUERY_TYPE_INVALID
+   *    AO_QUERY_INVALID
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_TIMEOUT_EXCEEDED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  queryStr  The query string.
+   *
+   * @param  params  Sequence of parameter names and values. The
+   *                 following parameters should be passed:
+   *                 
+   *                 Name: "MaxDuration"; 
+   *                 Type: T_LONG
+   *                 Comment: Can be used to restrict the processing
+   *                 time. The time is given in  milliseconds,
+   *                 Default value: 0 (no restriction)
+   *
+   * @return  The result of the query as a name value unit sequence
+   *          iterator. Each name value unit tuple is one cell of the
+   *          table. The name value unit sequence is one row of the
+   *          table.
+   */
+   NameValueUnitSequenceIterator getTableRows(
+      in T_STRING queryStr,
+      in NameValueSequence params)
+      raises (AoException);
+
+   /** (25002)
+   * Evaluate a query in synchronous mode.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_QUERY_TYPE_INVALID
+   *    AO_QUERY_INVALID
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_TIMEOUT_EXCEEDED
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  queryStr  The query string.
+   *
+   * @param  params  Sequence of parameter names and values. The
+   *                 following parameters should be passed:
+   *                 
+   *                 Name: "MaxDuration"; 
+   *                 Type: T_LONG
+   *                 Comment: Can be used to restrict the processing
+   *                 time. The time is given in  milliseconds,
+   *                 Default value: 0 (no restriction)
+   *
+   * @return  The result of the query as a name value sequence unit
+   *          sequence. Each name value sequence unit tuple is one column
+   *          of the table. The name value sequence unit sequence is  the
+   *          table. The result structure can be very huge.
+   */
+   NameValueSeqUnitSequence getTable(
+      in T_STRING queryStr,
+      in NameValueSequence params)
+      raises (AoException);
+
+   /** (25003)
+   * Create a query object to execute it in asynchronous mode.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_QUERY_TYPE_INVALID
+   *    AO_QUERY_INVALID
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  queryStr  The query string
+   *
+   * @param  params  Sequence of parameter names and values. The
+   *                 following parameters should be passed:
+   *                 
+   *                 Name: "QueryResultType"; 
+   *                 Type: ResultType.
+   *                 Comment: Specifies what kind of result is expected
+   *                 by the client.
+   *                 Default value: INSTELEM_ITERATOR_AS_RESULT
+   *                 
+   *                 Name: "MaxDuration"; 
+   *                 Type: T_LONG
+   *                 Comment: Can be used to restrict the processing
+   *                 time. The time is given in  milliseconds,
+   *                 Default value: 0 (no restriction)
+   *
+   * @return  The query object.
+   */
+   Query createQuery(
+      in T_STRING queryStr,
+      in NameValueSequence params)
+      raises (AoException);
+
+}; // Interface QueryEvaluator.
+
+/**
+* The ASAM ODS interface Query.
+*/
+interface Query {
+
+   /** (26000)
+   * Get the QueryEvaluator object which is responsible for this query.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The QueryEvaluator object which is responsible for this
+   *          query.
+   */
+   QueryEvaluator getQueryEvaluator()
+      raises (AoException);
+
+   /** (26001)
+   * Do the query pre-processing (optimization, etc.)  Call can be
+   * omitted by the client. In this case the functionality is executed on
+   * the call of executeQuery.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_INVALID_RESULTTYPE
+   *
+   * @param  params  Sequence of parameter names and values. The
+   *                 following parameters should be passed:
+   *                 
+   *                 Name: "QueryResultType"; 
+   *                 Type: ResultType.
+   *                 Comment: Specifies what kind of result is expected
+   *                 by the client, this parameter is required if the
+   *                 parameters isn't given at the method createQuery of
+   *                 the interface QueryEvaluator.
+   *                 Default value: INSTELEM_ITERATOR_AS_RESULT
+   */
+   void prepareQuery(
+      in NameValueSequence params)
+      raises (AoException);
+
+   /** (26002)
+   * Execute query in asynchronous mode.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_INVALID_RESULTTYPE
+   *
+   * @param  params  Sequence of parameter names and values. The
+   *                 following parameter should be passed:
+   *                 
+   *                 Name: "QueryResultType"; 
+   *                 Type: ResultType.
+   *                 Comment: Specifies what kind of result is expected
+   *                 by the client, this parameter is required if the
+   *                 parameters isn't given at the method prepareQuery or
+   *                 the method createQuery of the interface
+   *                 QueryEvaluator.
+   *                 Default value: INSTELEM_ITERATOR_AS_RESULT
+   *                 
+   *                 Name: "Synchronous";
+   *                 Type: T_BOOLEAN
+   *                 Comment: In case of "true" guarantees synchronous
+   *                 execution.
+   *                 Default value: "false"
+   */
+   void executeQuery(
+      in NameValueSequence params)
+      raises (AoException);
+
+   /** (26003)
+   * Return query status.
+   * 
+   * Returns INCOMPLETE if the query is still executing.
+   * 
+   * Returns COMPLETE if the query finished execution or if the query
+   * execution stopped because of an error or because the timeout was
+   * exceeded.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The status of the query.
+   */
+   QueryStatus getStatus()
+      raises (AoException);
+
+   /** (26004)
+   * Get the query result. This method should only be called after the
+   * query has been executed. It returns an iterator on the instances
+   * that were found by the query.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_TIMEOUT_EXCEEDED
+   *    AO_QUERY_INCOMPLETE
+   *    AO_QUERY_INVALID_RESULTTYPE
+   *
+   * @return  The result of the query as an instance element iterator.
+   */
+   InstanceElementIterator getInstances()
+      raises (AoException);
+
+   /** (26005)
+   * Get the query result. This method should only be called after the
+   * query has been executed. It returns an iterator on the name value
+   * unit sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_TIMEOUT_EXCEEDED
+   *    AO_QUERY_INCOMPLETE
+   *    AO_QUERY_INVALID_RESULTTYPE
+   *
+   * @return  The result of the query as a name value unit sequence
+   *          iterator. Each name value unit tuple is one cell of the
+   *          table. The name value unit sequence is one row of the
+   *          table.
+   */
+   NameValueUnitSequenceIterator getTableRows()
+      raises (AoException);
+
+   /** (26006)
+   * Get the query result. This method should only be called after the
+   * query has been executed. It returns the result as an structure.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_QUERY_PROCESSING_ERROR
+   *    AO_QUERY_TIMEOUT_EXCEEDED
+   *    AO_QUERY_INCOMPLETE
+   *    AO_QUERY_INVALID_RESULTTYPE
+   *
+   * @return  The result of the query as a name value sequence unit
+   *          sequence. Each name value sequence unit tuple is one column
+   *          of the table. The name value sequence unit sequence is  the
+   *          table. The result structure can be very huge.
+   */
+   NameValueSeqUnitSequence getTable()
+      raises (AoException);
+
+}; // Interface Query.
+
+/**
+* The name value unit sequence iterator. The table iterator as query
+* result.
+*/
+interface NameValueUnitSequenceIterator {
+
+   /** (27001)
+   * Destroy the iterator and free the associated memory.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (27002)
+   * Get the total number of elements accessible by the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of elements accessible by the iterator.
+   */
+   T_LONG getCount()
+      raises (AoException);
+
+   /** (27003)
+   * Get the next n elements from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  how_many  The number of requested elements.
+   *
+   * @return  The next n values of the name-value-unit  sequence. For
+   *          each NameValuUnit the next n values are stored in the value
+   *          sequence.
+   */
+   NameValueSeqUnitSequence nextN(
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (27004)
+   * Get the next element from the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The next name-value-unit tuple sequence from the
+   *          name-value-unit tuple.
+   */
+   NameValueSeqUnit nextOne()
+      raises (AoException);
+
+   /** (27005)
+   * Reset the pointer in the element iterator to the first element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void reset()
+      raises (AoException);
+
+}; // Interface NameValueUnitSequenceIterator.
+
+/**
+* The ASAM ODS enumeration interface.
+*/
+interface EnumerationDefinition {
+
+   /** (28000)
+   * List the possible names of the enumeration. The sort order of the
+   * list is the value of the item. The first item has the value zero.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  List with all possible names of the enumeration items.
+   */
+   NameSequence listItemNames()
+      raises (AoException);
+
+   /** (28001)
+   * Get the value of an item.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NOT_FOUND
+   *
+   * @param  itemName  The name of the item.
+   *
+   * @return  The number of the item.
+   */
+   T_LONG getItem(
+      in T_STRING itemName)
+      raises (AoException);
+
+   /** (28002)
+   * Get the name of an item.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NOT_FOUND
+   *
+   * @param  item  The value of the item.
+   *
+   * @return  The name of the item.
+   */
+   T_STRING getItemName(
+      in T_LONG item)
+      raises (AoException);
+
+   /** (28003)
+   * Add a new item to the enumeration. This method modifies the
+   * application model and is only allowed for the super user.
+   * 
+   * The name of an item must not exceed the maximum name length of the
+   * underlying physical storage. Current server implementations restrict
+   * it to 128 characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_ACCESS_DENIED
+   *    AO_DUPLICATE_NAME
+   *    AO_DUPLICATE_VALUE
+   *
+   * @param  itemName  The name of the new item.
+   */
+   void addItem(
+      in T_STRING itemName)
+      raises (AoException);
+
+   /** (28004)
+   * Rename the item of the enumeration. This method modifies the
+   * application model and is only allowed for the super user.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_NOT_FOUND
+   *
+   * @param  oldItemName  The existing name of the item.
+   *
+   * @param  newItemName  the new name of the item.
+   */
+   void renameItem(
+      in T_STRING oldItemName,
+      in T_STRING newItemName)
+      raises (AoException);
+
+   /** (28005)
+   * Get the name of the enumeration.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  Name of the enumeration.
+   */
+   T_STRING getName()
+      raises (AoException);
+
+   /** (28006)
+   * Set the name of the enumeration. This method modifies the
+   * application model and is only allowed for the super user.
+   * 
+   * The name of an enumeration definition must not exceed the maximum
+   * name length of the underlying physical storage. Current server
+   * implementations restrict it to 30 characters.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_TRANSACTION_NOT_ACTIVE
+   *    AO_ACCESS_DENIED
+   *
+   * @param  enumName  Name of the enumeration.
+   */
+   void setName(
+      in T_STRING enumName)
+      raises (AoException);
+
+   /** (28007)
+   * Get the index of the enumeration.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_BAD_PARAMETER
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The index of the enumeration.
+   */
+   T_LONG getIndex()
+      raises (AoException);
+
+}; // Interface EnumerationDefinition.
+
+/**
+* For iteration through the result elements, there is also a new iterator
+* necessary called ElemResultSetExtSeqIterator. ItÂ’s functionality is
+* still the same as all other iterators and needs therefore no further
+* explanation.
+* There is only one difference to the other iterations. The iteration is
+* done on the lowest level in that case on the TS_UnionSeq.
+*/
+interface ElemResultSetExtSeqIterator {
+
+   /** (29000)
+   * Destroy the iterator and free the associated memory.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void destroy()
+      raises (AoException);
+
+   /** (29001)
+   * Get the total number of elements accessible by the iterator.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The number of elements accessible by the iterator.
+   */
+   T_LONG getCount()
+      raises (AoException);
+
+   /** (29002)
+   * Get the next n elements from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @param  how_many  The number of requested elements.
+   *
+   * @return  The next n attribute values from the element result set
+   *          sequence.
+   */
+   ElemResultSetExtSequence nextN(
+      in T_LONG how_many)
+      raises (AoException);
+
+   /** (29003)
+   * Get the next  element from the sequence.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The next attribute values from the element result set
+   *          sequence.
+   */
+   ElemResultSetExt nextOne()
+      raises (AoException);
+
+   /** (29004)
+   * Reset the pointer in the element sequence to the first element.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void reset()
+      raises (AoException);
+
+}; // Interface ElemResultSetExtSeqIterator.
+
+/**
+* The interface ODSFile extends the interface InstanceElement. Thus all
+* methods of the interface InstanceElement do also work here. 
+* 
+* ODSFile allows to create a file that is under control of the ODS server
+* (a 'managed file'). ODSFile furthermore allows read, write, append or
+* remove operations to a managed file.
+* 
+* General information of the file can be retrieved from this interface as
+* well. Note, that no random access on a file is provided; only a
+* sequential read and a write by appending at the end is possible.
+* 
+* Replacing an existing file by a new one requires to first remove the
+* old one and then create the new one.
+*/
+interface ODSFile : InstanceElement {
+
+   /** (30000)
+   * Get the ODSWriteTransfer interface for the file, to allow appending
+   * further bytes to the file.
+   * 
+   * This method returns the ODSWriteTransfer interface for the file
+   * represented by this ODSFile object. That interface allows to write
+   * sequentially to the file, beginning at the end of the currently
+   * existing file.
+   * Before returning the interface ODSWriteTransfer, the physical file
+   * will be opened for subsequent write operations.
+   * 
+   * In case the current user has no UPDATE right for the instance (resp.
+   * for all of its attributes in case of attribute security) from which
+   * this ODSFile object was created, the exception AO_ACCESS_DENIED will
+   * be thrown.
+   * 
+   * In case the physical file referenced by this ODSFile object cannot
+   * be found, the exception AO_BAD_OPERATION will be thrown.
+   * 
+   * In case the physical file referenced by this ODSFile object is
+   * currently opened by an ODSReadTransfer or an ODSWriteTransfer
+   * object, the exception AO_FILE_LOCKED will be thrown.
+   * 
+   * In case the file cannot be opened for writing the exception
+   * AO_SYSTEM_PROBLEM will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_FILE_LOCKED
+   *    AO_ACCESS_DENIED
+   *    AO_BAD_OPERATION
+   *    AO_SYSTEM_PROBLEM
+   *
+   * @return  The ODSWriteTransfer interface to append to the file.
+   */
+   ODSWriteTransfer append()
+      raises (AoException);
+
+   /** (30001)
+   * Check whether the file may be opened for reading.
+   * 
+   * This method checks whether the file represented by this ODSFile
+   * object may be opened by the ODS server for reading access.
+   * 
+   * The method returns a boolean TRUE in case the file may be opened for
+   * reading, and a boolean FALSE in case it cannot be opened for reading
+   * or it is already opened for write access (i.e. an ODSWriteTransfer
+   * object for this file exists).
+   * 
+   * In case the physical file referenced by this ODSFile object cannot
+   * be found, false will be returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  Information about whether the file can be opened for
+   *          reading
+   */
+   T_BOOLEAN canRead()
+      raises (AoException);
+
+   /** (30002)
+   * Check whether the file may be opened for writing.
+   * 
+   * This method checks whether the file represented by this ODSFile
+   * object may be opened by the ODS server for writing access.
+   * 
+   * The method returns a boolean TRUE in case the user has appropriate
+   * rights and the file can be opened for writing, and a boolean FALSE
+   * in case it is already opened for write access (i.e. an
+   * ODSWriteTransfer object for this file exists) or for read access
+   * (i.e. one or more ODSReadTransfer objects for this file exist).
+   * 
+   * In case ao_location is defined and the current user has no UPDATE
+   * right for the instance from which this ODSFile object was created, a
+   * boolean FALSE will be returned.
+   * 
+   * In case ao_location is undefined and the current user has no INSERT
+   * right for the instance from which this ODSFile object was created, a
+   * boolean FALSE will be returned.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  Information about whether the file can be opened for
+   *          writing
+   */
+   T_BOOLEAN canWrite()
+      raises (AoException);
+
+   /** (30003)
+   * Create a new file at the ODS server and get the ODSWriteTransfer
+   * interface for that file, to allow storing bytes to the file.
+   * 
+   * This method returns the ODSWriteTransfer interface for the file
+   * represented by this ODSFile object. That interface allows to write
+   * sequentially to the (initially empty) file. 
+   * 
+   * Before returning the interface ODSWriteTransfer, the physical file
+   * will be created at the ODS server and opened for subsequent write
+   * operations. The file name will be decided by the ODS server and set
+   * as value of the attribute derived from the base attribute
+   * 'ao_location' of the instance from which this ODSFile object was
+   * created.
+   * 
+   * In case the current user has no INSERT right for the instance from
+   * which this ODSFile object was created, the exception
+   * AO_ACCESS_DENIED will be thrown.
+   * 
+   * If the attribute derived from 'ao_location' of the instance from
+   * which this ODSFile object was created already has a value, the
+   * instance potentially already references a file which was not yet
+   * removed, and the server will check whether that former file still
+   * exists. If so the exception AO_BAD_OPERATION will be thrown and no
+   * new file will be created.
+   * 
+   * In case the file cannot be opened for writing the exception
+   * AO_SYSTEM_PROBLEM will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_ACCESS_DENIED
+   *    AO_BAD_OPERATION
+   *    AO_SYSTEM_PROBLEM
+   *
+   * @return  The ODSWriteTransfer interface to a new file.
+   */
+   ODSWriteTransfer create()
+      raises (AoException);
+
+   /** (30004)
+   * Check whether the file physically exists at the ODS server.
+   * 
+   * This method checks whether the file represented by this ODSFile
+   * object truly exists at the expected location (e.g. on a specific
+   * drive/directory) within reach of  the ODS server.
+   * 
+   * The method returns a boolean TRUE in case the file exists, and a
+   * boolean FALSE in case it does not exist.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  Information about whether the file exists.
+   */
+   T_BOOLEAN exists()
+      raises (AoException);
+
+   /** (30005)
+   * Get the date of the file.
+   * This method returns the date of the file represented by this ODSFile
+   * object. The returned string follows the rules for ODS date and time
+   * specification strings.
+   * The date returned shall specify the timestamp of the latest change
+   * of the file. It is the information the operating system of the ODS
+   * server provides; if there is no date available from the operating
+   * system with exactly this meaning, the ODS server shall return the
+   * closest information available.
+   * In case the physical file referenced by this ODSFile object cannot
+   * be found, the exception AO_SYSTEM_PROBLEM will be thrown.
+   * In case the physical file referenced by this ODSFile object is
+   * currently opened by an ODSWriteTransfer object of another session,
+   * the exception AO_FILE_LOCKED will be thrown.
+   * In case there is no file defined by the attribute derived from
+   * 'ao_location', the exception AO_BAD_OPERATION will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_BAD_OPERATION
+   *    AO_SYSTEM_PROBLEM
+   *    AO_FILE_LOCKED
+   *
+   * @return  The date of last change of the file represented by this
+   *          ODSFile object.
+   */
+   T_DATE getDate()
+      raises (AoException);
+
+   /** (30006)
+   * Get the size of the file.
+   * This method returns the size of the file represented by this ODSFile
+   * object. 
+   * The returned value shall specify the exact file size in bytes. It is
+   * the information the operating system of the ODS server provides.
+   * In case the physical file referenced by this ODSFile object cannot
+   * be found, the exception AO_SYSTEM_PROBLEM will be thrown.
+   * In case there is no file defined by the attribute derived from
+   * 'ao_location', the exception AO_BAD_OPERATION will be thrown.
+   * In case the physical file referenced by this ODSFile object is
+   * currently opened by an ODSWriteTransfer object of another session,
+   * the exception AO_FILE_LOCKED will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_FILE_LOCKED
+   *    AO_BAD_OPERATION
+   *    AO_SYSTEM_PROBLEM
+   *
+   * @return  The size in bytes of the file represented by this ODSFile
+   *          object.
+   */
+   T_LONGLONG getSize()
+      raises (AoException);
+
+   /** (30007)
+   * Remove a file from the ODS server.
+   * This method removes the file represented by this ODSFile object from
+   * the ODS server if the user has appropriate rights. The attribute
+   * derived from the base attribute 'ao_location' of the instance from
+   * which this ODSFile object was created will become undefined and
+   * ao_size will be set to 0.
+   * In case the current user has no DELETE right for the instance from
+   * which this ODSFile object was created, the exception
+   * AO_ACCESS_DENIED will be thrown.
+   * In case the file is currently opened for write access (i.e. an
+   * ODSWriteTransfer object for this file exists) or for read access
+   * (i.e. one or more ODSReadTransfer objects for this file exist) an
+   * exception AO_FILE_LOCKED will be thrown.
+   * In case the physical file referenced by this ODSFile object does not
+   * exist, the method will return without any further file action; it
+   * will set the attribute derived from the base attribute 'ao_location'
+   * to undefined and 'ao_size' to 0; it will not throw an exception to
+   * signal the non-existence of the file.
+   * In case the file cannot be physically deleted from its location, the
+   * exception AO_SYSTEM_PROBLEM will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_FILE_LOCKED
+   *    AO_ACCESS_DENIED
+   *    AO_SYSTEM_PROBLEM
+   */
+   void remove()
+      raises (AoException);
+
+   /** (30008)
+   * Get the ODSReadTransfer interface for the file.
+   * This method returns the ODSReadTransfer interface for the file
+   * represented by this ODSFile object. That interface allows to read
+   * sequentially from the file, either starting at the very beginning or
+   * at a user-specified byte location within the file.
+   * Before returning the interface ODSReadTransfer, the physical file
+   * will be opened for reading.
+   * In case the physical file referenced by this ODSFile object is
+   * currently opened by an ODSWriteTransfer object, the exception
+   * AO_FILE_LOCKED will be thrown.
+   * In case there is no file defined by the attribute derived from
+   * 'ao_location', the exception AO_BAD_OPERATION will be thrown.
+   * In case the attribute derived from 'ao_location' is defined but the
+   * physical file referenced by this ODSFile object cannot be found or
+   * cannot be opened for reading, the exception AO_SYSTEM_PROBLEM will
+   * be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_FILE_LOCKED
+   *    AO_BAD_OPERATION
+   *    AO_SYSTEM_PROBLEM
+   *
+   * @return  The ODSReadTransfer interface to read from the file.
+   */
+   ODSReadTransfer read()
+      raises (AoException);
+
+   /** (30009)
+   * Put a file that is already residing within reach of the ODS server
+   * under control of the ODS server.
+   * This method allows to put files under control of the ODS server
+   * (make them a 'managed file') without the need to stream their bytes
+   * through the ODSWriteTransfer interface.
+   * The parameter 'sourceUrl' specifies the location of the file that
+   * shall become a managed file. This location must reference a file
+   * which is accessible by the server. The server will move the file to
+   * a location where managed files reside and give it a name of its own
+   * choice; the file will no longer exist at its previous location. The
+   * server will store file name and location in the attribute derived
+   * from 'ao_location' and store the size of the file in the attribute
+   * derived from 'ao_size'.
+   * The string value of 'sourceUrl' must comply to the URL specification
+   * given in RFC 2396 with the restriction that ASAM ODS only supports
+   * absolute URLs with the access scheme "file:", otherwise the
+   * exception AO_BAD_PARAMETER  will be thrown.
+   * In case there is no file defined by the attribute derived from
+   * 'ao_location', the exception AO_BAD_OPERATION will be thrown.
+   * In case the file cannot be physically moved from its original
+   * location to a server-location where managed files reside, the
+   * exception AO_SYSTEM_PROBLEM will be thrown (e.g. if the file
+   * specified by 'sourceUrl' does not exist, or if it cannot be
+   * physically moved, etc.).
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_BAD_PARAMETER
+   *    AO_BAD_OPERATION
+   *    AO_SYSTEM_PROBLEM
+   *
+   * @param  sourceUrl  Filename URL of the file to take under control as
+   *                    a managed file.
+   */
+   void takeUnderControl(
+      in T_STRING sourceUrl)
+      raises (AoException);
+
+   /** (30010)
+   * Remove a file that is currently under control of the ODS server out
+   * of control of the server and move it to a specified location within
+   * reach of the server.
+   * This method allows to take files out of control of the ODS server
+   * and place them at a specified location, without the need to stream
+   * their bytes through the ODSReadTransfer interface.
+   * The parameter 'targetUrl' specifies the location to which the
+   * currently managed file shall be moved. This location must be
+   * accessible by the server. The server will move the file from the
+   * location where managed files reside to the location given by
+   * 'targetUrl'; the file will no longer exist at its previous location.
+   * The server will set the value of the attribute derived from
+   * 'ao_location' to undefined and of the attribute derived from
+   * 'ao_size' to 0.
+   * The string value of 'targetUrl' must comply to the URL specification
+   * given in RFC 2396 with the restriction that ASAM ODS only supports
+   * absolute URLs with the access scheme "file:"; otherwise the
+   * exception AO_BAD_PARAMETER  will be thrown.
+   * In case the file specified by 'targetUrl' already exists the
+   * exception AO_BAD_PARAMETER will be thrown and no action will be
+   * performed by this method.
+   * In case the file specified by 'targetUrl' cannot be physically moved
+   * to the intended location, the exception AO_SYSTEM_PROBLEM will be
+   * thrown and no action will be performed by this method.
+   * In case the file referenced by this ODSFile object is currently
+   * opened for write access (i.e. an ODSWriteTransfer object for this
+   * file exists) or for read access (i.e. one or more ODSReadTransfer
+   * objects for this file exist) an exception AO_FILE_LOCKED will be
+   * thrown and no action will be performed by this method.
+   * In case there is no file defined by the attribute derived from
+   * 'ao_location', the exception AO_BAD_OPERATION will be thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_BAD_PARAMETER
+   *    AO_FILE_LOCKED
+   *    AO_SYSTEM_PROBLEM
+   *    AO_BAD_OPERATION
+   *    AO_BAD_PARAMETER
+   *
+   * @param  targetUrl  Filename URL of the file where to move the
+   *                    managed file.
+   */
+   void removeFromControl(
+      in T_STRING targetUrl)
+      raises (AoException);
+
+}; // Interface ODSFile.
+
+/**
+* The interface which allows a read transfer (from the ODS server to a
+* client) of the content of a file that is under control of the ODS
+* server.
+*/
+interface ODSReadTransfer {
+
+   const T_LONG READALL = -1; // Read all bytes of the file.
+
+   /** (31000)
+   * Close this ODSReadTransfer interface.
+   * 
+   * This method closes the file on the ODS server's file system and
+   * destroys this ODSReadTransfer object.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void close()
+      raises (AoException);
+
+   /** (31001)
+   * Read a sequence of bytes from the file.
+   * This method reads the file at the ODS server referenced by this
+   * ODSReadTransfer and returns a sequence of bytes from that file.
+   * 
+   * The parameter 'maxOctets' controls the return behavior of the ODS
+   * server. If the file contains more bytes than are given by
+   * 'maxOctets', only 'maxOctets' bytes will be returned in the first
+   * method invocation. A subsequent method invocation will return the
+   * next 'maxOctets' bytes from the file, etc., until the complete file
+   * contents has been returned. Further method invocations return an
+   * empty sequence.
+   * 
+   * If 'maxOctets' is given with a equal to the constant READALL(-1),
+   * there is no restriction on the number of bytes, and the complete
+   * file contents will be returned with only one method invocation.
+   * 
+   * Note that only a sequential reading, starting at the first byte of
+   * the file, is supported by this interface. If previous parts of the
+   * file need to be accessed again, the current ODSReadTransfer object
+   * must be closed and a new one must be instantiated.
+   * 
+   * In case the parameter 'maxOctets' is negative other then the
+   * constant READALL the exception AO_BAD_PARAMETER is thrown.
+   * 
+   * In case there is any problem reading the file, the exception
+   * AO_SYSTEM_PROBLEM is thrown.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_SYSTEM_PROBLEM
+   *    AO_BAD_PARAMETER
+   *
+   * @param  maxOctets  The maximum number of bytes to be returned by one
+   *                    method call.
+   *
+   * @return  The next (at most 'maxOctets') bytes in the file.
+   */
+   S_BYTE getOctetSeq(
+      in T_LONG maxOctets)
+      raises (AoException);
+
+   /** (31002)
+   * Skip a number of bytes while reading the file.
+   * This method moves the read pointer in the file a number of bytes
+   * ahead, starting at its current position; it will not return those
+   * bytes. The parameter 'numOctets' specifies the number of bytes to
+   * skip.
+   * 
+   * The method returns the true number of bytes that were skipped. This
+   * may differ from 'numOctets' e.g. if the end of the file was reached.
+   * If the read pointer has reached the end of the file any further
+   * method invocations will return a value of 0 for 'numSkipped'.
+   * 
+   * This method may be invoked several times and may be arbitrarily
+   * combined with getOctetSeq().
+   * 
+   * Note that only a sequential reading, starting at the first byte of
+   * the file, is supported by this interface. If previous parts of the
+   * file need to be accessed again, the current ODSReadTransfer object
+   * must be closed and a new one must be instantiated.
+   * 
+   * If 'numOctets' is given with a value less than 0, the method will
+   * throw the exception AO_BAD_PARAMETER and will not perform any file
+   * access nor change the read pointer.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_BAD_PARAMETER
+   *
+   * @param  numOctets  The number of bytes to be skipped.
+   *
+   * @return  the real number of bytes skipped in the file.
+   */
+   T_LONGLONG skipOctets(
+      in T_LONGLONG numOctets)
+      raises (AoException);
+
+   /** (31003)
+   * Retrieve the current position of the read pointer in the file.
+   * 
+   * This method returns the current byte position of the file pointer.
+   * The start of the file corresponds to a position of 0.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The current position of the read pointer in the file.
+   */
+   T_LONGLONG getPosition()
+      raises (AoException);
+
+}; // Interface ODSReadTransfer.
+
+/**
+* The interface which allows a write transfer (from a client to the ODS
+* server) of the content of a file that is under control of the ODS
+* server.
+*/
+interface ODSWriteTransfer {
+
+   /** (32000)
+   * Close this ODSWriteTransfer interface.
+   * This method closes the file on the ODS server's file system; thereby
+   * any data to be written to the file and still residing in ODS server
+   * cache will be flushed to the file. 
+   * The method finally destroys this ODSWriteTransfer object and also
+   * the corresponding CORBA object. Access to such objects after having
+   * invoked this close method will lead to a CORBA exception.
+   * In case the file creation and/or write operations have been
+   * performed within a transaction, this method will not yet save the
+   * operations' results permanently at the physical file location but
+   * keep them in intermediate storage until the transaction is
+   * committed. The file will be locked for any access through
+   * ODSReadTransfer or ODSWriteTransfer within any other session until
+   * the end of the transaction.
+   * Any subsequent read transfers or write transfers within the same
+   * transaction are allowed, and will work on the latest version of the
+   * file. In case the transaction is committed without a preceding close
+   * operation the ODSWriteTransfer will be closed automatically by the
+   * server.
+   * In case the file creation and/or write operations have been
+   * performed outside a transaction, this method will make all changes
+   * permanent.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   */
+   void close()
+      raises (AoException);
+
+   /** (32001)
+   * Write a sequence of bytes to the file.
+   * This method writes a sequence of bytes to the file at the ODS server
+   * represented by this ODSWriteTransfer. 
+   * 
+   * The parameter 'buffer' contains the byte sequence that is to be
+   * written to the file. The contents of 'buffer' will be appended at
+   * the end of the file (which may also be the very start of the file in
+   * case the file was newly created), and subsequent method invocations
+   * will add their bytes at the then actual end of the file.
+   * 
+   * Note that only a sequential writing is supported by this interface.
+   * If previous parts of the file need to be changed, the file must be
+   * removed and a new one must be created.
+   * 
+   * In case the current location of the file runs out of memory or any
+   * other operating system problem occurs the ODS server will return the
+   * exception AO_SYSTEM_PROBLEM. In this case the results of the actual
+   * putOctetSeq() invocation will be undone (no byte of 'buffer' is
+   * added to the file) and the file may be closed without containing
+   * 'buffer' at its end.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *    AO_NO_MEMORY
+   *    AO_SYSTEM_PROBLEM
+   *
+   * @param  buffer  The buffer containing the sequence of bytes that
+   *                 shall be written to the file.
+   */
+   void putOctectSeq(
+      in S_BYTE buffer)
+      raises (AoException);
+
+   /** (32002)
+   * Retrieve the current position of the write pointer in the file.
+   * 
+   * This method returns the current byte position of the write pointer.
+   * The start of the file corresponds to a position of 0.
+   *
+   * @throws AoException
+   * with the following possible error codes:
+   *    AO_CONNECTION_LOST
+   *    AO_IMPLEMENTATION_PROBLEM
+   *    AO_NOT_IMPLEMENTED
+   *    AO_NO_MEMORY
+   *    AO_SESSION_NOT_ACTIVE
+   *
+   * @return  The current position of the write pointer in the file.
+   */
+   T_LONGLONG getPosition()
+      raises (AoException);
+
+}; // Interface ODSWriteTransfer.
+
+}; // Module ods.
+
+}; // Module asam.
+
+}; // Module org.
+
+
+#endif
+
+/**
+* The ASAM ODS error codes.
+*
+* AO_ACCESS_DENIED
+* The ODS server denied the access.
+*
+* AO_BAD_OPERATION
+* A method was called which is not possible for the current state.
+*
+* AO_BAD_PARAMETER
+* A parameter of wrong type or value was passed to the method. The
+* minorCode tells which parameter (1, 2, 3 or 4) is bad. If more than one
+* parameter is bad, only the first one is reported.
+*
+* AO_CONNECTION_LOST
+* Due to a hardware or network software problem the connection to the
+* server was lost.
+*
+* AO_CONNECT_FAILED
+* The connect to a server failed. This error may occur if the server is
+* down or currently unreachable.
+*
+* AO_CONNECT_REFUSED
+* The connection was refused by the server. This error may occur if the
+* presented authentication information is either incorrect or incomplete.
+* This error shall not occur if the server does not accept any more
+* sessions due to overload problems. See AO_SESSION_LIMIT_REACHED for
+* this case.
+*
+* AO_DUPLICATE_BASE_ATTRIBUTE
+* Any application element may have only one base attribute of a certain
+* type. This means it may have only one attribute of base attribute type
+* NAME, one ID, one VERSION and so on.
+*
+* AO_DUPLICATE_NAME
+* The implicit or explicit specified name is already in use but it is
+* required to be unique.
+*
+* AO_DUPLICATE_VALUE
+* The attribute is marked unique in the application model. Thus duplicate
+* values are not allowed.
+*
+* AO_FILE_LOCKED
+* The kind of access to a managed file that was requested cannot be
+* granted, as the file is currently in use by another read or write
+* transfer through the OO-API.
+*
+* AO_HAS_BASE_ATTRIBUTE
+* Base attribute found. It is not allowed to modify the datatype, unique-
+* or obligatory flag .
+*
+* AO_HAS_BASE_RELATION
+* Base relation found. It is not allowed to modify the relationtype,
+* -range or -ship of an application relation derived from a base
+* relation.
+*
+* AO_HAS_INSTANCES
+* The operation is not allowed for elements that have instances.
+*
+* AO_HAS_REFERENCES
+* The requested operation is not permitted because the target element has
+* references.
+*
+* AO_IMPLEMENTATION_PROBLEM
+* This error is reserved for the reporting of implementation specific
+* problems that are not properly handled by the standard error
+* definitions. An application should not crash if this error occurs but
+* there is no way to react to this error other than reporting and
+* ignoring
+* it. The intend of this error is not to leave implementation specific
+* errors unreported.
+*
+* AO_INCOMPATIBLE_UNITS
+* The units are incompatible. No conversion rule is known.
+*
+* AO_INVALID_ASAM_PATH
+* The specified Asam path is invalid.
+*
+* AO_INVALID_ATTRIBUTE_TYPE
+* The requested attribute type is invalid.
+*
+* AO_INVALID_BASETYPE
+* The specified base type is invalid. The following basetypes are
+* allowed:
+*    AoAny
+*    AoAttributeMap
+*    AoEnvironment
+*    AoFile
+*    AoLocalColumn
+*    AoLog
+*    AoMeasurement
+*    AoMeasurementQuantity
+*    AoNameMap
+*    AoParameter
+*    AoParameterSet
+*    AoPhysicalDimension
+*    AoQuantity
+*    AoQuantityGroup
+*    AoSubmatrix
+*    AoSubTest
+*    AoTest
+*    AoTestDevice
+*    AoTestEquipment
+*    AoTestEquipmentPart
+*    AoTestSequence
+*    AoTestSequencePart
+*    AoUnit
+*    AoUnitGroup
+*    AoUnitUnderTest
+*    AoUnitUnderTestPart
+*    AoUser
+*    AoUserGroup
+*
+* AO_INVALID_BASE_ELEMENT
+* The base element is invalid in this context. If this is an element of
+* type measurement, another element of this type may already exist.
+*
+* AO_INVALID_BUILDUP_FUNCTION
+* The specified build-up function is invalid.
+*
+* AO_INVALID_COLUMN
+* The specified column is invalid.
+*
+* AO_INVALID_COUNT
+* The specified number of points is invalid (probably negative).
+*
+* AO_INVALID_DATATYPE
+* The datatype is not allowed in the given context or it conflicts with
+* an existing datatype definition.
+* 
+* This error may also occur in non-typesave language bindings. To avoid
+* this error in all language bindings it is recommended to use always the
+* definitions of the enumeration "DataType".
+*
+* AO_INVALID_ELEMENT
+* The element is invalid in this context.
+*
+* AO_INVALID_LENGTH
+* The given length is invalid. Negative length values are not allowed.
+*
+* AO_INVALID_ORDINALNUMBER
+* The ordinal number is either already used or less than zero.
+*
+* AO_INVALID_RELATION
+* The relation is invalid. The related elements and the base relation do
+* not fit.
+*
+* AO_INVALID_RELATIONSHIP
+* This error may occur only in non-typesave language bindings. To avoid
+* this error in all language bindings it is recommended to use always the
+* definitions of the enumeration "Relationship".
+*
+* AO_INVALID_RELATION_RANGE
+* The specified relation range is invalid.
+*
+* AO_INVALID_RELATION_TYPE
+* This error may occur only in non-typesave language bindings. To avoid
+* this error in all language bindings it is recommended to use always the
+* definitions of the enumeration "RelationType".
+*
+* AO_INVALID_SET_TYPE
+* The specified set-type is invalid.
+*
+* AO_INVALID_SMATLINK
+* The submatrix link is invalid. Either submatrix 1 or 2 is not specified
+* or the ordinal number is missing when there is more than one SMatLink.
+*
+* AO_INVALID_SUBMATRIX
+* The specified submatrix is invalid.
+*
+* AO_INVALID_VALUEMATRIX_STRUCTURE
+* The server is unable to create the valuematrix due to the data of the
+* measurement
+*      - if there are no independent column
+*      - if there are different independent columns
+*      - if there are submatrices with more than one independent
+*        column.
+*      - ..
+*
+* AO_IS_BASE_ATTRIBUTE
+* The application attribute is already of a base attribute type. It can
+* not be changed. If this is required, the application attribute has to
+* be removed from its application element and re-created. This error may
+* occur if an application attribute derived from a base attribute
+* 
+*    a. shall be overwritten by another base
+*       attribute type.
+*    b. shall receive another datatype.
+*    c. shall receive another unique-flag.
+*    d. shall receive another obligatory-flag.
+*
+* AO_IS_BASE_RELATION
+* Properties of base relations may not be changed.
+*
+* AO_IS_MEASUREMENT_MATRIX
+* The matrix is a complex, generated matrix from a measurement not just a
+* simple submatrix. It is only allowed to modify submatrices but not the
+* composed measurement matrices.
+*
+* AO_MATH_ERROR
+* A computation error occurred. This can be an overflow, an underflow or
+* a division by zero.
+*
+* AO_MISSING_APPLICATION_ELEMENT
+* A required application element is missing.
+*
+* AO_MISSING_ATTRIBUTE
+* A required (obligatory) attribute is missing.
+*
+* AO_MISSING_RELATION
+* A required relation is missing.
+*
+* AO_MISSING_VALUE
+* An obligatory value is missing.
+*
+* AO_NOT_FOUND
+* The requested element was not found. This error occurs only in remove
+* or rename operations if the subject of the operation is not found. All
+* get- and list-methods return an empty list if the requested item is not
+* found.
+*
+* AO_NOT_IMPLEMENTED
+* The requested method is not yet implemented. This error is not allowed
+* to occur in a certified implementation. It is intended to allow partial
+* operational tests. during the development process.
+*
+* AO_NOT_UNIQUE
+* This error occurs if the instances of a property are required to be
+* unique.
+*
+* AO_NO_MEMORY
+* No more volatile memory available.
+*
+* AO_NO_PATH_TO_ELEMENT
+* A free-floating element was detected. No navigation path leads to this
+* element.
+*
+* AO_NO_SCALING_COLUMN
+* The column is no scaling column.
+*
+* AO_OPEN_MODE_NOT_SUPPORTED
+* The requested open mode is not supported. Valid open modes are "read"
+* and "write". Anything else is rejected with this error and no session
+* is created.
+*
+* AO_QUERY_INCOMPLETE
+* The execution of the query was not yet completed.
+*
+* AO_QUERY_INVALID
+* Some error in the query string or some inconsistency between the return
+* type of the query string and the  result type specified by parameter
+* "QueryResultType".
+*
+* AO_QUERY_INVALID_RESULTTYPE
+* The requested result type of the query do no metch with the previous
+* definition of the result type.
+*
+* AO_QUERY_PROCESSING_ERROR
+* Some error occured during the execution of the query.
+*
+* AO_QUERY_TIMEOUT_EXCEEDED
+* It was not possible to execute the query within the  time limit set by
+* parameter "MaxDuration".
+*
+* AO_QUERY_TYPE_INVALID
+* The server does not support the specified query language type.
+*
+* AO_SESSION_LIMIT_REACHED
+* The server does not accept any new connections. This error may occur if
+* the server reached the session limit for a distinct user or the total
+* number of sessions allowed.
+*
+* AO_SESSION_NOT_ACTIVE
+* The session is no longer active. This error occurs if an attempt is
+* made to call a method of a closed session. This error shall not be
+* confused with the error AO_CONNECTION_LOST.
+*
+* AO_SYSTEM_PROBLEM
+* The ODS server detected a problem while accessing operating system
+* ressources (e.g. the specified file does not exist, the drive is
+* currently not available, ...).
+*
+* AO_TRANSACTION_ALREADY_ACTIVE
+* There may be only one active transaction at one time. If this error
+* occurs there is already an active transaction. That transaction remains
+* active in case of this error.
+*
+* AO_TRANSACTION_NOT_ACTIVE
+* Write operation have to be done always in the context of a transaction.
+* This error occurs if no transaction is active during a write operation.
+*
+* AO_UNKNOWN_ERROR
+* Use the zero as unknown error to avoid confusing error messages if no
+* error code has been set.
+*
+* AO_UNKNOWN_UNIT
+* The unit is unknown.
+*/
+
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEvent.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEvent.java
new file mode 100644
index 0000000..6f180f3
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEvent.java
@@ -0,0 +1,52 @@
+package com.highqsoft.avalonCorbaNotification.notification;
+
+
+/**
+* com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEvent.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/AvalonEvent.idl
+* Freitag, 5. August 2016 09:43 Uhr MESZ
+*/
+
+public final class AvalonNotificationCorbaEvent implements org.omg.CORBA.portable.IDLEntity
+{
+
+  /**
+  * The mode of the event.
+  */
+  public short mode = (short)0;
+
+  /**
+  * The Id of the application element.
+  */
+  public org.asam.ods.T_LONGLONG aeId = null;
+
+  /**
+  * The Id of the instance.
+  */
+  public org.asam.ods.T_LONGLONG ieId = null;
+
+  /**
+  * The Id of the AoUser instance.
+  */
+  public org.asam.ods.T_LONGLONG userId = null;
+
+  /**
+  * The timestamp of the event.
+  */
+  public String timestamp = null;
+
+  public AvalonNotificationCorbaEvent ()
+  {
+  } // ctor
+
+  public AvalonNotificationCorbaEvent (short _mode, org.asam.ods.T_LONGLONG _aeId, org.asam.ods.T_LONGLONG _ieId, org.asam.ods.T_LONGLONG _userId, String _timestamp)
+  {
+    mode = _mode;
+    aeId = _aeId;
+    ieId = _ieId;
+    userId = _userId;
+    timestamp = _timestamp;
+  } // ctor
+
+} // class AvalonNotificationCorbaEvent
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHelper.java
new file mode 100644
index 0000000..16cb18a
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHelper.java
@@ -0,0 +1,103 @@
+package com.highqsoft.avalonCorbaNotification.notification;
+
+
+/**
+* com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/AvalonEvent.idl
+* Freitag, 5. August 2016 09:43 Uhr MESZ
+*/
+
+abstract public class AvalonNotificationCorbaEventHelper
+{
+  private static String  _id = "IDL:com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEvent:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  private static boolean __active = false;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      synchronized (org.omg.CORBA.TypeCode.class)
+      {
+        if (__typeCode == null)
+        {
+          if (__active)
+          {
+            return org.omg.CORBA.ORB.init().create_recursive_tc ( _id );
+          }
+          __active = true;
+          org.omg.CORBA.StructMember[] _members0 = new org.omg.CORBA.StructMember [5];
+          org.omg.CORBA.TypeCode _tcOf_members0 = null;
+          _tcOf_members0 = org.omg.CORBA.ORB.init ().get_primitive_tc (org.omg.CORBA.TCKind.tk_short);
+          _members0[0] = new org.omg.CORBA.StructMember (
+            "mode",
+            _tcOf_members0,
+            null);
+          _tcOf_members0 = org.asam.ods.T_LONGLONGHelper.type ();
+          _members0[1] = new org.omg.CORBA.StructMember (
+            "aeId",
+            _tcOf_members0,
+            null);
+          _tcOf_members0 = org.asam.ods.T_LONGLONGHelper.type ();
+          _members0[2] = new org.omg.CORBA.StructMember (
+            "ieId",
+            _tcOf_members0,
+            null);
+          _tcOf_members0 = org.asam.ods.T_LONGLONGHelper.type ();
+          _members0[3] = new org.omg.CORBA.StructMember (
+            "userId",
+            _tcOf_members0,
+            null);
+          _tcOf_members0 = org.omg.CORBA.ORB.init ().create_string_tc (0);
+          _members0[4] = new org.omg.CORBA.StructMember (
+            "timestamp",
+            _tcOf_members0,
+            null);
+          __typeCode = org.omg.CORBA.ORB.init ().create_struct_tc (com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEventHelper.id (), "AvalonNotificationCorbaEvent", _members0);
+          __active = false;
+        }
+      }
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent read (org.omg.CORBA.portable.InputStream istream)
+  {
+    com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent value = new com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent ();
+    value.mode = istream.read_short ();
+    value.aeId = org.asam.ods.T_LONGLONGHelper.read (istream);
+    value.ieId = org.asam.ods.T_LONGLONGHelper.read (istream);
+    value.userId = org.asam.ods.T_LONGLONGHelper.read (istream);
+    value.timestamp = istream.read_string ();
+    return value;
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent value)
+  {
+    ostream.write_short (value.mode);
+    org.asam.ods.T_LONGLONGHelper.write (ostream, value.aeId);
+    org.asam.ods.T_LONGLONGHelper.write (ostream, value.ieId);
+    org.asam.ods.T_LONGLONGHelper.write (ostream, value.userId);
+    ostream.write_string (value.timestamp);
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHolder.java
new file mode 100644
index 0000000..fbed469
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHolder.java
@@ -0,0 +1,38 @@
+package com.highqsoft.avalonCorbaNotification.notification;
+
+/**
+* com/highqsoft/avalonCorbaNotification/notification/AvalonNotificationCorbaEventHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/AvalonEvent.idl
+* Freitag, 5. August 2016 09:43 Uhr MESZ
+*/
+
+public final class AvalonNotificationCorbaEventHolder implements org.omg.CORBA.portable.Streamable
+{
+  public com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent value = null;
+
+  public AvalonNotificationCorbaEventHolder ()
+  {
+  }
+
+  public AvalonNotificationCorbaEventHolder (com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEventHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEventHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEventHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_DELETE.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_DELETE.java
new file mode 100644
index 0000000..9e91cca
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_DELETE.java
@@ -0,0 +1,18 @@
+package com.highqsoft.avalonCorbaNotification.notification;
+
+
+/**
+* com/highqsoft/avalonCorbaNotification/notification/MODE_DELETE.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/AvalonEvent.idl
+* Freitag, 5. August 2016 09:43 Uhr MESZ
+*/
+
+public interface MODE_DELETE
+{
+
+  /**
+  * The value of the mode field in the event when a delete is registered.
+  */
+  public static final short value = (short)(3);
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_INSERT.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_INSERT.java
new file mode 100644
index 0000000..36a86e6
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_INSERT.java
@@ -0,0 +1,18 @@
+package com.highqsoft.avalonCorbaNotification.notification;
+
+
+/**
+* com/highqsoft/avalonCorbaNotification/notification/MODE_INSERT.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/AvalonEvent.idl
+* Freitag, 5. August 2016 09:43 Uhr MESZ
+*/
+
+public interface MODE_INSERT
+{
+
+  /**
+  * The value of the mode field in the event when an insert is registered.
+  */
+  public static final short value = (short)(1);
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_MODIFYRIGHTS.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_MODIFYRIGHTS.java
new file mode 100644
index 0000000..4d48ccd
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_MODIFYRIGHTS.java
@@ -0,0 +1,18 @@
+package com.highqsoft.avalonCorbaNotification.notification;
+
+
+/**
+* com/highqsoft/avalonCorbaNotification/notification/MODE_MODIFYRIGHTS.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/AvalonEvent.idl
+* Freitag, 5. August 2016 09:43 Uhr MESZ
+*/
+
+public interface MODE_MODIFYRIGHTS
+{
+
+  /**
+  * The value of the mode field in the event when a modifyrights is registered.
+  */
+  public static final short value = (short)(4);
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_REPLACE.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_REPLACE.java
new file mode 100644
index 0000000..dc121c2
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/avalonCorbaNotification/notification/MODE_REPLACE.java
@@ -0,0 +1,18 @@
+package com.highqsoft.avalonCorbaNotification.notification;
+
+
+/**
+* com/highqsoft/avalonCorbaNotification/notification/MODE_REPLACE.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/AvalonEvent.idl
+* Freitag, 5. August 2016 09:43 Uhr MESZ
+*/
+
+public interface MODE_REPLACE
+{
+
+  /**
+  * The value of the mode field in the event when a replace is registered.
+  */
+  public static final short value = (short)(2);
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerException.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerException.java
new file mode 100644
index 0000000..229f144
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerException.java
@@ -0,0 +1,39 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerException.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public final class CORBAFileServerException extends org.omg.CORBA.UserException
+{
+  public com.highqsoft.corbafileserver.generated.ErrorCode errCode = null;
+  public com.highqsoft.corbafileserver.generated.SeverityFlag sevFlag = null;
+  public String reason = null;
+
+  public CORBAFileServerException ()
+  {
+    super(CORBAFileServerExceptionHelper.id());
+  } // ctor
+
+  public CORBAFileServerException (com.highqsoft.corbafileserver.generated.ErrorCode _errCode, com.highqsoft.corbafileserver.generated.SeverityFlag _sevFlag, String _reason)
+  {
+    super(CORBAFileServerExceptionHelper.id());
+    errCode = _errCode;
+    sevFlag = _sevFlag;
+    reason = _reason;
+  } // ctor
+
+
+  public CORBAFileServerException (String $reason, com.highqsoft.corbafileserver.generated.ErrorCode _errCode, com.highqsoft.corbafileserver.generated.SeverityFlag _sevFlag, String _reason)
+  {
+    super(CORBAFileServerExceptionHelper.id() + "  " + $reason);
+    errCode = _errCode;
+    sevFlag = _sevFlag;
+    reason = _reason;
+  } // ctor
+
+} // class CORBAFileServerException
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHelper.java
new file mode 100644
index 0000000..c0c8e0f
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHelper.java
@@ -0,0 +1,93 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+abstract public class CORBAFileServerExceptionHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, com.highqsoft.corbafileserver.generated.CORBAFileServerException that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static com.highqsoft.corbafileserver.generated.CORBAFileServerException extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  private static boolean __active = false;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      synchronized (org.omg.CORBA.TypeCode.class)
+      {
+        if (__typeCode == null)
+        {
+          if (__active)
+          {
+            return org.omg.CORBA.ORB.init().create_recursive_tc ( _id );
+          }
+          __active = true;
+          org.omg.CORBA.StructMember[] _members0 = new org.omg.CORBA.StructMember [3];
+          org.omg.CORBA.TypeCode _tcOf_members0 = null;
+          _tcOf_members0 = com.highqsoft.corbafileserver.generated.ErrorCodeHelper.type ();
+          _members0[0] = new org.omg.CORBA.StructMember (
+            "errCode",
+            _tcOf_members0,
+            null);
+          _tcOf_members0 = com.highqsoft.corbafileserver.generated.SeverityFlagHelper.type ();
+          _members0[1] = new org.omg.CORBA.StructMember (
+            "sevFlag",
+            _tcOf_members0,
+            null);
+          _tcOf_members0 = org.omg.CORBA.ORB.init ().create_string_tc (0);
+          _members0[2] = new org.omg.CORBA.StructMember (
+            "reason",
+            _tcOf_members0,
+            null);
+          __typeCode = org.omg.CORBA.ORB.init ().create_exception_tc (com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.id (), "CORBAFileServerException", _members0);
+          __active = false;
+        }
+      }
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static com.highqsoft.corbafileserver.generated.CORBAFileServerException read (org.omg.CORBA.portable.InputStream istream)
+  {
+    com.highqsoft.corbafileserver.generated.CORBAFileServerException value = new com.highqsoft.corbafileserver.generated.CORBAFileServerException ();
+    // read and discard the repository ID
+    istream.read_string ();
+    value.errCode = com.highqsoft.corbafileserver.generated.ErrorCodeHelper.read (istream);
+    value.sevFlag = com.highqsoft.corbafileserver.generated.SeverityFlagHelper.read (istream);
+    value.reason = istream.read_string ();
+    return value;
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, com.highqsoft.corbafileserver.generated.CORBAFileServerException value)
+  {
+    // write the repository ID
+    ostream.write_string (id ());
+    com.highqsoft.corbafileserver.generated.ErrorCodeHelper.write (ostream, value.errCode);
+    com.highqsoft.corbafileserver.generated.SeverityFlagHelper.write (ostream, value.sevFlag);
+    ostream.write_string (value.reason);
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHolder.java
new file mode 100644
index 0000000..0ace26a
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHolder.java
@@ -0,0 +1,38 @@
+package com.highqsoft.corbafileserver.generated;
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerExceptionHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public final class CORBAFileServerExceptionHolder implements org.omg.CORBA.portable.Streamable
+{
+  public com.highqsoft.corbafileserver.generated.CORBAFileServerException value = null;
+
+  public CORBAFileServerExceptionHolder ()
+  {
+  }
+
+  public CORBAFileServerExceptionHolder (com.highqsoft.corbafileserver.generated.CORBAFileServerException initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIF.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIF.java
new file mode 100644
index 0000000..87ec4ef
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIF.java
@@ -0,0 +1,18 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerIF.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public interface CORBAFileServerIF extends CORBAFileServerIFOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity 
+{
+
+  /*
+  	  * The version number of the IDL
+  	  */
+  public static final String INTERFACEVERSION = "1.3";
+} // interface CORBAFileServerIF
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFHelper.java
new file mode 100644
index 0000000..5944a7d
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFHelper.java
@@ -0,0 +1,85 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerIFHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+abstract public class CORBAFileServerIFHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerIF:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, com.highqsoft.corbafileserver.generated.CORBAFileServerIF that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static com.highqsoft.corbafileserver.generated.CORBAFileServerIF extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      __typeCode = org.omg.CORBA.ORB.init ().create_interface_tc (com.highqsoft.corbafileserver.generated.CORBAFileServerIFHelper.id (), "CORBAFileServerIF");
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static com.highqsoft.corbafileserver.generated.CORBAFileServerIF read (org.omg.CORBA.portable.InputStream istream)
+  {
+    return narrow (istream.read_Object (_CORBAFileServerIFStub.class));
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, com.highqsoft.corbafileserver.generated.CORBAFileServerIF value)
+  {
+    ostream.write_Object ((org.omg.CORBA.Object) value);
+  }
+
+  public static com.highqsoft.corbafileserver.generated.CORBAFileServerIF narrow (org.omg.CORBA.Object obj)
+  {
+    if (obj == null)
+      return null;
+    else if (obj instanceof com.highqsoft.corbafileserver.generated.CORBAFileServerIF)
+      return (com.highqsoft.corbafileserver.generated.CORBAFileServerIF)obj;
+    else if (!obj._is_a (id ()))
+      throw new org.omg.CORBA.BAD_PARAM ();
+    else
+    {
+      org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();
+      com.highqsoft.corbafileserver.generated._CORBAFileServerIFStub stub = new com.highqsoft.corbafileserver.generated._CORBAFileServerIFStub ();
+      stub._set_delegate(delegate);
+      return stub;
+    }
+  }
+
+  public static com.highqsoft.corbafileserver.generated.CORBAFileServerIF unchecked_narrow (org.omg.CORBA.Object obj)
+  {
+    if (obj == null)
+      return null;
+    else if (obj instanceof com.highqsoft.corbafileserver.generated.CORBAFileServerIF)
+      return (com.highqsoft.corbafileserver.generated.CORBAFileServerIF)obj;
+    else
+    {
+      org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();
+      com.highqsoft.corbafileserver.generated._CORBAFileServerIFStub stub = new com.highqsoft.corbafileserver.generated._CORBAFileServerIFStub ();
+      stub._set_delegate(delegate);
+      return stub;
+    }
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFHolder.java
new file mode 100644
index 0000000..6acc46b
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFHolder.java
@@ -0,0 +1,38 @@
+package com.highqsoft.corbafileserver.generated;
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerIFHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public final class CORBAFileServerIFHolder implements org.omg.CORBA.portable.Streamable
+{
+  public com.highqsoft.corbafileserver.generated.CORBAFileServerIF value = null;
+
+  public CORBAFileServerIFHolder ()
+  {
+  }
+
+  public CORBAFileServerIFHolder (com.highqsoft.corbafileserver.generated.CORBAFileServerIF initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.CORBAFileServerIFHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.CORBAFileServerIFHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.CORBAFileServerIFHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFOperations.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFOperations.java
new file mode 100644
index 0000000..b5f74a7
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFOperations.java
@@ -0,0 +1,496 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerIFOperations.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public interface CORBAFileServerIFOperations 
+{
+
+  /**
+        * Save the data associated with the given intput stream.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  String save (org.asam.ods.AoSession aoSess, String name, String subDir, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  String saveForInstance (org.asam.ods.AoSession aoSess, String name, String subDir, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the name of an applciation element and the name of the instance element
+        * that holds the external reference
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aeName the application element name.
+        * @param  ieName the instance element name.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  String saveForInstanceName (org.asam.ods.AoSession aoSess, String name, String subDir, String aeName, String ieName, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Delete the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        */
+  void delete (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Move the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  urlo the url of the file.
+        */
+  void move (org.asam.ods.AoSession aoSess, String url) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Delete the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  url the url of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+  void deleteForInstance (org.asam.ods.AoSession aoSess, String url, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Move the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+  void moveForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+  void getBySocket (org.asam.ods.AoSession aoSess, String name, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the url specification of the file.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+  void getForInstanceBySocket (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  String saveBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  String saveForInstanceBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aeName the application element name.
+         * @param  ieName the instance element name.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  String saveForInstanceNameBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, String aeName, String ieName, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  stream the input stream, ready to read by the server.
+        */
+  com.highqsoft.corbafileserver.generated.InputStreamIF read (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        */
+  com.highqsoft.corbafileserver.generated.InputStreamIF readForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  size the size of the input stream.
+        */
+  long getSize (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  size the size of the input stream.
+        */
+  long getSizeForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+  void terminate (org.asam.ods.AoSession aoSess, String name, String parameter) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+  void terminateForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String parameter) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Get the name of the host where the server is running
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return the hostname
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  String getHostname (org.asam.ods.AoSession aoSess) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Get a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @return the context value
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY,
+        *    FILESERVER_NOT_FOUND
+        */
+  String getContext (org.asam.ods.AoSession aoSess, String key) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Set a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @param value the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  void setContext (org.asam.ods.AoSession aoSess, String key, String value) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Remove a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  void removeContext (org.asam.ods.AoSession aoSess, String key) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * List all context keywords.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return a sequence of strings.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  String[] listContext (org.asam.ods.AoSession aoSess) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Get the version of the CorbaFileServerIF.
+        * Returns getVersion of CorbaFileServer.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @return  The interface version of the CorbaFileServerIF.
+        *
+        */
+  String getInterfaceVersion () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Returns an array of long values representing the length
+        * of the files that were provided in the String array.
+        * The order of the long values must match with the order
+        * of the filenames.
+        *
+        * @param aoSess the aoSession of the caller
+        * @param names the String array of filenames for 
+        *              which to get the sizes
+        * @return an Array of long values containing the file sizes
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        *
+        */
+  long[] getSizes (org.asam.ods.AoSession aoSess, String[] names) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+} // interface CORBAFileServerIFOperations
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOA.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOA.java
new file mode 100644
index 0000000..d1c770a
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOA.java
@@ -0,0 +1,963 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOA.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public abstract class CORBAFileServerIFPOA extends org.omg.PortableServer.Servant
+ implements com.highqsoft.corbafileserver.generated.CORBAFileServerIFOperations, org.omg.CORBA.portable.InvokeHandler
+{
+
+  // Constructors
+
+  private static java.util.Hashtable _methods = new java.util.Hashtable ();
+  static
+  {
+    _methods.put ("save", new java.lang.Integer (0));
+    _methods.put ("saveForInstance", new java.lang.Integer (1));
+    _methods.put ("saveForInstanceName", new java.lang.Integer (2));
+    _methods.put ("delete", new java.lang.Integer (3));
+    _methods.put ("move", new java.lang.Integer (4));
+    _methods.put ("deleteForInstance", new java.lang.Integer (5));
+    _methods.put ("moveForInstance", new java.lang.Integer (6));
+    _methods.put ("getBySocket", new java.lang.Integer (7));
+    _methods.put ("getForInstanceBySocket", new java.lang.Integer (8));
+    _methods.put ("saveBySocket", new java.lang.Integer (9));
+    _methods.put ("saveForInstanceBySocket", new java.lang.Integer (10));
+    _methods.put ("saveForInstanceNameBySocket", new java.lang.Integer (11));
+    _methods.put ("read", new java.lang.Integer (12));
+    _methods.put ("readForInstance", new java.lang.Integer (13));
+    _methods.put ("getSize", new java.lang.Integer (14));
+    _methods.put ("getSizeForInstance", new java.lang.Integer (15));
+    _methods.put ("terminate", new java.lang.Integer (16));
+    _methods.put ("terminateForInstance", new java.lang.Integer (17));
+    _methods.put ("getHostname", new java.lang.Integer (18));
+    _methods.put ("getContext", new java.lang.Integer (19));
+    _methods.put ("setContext", new java.lang.Integer (20));
+    _methods.put ("removeContext", new java.lang.Integer (21));
+    _methods.put ("listContext", new java.lang.Integer (22));
+    _methods.put ("getInterfaceVersion", new java.lang.Integer (23));
+    _methods.put ("getSizes", new java.lang.Integer (24));
+  }
+
+  public org.omg.CORBA.portable.OutputStream _invoke (String $method,
+                                org.omg.CORBA.portable.InputStream in,
+                                org.omg.CORBA.portable.ResponseHandler $rh)
+  {
+    org.omg.CORBA.portable.OutputStream out = null;
+    java.lang.Integer __method = (java.lang.Integer)_methods.get ($method);
+    if (__method == null)
+      throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);
+
+    switch (__method.intValue ())
+    {
+
+  /**
+        * Save the data associated with the given intput stream.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+       case 0:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/save
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String subDir = in.read_string ();
+           com.highqsoft.corbafileserver.generated.InputStreamIF stream = com.highqsoft.corbafileserver.generated.InputStreamIFHelper.read (in);
+           String $result = null;
+           $result = this.save (aoSess, name, subDir, stream);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+       case 1:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/saveForInstance
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String subDir = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           com.highqsoft.corbafileserver.generated.InputStreamIF stream = com.highqsoft.corbafileserver.generated.InputStreamIFHelper.read (in);
+           String $result = null;
+           $result = this.saveForInstance (aoSess, name, subDir, aid, iid, stream);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the name of an applciation element and the name of the instance element
+        * that holds the external reference
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aeName the application element name.
+        * @param  ieName the instance element name.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+       case 2:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/saveForInstanceName
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String subDir = in.read_string ();
+           String aeName = in.read_string ();
+           String ieName = in.read_string ();
+           com.highqsoft.corbafileserver.generated.InputStreamIF stream = com.highqsoft.corbafileserver.generated.InputStreamIFHelper.read (in);
+           String $result = null;
+           $result = this.saveForInstanceName (aoSess, name, subDir, aeName, ieName, stream);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Delete the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        */
+       case 3:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/delete
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           this.delete (aoSess, name);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Move the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  urlo the url of the file.
+        */
+       case 4:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/move
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String url = in.read_string ();
+           this.move (aoSess, url);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Delete the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  url the url of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+       case 5:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/deleteForInstance
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String url = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           this.deleteForInstance (aoSess, url, aid, iid);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Move the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+       case 6:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/moveForInstance
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           this.moveForInstance (aoSess, name, aid, iid);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+       case 7:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getBySocket
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String host = in.read_string ();
+           int aPort = in.read_long ();
+           this.getBySocket (aoSess, name, host, aPort);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the url specification of the file.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+       case 8:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getForInstanceBySocket
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           String host = in.read_string ();
+           int aPort = in.read_long ();
+           this.getForInstanceBySocket (aoSess, name, aid, iid, host, aPort);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+       case 9:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/saveBySocket
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String subDir = in.read_string ();
+           String host = in.read_string ();
+           int aPort = in.read_long ();
+           String $result = null;
+           $result = this.saveBySocket (aoSess, name, subDir, host, aPort);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+       case 10:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/saveForInstanceBySocket
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String subDir = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           String host = in.read_string ();
+           int aPort = in.read_long ();
+           String $result = null;
+           $result = this.saveForInstanceBySocket (aoSess, name, subDir, aid, iid, host, aPort);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aeName the application element name.
+         * @param  ieName the instance element name.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+       case 11:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/saveForInstanceNameBySocket
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String subDir = in.read_string ();
+           String aeName = in.read_string ();
+           String ieName = in.read_string ();
+           String host = in.read_string ();
+           int aPort = in.read_long ();
+           String $result = null;
+           $result = this.saveForInstanceNameBySocket (aoSess, name, subDir, aeName, ieName, host, aPort);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  stream the input stream, ready to read by the server.
+        */
+       case 12:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/read
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           com.highqsoft.corbafileserver.generated.InputStreamIF $result = null;
+           $result = this.read (aoSess, name);
+           out = $rh.createReply();
+           com.highqsoft.corbafileserver.generated.InputStreamIFHelper.write (out, $result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        */
+       case 13:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/readForInstance
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           com.highqsoft.corbafileserver.generated.InputStreamIF $result = null;
+           $result = this.readForInstance (aoSess, name, aid, iid);
+           out = $rh.createReply();
+           com.highqsoft.corbafileserver.generated.InputStreamIFHelper.write (out, $result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  size the size of the input stream.
+        */
+       case 14:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getSize
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           long $result = (long)0;
+           $result = this.getSize (aoSess, name);
+           out = $rh.createReply();
+           out.write_longlong ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  size the size of the input stream.
+        */
+       case 15:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getSizeForInstance
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           long $result = (long)0;
+           $result = this.getSizeForInstance (aoSess, name, aid, iid);
+           out = $rh.createReply();
+           out.write_longlong ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+       case 16:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/terminate
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           String parameter = in.read_string ();
+           this.terminate (aoSess, name, parameter);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+       case 17:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/terminateForInstance
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String name = in.read_string ();
+           org.asam.ods.T_LONGLONG aid = org.asam.ods.T_LONGLONGHelper.read (in);
+           org.asam.ods.T_LONGLONG iid = org.asam.ods.T_LONGLONGHelper.read (in);
+           String parameter = in.read_string ();
+           this.terminateForInstance (aoSess, name, aid, iid, parameter);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Get the name of the host where the server is running
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return the hostname
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+       case 18:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getHostname
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String $result = null;
+           $result = this.getHostname (aoSess);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Get a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @return the context value
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY,
+        *    FILESERVER_NOT_FOUND
+        */
+       case 19:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getContext
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String key = in.read_string ();
+           String $result = null;
+           $result = this.getContext (aoSess, key);
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Set a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @param value the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+       case 20:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/setContext
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String key = in.read_string ();
+           String value = in.read_string ();
+           this.setContext (aoSess, key, value);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Remove a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+       case 21:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/removeContext
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String key = in.read_string ();
+           this.removeContext (aoSess, key);
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * List all context keywords.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return a sequence of strings.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+       case 22:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/listContext
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String $result[] = null;
+           $result = this.listContext (aoSess);
+           out = $rh.createReply();
+           com.highqsoft.corbafileserver.generated.DS_STRINGHelper.write (out, $result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Get the version of the CorbaFileServerIF.
+        * Returns getVersion of CorbaFileServer.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @return  The interface version of the CorbaFileServerIF.
+        *
+        */
+       case 23:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getInterfaceVersion
+       {
+         try {
+           String $result = null;
+           $result = this.getInterfaceVersion ();
+           out = $rh.createReply();
+           out.write_string ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Returns an array of long values representing the length
+        * of the files that were provided in the String array.
+        * The order of the long values must match with the order
+        * of the filenames.
+        *
+        * @param aoSess the aoSession of the caller
+        * @param names the String array of filenames for 
+        *              which to get the sizes
+        * @return an Array of long values containing the file sizes
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        *
+        */
+       case 24:  // com/highqsoft/corbafileserver/generated/CORBAFileServerIF/getSizes
+       {
+         try {
+           org.asam.ods.AoSession aoSess = org.asam.ods.AoSessionHelper.read (in);
+           String names[] = com.highqsoft.corbafileserver.generated.DS_STRINGHelper.read (in);
+           long $result[] = null;
+           $result = this.getSizes (aoSess, names);
+           out = $rh.createReply();
+           com.highqsoft.corbafileserver.generated.LONG_ARRAYHelper.write (out, $result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+       default:
+         throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);
+    }
+
+    return out;
+  } // _invoke
+
+  // Type-specific CORBA::Object operations
+  private static String[] __ids = {
+    "IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerIF:1.0"};
+
+  public String[] _all_interfaces (org.omg.PortableServer.POA poa, byte[] objectId)
+  {
+    return (String[])__ids.clone ();
+  }
+
+  public CORBAFileServerIF _this() 
+  {
+    return CORBAFileServerIFHelper.narrow(
+    super._this_object());
+  }
+
+  public CORBAFileServerIF _this(org.omg.CORBA.ORB orb) 
+  {
+    return CORBAFileServerIFHelper.narrow(
+    super._this_object(orb));
+  }
+
+
+} // class CORBAFileServerIFPOA
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOATie.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOATie.java
new file mode 100644
index 0000000..963e9b3
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOATie.java
@@ -0,0 +1,623 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/CORBAFileServerIFPOATie.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public class CORBAFileServerIFPOATie extends CORBAFileServerIFPOA
+{
+
+  // Constructors
+
+  public CORBAFileServerIFPOATie ( com.highqsoft.corbafileserver.generated.CORBAFileServerIFOperations delegate ) {
+      this._impl = delegate;
+  }
+  public CORBAFileServerIFPOATie ( com.highqsoft.corbafileserver.generated.CORBAFileServerIFOperations delegate , org.omg.PortableServer.POA poa ) {
+      this._impl = delegate;
+      this._poa      = poa;
+  }
+  public com.highqsoft.corbafileserver.generated.CORBAFileServerIFOperations _delegate() {
+      return this._impl;
+  }
+  public void _delegate (com.highqsoft.corbafileserver.generated.CORBAFileServerIFOperations delegate ) {
+      this._impl = delegate;
+  }
+  public org.omg.PortableServer.POA _default_POA() {
+      if(_poa != null) {
+          return _poa;
+      }
+      else {
+          return super._default_POA();
+      }
+  }
+
+  /**
+        * Save the data associated with the given intput stream.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  public String save (org.asam.ods.AoSession aoSess, String name, String subDir, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.save(aoSess, name, subDir, stream);
+  } // save
+
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  public String saveForInstance (org.asam.ods.AoSession aoSess, String name, String subDir, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.saveForInstance(aoSess, name, subDir, aid, iid, stream);
+  } // saveForInstance
+
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the name of an applciation element and the name of the instance element
+        * that holds the external reference
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aeName the application element name.
+        * @param  ieName the instance element name.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  public String saveForInstanceName (org.asam.ods.AoSession aoSess, String name, String subDir, String aeName, String ieName, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.saveForInstanceName(aoSess, name, subDir, aeName, ieName, stream);
+  } // saveForInstanceName
+
+
+  /**
+        * Delete the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        */
+  public void delete (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.delete(aoSess, name);
+  } // delete
+
+
+  /**
+        * Move the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  urlo the url of the file.
+        */
+  public void move (org.asam.ods.AoSession aoSess, String url) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.move(aoSess, url);
+  } // move
+
+
+  /**
+        * Delete the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  url the url of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+  public void deleteForInstance (org.asam.ods.AoSession aoSess, String url, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.deleteForInstance(aoSess, url, aid, iid);
+  } // deleteForInstance
+
+
+  /**
+        * Move the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+  public void moveForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.moveForInstance(aoSess, name, aid, iid);
+  } // moveForInstance
+
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+  public void getBySocket (org.asam.ods.AoSession aoSess, String name, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.getBySocket(aoSess, name, host, aPort);
+  } // getBySocket
+
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the url specification of the file.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+  public void getForInstanceBySocket (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.getForInstanceBySocket(aoSess, name, aid, iid, host, aPort);
+  } // getForInstanceBySocket
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  public String saveBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.saveBySocket(aoSess, name, subDir, host, aPort);
+  } // saveBySocket
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  public String saveForInstanceBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.saveForInstanceBySocket(aoSess, name, subDir, aid, iid, host, aPort);
+  } // saveForInstanceBySocket
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aeName the application element name.
+         * @param  ieName the instance element name.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  public String saveForInstanceNameBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, String aeName, String ieName, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.saveForInstanceNameBySocket(aoSess, name, subDir, aeName, ieName, host, aPort);
+  } // saveForInstanceNameBySocket
+
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  stream the input stream, ready to read by the server.
+        */
+  public com.highqsoft.corbafileserver.generated.InputStreamIF read (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.read(aoSess, name);
+  } // read
+
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        */
+  public com.highqsoft.corbafileserver.generated.InputStreamIF readForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.readForInstance(aoSess, name, aid, iid);
+  } // readForInstance
+
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  size the size of the input stream.
+        */
+  public long getSize (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.getSize(aoSess, name);
+  } // getSize
+
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  size the size of the input stream.
+        */
+  public long getSizeForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.getSizeForInstance(aoSess, name, aid, iid);
+  } // getSizeForInstance
+
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+  public void terminate (org.asam.ods.AoSession aoSess, String name, String parameter) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.terminate(aoSess, name, parameter);
+  } // terminate
+
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+  public void terminateForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String parameter) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.terminateForInstance(aoSess, name, aid, iid, parameter);
+  } // terminateForInstance
+
+
+  /**
+        * Get the name of the host where the server is running
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return the hostname
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public String getHostname (org.asam.ods.AoSession aoSess) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.getHostname(aoSess);
+  } // getHostname
+
+
+  /**
+        * Get a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @return the context value
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY,
+        *    FILESERVER_NOT_FOUND
+        */
+  public String getContext (org.asam.ods.AoSession aoSess, String key) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.getContext(aoSess, key);
+  } // getContext
+
+
+  /**
+        * Set a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @param value the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public void setContext (org.asam.ods.AoSession aoSess, String key, String value) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.setContext(aoSess, key, value);
+  } // setContext
+
+
+  /**
+        * Remove a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public void removeContext (org.asam.ods.AoSession aoSess, String key) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.removeContext(aoSess, key);
+  } // removeContext
+
+
+  /**
+        * List all context keywords.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return a sequence of strings.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public String[] listContext (org.asam.ods.AoSession aoSess) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.listContext(aoSess);
+  } // listContext
+
+
+  /**
+        * Get the version of the CorbaFileServerIF.
+        * Returns getVersion of CorbaFileServer.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @return  The interface version of the CorbaFileServerIF.
+        *
+        */
+  public String getInterfaceVersion () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.getInterfaceVersion();
+  } // getInterfaceVersion
+
+
+  /**
+        * Returns an array of long values representing the length
+        * of the files that were provided in the String array.
+        * The order of the long values must match with the order
+        * of the filenames.
+        *
+        * @param aoSess the aoSession of the caller
+        * @param names the String array of filenames for 
+        *              which to get the sizes
+        * @return an Array of long values containing the file sizes
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        *
+        */
+  public long[] getSizes (org.asam.ods.AoSession aoSess, String[] names) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.getSizes(aoSess, names);
+  } // getSizes
+
+  private com.highqsoft.corbafileserver.generated.CORBAFileServerIFOperations _impl;
+  private org.omg.PortableServer.POA _poa;
+
+} // class CORBAFileServerIFPOATie
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_BYTEHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_BYTEHelper.java
new file mode 100644
index 0000000..f2a9b61
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_BYTEHelper.java
@@ -0,0 +1,60 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/DS_BYTEHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+abstract public class DS_BYTEHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/DS_BYTE:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, byte[] that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static byte[] extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      __typeCode = org.omg.CORBA.ORB.init ().get_primitive_tc (org.omg.CORBA.TCKind.tk_octet);
+      __typeCode = org.omg.CORBA.ORB.init ().create_sequence_tc (0, __typeCode);
+      __typeCode = org.omg.CORBA.ORB.init ().create_alias_tc (com.highqsoft.corbafileserver.generated.DS_BYTEHelper.id (), "DS_BYTE", __typeCode);
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static byte[] read (org.omg.CORBA.portable.InputStream istream)
+  {
+    byte value[] = null;
+    int _len0 = istream.read_long ();
+    value = new byte[_len0];
+    istream.read_octet_array (value, 0, _len0);
+    return value;
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, byte[] value)
+  {
+    ostream.write_long (value.length);
+    ostream.write_octet_array (value, 0, value.length);
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_BYTEHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_BYTEHolder.java
new file mode 100644
index 0000000..eaa85f0
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_BYTEHolder.java
@@ -0,0 +1,39 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/DS_BYTEHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public final class DS_BYTEHolder implements org.omg.CORBA.portable.Streamable
+{
+  public byte value[] = null;
+
+  public DS_BYTEHolder ()
+  {
+  }
+
+  public DS_BYTEHolder (byte[] initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.DS_BYTEHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.DS_BYTEHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.DS_BYTEHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_STRINGHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_STRINGHelper.java
new file mode 100644
index 0000000..5bbe928
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_STRINGHelper.java
@@ -0,0 +1,62 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/DS_STRINGHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+abstract public class DS_STRINGHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/DS_STRING:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, String[] that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static String[] extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      __typeCode = org.omg.CORBA.ORB.init ().create_string_tc (0);
+      __typeCode = org.omg.CORBA.ORB.init ().create_sequence_tc (0, __typeCode);
+      __typeCode = org.omg.CORBA.ORB.init ().create_alias_tc (com.highqsoft.corbafileserver.generated.DS_STRINGHelper.id (), "DS_STRING", __typeCode);
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static String[] read (org.omg.CORBA.portable.InputStream istream)
+  {
+    String value[] = null;
+    int _len0 = istream.read_long ();
+    value = new String[_len0];
+    for (int _o1 = 0;_o1 < value.length; ++_o1)
+      value[_o1] = istream.read_string ();
+    return value;
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, String[] value)
+  {
+    ostream.write_long (value.length);
+    for (int _i0 = 0;_i0 < value.length; ++_i0)
+      ostream.write_string (value[_i0]);
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_STRINGHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_STRINGHolder.java
new file mode 100644
index 0000000..c37baca
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/DS_STRINGHolder.java
@@ -0,0 +1,39 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/DS_STRINGHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public final class DS_STRINGHolder implements org.omg.CORBA.portable.Streamable
+{
+  public String value[] = null;
+
+  public DS_STRINGHolder ()
+  {
+  }
+
+  public DS_STRINGHolder (String[] initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.DS_STRINGHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.DS_STRINGHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.DS_STRINGHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCode.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCode.java
new file mode 100644
index 0000000..5b283e8
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCode.java
@@ -0,0 +1,70 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/ErrorCode.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+
+/**
+   * The error code.
+   */
+public class ErrorCode implements org.omg.CORBA.portable.IDLEntity
+{
+  private        int __value;
+  private static int __size = 15;
+  private static com.highqsoft.corbafileserver.generated.ErrorCode[] __array = new com.highqsoft.corbafileserver.generated.ErrorCode [__size];
+
+  public static final int _FILESERVER_ASAMODS_EXCEPTION = 0;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_ASAMODS_EXCEPTION = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_ASAMODS_EXCEPTION);
+  public static final int _FILESERVER_ACCESS_DENIED = 1;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_ACCESS_DENIED = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_ACCESS_DENIED);
+  public static final int _FILESERVER_FILE_NOT_FOUND = 2;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_FILE_NOT_FOUND = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_FILE_NOT_FOUND);
+  public static final int _FILESERVER_IO_EXCEPTION = 3;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_IO_EXCEPTION = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_IO_EXCEPTION);
+  public static final int _FILESERVER_INFORMATION = 4;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_INFORMATION = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_INFORMATION);
+  public static final int _FILESERVER_BAD_PARAMETER = 5;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_BAD_PARAMETER = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_BAD_PARAMETER);
+  public static final int _FILESERVER_MISSING_PARAMETER = 6;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_MISSING_PARAMETER = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_MISSING_PARAMETER);
+  public static final int _FILESERVER_CONNECT_FAILED = 7;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_CONNECT_FAILED = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_CONNECT_FAILED);
+  public static final int _FILESERVER_CONNECT_REFUSED = 8;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_CONNECT_REFUSED = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_CONNECT_REFUSED);
+  public static final int _FILESERVER_CONNECTION_LOST = 9;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_CONNECTION_LOST = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_CONNECTION_LOST);
+  public static final int _FILESERVER_IMPLEMENTATION_PROBLEM = 10;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_IMPLEMENTATION_PROBLEM = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_IMPLEMENTATION_PROBLEM);
+  public static final int _FILESERVER_NOT_IMPLEMENTED = 11;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_NOT_IMPLEMENTED = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_NOT_IMPLEMENTED);
+  public static final int _FILESERVER_NO_MEMORY = 12;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_NO_MEMORY = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_NO_MEMORY);
+  public static final int _FILESERVER_NULL_PARAMETER = 13;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_NULL_PARAMETER = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_NULL_PARAMETER);
+  public static final int _FILESERVER_NOT_FOUND = 14;
+  public static final com.highqsoft.corbafileserver.generated.ErrorCode FILESERVER_NOT_FOUND = new com.highqsoft.corbafileserver.generated.ErrorCode(_FILESERVER_NOT_FOUND);
+
+  public int value ()
+  {
+    return __value;
+  }
+
+  public static com.highqsoft.corbafileserver.generated.ErrorCode from_int (int value)
+  {
+    if (value >= 0 && value < __size)
+      return __array[value];
+    else
+      throw new org.omg.CORBA.BAD_PARAM ();
+  }
+
+  protected ErrorCode (int value)
+  {
+    __value = value;
+    __array[__value] = this;
+  }
+} // class ErrorCode
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCodeHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCodeHelper.java
new file mode 100644
index 0000000..ccbc532
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCodeHelper.java
@@ -0,0 +1,57 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/ErrorCodeHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+
+/**
+   * The error code.
+   */
+abstract public class ErrorCodeHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/ErrorCode:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, com.highqsoft.corbafileserver.generated.ErrorCode that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static com.highqsoft.corbafileserver.generated.ErrorCode extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      __typeCode = org.omg.CORBA.ORB.init ().create_enum_tc (com.highqsoft.corbafileserver.generated.ErrorCodeHelper.id (), "ErrorCode", new String[] { "FILESERVER_ASAMODS_EXCEPTION", "FILESERVER_ACCESS_DENIED", "FILESERVER_FILE_NOT_FOUND", "FILESERVER_IO_EXCEPTION", "FILESERVER_INFORMATION", "FILESERVER_BAD_PARAMETER", "FILESERVER_MISSING_PARAMETER", "FILESERVER_CONNECT_FAILED", "FILESERVER_CONNECT_REFUSED", "FILESERVER_CONNECTION_LOST", "FILESERVER_IMPLEMENTATION_PROBLEM", "FILESERVER_NOT_IMPLEMENTED", "FILESERVER_NO_MEMORY", "FILESERVER_NULL_PARAMETER", "FILESERVER_NOT_FOUND"} );
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static com.highqsoft.corbafileserver.generated.ErrorCode read (org.omg.CORBA.portable.InputStream istream)
+  {
+    return com.highqsoft.corbafileserver.generated.ErrorCode.from_int (istream.read_long ());
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, com.highqsoft.corbafileserver.generated.ErrorCode value)
+  {
+    ostream.write_long (value.value ());
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCodeHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCodeHolder.java
new file mode 100644
index 0000000..debb152
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/ErrorCodeHolder.java
@@ -0,0 +1,42 @@
+package com.highqsoft.corbafileserver.generated;
+
+/**
+* com/highqsoft/corbafileserver/generated/ErrorCodeHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+
+/**
+   * The error code.
+   */
+public final class ErrorCodeHolder implements org.omg.CORBA.portable.Streamable
+{
+  public com.highqsoft.corbafileserver.generated.ErrorCode value = null;
+
+  public ErrorCodeHolder ()
+  {
+  }
+
+  public ErrorCodeHolder (com.highqsoft.corbafileserver.generated.ErrorCode initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.ErrorCodeHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.ErrorCodeHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.ErrorCodeHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIF.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIF.java
new file mode 100644
index 0000000..993e85e
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIF.java
@@ -0,0 +1,13 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/InputStreamIF.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public interface InputStreamIF extends InputStreamIFOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity 
+{
+} // interface InputStreamIF
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFHelper.java
new file mode 100644
index 0000000..c9edc25
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFHelper.java
@@ -0,0 +1,85 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/InputStreamIFHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+abstract public class InputStreamIFHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/InputStreamIF:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, com.highqsoft.corbafileserver.generated.InputStreamIF that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static com.highqsoft.corbafileserver.generated.InputStreamIF extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      __typeCode = org.omg.CORBA.ORB.init ().create_interface_tc (com.highqsoft.corbafileserver.generated.InputStreamIFHelper.id (), "InputStreamIF");
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static com.highqsoft.corbafileserver.generated.InputStreamIF read (org.omg.CORBA.portable.InputStream istream)
+  {
+    return narrow (istream.read_Object (_InputStreamIFStub.class));
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, com.highqsoft.corbafileserver.generated.InputStreamIF value)
+  {
+    ostream.write_Object ((org.omg.CORBA.Object) value);
+  }
+
+  public static com.highqsoft.corbafileserver.generated.InputStreamIF narrow (org.omg.CORBA.Object obj)
+  {
+    if (obj == null)
+      return null;
+    else if (obj instanceof com.highqsoft.corbafileserver.generated.InputStreamIF)
+      return (com.highqsoft.corbafileserver.generated.InputStreamIF)obj;
+    else if (!obj._is_a (id ()))
+      throw new org.omg.CORBA.BAD_PARAM ();
+    else
+    {
+      org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();
+      com.highqsoft.corbafileserver.generated._InputStreamIFStub stub = new com.highqsoft.corbafileserver.generated._InputStreamIFStub ();
+      stub._set_delegate(delegate);
+      return stub;
+    }
+  }
+
+  public static com.highqsoft.corbafileserver.generated.InputStreamIF unchecked_narrow (org.omg.CORBA.Object obj)
+  {
+    if (obj == null)
+      return null;
+    else if (obj instanceof com.highqsoft.corbafileserver.generated.InputStreamIF)
+      return (com.highqsoft.corbafileserver.generated.InputStreamIF)obj;
+    else
+    {
+      org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();
+      com.highqsoft.corbafileserver.generated._InputStreamIFStub stub = new com.highqsoft.corbafileserver.generated._InputStreamIFStub ();
+      stub._set_delegate(delegate);
+      return stub;
+    }
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFHolder.java
new file mode 100644
index 0000000..8145846
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFHolder.java
@@ -0,0 +1,38 @@
+package com.highqsoft.corbafileserver.generated;
+
+/**
+* com/highqsoft/corbafileserver/generated/InputStreamIFHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public final class InputStreamIFHolder implements org.omg.CORBA.portable.Streamable
+{
+  public com.highqsoft.corbafileserver.generated.InputStreamIF value = null;
+
+  public InputStreamIFHolder ()
+  {
+  }
+
+  public InputStreamIFHolder (com.highqsoft.corbafileserver.generated.InputStreamIF initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.InputStreamIFHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.InputStreamIFHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.InputStreamIFHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFOperations.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFOperations.java
new file mode 100644
index 0000000..fd811dd
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFOperations.java
@@ -0,0 +1,85 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/InputStreamIFOperations.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public interface InputStreamIFOperations 
+{
+
+  /**
+        * Reads up to len bytes of data from the input stream into an array
+        * of bytes. An attempt is made to read as many as len bytes, but a
+        * smaller number may be read, possibly zero. The number of bytes
+        * actually read is returned as an integer.
+        *
+        * This method blocks until input data is available, end of file
+        * is detected, or an exception is thrown.
+        *
+        * If b is null, a NullPointerException is thrown.
+        *
+        * If off is negative, or len is negative, or off+len is greater
+        * than the length of the array b, then an IndexOutOfBoundsException is thrown.
+        *
+        * If len is zero, then no bytes are read and 0 is returned;
+        * otherwise, there is an attempt to read at least one byte.
+        * If no byte is available because the stream is at end of file,
+        * the value -1 is returned; otherwise, at least one byte is read and stored into b.
+        *
+        * The first byte read is stored into element b[off], the next one into b[off+1],
+        * and so on. The number of bytes read is, at most, equal to len. Let k be the number
+        * of bytes actually read; these bytes will be stored in elements b[off] through b[off+k-1],
+        * leaving elements b[off+k] through b[off+len-1] unaffected.
+        *
+        * In every case, elements b[0] through b[off] and elements b[off+len]
+        * through b[b.length-1] are unaffected.
+        *
+        * If the first byte cannot be read for any reason other than end of file,
+        * then an IOException is thrown. In particular, an IOException is thrown
+        * if the input stream has been closed.
+        *
+        * The read(b, off, len) method for class InputStream simply calls the method
+        * read() repeatedly. If the first such call results in an IOException,
+        * that exception is returned from the call to the read(b, off, len) method.
+        * If any subsequent call to read() results in a IOException, the exception
+        * is caught and treated as if it were end of file; the bytes read up to that
+        * point are stored into b and the number of bytes read before the exception
+        * occurred is returned. Subclasses are encouraged to provide a more efficient
+        * implementation of this method.
+        *
+        * @param b - the buffer into which the data is read.
+        * @param off - the start offset in array b  at which the data is written.
+        * @param len - the maximum number of bytes to read.
+        * @return the total number of bytes read into the buffer,
+        *         or -1 is there is no more data because the end
+        *         of the stream has been reached.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  int read (com.highqsoft.corbafileserver.generated.DS_BYTEHolder b, int off, int len) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Close the input stream.
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  void close () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Get the length of the input stream.
+        *
+        * @return the length of the file to be transferd.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  int length () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+
+  /**
+        * Reset the stream
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  void reset () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+} // interface InputStreamIFOperations
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFPOA.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFPOA.java
new file mode 100644
index 0000000..19fb442
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFPOA.java
@@ -0,0 +1,190 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/InputStreamIFPOA.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public abstract class InputStreamIFPOA extends org.omg.PortableServer.Servant
+ implements com.highqsoft.corbafileserver.generated.InputStreamIFOperations, org.omg.CORBA.portable.InvokeHandler
+{
+
+  // Constructors
+
+  private static java.util.Hashtable _methods = new java.util.Hashtable ();
+  static
+  {
+    _methods.put ("read", new java.lang.Integer (0));
+    _methods.put ("close", new java.lang.Integer (1));
+    _methods.put ("length", new java.lang.Integer (2));
+    _methods.put ("reset", new java.lang.Integer (3));
+  }
+
+  public org.omg.CORBA.portable.OutputStream _invoke (String $method,
+                                org.omg.CORBA.portable.InputStream in,
+                                org.omg.CORBA.portable.ResponseHandler $rh)
+  {
+    org.omg.CORBA.portable.OutputStream out = null;
+    java.lang.Integer __method = (java.lang.Integer)_methods.get ($method);
+    if (__method == null)
+      throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);
+
+    switch (__method.intValue ())
+    {
+
+  /**
+        * Reads up to len bytes of data from the input stream into an array
+        * of bytes. An attempt is made to read as many as len bytes, but a
+        * smaller number may be read, possibly zero. The number of bytes
+        * actually read is returned as an integer.
+        *
+        * This method blocks until input data is available, end of file
+        * is detected, or an exception is thrown.
+        *
+        * If b is null, a NullPointerException is thrown.
+        *
+        * If off is negative, or len is negative, or off+len is greater
+        * than the length of the array b, then an IndexOutOfBoundsException is thrown.
+        *
+        * If len is zero, then no bytes are read and 0 is returned;
+        * otherwise, there is an attempt to read at least one byte.
+        * If no byte is available because the stream is at end of file,
+        * the value -1 is returned; otherwise, at least one byte is read and stored into b.
+        *
+        * The first byte read is stored into element b[off], the next one into b[off+1],
+        * and so on. The number of bytes read is, at most, equal to len. Let k be the number
+        * of bytes actually read; these bytes will be stored in elements b[off] through b[off+k-1],
+        * leaving elements b[off+k] through b[off+len-1] unaffected.
+        *
+        * In every case, elements b[0] through b[off] and elements b[off+len]
+        * through b[b.length-1] are unaffected.
+        *
+        * If the first byte cannot be read for any reason other than end of file,
+        * then an IOException is thrown. In particular, an IOException is thrown
+        * if the input stream has been closed.
+        *
+        * The read(b, off, len) method for class InputStream simply calls the method
+        * read() repeatedly. If the first such call results in an IOException,
+        * that exception is returned from the call to the read(b, off, len) method.
+        * If any subsequent call to read() results in a IOException, the exception
+        * is caught and treated as if it were end of file; the bytes read up to that
+        * point are stored into b and the number of bytes read before the exception
+        * occurred is returned. Subclasses are encouraged to provide a more efficient
+        * implementation of this method.
+        *
+        * @param b - the buffer into which the data is read.
+        * @param off - the start offset in array b  at which the data is written.
+        * @param len - the maximum number of bytes to read.
+        * @return the total number of bytes read into the buffer,
+        *         or -1 is there is no more data because the end
+        *         of the stream has been reached.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+       case 0:  // com/highqsoft/corbafileserver/generated/InputStreamIF/read
+       {
+         try {
+           com.highqsoft.corbafileserver.generated.DS_BYTEHolder b = new com.highqsoft.corbafileserver.generated.DS_BYTEHolder ();
+           int off = in.read_long ();
+           int len = in.read_long ();
+           int $result = (int)0;
+           $result = this.read (b, off, len);
+           out = $rh.createReply();
+           out.write_long ($result);
+           com.highqsoft.corbafileserver.generated.DS_BYTEHelper.write (out, b.value);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Close the input stream.
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+       case 1:  // com/highqsoft/corbafileserver/generated/InputStreamIF/close
+       {
+         try {
+           this.close ();
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Get the length of the input stream.
+        *
+        * @return the length of the file to be transferd.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+       case 2:  // com/highqsoft/corbafileserver/generated/InputStreamIF/length
+       {
+         try {
+           int $result = (int)0;
+           $result = this.length ();
+           out = $rh.createReply();
+           out.write_long ($result);
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+
+  /**
+        * Reset the stream
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+       case 3:  // com/highqsoft/corbafileserver/generated/InputStreamIF/reset
+       {
+         try {
+           this.reset ();
+           out = $rh.createReply();
+         } catch (com.highqsoft.corbafileserver.generated.CORBAFileServerException $ex) {
+           out = $rh.createExceptionReply ();
+           com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.write (out, $ex);
+         }
+         break;
+       }
+
+       default:
+         throw new org.omg.CORBA.BAD_OPERATION (0, org.omg.CORBA.CompletionStatus.COMPLETED_MAYBE);
+    }
+
+    return out;
+  } // _invoke
+
+  // Type-specific CORBA::Object operations
+  private static String[] __ids = {
+    "IDL:com/highqsoft/corbafileserver/generated/InputStreamIF:1.0"};
+
+  public String[] _all_interfaces (org.omg.PortableServer.POA poa, byte[] objectId)
+  {
+    return (String[])__ids.clone ();
+  }
+
+  public InputStreamIF _this() 
+  {
+    return InputStreamIFHelper.narrow(
+    super._this_object());
+  }
+
+  public InputStreamIF _this(org.omg.CORBA.ORB orb) 
+  {
+    return InputStreamIFHelper.narrow(
+    super._this_object(orb));
+  }
+
+
+} // class InputStreamIFPOA
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFPOATie.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFPOATie.java
new file mode 100644
index 0000000..75650cd
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/InputStreamIFPOATie.java
@@ -0,0 +1,128 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/InputStreamIFPOATie.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public class InputStreamIFPOATie extends InputStreamIFPOA
+{
+
+  // Constructors
+
+  public InputStreamIFPOATie ( com.highqsoft.corbafileserver.generated.InputStreamIFOperations delegate ) {
+      this._impl = delegate;
+  }
+  public InputStreamIFPOATie ( com.highqsoft.corbafileserver.generated.InputStreamIFOperations delegate , org.omg.PortableServer.POA poa ) {
+      this._impl = delegate;
+      this._poa      = poa;
+  }
+  public com.highqsoft.corbafileserver.generated.InputStreamIFOperations _delegate() {
+      return this._impl;
+  }
+  public void _delegate (com.highqsoft.corbafileserver.generated.InputStreamIFOperations delegate ) {
+      this._impl = delegate;
+  }
+  public org.omg.PortableServer.POA _default_POA() {
+      if(_poa != null) {
+          return _poa;
+      }
+      else {
+          return super._default_POA();
+      }
+  }
+
+  /**
+        * Reads up to len bytes of data from the input stream into an array
+        * of bytes. An attempt is made to read as many as len bytes, but a
+        * smaller number may be read, possibly zero. The number of bytes
+        * actually read is returned as an integer.
+        *
+        * This method blocks until input data is available, end of file
+        * is detected, or an exception is thrown.
+        *
+        * If b is null, a NullPointerException is thrown.
+        *
+        * If off is negative, or len is negative, or off+len is greater
+        * than the length of the array b, then an IndexOutOfBoundsException is thrown.
+        *
+        * If len is zero, then no bytes are read and 0 is returned;
+        * otherwise, there is an attempt to read at least one byte.
+        * If no byte is available because the stream is at end of file,
+        * the value -1 is returned; otherwise, at least one byte is read and stored into b.
+        *
+        * The first byte read is stored into element b[off], the next one into b[off+1],
+        * and so on. The number of bytes read is, at most, equal to len. Let k be the number
+        * of bytes actually read; these bytes will be stored in elements b[off] through b[off+k-1],
+        * leaving elements b[off+k] through b[off+len-1] unaffected.
+        *
+        * In every case, elements b[0] through b[off] and elements b[off+len]
+        * through b[b.length-1] are unaffected.
+        *
+        * If the first byte cannot be read for any reason other than end of file,
+        * then an IOException is thrown. In particular, an IOException is thrown
+        * if the input stream has been closed.
+        *
+        * The read(b, off, len) method for class InputStream simply calls the method
+        * read() repeatedly. If the first such call results in an IOException,
+        * that exception is returned from the call to the read(b, off, len) method.
+        * If any subsequent call to read() results in a IOException, the exception
+        * is caught and treated as if it were end of file; the bytes read up to that
+        * point are stored into b and the number of bytes read before the exception
+        * occurred is returned. Subclasses are encouraged to provide a more efficient
+        * implementation of this method.
+        *
+        * @param b - the buffer into which the data is read.
+        * @param off - the start offset in array b  at which the data is written.
+        * @param len - the maximum number of bytes to read.
+        * @return the total number of bytes read into the buffer,
+        *         or -1 is there is no more data because the end
+        *         of the stream has been reached.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public int read (com.highqsoft.corbafileserver.generated.DS_BYTEHolder b, int off, int len) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.read(b, off, len);
+  } // read
+
+
+  /**
+        * Close the input stream.
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public void close () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.close();
+  } // close
+
+
+  /**
+        * Get the length of the input stream.
+        *
+        * @return the length of the file to be transferd.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public int length () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    return _impl.length();
+  } // length
+
+
+  /**
+        * Reset the stream
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public void reset () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+    _impl.reset();
+  } // reset
+
+  private com.highqsoft.corbafileserver.generated.InputStreamIFOperations _impl;
+  private org.omg.PortableServer.POA _poa;
+
+} // class InputStreamIFPOATie
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/LONG_ARRAYHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/LONG_ARRAYHelper.java
new file mode 100644
index 0000000..76ba344
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/LONG_ARRAYHelper.java
@@ -0,0 +1,60 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/LONG_ARRAYHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+abstract public class LONG_ARRAYHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/LONG_ARRAY:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, long[] that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static long[] extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      __typeCode = org.omg.CORBA.ORB.init ().get_primitive_tc (org.omg.CORBA.TCKind.tk_longlong);
+      __typeCode = org.omg.CORBA.ORB.init ().create_sequence_tc (0, __typeCode);
+      __typeCode = org.omg.CORBA.ORB.init ().create_alias_tc (com.highqsoft.corbafileserver.generated.LONG_ARRAYHelper.id (), "LONG_ARRAY", __typeCode);
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static long[] read (org.omg.CORBA.portable.InputStream istream)
+  {
+    long value[] = null;
+    int _len0 = istream.read_long ();
+    value = new long[_len0];
+    istream.read_longlong_array (value, 0, _len0);
+    return value;
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, long[] value)
+  {
+    ostream.write_long (value.length);
+    ostream.write_longlong_array (value, 0, value.length);
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/LONG_ARRAYHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/LONG_ARRAYHolder.java
new file mode 100644
index 0000000..d3ab069
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/LONG_ARRAYHolder.java
@@ -0,0 +1,39 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/LONG_ARRAYHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public final class LONG_ARRAYHolder implements org.omg.CORBA.portable.Streamable
+{
+  public long value[] = null;
+
+  public LONG_ARRAYHolder ()
+  {
+  }
+
+  public LONG_ARRAYHolder (long[] initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.LONG_ARRAYHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.LONG_ARRAYHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.LONG_ARRAYHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlag.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlag.java
new file mode 100644
index 0000000..f91647f
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlag.java
@@ -0,0 +1,48 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/SeverityFlag.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+
+/**
+   * The error severity flags.
+   */
+public class SeverityFlag implements org.omg.CORBA.portable.IDLEntity
+{
+  private        int __value;
+  private static int __size = 4;
+  private static com.highqsoft.corbafileserver.generated.SeverityFlag[] __array = new com.highqsoft.corbafileserver.generated.SeverityFlag [__size];
+
+  public static final int _SUCCESS = 0;
+  public static final com.highqsoft.corbafileserver.generated.SeverityFlag SUCCESS = new com.highqsoft.corbafileserver.generated.SeverityFlag(_SUCCESS);
+  public static final int _INFORMATION = 1;
+  public static final com.highqsoft.corbafileserver.generated.SeverityFlag INFORMATION = new com.highqsoft.corbafileserver.generated.SeverityFlag(_INFORMATION);
+  public static final int _WARNING = 2;
+  public static final com.highqsoft.corbafileserver.generated.SeverityFlag WARNING = new com.highqsoft.corbafileserver.generated.SeverityFlag(_WARNING);
+  public static final int _ERROR = 3;
+  public static final com.highqsoft.corbafileserver.generated.SeverityFlag ERROR = new com.highqsoft.corbafileserver.generated.SeverityFlag(_ERROR);
+
+  public int value ()
+  {
+    return __value;
+  }
+
+  public static com.highqsoft.corbafileserver.generated.SeverityFlag from_int (int value)
+  {
+    if (value >= 0 && value < __size)
+      return __array[value];
+    else
+      throw new org.omg.CORBA.BAD_PARAM ();
+  }
+
+  protected SeverityFlag (int value)
+  {
+    __value = value;
+    __array[__value] = this;
+  }
+} // class SeverityFlag
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlagHelper.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlagHelper.java
new file mode 100644
index 0000000..28f7b5b
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlagHelper.java
@@ -0,0 +1,57 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/SeverityFlagHelper.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+
+/**
+   * The error severity flags.
+   */
+abstract public class SeverityFlagHelper
+{
+  private static String  _id = "IDL:com/highqsoft/corbafileserver/generated/SeverityFlag:1.0";
+
+  public static void insert (org.omg.CORBA.Any a, com.highqsoft.corbafileserver.generated.SeverityFlag that)
+  {
+    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();
+    a.type (type ());
+    write (out, that);
+    a.read_value (out.create_input_stream (), type ());
+  }
+
+  public static com.highqsoft.corbafileserver.generated.SeverityFlag extract (org.omg.CORBA.Any a)
+  {
+    return read (a.create_input_stream ());
+  }
+
+  private static org.omg.CORBA.TypeCode __typeCode = null;
+  synchronized public static org.omg.CORBA.TypeCode type ()
+  {
+    if (__typeCode == null)
+    {
+      __typeCode = org.omg.CORBA.ORB.init ().create_enum_tc (com.highqsoft.corbafileserver.generated.SeverityFlagHelper.id (), "SeverityFlag", new String[] { "SUCCESS", "INFORMATION", "WARNING", "ERROR"} );
+    }
+    return __typeCode;
+  }
+
+  public static String id ()
+  {
+    return _id;
+  }
+
+  public static com.highqsoft.corbafileserver.generated.SeverityFlag read (org.omg.CORBA.portable.InputStream istream)
+  {
+    return com.highqsoft.corbafileserver.generated.SeverityFlag.from_int (istream.read_long ());
+  }
+
+  public static void write (org.omg.CORBA.portable.OutputStream ostream, com.highqsoft.corbafileserver.generated.SeverityFlag value)
+  {
+    ostream.write_long (value.value ());
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlagHolder.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlagHolder.java
new file mode 100644
index 0000000..1c0f790
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/SeverityFlagHolder.java
@@ -0,0 +1,42 @@
+package com.highqsoft.corbafileserver.generated;
+
+/**
+* com/highqsoft/corbafileserver/generated/SeverityFlagHolder.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+
+/**
+   * The error severity flags.
+   */
+public final class SeverityFlagHolder implements org.omg.CORBA.portable.Streamable
+{
+  public com.highqsoft.corbafileserver.generated.SeverityFlag value = null;
+
+  public SeverityFlagHolder ()
+  {
+  }
+
+  public SeverityFlagHolder (com.highqsoft.corbafileserver.generated.SeverityFlag initialValue)
+  {
+    value = initialValue;
+  }
+
+  public void _read (org.omg.CORBA.portable.InputStream i)
+  {
+    value = com.highqsoft.corbafileserver.generated.SeverityFlagHelper.read (i);
+  }
+
+  public void _write (org.omg.CORBA.portable.OutputStream o)
+  {
+    com.highqsoft.corbafileserver.generated.SeverityFlagHelper.write (o, value);
+  }
+
+  public org.omg.CORBA.TypeCode _type ()
+  {
+    return com.highqsoft.corbafileserver.generated.SeverityFlagHelper.type ();
+  }
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/_CORBAFileServerIFStub.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/_CORBAFileServerIFStub.java
new file mode 100644
index 0000000..fd7e9f7
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/_CORBAFileServerIFStub.java
@@ -0,0 +1,1136 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/_CORBAFileServerIFStub.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public class _CORBAFileServerIFStub extends org.omg.CORBA.portable.ObjectImpl implements com.highqsoft.corbafileserver.generated.CORBAFileServerIF
+{
+
+
+  /**
+        * Save the data associated with the given intput stream.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  public String save (org.asam.ods.AoSession aoSess, String name, String subDir, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("save", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (subDir);
+                com.highqsoft.corbafileserver.generated.InputStreamIFHelper.write ($out, stream);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return save (aoSess, name, subDir, stream        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // save
+
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  public String saveForInstance (org.asam.ods.AoSession aoSess, String name, String subDir, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("saveForInstance", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (subDir);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                com.highqsoft.corbafileserver.generated.InputStreamIFHelper.write ($out, stream);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return saveForInstance (aoSess, name, subDir, aid, iid, stream        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // saveForInstance
+
+
+  /**
+        * Save the data associated with the given intput stream.
+        * Specify the name of an applciation element and the name of the instance element
+        * that holds the external reference
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  subDir an alternative sub directory, that can be specified,
+        *                if the filename should not used to determine the destination folder.
+        * @param  aeName the application element name.
+        * @param  ieName the instance element name.
+        * @param  stream the input stream, ready to read by the server.
+        * @return the url string of the created file.
+        */
+  public String saveForInstanceName (org.asam.ods.AoSession aoSess, String name, String subDir, String aeName, String ieName, com.highqsoft.corbafileserver.generated.InputStreamIF stream) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("saveForInstanceName", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (subDir);
+                $out.write_string (aeName);
+                $out.write_string (ieName);
+                com.highqsoft.corbafileserver.generated.InputStreamIFHelper.write ($out, stream);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return saveForInstanceName (aoSess, name, subDir, aeName, ieName, stream        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // saveForInstanceName
+
+
+  /**
+        * Delete the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        */
+  public void delete (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("delete", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                delete (aoSess, name        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // delete
+
+
+  /**
+        * Move the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  urlo the url of the file.
+        */
+  public void move (org.asam.ods.AoSession aoSess, String url) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("move", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (url);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                move (aoSess, url        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // move
+
+
+  /**
+        * Delete the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  url the url of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+  public void deleteForInstance (org.asam.ods.AoSession aoSess, String url, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("deleteForInstance", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (url);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                deleteForInstance (aoSess, url, aid, iid        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // deleteForInstance
+
+
+  /**
+        * Move the data associated with the given name.
+        * Specify the ApplicationElement id and the InstanceElement id
+        * of the component that holds the external reference.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        */
+  public void moveForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("moveForInstance", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                moveForInstance (aoSess, name, aid, iid        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // moveForInstance
+
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+  public void getBySocket (org.asam.ods.AoSession aoSess, String name, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getBySocket", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (host);
+                $out.write_long (aPort);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                getBySocket (aoSess, name, host, aPort        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getBySocket
+
+
+  /**
+         * Get the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the url specification of the file.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         */
+  public void getForInstanceBySocket (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getForInstanceBySocket", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                $out.write_string (host);
+                $out.write_long (aPort);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                getForInstanceBySocket (aoSess, name, aid, iid, host, aPort        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getForInstanceBySocket
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  public String saveBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("saveBySocket", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (subDir);
+                $out.write_string (host);
+                $out.write_long (aPort);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return saveBySocket (aoSess, name, subDir, host, aPort        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // saveBySocket
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aid the application element id.
+         * @param  iid the instance element id.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  public String saveForInstanceBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("saveForInstanceBySocket", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (subDir);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                $out.write_string (host);
+                $out.write_long (aPort);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return saveForInstanceBySocket (aoSess, name, subDir, aid, iid, host, aPort        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // saveForInstanceBySocket
+
+
+  /**
+         * Save the data using a socket.
+         *
+         * @throws CORBAFileServerException
+         * with the following possible error codes:
+         *    FILESERVER_CONNECT_FAILED
+         *    FILESERVER_BAD_PARAMETER
+         *    FILESERVER_CONNECTION_LOST
+         *    FILESERVER_IMPLEMENTATION_PROBLEM
+         *    FILESERVER_NOT_IMPLEMENTED
+         *    FILESERVER_NO_MEMORY
+         *
+         * @param  aoSess the ASAM ODS session.
+         * @param  name the name of the file.
+         * @param  subDir an alternative sub directory, that can be specified,
+         *                if the filename should not used to determine the destination folder.
+         * @param  aeName the application element name.
+         * @param  ieName the instance element name.
+         * @param  host the hostname for the socket connection.
+         * @param  port the port for the socket connection.
+         * @return the url string of the created file.
+         */
+  public String saveForInstanceNameBySocket (org.asam.ods.AoSession aoSess, String name, String subDir, String aeName, String ieName, String host, int aPort) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("saveForInstanceNameBySocket", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (subDir);
+                $out.write_string (aeName);
+                $out.write_string (ieName);
+                $out.write_string (host);
+                $out.write_long (aPort);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return saveForInstanceNameBySocket (aoSess, name, subDir, aeName, ieName, host, aPort        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // saveForInstanceNameBySocket
+
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  stream the input stream, ready to read by the server.
+        */
+  public com.highqsoft.corbafileserver.generated.InputStreamIF read (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("read", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $in = _invoke ($out);
+                com.highqsoft.corbafileserver.generated.InputStreamIF $result = com.highqsoft.corbafileserver.generated.InputStreamIFHelper.read ($in);
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return read (aoSess, name        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // read
+
+
+  /**
+        * Read the data associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  stream the input stream, ready to read by the server.
+        */
+  public com.highqsoft.corbafileserver.generated.InputStreamIF readForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("readForInstance", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                $in = _invoke ($out);
+                com.highqsoft.corbafileserver.generated.InputStreamIF $result = com.highqsoft.corbafileserver.generated.InputStreamIFHelper.read ($in);
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return readForInstance (aoSess, name, aid, iid        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // readForInstance
+
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  size the size of the input stream.
+        */
+  public long getSize (org.asam.ods.AoSession aoSess, String name) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getSize", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $in = _invoke ($out);
+                long $result = $in.read_longlong ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return getSize (aoSess, name        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getSize
+
+
+  /**
+        *  Get size of the file associated with the given name.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  size the size of the input stream.
+        */
+  public long getSizeForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getSizeForInstance", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                $in = _invoke ($out);
+                long $result = $in.read_longlong ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return getSizeForInstance (aoSess, name, aid, iid        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getSizeForInstance
+
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+  public void terminate (org.asam.ods.AoSession aoSess, String name, String parameter) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("terminate", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                $out.write_string (parameter);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                terminate (aoSess, name, parameter        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // terminate
+
+
+  /**
+        * This method can be called by the client when the server should be start a termination process.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECT_FAILED
+        *    FILESERVER_BAD_PARAMETER
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param  name the name of the file.
+        * @param  aid the application element id.
+        * @param  iid the instance element id.
+        * @param  parameter the parameter string. The content depends on the
+        *         server side terminate implementation.
+        */
+  public void terminateForInstance (org.asam.ods.AoSession aoSess, String name, org.asam.ods.T_LONGLONG aid, org.asam.ods.T_LONGLONG iid, String parameter) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("terminateForInstance", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (name);
+                org.asam.ods.T_LONGLONGHelper.write ($out, aid);
+                org.asam.ods.T_LONGLONGHelper.write ($out, iid);
+                $out.write_string (parameter);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                terminateForInstance (aoSess, name, aid, iid, parameter        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // terminateForInstance
+
+
+  /**
+        * Get the name of the host where the server is running
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return the hostname
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public String getHostname (org.asam.ods.AoSession aoSess) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getHostname", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return getHostname (aoSess        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getHostname
+
+
+  /**
+        * Get a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @return the context value
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY,
+        *    FILESERVER_NOT_FOUND
+        */
+  public String getContext (org.asam.ods.AoSession aoSess, String key) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getContext", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (key);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return getContext (aoSess, key        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getContext
+
+
+  /**
+        * Set a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @param value the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public void setContext (org.asam.ods.AoSession aoSess, String key, String value) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("setContext", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (key);
+                $out.write_string (value);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                setContext (aoSess, key, value        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // setContext
+
+
+  /**
+        * Remove a context variable.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @param key the keyword of the context value.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public void removeContext (org.asam.ods.AoSession aoSess, String key) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("removeContext", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $out.write_string (key);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                removeContext (aoSess, key        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // removeContext
+
+
+  /**
+        * List all context keywords.
+        *
+        * @param  aoSess the ASAM ODS session.
+        * @return a sequence of strings.
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        */
+  public String[] listContext (org.asam.ods.AoSession aoSess) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("listContext", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                $in = _invoke ($out);
+                String $result[] = com.highqsoft.corbafileserver.generated.DS_STRINGHelper.read ($in);
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return listContext (aoSess        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // listContext
+
+
+  /**
+        * Get the version of the CorbaFileServerIF.
+        * Returns getVersion of CorbaFileServer.
+        *
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        * @return  The interface version of the CorbaFileServerIF.
+        *
+        */
+  public String getInterfaceVersion () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getInterfaceVersion", true);
+                $in = _invoke ($out);
+                String $result = $in.read_string ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return getInterfaceVersion (        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getInterfaceVersion
+
+
+  /**
+        * Returns an array of long values representing the length
+        * of the files that were provided in the String array.
+        * The order of the long values must match with the order
+        * of the filenames.
+        *
+        * @param aoSess the aoSession of the caller
+        * @param names the String array of filenames for 
+        *              which to get the sizes
+        * @return an Array of long values containing the file sizes
+        * @throws CORBAFileServerException
+        * with the following possible error codes:
+        *    FILESERVER_CONNECTION_LOST
+        *    FILESERVER_IMPLEMENTATION_PROBLEM
+        *    FILESERVER_NOT_IMPLEMENTED
+        *    FILESERVER_NO_MEMORY
+        *
+        *
+        */
+  public long[] getSizes (org.asam.ods.AoSession aoSess, String[] names) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("getSizes", true);
+                org.asam.ods.AoSessionHelper.write ($out, aoSess);
+                com.highqsoft.corbafileserver.generated.DS_STRINGHelper.write ($out, names);
+                $in = _invoke ($out);
+                long $result[] = com.highqsoft.corbafileserver.generated.LONG_ARRAYHelper.read ($in);
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return getSizes (aoSess, names        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // getSizes
+
+  // Type-specific CORBA::Object operations
+  private static String[] __ids = {
+    "IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerIF:1.0"};
+
+  public String[] _ids ()
+  {
+    return (String[])__ids.clone ();
+  }
+
+  private void readObject (java.io.ObjectInputStream s) throws java.io.IOException
+  {
+     String str = s.readUTF ();
+     String[] args = null;
+     java.util.Properties props = null;
+     org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props);
+   try {
+     org.omg.CORBA.Object obj = orb.string_to_object (str);
+     org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl) obj)._get_delegate ();
+     _set_delegate (delegate);
+   } finally {
+     orb.destroy() ;
+   }
+  }
+
+  private void writeObject (java.io.ObjectOutputStream s) throws java.io.IOException
+  {
+     String[] args = null;
+     java.util.Properties props = null;
+     org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props);
+   try {
+     String str = orb.object_to_string (this);
+     s.writeUTF (str);
+   } finally {
+     orb.destroy() ;
+   }
+  }
+} // class _CORBAFileServerIFStub
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/_InputStreamIFStub.java b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/_InputStreamIFStub.java
new file mode 100644
index 0000000..e6a97ec
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/com/highqsoft/corbafileserver/generated/_InputStreamIFStub.java
@@ -0,0 +1,207 @@
+package com.highqsoft.corbafileserver.generated;
+
+
+/**
+* com/highqsoft/corbafileserver/generated/_InputStreamIFStub.java .
+* Generated by the IDL-to-Java compiler (portable), version "3.2"
+* from src/main/idl/corbafileserver.idl
+* Donnerstag, 16. Juni 2016 10:30 Uhr MESZ
+*/
+
+public class _InputStreamIFStub extends org.omg.CORBA.portable.ObjectImpl implements com.highqsoft.corbafileserver.generated.InputStreamIF
+{
+
+
+  /**
+        * Reads up to len bytes of data from the input stream into an array
+        * of bytes. An attempt is made to read as many as len bytes, but a
+        * smaller number may be read, possibly zero. The number of bytes
+        * actually read is returned as an integer.
+        *
+        * This method blocks until input data is available, end of file
+        * is detected, or an exception is thrown.
+        *
+        * If b is null, a NullPointerException is thrown.
+        *
+        * If off is negative, or len is negative, or off+len is greater
+        * than the length of the array b, then an IndexOutOfBoundsException is thrown.
+        *
+        * If len is zero, then no bytes are read and 0 is returned;
+        * otherwise, there is an attempt to read at least one byte.
+        * If no byte is available because the stream is at end of file,
+        * the value -1 is returned; otherwise, at least one byte is read and stored into b.
+        *
+        * The first byte read is stored into element b[off], the next one into b[off+1],
+        * and so on. The number of bytes read is, at most, equal to len. Let k be the number
+        * of bytes actually read; these bytes will be stored in elements b[off] through b[off+k-1],
+        * leaving elements b[off+k] through b[off+len-1] unaffected.
+        *
+        * In every case, elements b[0] through b[off] and elements b[off+len]
+        * through b[b.length-1] are unaffected.
+        *
+        * If the first byte cannot be read for any reason other than end of file,
+        * then an IOException is thrown. In particular, an IOException is thrown
+        * if the input stream has been closed.
+        *
+        * The read(b, off, len) method for class InputStream simply calls the method
+        * read() repeatedly. If the first such call results in an IOException,
+        * that exception is returned from the call to the read(b, off, len) method.
+        * If any subsequent call to read() results in a IOException, the exception
+        * is caught and treated as if it were end of file; the bytes read up to that
+        * point are stored into b and the number of bytes read before the exception
+        * occurred is returned. Subclasses are encouraged to provide a more efficient
+        * implementation of this method.
+        *
+        * @param b - the buffer into which the data is read.
+        * @param off - the start offset in array b  at which the data is written.
+        * @param len - the maximum number of bytes to read.
+        * @return the total number of bytes read into the buffer,
+        *         or -1 is there is no more data because the end
+        *         of the stream has been reached.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public int read (com.highqsoft.corbafileserver.generated.DS_BYTEHolder b, int off, int len) throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("read", true);
+                $out.write_long (off);
+                $out.write_long (len);
+                $in = _invoke ($out);
+                int $result = $in.read_long ();
+                b.value = com.highqsoft.corbafileserver.generated.DS_BYTEHelper.read ($in);
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return read (b, off, len        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // read
+
+
+  /**
+        * Close the input stream.
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public void close () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("close", true);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                close (        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // close
+
+
+  /**
+        * Get the length of the input stream.
+        *
+        * @return the length of the file to be transferd.
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public int length () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("length", true);
+                $in = _invoke ($out);
+                int $result = $in.read_long ();
+                return $result;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                return length (        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // length
+
+
+  /**
+        * Reset the stream
+        *
+        * @throws CORBAFileServerException if an IO exception occurs.
+        */
+  public void reset () throws com.highqsoft.corbafileserver.generated.CORBAFileServerException
+  {
+            org.omg.CORBA.portable.InputStream $in = null;
+            try {
+                org.omg.CORBA.portable.OutputStream $out = _request ("reset", true);
+                $in = _invoke ($out);
+                return;
+            } catch (org.omg.CORBA.portable.ApplicationException $ex) {
+                $in = $ex.getInputStream ();
+                String _id = $ex.getId ();
+                if (_id.equals ("IDL:com/highqsoft/corbafileserver/generated/CORBAFileServerException:1.0"))
+                    throw com.highqsoft.corbafileserver.generated.CORBAFileServerExceptionHelper.read ($in);
+                else
+                    throw new org.omg.CORBA.MARSHAL (_id);
+            } catch (org.omg.CORBA.portable.RemarshalException $rm) {
+                reset (        );
+            } finally {
+                _releaseReply ($in);
+            }
+  } // reset
+
+  // Type-specific CORBA::Object operations
+  private static String[] __ids = {
+    "IDL:com/highqsoft/corbafileserver/generated/InputStreamIF:1.0"};
+
+  public String[] _ids ()
+  {
+    return (String[])__ids.clone ();
+  }
+
+  private void readObject (java.io.ObjectInputStream s) throws java.io.IOException
+  {
+     String str = s.readUTF ();
+     String[] args = null;
+     java.util.Properties props = null;
+     org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props);
+   try {
+     org.omg.CORBA.Object obj = orb.string_to_object (str);
+     org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl) obj)._get_delegate ();
+     _set_delegate (delegate);
+   } finally {
+     orb.destroy() ;
+   }
+  }
+
+  private void writeObject (java.io.ObjectOutputStream s) throws java.io.IOException
+  {
+     String[] args = null;
+     java.util.Properties props = null;
+     org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init (args, props);
+   try {
+     String str = orb.object_to_string (this);
+     s.writeUTF (str);
+   } finally {
+     orb.destroy() ;
+   }
+  }
+} // class _InputStreamIFStub
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java
new file mode 100644
index 0000000..2e40f5c
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContext.java
@@ -0,0 +1,230 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.asam.ods.AoException;
+import org.asam.ods.AoSession;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.file.FileService;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.odsadapter.filetransfer.CORBAFileService;
+import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
+import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
+import org.eclipse.mdm.api.odsadapter.notification.ODSNotificationServiceFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.query.ODSQueryService;
+import org.eclipse.mdm.api.odsadapter.search.ODSSearchService;
+import org.omg.CORBA.ORB;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.highqsoft.corbafileserver.generated.CORBAFileServerIF;
+
+/**
+ * ODSContext encapsulates a session to the ASAM ODS CORBA API and provides the
+ * ODS specific services implementations.
+ *
+ * @since 1.0.0
+ */
+public class ODSContext implements ApplicationContext {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSContext.class);
+
+	private Map<String, String> parameters;
+	private final Transfer transfer = Transfer.SOCKET;
+
+	private CORBAFileServerIF fileServer;
+	private ODSModelManager modelManager;
+	private ODSQueryService queryService;
+	private EntityLoader entityLoader;
+	private ODSEntityManager entityManager;
+	private ODSSearchService searchService;
+
+	/**
+	 * Creates a new ODS application context.
+	 * 
+	 * @param orb        the CORBA ORB used to connect to the ODS API
+	 * @param aoSession
+	 * @param fileServer
+	 * @param parameters
+	 * @throws AoException
+	 */
+	public ODSContext(ORB orb, AoSession aoSession, CORBAFileServerIF fileServer, Map<String, String> parameters)
+			throws AoException {
+		this.fileServer = fileServer;
+		this.parameters = parameters;
+
+		this.modelManager = new ODSModelManager(orb, aoSession);
+		this.queryService = new ODSQueryService(this.modelManager);
+		this.entityManager = new ODSEntityManager(this);
+		this.entityLoader = new EntityLoader(modelManager, queryService);
+		this.searchService = new ODSSearchService(this, queryService, entityLoader);
+		LOGGER.debug("ODSContext initialized.");
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<EntityManager> getEntityManager() {
+		return Optional.of(entityManager);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<EntityFactory> getEntityFactory() {
+		try {
+			return Optional.of(new ODSEntityFactory(modelManager, entityManager.loadLoggedOnUser()));
+		} catch (DataAccessException e) {
+			throw new IllegalStateException("Unable to load instance of the logged in user.");
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<ModelManager> getModelManager() {
+		return Optional.of(modelManager);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<QueryService> getQueryService() {
+		// TODO
+		// java docs: cache this service for ONE request!
+		return Optional.of(new ODSQueryService(modelManager));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<SearchService> getSearchService() {
+		return Optional.of(searchService);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<FileService> getFileService() {
+		if (fileServer == null) {
+			return Optional.empty();
+		}
+		return Optional.of(new CORBAFileService(this, transfer));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<NotificationService> getNotificationService() {
+		try {
+			return Optional.of(new ODSNotificationServiceFactory().create(this, parameters));
+		} catch (ConnectionException e) {
+			throw new IllegalStateException("Unable to create notification manager.", e);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<String, String> getParameters() {
+		return parameters;
+	}
+
+	/**
+	 * @returns the string "ods"
+	 */
+	@Override
+	public String getAdapterType() {
+		return "ods";
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void close() {
+		try {
+			modelManager.close();
+		} catch (AoException e) {
+			LOGGER.warn("Unable to close sesssion due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Returns the {@link ODSModelManager} used for this context.
+	 * 
+	 * @return the {@link ODSModelManager}
+	 */
+	public ODSModelManager getODSModelManager() {
+		return modelManager;
+	}
+
+	/**
+	 * Returns the {@link AoSession} used for this context.
+	 * 
+	 * @return {@link AoSession} used for this context.
+	 */
+	public AoSession getAoSession() {
+		return modelManager.getAoSession();
+	}
+
+	/**
+	 * Returns the ORB used for this context
+	 * 
+	 * @return ORB used for this context
+	 */
+	public ORB getORB() {
+		return modelManager.getORB();
+	}
+
+	/**
+	 * Returns the {@link CORBAFileServerIF}.
+	 *
+	 * @return The {@code CORBAFileServerIF} is returned or null, if missing.
+	 */
+	public CORBAFileServerIF getFileServer() {
+		return fileServer;
+	}
+
+	/**
+	 * Returns a new {@link ODSContext} with a new ODS co-session.
+	 *
+	 * @return The created {@code ODSContext} is returned.
+	 * @throws AoException Thrown on errors.
+	 */
+	public ODSContext newContext() throws AoException {
+		return new ODSContext(modelManager.getORB(), getAoSession().createCoSession(), fileServer, parameters);
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
new file mode 100644
index 0000000..0310632
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSContextFactory.java
@@ -0,0 +1,237 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.asam.ods.AoException;
+import org.asam.ods.AoFactory;
+import org.asam.ods.AoFactoryHelper;
+import org.asam.ods.AoSession;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.ApplicationContextFactory;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Object;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContextExt;
+import org.omg.CosNaming.NamingContextExtHelper;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+import com.highqsoft.corbafileserver.generated.CORBAFileServerIF;
+import com.highqsoft.corbafileserver.generated.CORBAFileServerIFHelper;
+
+/**
+ * ASAM ODS implementation of the {@link ApplicationContextFactory} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ODSContextFactory implements ApplicationContextFactory {
+
+	public static final String PARAM_NAMESERVICE = "nameservice";
+
+	public static final String PARAM_SERVICENAME = "servicename";
+
+	public static final String PARAM_USER = "user";
+
+	public static final String PARAM_PASSWORD = "password";
+
+	private static final String PARAM_FOR_USER = "for_user";
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSContextFactory.class);
+
+	private static final ORB orb = ORB.init(new String[] {}, System.getProperties());
+
+	public ODSContextFactory() {
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * <p>
+	 * <b>Note:</b> Given parameters {@code Map} must contain values for each of the
+	 * following keys:
+	 *
+	 * <ul>
+	 * <li>{@value #PARAM_NAMESERVICE}</li>
+	 * <li>{@value #PARAM_SERVICENAME}</li>
+	 * <li>{@value #PARAM_USER}</li>
+	 * <li>{@value #PARAM_PASSWORD}</li>
+	 * </ul>
+	 *
+	 * Listed names are available via public fields of this class.
+	 */
+	@Override
+	public ApplicationContext connect(Map<String, String> parameters) throws ConnectionException {
+		AoSession aoSession = null;
+		try (ServiceLocator serviceLocator = new ServiceLocator(orb, getParameter(parameters, PARAM_NAMESERVICE))) {
+			String nameOfService = getParameter(parameters, PARAM_SERVICENAME).replace(".ASAM-ODS", "");
+
+			AoFactory aoFactory = serviceLocator.resolveFactory(nameOfService);
+			String aoFactoryName = aoFactory.getName();
+			LOGGER.info("Connecting to ODS Server (name: {}, description: {}, interface version: {}, type: {}) ...",
+					aoFactoryName, aoFactory.getDescription(), aoFactory.getInterfaceVersion(), aoFactory.getType());
+
+			// Create a parameters map without password (which should not be visible from
+			// this point onwards),
+			// leaving the original map untouched:
+			Map<String, String> parametersWithoutPassword = new HashMap<>(parameters);
+			if (LOGGER.isDebugEnabled()) {
+				parametersWithoutPassword.put(PARAM_PASSWORD, "****");
+				LOGGER.debug("Connecting to ODS using the connection parameters: {}",
+						sessionParametersAsString(parametersWithoutPassword));
+			}
+			parametersWithoutPassword.remove(PARAM_PASSWORD);
+
+			aoSession = aoFactory.newSession(sessionParametersAsString(parameters));
+
+			LOGGER.info("Connection to ODS server '{}' established.", aoFactoryName);
+
+			CORBAFileServerIF fileServer = serviceLocator.resolveFileServer(nameOfService);
+
+			return new ODSContext(orb, aoSession, fileServer, parametersWithoutPassword);
+		} catch (AoException e) {
+			closeSession(aoSession);
+			throw new ConnectionException("Unable to connect to ODS server due to: " + e.reason, e);
+		}
+	}
+
+	private String sessionParametersAsString(Map<String, String> parameters) throws ConnectionException {
+		ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder()
+				.put("USER", getParameter(parameters, PARAM_USER))
+				.put("PASSWORD", getParameter(parameters, PARAM_PASSWORD)).put("CREATE_COSESSION_ALLOWED", "TRUE");
+
+		String forUserName = parameters.get(PARAM_FOR_USER);
+		if (!Strings.isNullOrEmpty(forUserName)) {
+			builder.put("FOR_USER", forUserName);
+		}
+		return Joiner.on(",").withKeyValueSeparator("=").join(builder.build());
+	}
+
+	/**
+	 * Closes given {@link AoSession} with catching and logging errors.
+	 *
+	 * @param aoSession The {@code AoSession} that shall be closed.
+	 */
+	private static void closeSession(AoSession aoSession) {
+		if (aoSession == null) {
+			return;
+		}
+
+		try {
+			aoSession.close();
+		} catch (AoException e) {
+			LOGGER.warn("Unable to close sesssion due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Reads the property identified by given property name.
+	 *
+	 * @param parameters The properties {@code Map}.
+	 * @param name       The property name.
+	 * @return The property value is returned.
+	 * @throws ConnectionException Thrown if property does not exist or is empty.
+	 */
+	private static String getParameter(Map<String, String> parameters, String name) throws ConnectionException {
+		String value = parameters.get(name);
+		if (value == null || value.isEmpty()) {
+			throw new ConnectionException("Connection parameter with name '" + name + "' is either missing or empty.");
+		}
+
+		return value;
+	}
+
+	/**
+	 * Used to resolve CORBA service object by ID and kind.
+	 */
+	private static final class ServiceLocator implements AutoCloseable {
+
+		private NamingContextExt namingContext;
+
+		/**
+		 * Constructor.
+		 *
+		 * @param orb  The {@link ORB} singleton instance.
+		 * @param path The naming context path.
+		 * @throws ConnectionException Thrown if unable to resolve the naming context.
+		 */
+		public ServiceLocator(ORB orb, String path) throws ConnectionException {
+			namingContext = NamingContextExtHelper.narrow(orb.string_to_object(path));
+			if (namingContext == null) {
+				throw new ConnectionException("Unable to resolve NameService '" + path + "'.");
+			}
+		}
+
+		/**
+		 * Resolves and returns the {@link AoFactory} service for given ID.
+		 *
+		 * @param id Used as identifier.
+		 * @return The {@code AoFactory} is returned.
+		 * @throws ConnectionException Thrown if unable to resolve the {@code
+		 * 		AoFactory}          .
+		 */
+		public AoFactory resolveFactory(String id) throws ConnectionException {
+			return AoFactoryHelper.narrow(resolve(id, "ASAM-ODS"));
+		}
+
+		/**
+		 * Resolves and returns the {@link CORBAFileServerIF} service for given ID.
+		 *
+		 * @param id Used as identifier.
+		 * @return The {@code CORBAFileServerIF} or null, if none found, is returned.
+		 */
+		public CORBAFileServerIF resolveFileServer(String id) {
+			try {
+				return CORBAFileServerIFHelper.narrow(resolve(id, "CORBA-FT"));
+			} catch (ConnectionException e) {
+				LOGGER.warn(e.getMessage());
+				return null;
+			}
+		}
+
+		/**
+		 * Resolves a CORBA service object for given id and kind.
+		 *
+		 * @param id   Used as identifier.
+		 * @param kind Used as qualifier.
+		 * @return The resolved CORBA service object is returned.
+		 * @throws ConnectionException Thrown in case of errors.
+		 */
+		public Object resolve(String id, String kind) throws ConnectionException {
+			try {
+				return namingContext.resolve(new NameComponent[] { new NameComponent(id, kind) });
+			} catch (NotFound | CannotProceed | InvalidName e) {
+				throw new ConnectionException("Unable to resolve service '" + id + "." + kind + "'.", e);
+			}
+		}
+
+		@Override
+		public void close() throws ConnectionException {
+			namingContext._release();
+		}
+
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
new file mode 100644
index 0000000..3be7627
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ODSEntityManager.java
@@ -0,0 +1,467 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.asam.ods.AoException;
+import org.asam.ods.ApplicationStructure;
+import org.asam.ods.ElemId;
+import org.asam.ods.InstanceElement;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.massdata.ReadRequest;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ContextDescribable;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Environment;
+import org.eclipse.mdm.api.base.model.MeasuredValues;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.JoinType;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.Classification;
+import org.eclipse.mdm.api.dflt.model.Status;
+import org.eclipse.mdm.api.dflt.model.TemplateTest;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
+import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
+import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.transaction.ODSTransaction;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ASAM ODS implementation of the {@link EntityManager} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ODSEntityManager implements EntityManager {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSEntityManager.class);
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+	private final Transfer transfer = Transfer.SOCKET;
+
+	private final ODSContext context;
+	private final ODSModelManager odsModelManager;
+	private final QueryService queryService;
+	private final EntityLoader entityLoader;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param context The {@link ODSContext}.
+	 */
+	public ODSEntityManager(ODSContext context) {
+		this.context = context;
+		this.odsModelManager = context.getODSModelManager();
+		this.queryService = context.getQueryService()
+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+		entityLoader = new EntityLoader(odsModelManager, queryService);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Environment loadEnvironment() throws DataAccessException {
+		List<Environment> environments = loadAll(Environment.class);
+		if (environments.size() != 1) {
+			throw new DataAccessException("Unable to laod the environment entity.");
+		}
+
+		return environments.get(0);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<User> loadLoggedOnUser() throws DataAccessException {
+		InstanceElement ieUser = null;
+		try {
+			ieUser = odsModelManager.getAoSession().getUser();
+			return Optional.of(
+					entityLoader.load(new Key<>(User.class), Long.toString(ODSConverter.fromODSLong(ieUser.getId()))));
+		} catch (AoException e) {
+			throw new DataAccessException("Unable to load the logged in user entity due to: " + e.reason, e);
+		} finally {
+			try {
+				if (ieUser != null) {
+					ieUser.destroy();
+					ieUser._release();
+				}
+			} catch (AoException aoe) {
+				LOGGER.warn("Unable to destroy the CORBA resource due to: " + aoe.reason, aoe);
+				ieUser._release();
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> List<T> load(Class<T> entityClass, Collection<String> instanceIDs)
+			throws DataAccessException {
+		return entityLoader.loadAll(new Key<>(entityClass), instanceIDs);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> List<T> load(Class<T> entityClass, ContextType contextType,
+			Collection<String> instanceIDs) throws DataAccessException {
+		return entityLoader.loadAll(new Key<>(entityClass, contextType), instanceIDs);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> Optional<T> loadParent(Entity child, Class<T> entityClass) throws DataAccessException {
+		EntityType parentEntityType = odsModelManager.getEntityType(entityClass);
+		EntityType childEntityType = odsModelManager.getEntityType(child);
+		Query query = queryService.createQuery().selectID(parentEntityType);
+
+		if (child instanceof Channel && ChannelGroup.class.equals(entityClass)) {
+			// this covers the gap between channel and channel group via local
+			// column
+			EntityType localColumnEntityType = odsModelManager.getEntityType("LocalColumn");
+			query.join(childEntityType, localColumnEntityType).join(localColumnEntityType, parentEntityType);
+		} else {
+			query.join(childEntityType, parentEntityType);
+		}
+
+		Optional<String> instanceID = query.fetchSingleton(Filter.idOnly(childEntityType, child.getID()))
+				.map(r -> r.getRecord(parentEntityType)).map(Record::getID);
+		if (instanceID.isPresent()) {
+			return Optional.of(entityLoader.load(new Key<>(entityClass), instanceID.get()));
+		}
+
+		return Optional.empty();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> List<T> loadAll(Class<T> entityClass, String pattern) throws DataAccessException {
+		return entityLoader.loadAll(new Key<>(entityClass), pattern);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends StatusAttachable> List<T> loadAll(Class<T> entityClass, Status status, String pattern)
+			throws DataAccessException {
+		EntityType entityType = odsModelManager.getEntityType(entityClass);
+		EntityType classificationType = odsModelManager.getEntityType(Classification.class);
+		EntityType statusEntityType = odsModelManager.getEntityType(status.getTypeName());
+
+		List<String> instanceIDs = queryService.createQuery().join(entityType, classificationType)
+				.join(classificationType, statusEntityType).selectID(entityType)
+				.fetch(Filter.and().id(statusEntityType, status.getID()).name(entityType, pattern)).stream()
+				.map(r -> r.getRecord(entityType)).map(Record::getID).collect(Collectors.toList());
+
+		return entityLoader.loadAll(new Key<>(entityClass), instanceIDs);
+	}
+
+	/*
+	 * @Override public List<Status> loadAllStatus(Class<? extends StatusAttachable>
+	 * entityClass, String pattern) throws DataAccessException { return
+	 * entityLoader.loadAll(new Key<>(Status.class, entityClass), pattern); }
+	 */
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> List<T> loadAll(Class<T> entityClass, ContextType contextType, String pattern)
+			throws DataAccessException {
+		return entityLoader.loadAll(new Key<>(entityClass, contextType), pattern);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> List<T> loadChildren(Entity parent, Class<T> entityClass, String pattern)
+			throws DataAccessException {
+		EntityType parentEntityType = odsModelManager.getEntityType(parent);
+		EntityType childEntityType = odsModelManager.getEntityType(entityClass);
+		Query query = queryService.createQuery();
+
+		if (parent instanceof ChannelGroup && Channel.class.equals(entityClass)) {
+			// this covers the gap between channel and channel group via local
+			// column
+			EntityType localColumnEntityType = odsModelManager.getEntityType("LocalColumn");
+			query.join(childEntityType, localColumnEntityType).join(localColumnEntityType, parentEntityType);
+		} else {
+			query.join(childEntityType, parentEntityType);
+		}
+
+		List<String> instanceIDs = query.selectID(childEntityType)
+				.fetch(Filter.and().id(parentEntityType, parent.getID()).name(childEntityType, pattern)).stream()
+				.map(r -> r.getRecord(childEntityType)).map(Record::getID).collect(Collectors.toList());
+		return entityLoader.loadAll(new Key<>(entityClass), instanceIDs);
+	}
+
+	// /**
+	// * {@inheritDoc}
+	// */
+	// @Override
+	// public <T extends StatusAttachable> List<T> loadChildren(Entity parent,
+	// Class<T> entityClass, Status status,
+	// String pattern) throws DataAccessException {
+	// EntityType parentEntityType = modelManager.getEntityType(parent);
+	// EntityType childEntityType = modelManager.getEntityType(entityClass);
+	// EntityType statusEntityType =
+	// modelManager.getEntityType(status.getTypeName());
+	//
+	// List<String> instanceIDs = modelManager.createQuery()
+	// .join(childEntityType, parentEntityType, statusEntityType)
+	// .selectID(childEntityType)
+	// .fetch(Filter.and()
+	// .id(parentEntityType, parent.getID())
+	// .id(statusEntityType, status.getID())
+	// .name(childEntityType, pattern))
+	// .stream().map(r ->
+	// r.getRecord(childEntityType)).map(Record::getID).collect(Collectors.toList());
+	//
+	// return entityLoader.loadAll(new Key<>(entityClass), instanceIDs);
+	// }
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<ContextType> loadContextTypes(ContextDescribable contextDescribable) throws DataAccessException {
+		EntityType contextDescribableEntityType = odsModelManager.getEntityType(contextDescribable);
+		Query query = queryService.createQuery();
+
+		Map<ContextType, EntityType> contextRootEntityTypes = new EnumMap<>(ContextType.class);
+		for (ContextType contextType : ContextType.values()) {
+			EntityType entityType = odsModelManager.getEntityType(ContextRoot.class, contextType);
+			contextRootEntityTypes.put(contextType, entityType);
+			query.join(contextDescribableEntityType.getRelation(entityType), JoinType.OUTER).selectID(entityType);
+		}
+
+		Optional<Result> result = query
+				.fetchSingleton(Filter.idOnly(contextDescribableEntityType, contextDescribable.getID()));
+		if (result.isPresent()) {
+			List<ContextType> contextTypes = new ArrayList<>();
+			for (Entry<ContextType, EntityType> entry : contextRootEntityTypes.entrySet()) {
+				Optional<String> instanceID = result.map(r -> r.getRecord(entry.getValue())).map(Record::getID);
+				if (instanceID.isPresent()) {
+					contextTypes.add(entry.getKey());
+				}
+			}
+
+			return contextTypes;
+		}
+
+		return Collections.emptyList();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<ContextType, ContextRoot> loadContexts(ContextDescribable contextDescribable,
+			ContextType... contextTypes) throws DataAccessException {
+		EntityType contextDescribableEntityType = odsModelManager.getEntityType(contextDescribable);
+		Query query = queryService.createQuery();
+
+		Map<ContextType, EntityType> contextRootEntityTypes = new EnumMap<>(ContextType.class);
+		for (ContextType contextType : contextTypes.length == 0 ? ContextType.values() : contextTypes) {
+			EntityType entityType = odsModelManager.getEntityType(ContextRoot.class, contextType);
+			contextRootEntityTypes.put(contextType, entityType);
+			query.join(contextDescribableEntityType.getRelation(entityType), JoinType.OUTER).selectID(entityType);
+		}
+
+		Optional<Result> result = query
+				.fetchSingleton(Filter.idOnly(contextDescribableEntityType, contextDescribable.getID()));
+		if (result.isPresent()) {
+			Map<ContextType, ContextRoot> contextRoots = new EnumMap<>(ContextType.class);
+			for (Entry<ContextType, EntityType> entry : contextRootEntityTypes.entrySet()) {
+				String instanceID = result.get().getRecord(entry.getValue()).getID();
+				if (ODSUtils.isValidID(instanceID)) {
+					contextRoots.put(entry.getKey(),
+							entityLoader.load(new Key<>(ContextRoot.class, entry.getKey()), instanceID));
+				}
+			}
+
+			return contextRoots;
+		}
+
+		return Collections.emptyMap();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public <T extends Entity> List<T> loadRelatedEntities(Entity entity, String relationName, Class<T> relatedClass) {
+		ODSEntityType entityType = ((ODSEntityType) context.getODSModelManager().getEntityType(entity));
+		ElemId elemId = new ElemId(entityType.getODSID(), ODSConverter.toODSID(entity.getID()));
+
+		try {
+			T_LONGLONG[] instanceIds = context.getAoSession().getApplElemAccess().getRelInst(elemId, relationName);
+			List<String> instanceIDs = Stream.of(instanceIds).map(ODSConverter::fromODSLong).map(l -> l.toString())
+					.collect(Collectors.toList());
+			return entityLoader.loadAll(new Key<>(relatedClass), instanceIDs);
+		} catch (AoException e) {
+			throw new DataAccessException("" + e.reason, e); // TODO
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<MeasuredValues> readMeasuredValues(ReadRequest readRequest) throws DataAccessException {
+		return new ReadRequestHandler(odsModelManager, queryService).execute(readRequest);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Transaction startTransaction() throws DataAccessException {
+		try {
+			return new ODSTransaction(context, loadEnvironment(), transfer);
+		} catch (AoException e) {
+			throw new DataAccessException("Unable to start transaction due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Retrives the ASAM paths for the given entities. The ASAM paths are prefixed
+	 * with a servicename, in the form
+	 * <code>corbaloc:[iop|ssliop]:1.2@HOSTNAME:PORT/NameService/MDM.ASAM-ODS/</code>
+	 * 
+	 * @returns returns a map with the ASAM paths to the given entities. If a entity
+	 *          is not found in the ODS server the entity is not included in the
+	 *          result map.
+	 * @throws DataAccessException      if links could not be loaded for the given
+	 *                                  entities
+	 * @throws IllegalArgumentException if a the source or typeName of an entity is
+	 *                                  invalid
+	 * @see org.eclipse.mdm.api.base.BaseEntityManager#getLinks(Collection)
+	 */
+	@Override
+	public Map<Entity, String> getLinks(Collection<Entity> entities) throws DataAccessException {
+
+		Map<Entity, String> linkMap = new HashMap<>();
+
+		ApplicationStructure appStructure;
+		try {
+			appStructure = odsModelManager.getAoSession().getApplicationStructure();
+		} catch (AoException e) {
+			throw new DataAccessException("Could not load application structure! Reason: " + e.reason, e);
+		}
+
+		String serverRoot = context.getParameters().get(ODSContextFactory.PARAM_NAMESERVICE) + "/"
+				+ context.getParameters().get(ODSContextFactory.PARAM_SERVICENAME);
+
+		Map<String, List<Entity>> entitiesByTypeName = entities.stream().filter(e -> e.getTypeName() != null)
+				.collect(Collectors.groupingBy(Entity::getTypeName));
+
+		for (Map.Entry<String, List<Entity>> entry : entitiesByTypeName.entrySet()) {
+			ODSEntityType et = (ODSEntityType) odsModelManager.getEntityType(entry.getKey());
+
+			List<ElemId> elemIds = entry.getValue().stream()
+					.map(e -> new ElemId(et.getODSID(), ODSConverter.toODSLong(Long.parseLong(e.getID()))))
+					.collect(Collectors.toList());
+
+			try {
+				InstanceElement[] instances = appStructure.getInstancesById(elemIds.toArray(new ElemId[0]));
+
+				for (InstanceElement ie : instances) {
+					String id = Long.toString(ODSConverter.fromODSLong(ie.getId()));
+					String asamPath = serverRoot + ie.getAsamPath();
+					entry.getValue().stream().filter(e -> e.getID().equals(id)).findFirst()
+							.ifPresent(e -> linkMap.put(e, asamPath));
+				}
+			} catch (AoException e) {
+				LOGGER.debug("Could not load links for entities: " + entities + ". Reason: " + e.reason, e);
+			}
+		}
+
+		return linkMap;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<TemplateTest> loadTemplate(Test test) {
+		return Optional.ofNullable(ODSEntityFactory.extract(test).getMutableStore().get(TemplateTest.class));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<TemplateTestStep> loadTemplate(TestStep testStep) {
+		return Optional.ofNullable(ODSEntityFactory.extract(testStep).getMutableStore().get(TemplateTestStep.class));
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ReadRequestHandler.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ReadRequestHandler.java
new file mode 100644
index 0000000..bd6b2d0
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/ReadRequestHandler.java
@@ -0,0 +1,377 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.asam.ods.AoException;
+import org.asam.ods.Column;
+import org.asam.ods.ElemId;
+import org.asam.ods.NameValueSeqUnit;
+import org.asam.ods.T_LONGLONG;
+import org.asam.ods.ValueMatrix;
+import org.asam.ods.ValueMatrixMode;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.massdata.ReadRequest;
+import org.eclipse.mdm.api.base.massdata.ReadRequest.ValuesMode;
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.MeasuredValues;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Reads mass data specified in {@link ReadRequest}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class ReadRequestHandler {
+	public static final class ColumnAttributes {
+		private String name;
+		private SequenceRepresentation sequenceRepresentation;
+		private double[] generationParameters;
+		private boolean independent;
+		private AxisType axisType;
+
+		public ColumnAttributes(String name, SequenceRepresentation sequenceRepresentation,
+				double[] generationParameters, boolean independent, AxisType axisType) {
+			this.name = name;
+			this.sequenceRepresentation = sequenceRepresentation;
+			this.generationParameters = generationParameters;
+			this.independent = independent;
+			this.axisType = axisType;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		public SequenceRepresentation getSequenceRepresentation() {
+			return sequenceRepresentation;
+		}
+
+		public void setSequenceRepresentation(SequenceRepresentation sequenceRepresentation) {
+			this.sequenceRepresentation = sequenceRepresentation;
+		}
+
+		public double[] getGenerationParameters() {
+			return generationParameters;
+		}
+
+		public void setGenerationParameters(double[] generationParameters) {
+			this.generationParameters = generationParameters;
+		}
+
+		public boolean isIndependentColumn() {
+			return independent;
+		}
+
+		public void setIndependentColumn(boolean independent) {
+			this.independent = independent;
+		}
+
+		public AxisType getAxisType() {
+			return axisType;
+		}
+
+		public void setAxisType(AxisType axisType) {
+			this.axisType = axisType;
+		}
+
+	}
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ODSModelManager modelManager;
+	private final QueryService queryService;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to gain access to value matrices.
+	 */
+	public ReadRequestHandler(ODSModelManager modelManager, QueryService queryService) {
+		this.modelManager = modelManager;
+		this.queryService = queryService;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Loads {@link MeasuredValues} as defined in given {@link ReadRequest}.
+	 *
+	 * @param readRequest The {@code MeasuredValues} request configuration.
+	 * @return The loaded {@code MeasuredValues} are returned.
+	 * @throws DataAccessException Thrown if unable to load {@code
+	 * 		MeasuredValues}     .
+	 */
+	public List<MeasuredValues> execute(ReadRequest readRequest) throws DataAccessException {
+		ValueMatrix valueMatrix = null;
+		Column[] arrColumns = null;
+
+		try {
+			valueMatrix = getValueMatrix(readRequest);
+			List<Pair<Column, ColumnAttributes>> listColumnPairs = getODSColumns(readRequest, valueMatrix);
+
+			arrColumns = listColumnPairs.stream().map(Pair::getLeft).toArray(Column[]::new);
+			ColumnAttributes[] arrColumnAttributes = listColumnPairs.stream().map(Pair::getRight)
+					.toArray(ColumnAttributes[]::new);
+
+			NameValueSeqUnit[] nvsus = valueMatrix.getValue(arrColumns, readRequest.getStartIndex(),
+					readRequest.getRequestSize());
+			return ODSConverter.fromODSMeasuredValuesSeq(nvsus, arrColumnAttributes);
+		} catch (AoException aoe) {
+			throw new DataAccessException(aoe.reason, aoe);
+		} finally {
+			releaseColumns(arrColumns);
+			releaseValueMatrix(valueMatrix);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Loads all for each defined {@link Channel} in given {@link ReadRequest} and
+	 * loads the corresponding {@link Column} using given {@link ValueMatrix}.
+	 *
+	 * @param readRequest Defines required {@code Column}s.
+	 * @param valueMatrix Used to load required {@code Column}s.
+	 * @return {@code Column} configured in given {@code ReadRequest} are returned
+	 *         with defined {@link Unit} setup.
+	 * @throws AoException         Throw if unable to load all available
+	 *                             {@code Column}s.
+	 * @throws DataAccessException Thrown on wrong {@code ReadRequest} setup.
+	 */
+	private List<Pair<Column, ColumnAttributes>> getODSColumns(ReadRequest readRequest, ValueMatrix valueMatrix)
+			throws AoException, DataAccessException {
+		List<Pair<Column, ColumnAttributes>> listColumnPairs = new ArrayList<>();
+		Map<String, Column> mapColumns = new HashMap<>();
+
+		try {
+			if (readRequest.isLoadAllChannels()) {
+				// TODO should it be possible to overwrite the unit of some
+				// channels?!
+				// -> this results in a performance issue since we need to call
+				// getName()
+				// on each column for mapping! (no longer, see below!)
+				Column[] columns = valueMatrix.getColumns("*");
+
+				if (null != columns) {
+					for (Column column : columns) {
+						String columnName = column.getName();
+						if (mapColumns.containsKey(columnName)) {
+							releaseColumns(columns);
+							throw new DataAccessException(
+									String.format("Duplicate column name '%s' found within submatrix ID %d!",
+											columnName, Long.valueOf(readRequest.getChannelGroup().getID())));
+						}
+
+						mapColumns.put(columnName, column);
+					}
+				}
+			} else {
+				for (Entry<Channel, Unit> entry : readRequest.getChannels().entrySet()) {
+					Channel channel = entry.getKey();
+					Unit unit = entry.getValue();
+					String channelName = channel.getName();
+					Column[] columns = valueMatrix.getColumns(channelName);
+					if (columns == null || columns.length != 1) {
+						releaseColumns(columns);
+						throw new DataAccessException(String.format(
+								"Zero or more than one column with name '%s' found within submatrix ID %d!",
+								channelName, Long.valueOf(readRequest.getChannelGroup().getID())));
+					}
+
+					Column column = columns[0];
+					if (!unit.nameEquals(channel.getUnit().getName())) {
+						column.setUnit(unit.getName());
+					}
+
+					mapColumns.put(channelName, column);
+				}
+			}
+
+			if (mapColumns.size() > 0) {
+				EntityType localColumnEntityType = modelManager.getEntityType("LocalColumn");
+				Attribute idAttr = localColumnEntityType.getAttribute("Id");
+				Attribute nameAttr = localColumnEntityType.getAttribute("Name");
+				Attribute submatrixAttr = localColumnEntityType.getAttribute("SubMatrix");
+
+				// Don't query GenerationParameters together with other non-ID attributes as
+				// Avalon dislikes this:
+				Query query1 = queryService.createQuery()
+						.select(Lists.newArrayList(idAttr, nameAttr,
+								localColumnEntityType.getAttribute("SequenceRepresentation"),
+								localColumnEntityType.getAttribute("IndependentFlag"),
+								localColumnEntityType.getAttribute("axistype")));
+
+				Filter filter = Filter.and().add(ComparisonOperator.EQUAL.create(submatrixAttr,
+						Long.valueOf(readRequest.getChannelGroup().getID())));
+
+				Set<String> setColumnNames = mapColumns.keySet();
+
+				Map<String, ColumnAttributes> mapColumnAttributes = new HashMap<>();
+
+				for (Result result : query1.fetch(filter)) {
+					Map<String, Value> mapValues = result.getRecord(localColumnEntityType).getValues();
+
+					String columnName = mapValues.get("Name").extract();
+
+					if (setColumnNames.contains(columnName)) {
+						ColumnAttributes ca = new ColumnAttributes(columnName,
+								(ValuesMode.CALCULATED == readRequest.getValuesMode() ? SequenceRepresentation.EXPLICIT
+										: mapValues.get("SequenceRepresentation").extract()),
+								new double[0], ((short) mapValues.get("IndependentFlag").extract() != 0),
+								mapValues.get("axistype").extract());
+
+						mapColumnAttributes.put(mapValues.get("Id").extract(), ca);
+					}
+				}
+
+				if (ValuesMode.CALCULATED != readRequest.getValuesMode()) {
+					Query query2 = queryService.createQuery().select(idAttr,
+							localColumnEntityType.getAttribute("GenerationParameters"));
+
+					for (Result result : query2.fetch(filter)) {
+						Map<String, Value> mapValues = result.getRecord(localColumnEntityType).getValues();
+
+						ColumnAttributes ca = mapColumnAttributes.get(mapValues.get("Id").extract());
+
+						if (ca != null) {
+							ca.setGenerationParameters(mapValues.get("GenerationParameters").extract());
+						}
+					}
+				}
+
+				for (Map.Entry<String, ColumnAttributes> me : mapColumnAttributes.entrySet()) {
+					ColumnAttributes ca = me.getValue();
+					listColumnPairs.add(new ImmutablePair<Column, ColumnAttributes>(mapColumns.get(ca.getName()), ca));
+				}
+			}
+
+			return listColumnPairs;
+		} catch (AoException e) {
+			releaseColumns(listColumnPairs.stream().map(Pair::getLeft).toArray(Column[]::new));
+			throw new DataAccessException("Unable to load column due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Returns the {@link ValueMatrix} CORBA service object associated with given
+	 * {@link ReadRequest}.
+	 *
+	 * @param readRequest The {@code ReadRequest}.
+	 * @return The {@code ValueMatrix} is returned.
+	 * @throws AoException Thrown if unable to load the {@code ValueMatrix}.
+	 */
+	private ValueMatrix getValueMatrix(ReadRequest readRequest) throws AoException {
+		Entity entity = readRequest.getChannelGroup();
+		T_LONGLONG iid = ODSConverter.toODSID(entity.getID());
+		T_LONGLONG aid = ((ODSEntityType) modelManager.getEntityType(entity)).getODSID();
+		ValueMatrixMode valueMatrixMode = ValueMatrixMode.CALCULATED;
+		switch (readRequest.getValuesMode()) {
+		case CALCULATED:
+			valueMatrixMode = ValueMatrixMode.CALCULATED;
+			break;
+		case STORAGE:
+			valueMatrixMode = ValueMatrixMode.STORAGE;
+			break;
+		default:
+			throw new DataAccessException(
+					String.format("Unsupported ValueMode %s!", readRequest.getValuesMode().name()));
+		}
+
+		return modelManager.getApplElemAccess().getValueMatrixInMode(new ElemId(aid, iid), valueMatrixMode);
+	}
+
+	/**
+	 * Releases given {@link ValueMatrix} CORBA object.
+	 *
+	 * @param valueMatrix Will be released.
+	 */
+	private void releaseValueMatrix(ValueMatrix valueMatrix) {
+		if (valueMatrix == null) {
+			return;
+		}
+
+		try {
+			valueMatrix.destroy();
+		} catch (AoException aoe) {
+			// ignore
+		} finally {
+			valueMatrix._release();
+		}
+	}
+
+	/**
+	 * Releases each CORBA {@link Column} object.
+	 *
+	 * @param columns Will be released.
+	 */
+	private void releaseColumns(Column[] columns) {
+		if (columns == null) {
+			return;
+		}
+
+		for (Column column : columns) {
+			try {
+				column.destroy();
+			} catch (AoException e) {
+				// ignore
+			} catch (Exception e) {
+				// ignore
+			} finally {
+				column._release();
+			}
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
new file mode 100644
index 0000000..acc7865
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileServer.java
@@ -0,0 +1,521 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.filetransfer;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.asam.ods.AoSession;
+import org.asam.ods.ElemId;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.ORBPackage.InvalidName;
+import org.omg.PortableServer.POA;
+import org.omg.PortableServer.POAHelper;
+import org.omg.PortableServer.POAManagerPackage.AdapterInactive;
+import org.omg.PortableServer.POAPackage.ObjectNotActive;
+import org.omg.PortableServer.POAPackage.ServantAlreadyActive;
+import org.omg.PortableServer.POAPackage.WrongPolicy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.highqsoft.corbafileserver.generated.CORBAFileServerException;
+import com.highqsoft.corbafileserver.generated.CORBAFileServerIF;
+import com.highqsoft.corbafileserver.generated.DS_BYTEHolder;
+import com.highqsoft.corbafileserver.generated.ErrorCode;
+import com.highqsoft.corbafileserver.generated.InputStreamIF;
+import com.highqsoft.corbafileserver.generated.InputStreamIFPOA;
+import com.highqsoft.corbafileserver.generated.SeverityFlag;
+
+/**
+ * Service provides access to the low level {@link CORBAFileServerIF} file
+ * service API.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class CORBAFileServer {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(CORBAFileServer.class);
+	private static final int DEFAULT_BUFFER_SIZE = 100_000;
+	private static final int SOCKET_TIMEOUT = 5_000;
+	private static final String INTERFACE_NAME_PROPERTY = "org.eclipse.mdm.api.odsadapter.filetransfer.interfaceName";
+	private static final String HOST_NAME_PROPERTY = "org.eclipse.mdm.api.odsadapter.filetransfer.hostname";
+
+	private final CORBAFileServerIF fileServer;
+	private final AoSession aoSession;
+	private final ORB orb;
+
+	private final Transfer transfer;
+
+	private final int bufferSize;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param context  Used for setup.
+	 * @param transfer The transfer type for up- and downloads.
+	 */
+	CORBAFileServer(ODSContext context, Transfer transfer) {
+		ModelManager mm = context.getModelManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+		if (!(mm instanceof ODSModelManager)) {
+			throw new IllegalArgumentException("The supplied ModelManager must be an ODSModelManager!");
+		}
+
+		fileServer = context.getFileServer();
+		aoSession = context.getAoSession();
+		orb = context.getORB();
+		this.transfer = transfer;
+
+		bufferSize = getBufferSize();
+	}
+
+	/**
+	 * Opens a consumable download {@link InputStream} for given {@link FileLink}.
+	 *
+	 * @param fileLink Used to access the remote path.
+	 * @param elemId   Used for security checks.
+	 * @return The consumable {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to open an the {@code InputStream}.
+	 */
+	public InputStream openStream(FileLink fileLink, ElemId elemId) throws IOException {
+		InputStream inputStream;
+		if (transfer.isStream()) {
+			inputStream = new InputStreamAdapter(openSimpleStream(fileLink, elemId));
+		} else if (transfer.isSocket()) {
+			inputStream = openSocketStream(fileLink, elemId);
+		} else {
+			throw new IllegalStateException("Transfer state '" + transfer + "' is not supported.");
+		}
+
+		return new BufferedInputStream(inputStream, bufferSize);
+	}
+
+	/**
+	 * Uploads given {@link InputStream} for given {@link FileLink}.
+	 *
+	 * @param inputStream The {@code InputStream} to be uploaded.
+	 * @param fileLink    The associated {@code FileLink}.
+	 * @param elemId      Used for security checks.
+	 * @throws IOException Thrown if unable to upload given {@code InputStream}.
+	 */
+	public void uploadStream(InputStream inputStream, FileLink fileLink, ElemId elemId) throws IOException {
+		String remotePath;
+		if (transfer.isStream()) {
+			remotePath = uploadVIAStream(inputStream, fileLink, elemId);
+		} else if (transfer.isSocket()) {
+			remotePath = uploadVIASocket(inputStream, fileLink, elemId);
+		} else {
+			throw new IllegalStateException("Transfer state '" + transfer + "' is not supported.");
+		}
+
+		fileLink.setRemotePath(remotePath);
+	}
+
+	/**
+	 * Loads the file size for given {@link FileLink}.
+	 *
+	 * @param fileLink The {@code FileLink} whose file size will be loaded.
+	 * @param elemId   Used for security checks.
+	 * @return The file size is returned.
+	 * @throws IOException Thrown if unable to load the file size.
+	 */
+	public long loadSize(FileLink fileLink, ElemId elemId) throws IOException {
+		try {
+			return fileServer.getSizeForInstance(aoSession, fileLink.getRemotePath(), elemId.aid, elemId.iid);
+		} catch (CORBAFileServerException e) {
+			throw new IOException("Unable to query file size due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Deletes the {@link FileLink} from the remote storage.
+	 *
+	 * @param fileLink Will be deleted from the remote storage.
+	 * @param elemId   Used for security checks.
+	 * @throws IOException Thrown if unable to delete given {@code FileLink}.
+	 */
+	public void delete(FileLink fileLink, ElemId elemId) throws IOException {
+		try {
+			fileServer.deleteForInstance(aoSession, fileLink.getRemotePath(), elemId.aid, elemId.iid);
+		} catch (CORBAFileServerException e) {
+			throw new IOException("Unable to delete remote file due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Opens a simple {@link InputStreamIF} using the {@link CORBAFileServerIF}.
+	 *
+	 * @param fileLink Used to access the remote path.
+	 * @param elemId   Used for security checks.
+	 * @return The {@code InputStreamIF} is returned.
+	 * @throws IOException Thrown if unable to open the {@code InputStreamIF}.
+	 */
+	private InputStreamIF openSimpleStream(FileLink fileLink, ElemId elemId) throws IOException {
+		try {
+			return fileServer.readForInstance(aoSession, fileLink.getRemotePath(), elemId.aid, elemId.iid);
+		} catch (CORBAFileServerException e) {
+			throw new IOException("Unable to open stream for file transfer due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Opens a socket {@link InputStream} using the {@link CORBAFileServerIF}.
+	 *
+	 * @param fileLink Used to access the remote path.
+	 * @param elemId   Used for security checks.
+	 * @return The {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to open the socket {@code
+	 * 		InputStream}.
+	 */
+	private InputStream openSocketStream(FileLink fileLink, ElemId elemId) throws IOException {
+		// auto assigned port with awaiting exactly ONE incoming connection
+		try (ServerSocket serverSocket = new ServerSocket(0, 1, getInterfaceAddress())) {
+			serverSocket.setSoTimeout(SOCKET_TIMEOUT * 6);
+
+			new Thread(() -> {
+				try {
+					/*
+					 * NOTE: Since a socket file transfer registration may block until this server
+					 * socket's accept method is called, the registration is done asynchronously!
+					 */
+					fileServer.getForInstanceBySocket(aoSession, fileLink.getRemotePath(), elemId.aid, elemId.iid,
+							serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
+				} catch (CORBAFileServerException e) {
+					LOGGER.error("Unable to initialize socket stream, awaiting socket timeout.", e);
+				}
+			}).start();
+
+			Socket client = serverSocket.accept();
+			client.setSoTimeout(SOCKET_TIMEOUT);
+			return client.getInputStream();
+		}
+	}
+
+	private InetAddress getInterfaceAddress() throws SocketException {
+		String hostnameProperty = System.getProperty(HOST_NAME_PROPERTY);
+		if (!StringUtils.isEmpty(hostnameProperty)) {
+			LOGGER.debug("Using host name '" + hostnameProperty + "' for file transfer.");
+			try {
+				return InetAddress.getByName(hostnameProperty);
+			} catch (UnknownHostException e) {
+				LOGGER.warn("Specified host name '" + hostnameProperty + "' cannot be used for file transfer.", e);
+				// continue with lookup by interface name
+			}
+		}
+
+		String property = System.getProperty(INTERFACE_NAME_PROPERTY);
+		if (StringUtils.isEmpty(property)) {
+			LOGGER.debug("Using no specified interface for file transfer, property not set.");
+			return null;
+		}
+		List<NetworkInterface> interfaces = getInterfaceList();
+		List<NetworkInterface> filteredInterfaces = getFilteredInterfaces(interfaces);
+		for (NetworkInterface filteredInterface : filteredInterfaces) {
+			if (filteredInterface.getName().equals(property)
+					&& filteredInterface.getInetAddresses().hasMoreElements()) {
+				InetAddress inetAddress = filteredInterface.getInetAddresses().nextElement();
+				LOGGER.debug("Using interface {} with address {} for file transfer.", filteredInterface.getName(),
+						inetAddress);
+				return inetAddress;
+			}
+		}
+		return getFallback(filteredInterfaces);
+	}
+
+	private InetAddress getFallback(List<NetworkInterface> filteredInterfaces) {
+		if (filteredInterfaces.isEmpty()) {
+			LOGGER.debug("Using no specified interface for file transfer, property set but no running interface.");
+			return null;
+		}
+		NetworkInterface networkInterface = filteredInterfaces.get(0);
+		Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
+		if (inetAddresses.hasMoreElements()) {
+			InetAddress address = inetAddresses.nextElement();
+			LOGGER.debug("Using interface {} with address {} for file transfer.", networkInterface.getName(), address);
+			return address;
+		}
+		return null;
+	}
+
+	private List<NetworkInterface> getFilteredInterfaces(List<NetworkInterface> interfaces) throws SocketException {
+		List<NetworkInterface> filteredInterfaces = new ArrayList<>();
+		for (NetworkInterface anInterface : interfaces) {
+			if (anInterface.isUp() && !anInterface.isLoopback() && !anInterface.isVirtual()) {
+				filteredInterfaces.add(anInterface);
+			}
+		}
+		return filteredInterfaces;
+	}
+
+	private List<NetworkInterface> getInterfaceList() throws SocketException {
+		List<NetworkInterface> result = new ArrayList<>();
+		Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
+		while (networkInterfaces.hasMoreElements()) {
+			result.add(networkInterfaces.nextElement());
+		}
+		return result;
+	}
+
+	/**
+	 * Uploads given {@link InputStream} for given {@link FileLink} using the
+	 * {@link CORBAFileServerIF}.
+	 *
+	 * @param inputStream The {@code InputStream} to be uploaded.
+	 * @param fileLink    The associated {@code FileLink}.
+	 * @param elemId      Used for security checks.
+	 * @return The remote path of the uploaded {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to upload given {@code InputStream}.
+	 */
+	private String uploadVIAStream(InputStream inputStream, FileLink fileLink, ElemId elemId) throws IOException {
+		try (CORBAInputStreamAdapter stream = new CORBAInputStreamAdapter(orb, inputStream, fileLink.getSize())) {
+			return fileServer.saveForInstance(aoSession, fileLink.getFileName(), "", elemId.aid, elemId.iid,
+					stream._this());
+		} catch (CORBAFileServerException e) {
+			throw new IOException("Unable to upload file via stream due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * Uploads given {@link InputStream} for given {@link FileLink} via socket
+	 * upload using the {@link CORBAFileServerIF}.
+	 *
+	 * @param inputStream The {@code InputStream} to be uploaded.
+	 * @param fileLink    The associated {@code FileLink}.
+	 * @param elemId      Used for security checks.
+	 * @return The remote path of the uploaded {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to upload given {@code InputStream}.
+	 */
+	private String uploadVIASocket(InputStream inputStream, FileLink fileLink, ElemId elemId) throws IOException {
+		// auto assigned port with awaiting exactly ONE incoming connection
+		try (ServerSocket serverSocket = new ServerSocket(0, 1, getInterfaceAddress())) {
+			serverSocket.setSoTimeout(SOCKET_TIMEOUT * 6);
+
+			new Thread(() -> {
+				try (Socket client = serverSocket.accept(); OutputStream outputStream = client.getOutputStream()) {
+					byte[] buffer = new byte[bufferSize];
+
+					int length;
+					while ((length = inputStream.read(buffer)) > -1) {
+						outputStream.write(buffer, 0, length);
+					}
+				} catch (IOException e) {
+					LOGGER.error("Unable to initialize socket stream, awaiting socket timeout.", e);
+				}
+			}).start();
+
+			int localPort = serverSocket.getLocalPort();
+			String localHostName = serverSocket.getInetAddress().getHostAddress();
+			try {
+				return fileServer.saveForInstanceBySocket(aoSession, fileLink.getFileName(), "", elemId.aid, elemId.iid,
+						localHostName, localPort);
+			} catch (CORBAFileServerException e) {
+				String message = String.format("Unable to upload file via socket to %s:%d due to: %s", localHostName,
+						localPort, e.reason);
+				throw new IOException(message, e);
+			}
+		}
+	}
+
+	/**
+	 * Tries to load the buffer size used by the {@link CORBAFileServerIF} to reach
+	 * best performance. In case of errors a default buffer size of of
+	 * {@value #DEFAULT_BUFFER_SIZE} is used.
+	 *
+	 * @return The buffer size is returned.
+	 */
+	private int getBufferSize() {
+		try {
+			// try to use the same buffer size as the corba file server for best
+			// performance
+			return Integer.parseInt(fileServer.getContext(aoSession, "CORBAFileServer.BufferSize"));
+		} catch (NumberFormatException | CORBAFileServerException e) {
+			return DEFAULT_BUFFER_SIZE;
+		}
+	}
+
+	/**
+	 * A simple {@link InputStream} adapter implementation for an
+	 * {@link InputStreamIF}.
+	 */
+	private static final class InputStreamAdapter extends InputStream {
+
+		private final InputStreamIF inputStream;
+
+		/**
+		 * Constructor.
+		 *
+		 * @param inputStream The wrapped {@link InputStreamIF}.
+		 */
+		private InputStreamAdapter(InputStreamIF inputStream) {
+			this.inputStream = inputStream;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public int read() throws IOException {
+			byte[] b = new byte[1];
+			return read(b) == -1 ? -1 : b[0];
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public int read(byte[] buffer, int offset, int length) throws IOException {
+			try {
+				DS_BYTEHolder byteHolder = new DS_BYTEHolder();
+				int receivedBytes = inputStream.read(byteHolder, offset, length);
+				if (receivedBytes > 0) {
+					System.arraycopy(byteHolder.value, 0, buffer, 0, receivedBytes);
+				}
+				return receivedBytes;
+			} catch (CORBAFileServerException e) {
+				throw new IOException("Failed to retrieve bytes from CORBA input stream due to: " + e.reason, e);
+			}
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void close() throws IOException {
+			try {
+				inputStream.close();
+			} catch (CORBAFileServerException e) {
+				throw new IOException("Unable to close CORBA input stream due to: " + e.reason, e);
+			} finally {
+				inputStream._release();
+			}
+		}
+
+	}
+
+	// remotely consumable local input stream
+	/**
+	 * A simple {@link InputStreamIF} adapter implementation for an
+	 * {@link InputStream}.
+	 */
+	private static final class CORBAInputStreamAdapter extends InputStreamIFPOA implements AutoCloseable {
+
+		private final InputStream inputStream;
+		private final long length;
+
+		private final byte[] objectID;
+		private final POA poa;
+
+		/**
+		 * Constructor.
+		 *
+		 * @param orb         Used to access the root {@link POA} to activate this CORBA
+		 *                    service object.
+		 * @param inputStream The wrapped {@link InputStream}.
+		 * @param length      The length of the wrapped {@code InputStream}.
+		 * @throws IOException Thrown on errors.
+		 */
+		private CORBAInputStreamAdapter(ORB orb, InputStream inputStream, long length) throws IOException {
+			this.inputStream = inputStream;
+			this.length = length;
+
+			try {
+				poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
+				poa.the_POAManager().activate();
+				objectID = poa.activate_object(this);
+			} catch (AdapterInactive | InvalidName | ServantAlreadyActive | WrongPolicy e) {
+				throw new IOException("Unable to create CORBA input stream.", e);
+			}
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public int read(DS_BYTEHolder b, int off, int len) throws CORBAFileServerException {
+			b.value = new byte[len];
+
+			try {
+				return inputStream.read(b.value, off, len);
+			} catch (IOException e) {
+				throw new CORBAFileServerException(ErrorCode.FILESERVER_IO_EXCEPTION, SeverityFlag.ERROR,
+						e.getMessage());
+			}
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void close() throws CORBAFileServerException {
+			try {
+				inputStream.close();
+			} catch (IOException e) {
+				throw new CORBAFileServerException(ErrorCode.FILESERVER_IO_EXCEPTION, SeverityFlag.ERROR,
+						e.getMessage());
+			} finally {
+				try {
+					poa.deactivate_object(objectID);
+				} catch (ObjectNotActive | WrongPolicy e) {
+					LOGGER.warn("Unable to deactive CORBA input stream", e);
+				}
+			}
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public int length() throws CORBAFileServerException {
+			/*
+			 * NOTE: A file length is of type long and therefore, for very large files (>
+			 * 2.14 GB), the exact length is lost due to narrowing conversion!
+			 */
+			return (int) length;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void reset() throws CORBAFileServerException {
+			try {
+				inputStream.reset();
+			} catch (IOException e) {
+				throw new CORBAFileServerException(ErrorCode.FILESERVER_IO_EXCEPTION, SeverityFlag.ERROR,
+						e.getMessage());
+			}
+		}
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileService.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileService.java
new file mode 100644
index 0000000..2e84f2e
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/CORBAFileService.java
@@ -0,0 +1,473 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.filetransfer;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.reducing;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+
+import org.asam.ods.ElemId;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.file.FileService;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * CORBA file service implementation of the {@link FileService} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class CORBAFileService implements FileService {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(CORBAFileService.class);
+
+	private static final int THREAD_POOL_SIZE = 5;
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final CORBAFileServer fileServer;
+	private final ModelManager modelManager;
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param context  Used for {@link Entity} to {@link ElemId} conversion.
+	 * @param transfer The transfer type for up- and downloads.
+	 */
+	public CORBAFileService(ODSContext context, Transfer transfer) {
+		this.modelManager = context.getModelManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+
+		fileServer = new CORBAFileServer(context, transfer);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void downloadSequential(Entity entity, Path target, Collection<FileLink> fileLinks,
+			ProgressListener progressListener) throws IOException {
+		downloadSequential(toElemID(entity), target, fileLinks, progressListener);
+	}
+
+	private void downloadSequential(ElemId elemId, Path target, Collection<FileLink> fileLinks,
+			ProgressListener progressListener) throws IOException {
+		Map<String, List<FileLink>> groups = fileLinks.stream().filter(FileLink::isRemote)
+				.collect(Collectors.groupingBy(FileLink::getRemotePath));
+
+		long totalSize = calculateDownloadSize(elemId, groups);
+		final AtomicLong transferred = new AtomicLong();
+		LocalTime start = LocalTime.now();
+		UUID id = UUID.randomUUID();
+		LOGGER.debug("Sequential download of {} file(s) with id '{}' started.", groups.size(), id);
+		for (List<FileLink> group : groups.values()) {
+			FileLink fileLink = group.get(0);
+
+			download(elemId, target, fileLink, (b, p) -> {
+				double tranferredBytes = transferred.addAndGet(b);
+				if (progressListener != null) {
+					progressListener.progress(b, (float) (tranferredBytes / totalSize));
+				}
+			});
+
+			for (FileLink other : group.subList(1, group.size())) {
+				other.setLocalStream(fileLink.getLocalStream());
+			}
+		}
+		LOGGER.debug("Sequential download with id '{}' finished in {}.", id, Duration.between(start, LocalTime.now()));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void downloadParallel(Entity entity, Path target, Collection<FileLink> fileLinks,
+			ProgressListener progressListener) throws IOException {
+		downloadParallel(toElemID(entity), target, fileLinks, progressListener);
+	}
+
+	private void downloadParallel(ElemId elemId, Path target, Collection<FileLink> fileLinks,
+			ProgressListener progressListener) throws IOException {
+		Map<String, List<FileLink>> groups = fileLinks.stream().filter(FileLink::isRemote)
+				.collect(Collectors.groupingBy(FileLink::getRemotePath));
+
+		long totalSize = calculateDownloadSize(elemId, groups);
+		final AtomicLong transferred = new AtomicLong();
+		List<Callable<Void>> downloadTasks = new ArrayList<>();
+		for (List<FileLink> group : groups.values()) {
+			downloadTasks.add(() -> {
+				FileLink fileLink = group.get(0);
+
+				download(elemId, target, fileLink, (b, p) -> {
+					double tranferredBytes = transferred.addAndGet(b);
+					if (progressListener != null) {
+						progressListener.progress(b, (float) (tranferredBytes / totalSize));
+					}
+				});
+
+				for (FileLink other : group.subList(1, group.size())) {
+					other.setLocalStream(fileLink.getLocalStream());
+				}
+
+				return null;
+			});
+		}
+
+		ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
+		LocalTime start = LocalTime.now();
+		UUID id = UUID.randomUUID();
+		LOGGER.debug("Parallel download of {} file(s) with id '{}' started.", groups.size(), id);
+		try {
+			List<Throwable> errors = executorService.invokeAll(downloadTasks).stream().map(future -> {
+				try {
+					future.get();
+					return null;
+				} catch (ExecutionException | InterruptedException e) {
+					LOGGER.error("Download of failed due to: " + e.getMessage(), e);
+					return e;
+				}
+			}).filter(Objects::nonNull).collect(Collectors.toList());
+
+			if (!errors.isEmpty()) {
+				throw new IOException("Download faild for '" + errors.size() + "' files.");
+			}
+			LOGGER.debug("Parallel download with id '{}' finished in {}.", id,
+					Duration.between(start, LocalTime.now()));
+		} catch (InterruptedException e) {
+			throw new IOException("Unable to download files due to: " + e.getMessage(), e);
+		} finally {
+			executorService.shutdown();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void download(Entity entity, Path target, FileLink fileLink, ProgressListener progressListener)
+			throws IOException {
+		download(toElemID(entity), target, fileLink, progressListener);
+	}
+
+	private void download(ElemId elemId, Path target, FileLink fileLink, ProgressListener progressListener)
+			throws IOException {
+		if (Files.exists(target)) {
+			if (!Files.isDirectory(target)) {
+				throw new IllegalArgumentException("Target path is not a directory.");
+			}
+		} else {
+			Files.createDirectory(target);
+		}
+
+		try (InputStream inputStream = openStream(elemId, fileLink, progressListener)) {
+			Path absolutePath = target.resolve(fileLink.getFileName()).toAbsolutePath();
+			String remotePath = fileLink.getRemotePath();
+			LOGGER.debug("Starting download of file '{}' to '{}'.", remotePath, absolutePath);
+			LocalTime start = LocalTime.now();
+			Files.copy(inputStream, absolutePath);
+			LOGGER.debug("File '{}' successfully downloaded in {} to '{}'.", remotePath,
+					Duration.between(start, LocalTime.now()), absolutePath);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public InputStream openStream(Entity entity, FileLink fileLink, ProgressListener progressListener)
+			throws IOException {
+		return openStream(toElemID(entity), fileLink, progressListener);
+	}
+
+	private InputStream openStream(ElemId elemId, FileLink fileLink, ProgressListener progressListener)
+			throws IOException {
+		InputStream sourceStream;
+		if (fileLink.isLocal()) {
+			// file is locally available -> USE this shortcut!
+			sourceStream = fileLink.getLocalStream();
+		} else if (fileLink.isRemote()) {
+			sourceStream = fileServer.openStream(fileLink, elemId);
+		} else {
+			throw new IllegalArgumentException("File link is neither in local nor remote state: " + fileLink);
+		}
+
+		// NOTE: Access to immediate input stream is buffered.
+		if (progressListener != null) {
+			loadSize(elemId, fileLink);
+			// NOTE: Progress updates immediately triggered by the stream
+			// consumer.
+			return new TracedInputStream(sourceStream, progressListener, fileLink.getSize());
+		}
+		return sourceStream;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void loadSize(Entity entity, FileLink fileLink) throws IOException {
+		loadSize(toElemID(entity), fileLink);
+	}
+
+	private void loadSize(ElemId elemId, FileLink fileLink) throws IOException {
+		if (fileLink.getSize() > -1) {
+			// file size is already known
+			return;
+		} else if (fileLink.isRemote()) {
+			fileLink.setFileSize(fileServer.loadSize(fileLink, elemId));
+		} else {
+			throw new IllegalArgumentException("File link is neither in local nor remote state: " + fileLink);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void uploadSequential(Entity entity, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException {
+		uploadSequential(toElemID(entity), fileLinks, progressListener);
+	}
+
+	private void uploadSequential(ElemId elemId, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException {
+		Map<InputStream, List<FileLink>> groups = fileLinks.stream().filter(FileLink::isLocal)
+				.collect(Collectors.groupingBy(FileLink::getLocalStream));
+
+		long totalSize = groups.values().stream().map(l -> l.get(0)).mapToLong(FileLink::getSize).sum();
+		final AtomicLong transferred = new AtomicLong();
+		LocalTime start = LocalTime.now();
+		UUID id = UUID.randomUUID();
+		LOGGER.debug("Sequential upload of {} file(s) with id '{}' started.", groups.size(), id);
+		for (List<FileLink> group : groups.values()) {
+			FileLink fileLink = group.get(0);
+
+			upload(elemId, fileLink, (b, p) -> {
+				double tranferredBytes = transferred.addAndGet(b);
+				if (progressListener != null) {
+					progressListener.progress(b, (float) (tranferredBytes / totalSize));
+				}
+			});
+
+			for (FileLink other : group.subList(1, group.size())) {
+				other.setRemotePath(fileLink.getRemotePath());
+			}
+		}
+		LOGGER.debug("Sequential upload with id '{}' finished in {}.", id, Duration.between(start, LocalTime.now()));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void uploadParallel(Entity entity, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException {
+		uploadParallel(toElemID(entity), fileLinks, progressListener);
+	}
+
+	private void uploadParallel(ElemId elemId, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException {
+		Map<InputStream, List<FileLink>> groups = fileLinks.stream().filter(FileLink::isLocal)
+				.collect(Collectors.groupingBy(FileLink::getLocalStream));
+
+		long totalSize = groups.values().stream().map(l -> l.get(0)).mapToLong(FileLink::getSize).sum();
+		final AtomicLong transferred = new AtomicLong();
+		List<Callable<Void>> downloadTasks = new ArrayList<>();
+		for (List<FileLink> group : groups.values()) {
+			downloadTasks.add(() -> {
+				FileLink fileLink = group.get(0);
+
+				upload(elemId, fileLink, (b, p) -> {
+					double tranferredBytes = transferred.addAndGet(b);
+					if (progressListener != null) {
+						progressListener.progress(b, (float) (tranferredBytes / totalSize));
+					}
+				});
+
+				for (FileLink other : group.subList(1, group.size())) {
+					other.setRemotePath(fileLink.getRemotePath());
+				}
+
+				return null;
+			});
+		}
+
+		ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
+		LocalTime start = LocalTime.now();
+		UUID id = UUID.randomUUID();
+		LOGGER.debug("Parallel upload of {} file(s) with id '{}' started.", groups.size(), id);
+		try {
+			List<Throwable> errors = executorService.invokeAll(downloadTasks).stream().map(future -> {
+				try {
+					future.get();
+					return null;
+				} catch (ExecutionException | InterruptedException e) {
+					LOGGER.error("Upload of failed due to: " + e.getMessage(), e);
+					return e;
+				}
+			}).filter(Objects::nonNull).collect(Collectors.toList());
+
+			if (!errors.isEmpty()) {
+				throw new IOException("Upload faild for '" + errors.size() + "' files.");
+			}
+			LOGGER.debug("Parallel upload with id '{}' finished in {}.", id, Duration.between(start, LocalTime.now()));
+		} catch (InterruptedException e) {
+			throw new IOException("Unable to upload files due to: " + e.getMessage(), e);
+		} finally {
+			executorService.shutdown();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void delete(Entity entity, Collection<FileLink> fileLinks) {
+		delete(toElemID(entity), fileLinks);
+	}
+
+	private void delete(ElemId elemId, Collection<FileLink> fileLinks) {
+		fileLinks.stream().filter(FileLink::isRemote)
+				.collect(groupingBy(FileLink::getRemotePath, reducing((fl1, fl2) -> fl1))).values().stream()
+				.filter(Optional::isPresent).map(Optional::get).forEach(fl -> delete(elemId, fl));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void delete(Entity entity, FileLink fileLink) {
+		delete(toElemID(entity), fileLink);
+	}
+
+	private void delete(ElemId elemId, FileLink fileLink) {
+		if (!fileLink.isRemote()) {
+			// nothing to do
+			return;
+		}
+
+		try {
+			fileServer.delete(fileLink, elemId);
+			LOGGER.debug("File '{}' sucessfully deleted.", fileLink.getRemotePath());
+		} catch (IOException e) {
+			LOGGER.warn("Failed to delete remote file.", e);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+	
+	/**
+	 * Uploads given {@link FileLink}. The upload progress may be traced with a
+	 * progress listener.
+	 *
+	 * @param elemId           Used for security checks.
+	 * @param fileLink         The {@code FileLink} to upload.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to upload file.
+	 */
+	private void upload(ElemId elemId, FileLink fileLink, ProgressListener progressListener) throws IOException {
+		if (fileLink.isRemote()) {
+			// nothing to do
+			return;
+		} else if (!fileLink.isLocal()) {
+			throw new IllegalArgumentException("File link does not have a local path.");
+		}
+
+		InputStream sourceStream = fileLink.getLocalStream();
+		if (progressListener != null) {
+			sourceStream = new TracedInputStream(sourceStream, progressListener, fileLink.getSize());
+		}
+
+		LOGGER.debug("Starting upload of file '{}'.", fileLink.getFileName());
+		LocalTime start = LocalTime.now();
+		fileServer.uploadStream(sourceStream, fileLink, elemId);
+		LOGGER.debug("File '{}' successfully uploaded in {} to '{}'.", fileLink.getFileName(),
+				Duration.between(start, LocalTime.now()), fileLink.getRemotePath());
+	}
+
+	/**
+	 * Creates an ODS entity identity {@link ElemId} object for given
+	 * {@link Entity}.
+	 *
+	 * @param entity The {@code Entity}.
+	 * @return The created {@code ElemId} is returned.
+	 */
+	private ElemId toElemID(Entity entity) {
+		return new ElemId(((ODSEntityType) modelManager.getEntityType(entity)).getODSID(),
+				ODSConverter.toODSID(entity.getID()));
+	}
+
+	/**
+	 * Calculates the total download size for given {@link FileLink} groups.
+	 *
+	 * @param entity Used for security checks.
+	 * @param groups The {@code FileLink} groups.
+	 * @return The total download size is returned.
+	 * @throws IOException Thrown if unable to load the file size.
+	 */
+	private long calculateDownloadSize(ElemId elemId, Map<String, List<FileLink>> groups) throws IOException {
+		List<FileLink> links = groups.values().stream().map(l -> l.get(0)).collect(Collectors.toList());
+		long totalSize = 0;
+		for (FileLink fileLink : links) {
+			loadSize(elemId, fileLink);
+			// overflow may occur in case of total size exceeds 9223 PB!
+			totalSize = Math.addExact(totalSize, fileLink.getSize());
+		}
+
+		return totalSize;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/TracedInputStream.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/TracedInputStream.java
new file mode 100644
index 0000000..27c4184
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/TracedInputStream.java
@@ -0,0 +1,92 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.filetransfer;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.mdm.api.base.file.FileService.ProgressListener;
+
+/**
+ * This is an {@link InputStream} wrapper implementation to trace the progress
+ * of an {@code InputStream}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class TracedInputStream extends InputStream {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ProgressListener progressListener;
+	private final InputStream inputStream;
+	private final long size;
+
+	private double transferred = 0;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param inputStream      The traced {@link InputStream}.
+	 * @param progressListener The listener will be used to fire update
+	 *                         notifications.
+	 * @param length           The length of the consumed {@code InputStream}.
+	 */
+	TracedInputStream(InputStream inputStream, ProgressListener progressListener, long length) {
+		this.progressListener = progressListener;
+		this.inputStream = inputStream;
+		size = length;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int read() throws IOException {
+		return inputStream.read();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int read(byte[] buffer, int offset, int length) throws IOException {
+		int read = inputStream.read(buffer, offset, length);
+		if (read > -1) {
+			transferred += read;
+			progressListener.progress(read, (float) (transferred / size));
+		}
+		return read;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void close() throws IOException {
+		inputStream.close();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/Transfer.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/Transfer.java
new file mode 100644
index 0000000..a658553
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/filetransfer/Transfer.java
@@ -0,0 +1,63 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.filetransfer;
+
+import java.io.InputStream;
+
+/**
+ * Transfer type enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public enum Transfer {
+
+	// ======================================================================
+	// Enum constants
+	// ======================================================================
+
+	/**
+	 * Simple {@link InputStream}s are used for up- and downloads.
+	 */
+	STREAM,
+
+	/**
+	 * Socket {@link InputStream}s are used for up- and downloads.
+	 */
+	SOCKET;
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Checks whether this transfer is {@link #STREAM}.
+	 *
+	 * @return Returns {@code true} if this instance is {@link #STREAM}.
+	 */
+	boolean isStream() {
+		return STREAM == this;
+	}
+
+	/**
+	 * Checks whether this transfer is {@link #SOCKET}.
+	 *
+	 * @return Returns {@code true} if this instance is {@link #SOCKET}.
+	 */
+	boolean isSocket() {
+		return SOCKET == this;
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/Cache.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/Cache.java
new file mode 100644
index 0000000..f9264b1
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/Cache.java
@@ -0,0 +1,68 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+
+/**
+ * Used to temporarily cache {@link EntityResult}s fore reuse in subsequent
+ * {@link EntityRequest}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class Cache {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<EntityConfig<?>, EntityResult<?>> cache = new HashMap<>();
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Caches given {@link EntityResult}.
+	 *
+	 * @param entityResult The {@link EntityResult}.
+	 */
+	public void add(EntityResult<?> entityResult) {
+		cache.put(entityResult.request.entityConfig, entityResult);
+	}
+
+	/**
+	 * Returns the cached {@link EntityResult} associated with given
+	 * {@link EntityConfig}.
+	 *
+	 * @param entityConfig Used as identifier.
+	 * @return The {@code EntityResult} is returned.
+	 * @throws IllegalArgumentException Thrown if requested {@code
+	 * 		EntityResult}            not found.
+	 */
+	public EntityResult<?> get(EntityConfig<?> entityConfig) {
+		EntityResult<?> entityResult = cache.get(entityConfig);
+		if (entityResult == null) {
+			throw new IllegalArgumentException("Entity result not found");
+		}
+
+		return entityResult;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/ChildRequest.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/ChildRequest.java
new file mode 100644
index 0000000..bb1a24b
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/ChildRequest.java
@@ -0,0 +1,205 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup;
+
+import static java.util.stream.Stream.concat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+
+/**
+ * Extends {@link EntityRequest} to load children for a given
+ * {@link EntityRequest}.
+ *
+ * @param <T> The entity type.
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class ChildRequest<T extends Deletable> extends EntityRequest<T> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final EntityRequest<?> parent;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param parentRequest The parent {@link EntityRequest}.
+	 * @param entityConfig  The {@link EntityConfig}.
+	 */
+	ChildRequest(EntityRequest<?> parentRequest, EntityConfig<T> entityConfig) {
+		super(parentRequest, entityConfig);
+		parent = parentRequest;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Loads all related child entities.
+	 *
+	 * @return Returns the queried {@code EntityResult}.
+	 * @throws DataAccessException Thrown if unable to load entities.
+	 */
+	public EntityResult<T> load() throws DataAccessException {
+		filtered = parent.filtered;
+
+		EntityType entityType = entityConfig.getEntityType();
+		Relation parentRelation = entityConfig.getEntityType().getRelation(parent.entityConfig.getEntityType());
+		Relation reflexiveRelation = entityConfig.isReflexive() ? entityType.getRelation(entityType) : null;
+
+		Query query = queryService.createQuery()
+				// select entity attributes
+				.selectAll(entityConfig.getEntityType())
+				// select parent entity ID
+				.select(parentRelation.getAttribute());
+
+		if (entityConfig.isReflexive()) {
+			query.select(reflexiveRelation.getAttribute());
+			// entities with children have to be processed before their
+			// children!
+			query.order(entityType.getIDAttribute());
+		}
+
+		// prepare relations select statements
+		List<RelationConfig> optionalRelations = selectRelations(query, entityConfig.getOptionalConfigs(), false);
+		List<RelationConfig> mandatoryRelations = selectRelations(query, entityConfig.getMandatoryConfigs(), true);
+		List<RelationConfig> inheritedRelations = selectRelations(query, entityConfig.getInheritedConfigs(), true);
+
+		// configure filter
+		Filter adjustedFilter = Filter.or();
+		if (filtered) {
+			// preserve current conditions
+			adjustedFilter.ids(parentRelation, parent.entityResult.getIDs());
+			if (entityConfig.isReflexive()) {
+				// extend to retrieve all reflexive child candidates
+				adjustedFilter.add(ComparisonOperator.IS_NOT_NULL.create(reflexiveRelation.getAttribute(), 0L));
+			}
+		}
+
+		// load entities and prepare mappings for required related entities
+		List<EntityRecord<?>> parentRecords = new ArrayList<>();
+		for (Record record : collectRecords(query.fetch(adjustedFilter))) {
+			Optional<String> parentID = record.getID(parentRelation);
+			Optional<String> reflexiveParentID = Optional.empty();
+			if (entityConfig.isReflexive()) {
+				reflexiveParentID = record.getID(reflexiveRelation);
+			}
+			EntityRecord<T> entityRecord;
+
+			if (parentID.isPresent()) {
+				EntityResult<?> parentResult = parent.entityResult;
+				@SuppressWarnings({ "unchecked", "rawtypes" })
+				Optional<EntityRecord<?>> parentRecord = (Optional) parentResult.get(parentID.get());
+				if (!parentRecord.isPresent()) {
+					continue;
+				}
+
+				entityRecord = entityResult.add(parentRecord.get(), record);
+				parentRecords.add(parentRecord.get());
+			} else if (entityConfig.isReflexive() && reflexiveParentID.isPresent()) {
+				Optional<EntityRecord<T>> parentRecord = entityResult.get(reflexiveParentID.get());
+				if (!parentRecord.isPresent()) {
+					// this entity's parent was not loaded -> skip
+					continue;
+				}
+				// reflexive child
+				entityRecord = entityResult.add(parentRecord.get(), record);
+				parentRecords.add(parentRecord.get());
+			} else {
+				throw new IllegalStateException("Entity without parent found");
+			}
+
+			// collect related instance IDs
+			concat(concat(optionalRelations.stream(), mandatoryRelations.stream()), inheritedRelations.stream())
+					.forEach(rc -> rc.add(entityRecord, record));
+		}
+
+		if (entityResult.isEmpty()) {
+			// no entities found -> neither related nor child entities required
+			return entityResult;
+		}
+
+		// load and map related entities
+		loadRelatedEntities(optionalRelations);
+		loadRelatedEntities(mandatoryRelations);
+		assignRelatedEntities(inheritedRelations);
+
+		// sort children of parent
+		for (EntityRecord<?> entityRecord : parentRecords) {
+			entityRecord.core.getChildrenStore().sort(entityConfig.getEntityClass(), entityConfig.getComparator());
+		}
+
+		// load children
+		for (EntityConfig<? extends Deletable> childConfig : entityConfig.getChildConfigs()) {
+			cache.add(new ChildRequest<>(this, childConfig).load());
+		}
+
+		return entityResult;
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Maps related entities for each given {@link RelationConfig} using the
+	 * entities loaded in previous {@link EntityRequest}.
+	 *
+	 * @param relationConfigs The {@code RelationConfig}s.
+	 * @throws DataAccessException Thrown if unable to load related entities.
+	 */
+	private void assignRelatedEntities(List<RelationConfig> relationConfigs) throws DataAccessException {
+		for (RelationConfig relationConfig : relationConfigs) {
+			EntityConfig<?> relatedConfig = relationConfig.entityConfig;
+
+			boolean isContextTypeDefined = entityConfig.getContextType().isPresent();
+			for (Entity relatedEntity : cache.get(relatedConfig).getEntities()) {
+				boolean setByContextType = !isContextTypeDefined && relatedConfig.getContextType().isPresent();
+				List<EntityRecord<?>> entityRecords = relationConfig.dependants.remove(relatedEntity.getID());
+				entityRecords = entityRecords == null ? new ArrayList<EntityRecord<?>>() : entityRecords;
+				for (EntityRecord<?> entityRecord : entityRecords) {
+					setRelatedEntity(entityRecord, relatedEntity,
+							setByContextType ? relatedConfig.getContextType().get() : null);
+				}
+			}
+
+			if (!relationConfig.dependants.isEmpty()) {
+				// this may occur if the instance id of the related entity
+				// is defined, but the entity itself does not exist
+				throw new IllegalStateException("Unable to load related entities.");
+			}
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityLoader.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityLoader.java
new file mode 100644
index 0000000..fc7a3e4
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityLoader.java
@@ -0,0 +1,123 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+
+/**
+ * Loads complete {@link Entity}s by using the {@link EntityConfig} identified
+ * by given {@link Key}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class EntityLoader {
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ODSModelManager modelManager;
+	private final QueryService queryService;
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager The {@link ODSModelManager}.
+	 */
+	public EntityLoader(ODSModelManager modelManager, QueryService queryService) {
+		this.modelManager = modelManager;
+		this.queryService = queryService;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Loads the entity with given instance ID.
+	 *
+	 * @param <T>        The entity type.
+	 * @param key        Used to resolve the entity configuration.
+	 * @param instanceID The instance ID.
+	 * @return The queried {@code Entity} is returned.
+	 * @throws DataAccessException Thrown if unable to load entities.
+	 */
+	public <T extends Entity> T load(Key<T> key, String instanceID) throws DataAccessException {
+		List<T> entities = loadAll(key, Collections.singletonList(instanceID));
+		if (entities.size() != 1) {
+			throw new DataAccessException("Failed to load entity by instance ID.");
+		}
+		return entities.get(0);
+	}
+
+	/**
+	 * Loads all entities matching given name pattern.
+	 *
+	 * @param <T>     The entity type.
+	 * @param key     Used to resolve the entity configuration.
+	 * @param pattern Is always case sensitive and may contain wildcard characters
+	 *                as follows: "?" for one matching character and "*" for a
+	 *                sequence of matching characters.
+	 * @return A {@link List} with queried entities is returned.
+	 * @throws DataAccessException Thrown if unable to load entities.
+	 */
+	public <T extends Entity> List<T> loadAll(Key<T> key, String pattern) throws DataAccessException {
+		return createRequest(key).loadAll(pattern);
+	}
+
+	/**
+	 * Loads all entities matching given instance IDs.
+	 *
+	 * @param <T>         The entity type.
+	 * @param key         Used to resolve the entity configuration.
+	 * @param instanceIDs The instance IDs.
+	 * @return A {@link List} with queried entities is returned.
+	 * @throws DataAccessException Thrown if unable to load entities.
+	 */
+	public <T extends Entity> List<T> loadAll(Key<T> key, Collection<String> instanceIDs) throws DataAccessException {
+		return createRequest(key).loadAll(instanceIDs);
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link EntityRequest} for given {@link Key}.
+	 *
+	 * @param <T> The entity type.
+	 * @param key Used to resolve the entity configuration.
+	 * @return The created {@code EntityRequest} is returned.
+	 */
+	private <T extends Entity> EntityRequest<T> createRequest(Key<T> key) {
+		/*
+		 * TODO: add custom request implementations here!
+		 */
+		return new EntityRequest<>(modelManager, queryService, key);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRecord.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRecord.java
new file mode 100644
index 0000000..6f8e89d
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRecord.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.Entity;
+
+/**
+ * Utility class to group {@link Entity} and its {@link Core}.
+ *
+ * @param <T> The entity type.
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class EntityRecord<T extends Entity> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	final Core core;
+	final T entity;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param entity The {@link Entity}.
+	 * @param core   The {@link Core} of the {@code Entity}.
+	 */
+	EntityRecord(T entity, Core core) {
+		this.entity = entity;
+		this.core = core;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return "EntityRecord [core=" + core + ", entity=" + entity + "]";
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRequest.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRequest.java
new file mode 100644
index 0000000..067da7a
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityRequest.java
@@ -0,0 +1,334 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup;
+
+import static java.util.stream.Collectors.toList;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextSensor;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
+import org.eclipse.mdm.api.dflt.model.TemplateComponent;
+import org.eclipse.mdm.api.dflt.model.TemplateSensor;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+
+/**
+ * Recursively loads entities for a given {@link EntityConfig} with all resolved
+ * dependencies (optional, mandatory children).
+ *
+ * @param <T> The entity type.
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class EntityRequest<T extends Entity> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	final ODSModelManager odsModelManager;
+	final QueryService queryService;
+	final EntityConfig<T> entityConfig;
+	final EntityResult<T> entityResult = new EntityResult<>(this);
+
+	final Cache cache;
+
+	boolean filtered;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager The {@link ODSModelManager}.
+	 * @param config       The {@link EntityConfig}.
+	 */
+	public EntityRequest(ODSModelManager modelManager, QueryService queryService, Key<T> key) {
+		this.odsModelManager = modelManager;
+		this.queryService = queryService;
+		this.entityConfig = modelManager.getEntityConfig(key);
+		cache = new Cache();
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param parentRequest The parent {@link EntityRequest}.
+	 * @param entityConfig  The {@link EntityConfig}.
+	 */
+	protected EntityRequest(EntityRequest<?> parentRequest, EntityConfig<T> entityConfig) {
+		odsModelManager = parentRequest.odsModelManager;
+		queryService = parentRequest.queryService;
+		cache = parentRequest.cache;
+		this.entityConfig = entityConfig;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Loads all entities matching given name pattern.
+	 *
+	 * @param pattern Is always case sensitive and may contain wildcard characters
+	 *                as follows: "?" for one matching character and "*" for a
+	 *                sequence of matching characters.
+	 * @return A sorted {@link List} with queried entities is returned.
+	 * @throws DataAccessException Thrown if unable to load entities.
+	 */
+	public List<T> loadAll(String pattern) throws DataAccessException {
+		return load(Filter.nameOnly(entityConfig.getEntityType(), pattern)).getSortedEntities();
+	}
+
+	/**
+	 * Loads all entities matching given instance IDs.
+	 *
+	 * @param instanceIDs The instance IDs.
+	 * @return A sorted {@link List} with queried entities is returned.
+	 * @throws DataAccessException Thrown if unable to load entities.
+	 */
+	public List<T> loadAll(Collection<String> instanceIDs) throws DataAccessException {
+		if (instanceIDs.isEmpty()) {
+			// just to be sure...
+			return Collections.emptyList();
+		}
+
+		return load(Filter.idsOnly(entityConfig.getEntityType(), instanceIDs)).getSortedEntities();
+	}
+
+	public ODSModelManager getODSModelManager() {
+		return odsModelManager;
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Adds foreign key select statements to given {@link Query} for each given
+	 * {@link EntityConfig}.
+	 *
+	 * @param query          The {@link Query}.
+	 * @param relatedConfigs The {@code EntityConfig}s.
+	 * @param mandatory      Flag indicates whether given {@code EntityConfig}s are
+	 *                       mandatory or not.
+	 * @return For each {@code EntityConfig} a corresponding {@code
+	 * 		RelationConfig} is returned in a {@code List}.
+	 */
+	protected List<RelationConfig> selectRelations(Query query, List<EntityConfig<?>> relatedConfigs,
+			boolean mandatory) {
+		List<RelationConfig> relationConfigs = new ArrayList<>();
+		EntityType entityType = entityConfig.getEntityType();
+		for (EntityConfig<?> relatedEntityConfig : relatedConfigs) {
+			RelationConfig relationConfig = new RelationConfig(entityType, relatedEntityConfig, mandatory);
+			query.select(relationConfig.relation.getAttribute());
+			relationConfigs.add(relationConfig);
+		}
+
+		return relationConfigs;
+	}
+
+	/**
+	 * Convenience method collects the queried {@link Record} from each
+	 * {@link Result}.
+	 *
+	 * @param results The {@code Result}s.
+	 * @return The queried {@link Record}s are returned.
+	 */
+	protected List<Record> collectRecords(List<Result> results) {
+		return results.stream().map(r -> r.getRecord(entityConfig.getEntityType())).collect(toList());
+	}
+
+	/**
+	 * Loads and maps related entities for each given {@link RelationConfig}.
+	 *
+	 * @param relationConfigs The {@code RelationConfig}s.
+	 * @throws DataAccessException Thrown if unable to load related entities.
+	 */
+	protected void loadRelatedEntities(List<RelationConfig> relationConfigs) throws DataAccessException {
+		for (RelationConfig relationConfig : relationConfigs) {
+			EntityConfig<?> relatedConfig = relationConfig.entityConfig;
+
+			boolean isContextTypeDefined = entityConfig.getContextType().isPresent();
+			for (Entity relatedEntity : new EntityRequest<>(this, relatedConfig)
+					.loadAll(relationConfig.dependants.keySet())) {
+				boolean setByContextType = !isContextTypeDefined && relatedConfig.getContextType().isPresent();
+				for (EntityRecord<?> entityRecord : relationConfig.dependants.remove(relatedEntity.getID())) {
+					setRelatedEntity(entityRecord, relatedEntity,
+							setByContextType ? relatedConfig.getContextType().get() : null);
+				}
+			}
+
+			if (!relationConfig.dependants.isEmpty()) {
+				// this may occur if the instance id of the related entity
+				// is defined, but the entity itself does not exist
+				throw new IllegalStateException(
+						"Unable to load related entities: " + relationConfig.dependants.toString());
+			}
+		}
+	}
+
+	/**
+	 * Assigns given related {@link Entity} to given {@link EntityRecord}.
+	 *
+	 * @param entityRecord  The {@code EntityRecord} which references given
+	 *                      {@code Entity}.
+	 * @param relatedEntity The related {@code Entity}.
+	 * @param contextType   Used as qualifier for relation assignment.
+	 */
+	protected void setRelatedEntity(EntityRecord<?> entityRecord, Entity relatedEntity, ContextType contextType) {
+		if (contextType == null) {
+			entityRecord.core.getMutableStore().set(relatedEntity);
+		} else {
+			entityRecord.core.getMutableStore().set(relatedEntity, contextType);
+		}
+
+		List<TemplateAttribute> templateAttributes = new ArrayList<>();
+		if (entityRecord.entity instanceof ContextComponent && relatedEntity instanceof TemplateComponent) {
+			templateAttributes.addAll(((TemplateComponent) relatedEntity).getTemplateAttributes());
+		} else if (entityRecord.entity instanceof ContextSensor && relatedEntity instanceof TemplateSensor) {
+			templateAttributes.addAll(((TemplateSensor) relatedEntity).getTemplateAttributes());
+		}
+
+		if (!templateAttributes.isEmpty()) {
+			// hide Value containers that are missing in the template
+			Set<String> names = new HashSet<>(entityRecord.core.getValues().keySet());
+			names.remove(Entity.ATTR_NAME);
+			names.remove(Entity.ATTR_MIMETYPE);
+			templateAttributes.stream().map(Entity::getName).forEach(names::remove);
+			entityRecord.core.hideValues(names);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Loads all entities matching given {@link Filter} including all of related
+	 * entities (optional, mandatory and children).
+	 *
+	 * @param filter The {@link Filter}.
+	 * @return Returns the queried {@code EntityResult}.
+	 * @throws DataAccessException Thrown if unable to load entities.
+	 */
+	private EntityResult<T> load(Filter filter) throws DataAccessException {
+		filtered = !filter.isEmtpty() || entityConfig.isReflexive();
+
+		EntityType entityType = entityConfig.getEntityType();
+		Relation reflexiveRelation = entityConfig.isReflexive() ? entityType.getRelation(entityType) : null;
+
+		Query query = queryService.createQuery().selectAll(entityConfig.getEntityType());
+
+		if (entityConfig.isReflexive()) {
+			query.select(reflexiveRelation.getAttribute());
+			// entities with children have to be processed before their
+			// children!
+			query.order(entityType.getIDAttribute());
+		}
+
+		// prepare relations select statements
+		List<RelationConfig> optionalRelations = selectRelations(query, entityConfig.getOptionalConfigs(), false);
+		List<RelationConfig> mandatoryRelations = selectRelations(query, entityConfig.getMandatoryConfigs(), true);
+
+		// configure filter
+		Filter adjustedFilter = Filter.or();
+		if (filtered) {
+			// preserve current conditions
+			adjustedFilter.merge(filter);
+			if (entityConfig.isReflexive()) {
+				// extend to retrieve all reflexive child candidates
+				adjustedFilter.add(ComparisonOperator.IS_NOT_NULL.create(reflexiveRelation.getAttribute(), 0L));
+			}
+		}
+
+		// load entities and prepare mappings for required related entities
+		List<EntityRecord<?>> parentRecords = new ArrayList<>();
+		for (Record record : collectRecords(query.fetch(adjustedFilter))) {
+			Optional<String> reflexiveParentID = Optional.empty();
+			if (entityConfig.isReflexive()) {
+				reflexiveParentID = record.getID(reflexiveRelation);
+			}
+			EntityRecord<T> entityRecord;
+
+			if (entityConfig.isReflexive() && reflexiveParentID.isPresent()) {
+				Optional<EntityRecord<T>> parentRecord = entityResult.get(reflexiveParentID.get());
+				if (!parentRecord.isPresent()) {
+					// this entity's parent was not loaded -> skip
+					continue;
+				}
+
+				entityRecord = entityResult.add(parentRecord.get(), record);
+				parentRecords.add(parentRecord.get());
+			} else {
+				entityRecord = entityResult.add(record);
+			}
+
+			// collect related instance IDs
+			Stream.concat(optionalRelations.stream(), mandatoryRelations.stream())
+					.forEach(rc -> rc.add(entityRecord, record));
+		}
+
+		if (entityResult.isEmpty()) {
+			// no entities found -> neither related nor child entities required
+			return entityResult;
+		}
+
+		// load and map related entities
+		loadRelatedEntities(optionalRelations);
+		loadRelatedEntities(mandatoryRelations);
+
+		// sort children of parent
+		if (entityConfig.isReflexive()) {
+			@SuppressWarnings("unchecked")
+			EntityConfig<Deletable> childConfig = (EntityConfig<Deletable>) entityConfig;
+			for (EntityRecord<?> entityRecord : parentRecords) {
+				entityRecord.core.getChildrenStore().sort(childConfig.getEntityClass(), childConfig.getComparator());
+			}
+		}
+
+		// load children
+		for (EntityConfig<? extends Deletable> childConfig : entityConfig.getChildConfigs()) {
+			cache.add(new ChildRequest<>(this, childConfig).load());
+		}
+
+		return entityResult;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityResult.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityResult.java
new file mode 100644
index 0000000..ac17653
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/EntityResult.java
@@ -0,0 +1,206 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup;
+
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_ENUMERATION_NAME;
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SCALAR_TYPE;
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SEQUENCE;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.DefaultCore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
+import org.eclipse.mdm.api.dflt.model.CatalogComponent;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+
+/**
+ * Container for entities by executing an {@link EntityRequest}.
+ *
+ * @param <T> The entity type.
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class EntityResult<T extends Entity> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<String, EntityRecord<T>> entityRecords = new HashMap<>();
+	private final List<T> entities = new ArrayList<>();
+
+	final EntityRequest<T> request;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param request The associated {@link EntityRequest}.
+	 */
+	EntityResult(EntityRequest<T> request) {
+		this.request = request;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link EntityRecord} identified by given instance ID.
+	 *
+	 * @param id The instance ID.
+	 * @return {@code Optional} is empty if {@code EntityRecord} not found.
+	 */
+	public Optional<EntityRecord<T>> get(String id) {
+		return Optional.ofNullable(entityRecords.get(id));
+	}
+
+	/**
+	 * Creates an {@link EntityRecord} for given {@link Record} and mapps it
+	 * internally by its instance ID.
+	 *
+	 * @param record The {@code Record}.
+	 * @return The created {@code EntityRecord} is returned.
+	 */
+	public EntityRecord<T> add(Record record) {
+		return create(new DefaultCore(record));
+	}
+
+	/**
+	 * Creates an {@link EntityRecord} for given {@link Record} using given parent
+	 * {@code EntityRecord} and maps it internally by its instance ID.
+	 *
+	 * @param parentRecord The created {@code EntityRecord} will be related as a
+	 *                     child with this one.
+	 * @param record       The {@code Record}.
+	 * @return The created {@code EntityRecord} is returned.
+	 */
+	public EntityRecord<T> add(EntityRecord<?> parentRecord, Record record) {
+		Core core = new DefaultCore(record);
+
+		if (CatalogAttribute.class.equals(request.entityConfig.getEntityClass())) {
+			// add read only properties from application model
+			adjustCatalogAttributeCore(parentRecord.entity, core);
+		}
+
+		EntityRecord<T> childRecord = create(core);
+		childRecord.core.getPermanentStore().set(parentRecord.entity);
+		parentRecord.core.getChildrenStore().add((Deletable) childRecord.entity);
+		return childRecord;
+	}
+
+	/**
+	 * Returns the {@link Entity}s of this entity result.
+	 *
+	 * @return Returned {@code Collection} is unmodifiable.
+	 */
+	public List<T> getEntities() {
+		return Collections.unmodifiableList(entities);
+	}
+
+	/**
+	 * Returns the {@link Entity}s of this entity result sorted.
+	 *
+	 * @return Returned {@code Collection} is unmodifiable.
+	 */
+	public List<T> getSortedEntities() {
+		return Collections.unmodifiableList(
+				entities.stream().sorted(request.entityConfig.getComparator()).collect(Collectors.toList()));
+	}
+
+	/**
+	 * Returns the instance IDs of the entities held by this entity result.
+	 *
+	 * @return Returned {@code Collection} is unmodifiable.
+	 */
+	public Collection<String> getIDs() {
+		return Collections.unmodifiableCollection(entityRecords.keySet());
+	}
+
+	/**
+	 * Checks whether this entity result holds entities or is empty.
+	 *
+	 * @return Returns {@code true} if this entity result has no entities.
+	 */
+	public boolean isEmpty() {
+		return entities.isEmpty();
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Adds further meta data to the given {@link CatalogAttribute} {@link Core}.
+	 *
+	 * @param catalogComponent     The parent {@link CatalogComponent}.
+	 * @param catalogAttributeCore The {@code CatalogAttribute} {@code Core}.
+	 */
+	private void adjustCatalogAttributeCore(Entity catalogComponent, Core catalogAttributeCore) {
+		EntityType entityType = request.odsModelManager.getEntityType(catalogComponent.getName());
+		Attribute attribute = entityType.getAttribute(catalogAttributeCore.getValues().get(Entity.ATTR_NAME).extract());
+
+		Map<String, Value> values = catalogAttributeCore.getValues();
+		Value enumerationName = ValueType.STRING.create(VATTR_ENUMERATION_NAME);
+		values.put(VATTR_ENUMERATION_NAME, enumerationName);
+		if (attribute.getValueType().isEnumerationType()) {
+			enumerationName.set(attribute.getEnumObj().getName());
+		}
+
+		Enumeration<?> scalarTypeObj = EnumRegistry.getInstance().get("ScalarType");
+		Value scalarType = ValueType.ENUMERATION.create(scalarTypeObj, VATTR_SCALAR_TYPE);
+		scalarType.set(scalarTypeObj.valueOf(attribute.getValueType().toSingleType().name()));
+		values.put(VATTR_SCALAR_TYPE, scalarType);
+
+		values.put(VATTR_SEQUENCE, ValueType.BOOLEAN.create(VATTR_SEQUENCE, attribute.getValueType().isSequence()));
+	}
+
+	/**
+	 * Creates a new {@link EntityRecord} instance for given {@link Core}. The
+	 * {@link EntityRecord} is internally mapped the its instance ID.
+	 *
+	 * @param core The {@code Core}.
+	 * @return The created {@link EntityRecord} is returned.
+	 */
+	private EntityRecord<T> create(Core core) {
+		ODSEntityFactory odsEntityFactory = new ODSEntityFactory(request.getODSModelManager(), null);
+		EntityRecord<T> entityRecord = new EntityRecord<>(
+				odsEntityFactory.createEntity(request.entityConfig.getEntityClass(), core), core);
+		entityRecords.put(core.getID(), entityRecord);
+		entities.add(entityRecord.entity);
+		return entityRecord;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/RelationConfig.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/RelationConfig.java
new file mode 100644
index 0000000..1a4f8c9
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/RelationConfig.java
@@ -0,0 +1,86 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+
+/**
+ * Utility class to collect {@link EntityRecord} referencing entities of the
+ * same type specified by an instance of this class.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class RelationConfig {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	final Map<String, List<EntityRecord<?>>> dependants = new HashMap<>();
+	final EntityConfig<?> entityConfig;
+	final Relation relation;
+	final boolean mandatory;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param source       The source {@link EntityType}.
+	 * @param entityConfig The target {@link EntityConfig}.
+	 * @param mandatory    Flag indicates whether a related must exist or not.
+	 */
+	public RelationConfig(EntityType source, EntityConfig<?> entityConfig, boolean mandatory) {
+		this.entityConfig = entityConfig;
+		relation = source.getRelation(entityConfig.getEntityType());
+		this.mandatory = mandatory;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Given {@link EntityRecord} depends on {@link Entity}s which are loaded by
+	 * processing this relation config. Therefore given {@code EntityRecord} cached
+	 * and satisfied as soon as the corresponding entities are loaded.
+	 *
+	 * @param entityRecord The dependant {@code EntityRecord}.
+	 * @param record       The {@link Record} associated with given
+	 *                     {@link EntityRecord}.
+	 */
+	public void add(EntityRecord<?> entityRecord, Record record) {
+		Optional<String> relatedEntityID = record.getID(relation);
+		if (relatedEntityID.isPresent()) {
+			dependants.computeIfAbsent(relatedEntityID.get(), k -> new ArrayList<>()).add(entityRecord);
+		} else if (mandatory) {
+			throw new IllegalStateException("Mandatory relation unsatisfied for relation " + relation.getName());
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/DefaultEntityConfigRepositoryLoader.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/DefaultEntityConfigRepositoryLoader.java
new file mode 100644
index 0000000..0b6e839
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/DefaultEntityConfigRepositoryLoader.java
@@ -0,0 +1,370 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup.config;
+
+import java.util.Locale;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextSensor;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Environment;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Parameter;
+import org.eclipse.mdm.api.base.model.ParameterSet;
+import org.eclipse.mdm.api.base.model.PhysicalDimension;
+import org.eclipse.mdm.api.base.model.Quantity;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
+import org.eclipse.mdm.api.dflt.model.CatalogComponent;
+import org.eclipse.mdm.api.dflt.model.CatalogSensor;
+import org.eclipse.mdm.api.dflt.model.Classification;
+import org.eclipse.mdm.api.dflt.model.Domain;
+import org.eclipse.mdm.api.dflt.model.ExtSystem;
+import org.eclipse.mdm.api.dflt.model.ExtSystemAttribute;
+import org.eclipse.mdm.api.dflt.model.MDMAttribute;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.dflt.model.ProjectDomain;
+import org.eclipse.mdm.api.dflt.model.Role;
+import org.eclipse.mdm.api.dflt.model.Status;
+import org.eclipse.mdm.api.dflt.model.SystemParameter;
+import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
+import org.eclipse.mdm.api.dflt.model.TemplateComponent;
+import org.eclipse.mdm.api.dflt.model.TemplateRoot;
+import org.eclipse.mdm.api.dflt.model.TemplateSensor;
+import org.eclipse.mdm.api.dflt.model.TemplateTest;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStepUsage;
+import org.eclipse.mdm.api.dflt.model.UserParameter;
+import org.eclipse.mdm.api.dflt.model.ValueList;
+import org.eclipse.mdm.api.dflt.model.ValueListValue;
+import org.eclipse.mdm.api.dflt.model.Versionable;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultEntityConfigRepositoryLoader implements EntityConfigRepositoryLoader {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(DefaultEntityConfigRepositoryLoader.class);
+
+	EntityConfigRepository entityConfigRepository;
+
+	public DefaultEntityConfigRepositoryLoader() {
+	}
+
+	/**
+	 * Loads the {@link EntityConfig}s.
+	 * 
+	 * @return
+	 */
+	@Override
+	public EntityConfigRepository loadEntityConfigurations(ODSModelManager modelManager) {
+		LOGGER.debug("Loading entity configurations...");
+		long start = System.currentTimeMillis();
+
+		entityConfigRepository = new EntityConfigRepository();
+
+		entityConfigRepository.register(create(modelManager, new Key<>(Role.class), "Role", false));
+
+		// Environment | Project | Pool | PhysicalDimension | User | Measurement
+		// | ChannelGroup
+		entityConfigRepository.register(create(modelManager, new Key<>(Environment.class), "Environment", false));
+		entityConfigRepository.register(create(modelManager, new Key<>(Project.class), "Project", false));
+		entityConfigRepository.register(create(modelManager, new Key<>(Pool.class), "StructureLevel", true));
+		entityConfigRepository
+				.register(create(modelManager, new Key<>(PhysicalDimension.class), "PhysDimension", false));
+		entityConfigRepository.register(create(modelManager, new Key<>(User.class), "User", false));
+		entityConfigRepository.register(create(modelManager, new Key<>(Measurement.class), "MeaResult", false));
+		entityConfigRepository.register(create(modelManager, new Key<>(ChannelGroup.class), "SubMatrix", false));
+
+		// Unit
+		EntityConfig<Unit> unitConfig = create(modelManager, new Key<>(Unit.class), "Unit", false);
+		unitConfig.addMandatory(entityConfigRepository.findRoot(new Key<>(PhysicalDimension.class)));
+		entityConfigRepository.register(unitConfig);
+
+		// Quantity
+		EntityConfig<Quantity> quantityConfig = create(modelManager, new Key<>(Quantity.class), "Quantity", false);
+		quantityConfig.addMandatory(entityConfigRepository.findRoot(new Key<>(Unit.class)));
+		entityConfigRepository.register(quantityConfig);
+
+		// Channel
+		EntityConfig<Channel> channelConfig = create(modelManager, new Key<>(Channel.class), "MeaQuantity", false);
+		channelConfig.addMandatory(entityConfigRepository.findRoot(new Key<>(Unit.class)));
+		channelConfig.addMandatory(entityConfigRepository.findRoot(new Key<>(Quantity.class)));
+		entityConfigRepository.register(channelConfig);
+
+		// ValueList
+		EntityConfig<ValueListValue> valueListValueConfig = create(modelManager, new Key<>(ValueListValue.class),
+				"ValueListValue", true);
+		valueListValueConfig.setComparator(Sortable.COMPARATOR);
+		EntityConfig<ValueList> valueListConfig = create(modelManager, new Key<>(ValueList.class), "ValueList", true);
+		valueListConfig.addChild(valueListValueConfig);
+		entityConfigRepository.register(valueListConfig);
+
+		// ParameterSet
+		EntityConfig<Parameter> parameterConfig = create(modelManager, new Key<>(Parameter.class), "ResultParameter",
+				true);
+		parameterConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Unit.class)));
+		EntityConfig<ParameterSet> parameterSetConfig = create(modelManager, new Key<>(ParameterSet.class),
+				"ResultParameterSet", true);
+		parameterSetConfig.addChild(parameterConfig);
+		entityConfigRepository.register(parameterSetConfig);
+
+		// CatalogComponents
+		registerCatalogComponent(modelManager, ContextType.UNITUNDERTEST);
+		registerCatalogComponent(modelManager, ContextType.TESTSEQUENCE);
+		registerCatalogComponent(modelManager, ContextType.TESTEQUIPMENT);
+
+		// TemplateRoots
+		registerTemplateRoot(modelManager, ContextType.UNITUNDERTEST);
+		registerTemplateRoot(modelManager, ContextType.TESTSEQUENCE);
+		registerTemplateRoot(modelManager, ContextType.TESTEQUIPMENT);
+
+		// TemplateTestStep
+		EntityConfig<TemplateTestStep> templateTestStepConfig = create(modelManager, new Key<>(TemplateTestStep.class),
+				"TplTestStep", true);
+		templateTestStepConfig
+				.addOptional(entityConfigRepository.findRoot(new Key<>(TemplateRoot.class, ContextType.UNITUNDERTEST)));
+		templateTestStepConfig
+				.addOptional(entityConfigRepository.findRoot(new Key<>(TemplateRoot.class, ContextType.TESTSEQUENCE)));
+		templateTestStepConfig
+				.addOptional(entityConfigRepository.findRoot(new Key<>(TemplateRoot.class, ContextType.TESTEQUIPMENT)));
+		templateTestStepConfig.setComparator(Versionable.COMPARATOR);
+		entityConfigRepository.register(templateTestStepConfig);
+
+		// Status
+		entityConfigRepository.register(create(modelManager, new Key<>(Status.class), "Status", false));
+
+		// ProjectDomain
+		entityConfigRepository.register(create(modelManager, new Key<>(ProjectDomain.class), "ProjectDomain", false));
+
+		// Domain
+		entityConfigRepository.register(create(modelManager, new Key<>(Domain.class), "Domain", false));
+
+		// Classification
+		EntityConfig<Classification> classificationConfig = create(modelManager, new Key<>(Classification.class),
+				"Classification", false);
+		classificationConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Status.class)));
+		classificationConfig.addOptional(entityConfigRepository.findRoot(new Key<>(ProjectDomain.class)));
+		classificationConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Domain.class)));
+		entityConfigRepository.register(classificationConfig);
+
+		// TestStep
+		EntityConfig<TestStep> testStepConfig = create(modelManager, new Key<>(TestStep.class), "TestStep", true);
+		// testStepConfig.addMandatory(entityConfigRepository.findRoot(new
+		// Key<>(Status.class, TestStep.class)));
+		testStepConfig.addOptional(entityConfigRepository.findRoot(new Key<>(TemplateTestStep.class)));
+		testStepConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Classification.class)));
+		testStepConfig.setComparator(Sortable.COMPARATOR);
+		entityConfigRepository.register(testStepConfig);
+
+		// TemplateTest
+		EntityConfig<TemplateTestStepUsage> templateTestStepUsageConfig = create(modelManager,
+				new Key<>(TemplateTestStepUsage.class), "TplTestStepUsage", true);
+		templateTestStepUsageConfig.addMandatory(templateTestStepConfig);
+		templateTestStepUsageConfig.setComparator(Sortable.COMPARATOR);
+		EntityConfig<TemplateTest> templateTestConfig = create(modelManager, new Key<>(TemplateTest.class), "TplTest",
+				true);
+		templateTestConfig.addChild(templateTestStepUsageConfig);
+		templateTestConfig.setComparator(Versionable.COMPARATOR);
+		entityConfigRepository.register(templateTestConfig);
+
+		// Status Test
+		// TODO check MIME type genration
+		// entityConfigRepository.register(create(new Key<>(Status.class,
+		// Test.class), "StatusTest", true));
+
+		// Test
+		EntityConfig<Test> testConfig = create(modelManager, new Key<>(Test.class), "Test", true);
+		testConfig.addMandatory(entityConfigRepository.findRoot(new Key<>(User.class)));
+		// testConfig.addMandatory(entityConfigRepository.findRoot(new
+		// Key<>(Status.class, Test.class)));
+		testConfig.addOptional(entityConfigRepository.findRoot(new Key<>(TemplateTest.class)));
+		testConfig.addOptional(entityConfigRepository.findRoot(new Key<>(Classification.class)));
+		entityConfigRepository.register(testConfig);
+
+		// ContextRoots
+		registerContextRoot(modelManager, ContextType.UNITUNDERTEST);
+		registerContextRoot(modelManager, ContextType.TESTSEQUENCE);
+		registerContextRoot(modelManager, ContextType.TESTEQUIPMENT);
+
+		entityConfigRepository
+				.register(create(modelManager, new Key<>(SystemParameter.class), "SystemParameter", false));
+		entityConfigRepository.register(create(modelManager, new Key<>(UserParameter.class), "UserParameter", false));
+
+		// MDMAttr for external systems
+		EntityConfig<MDMAttribute> mdmAttrConfig = create(modelManager, new Key<>(MDMAttribute.class), "MDMAttr", true);
+		entityConfigRepository.register(mdmAttrConfig);
+		// ExtSystemAttr for external systems
+		EntityConfig<ExtSystemAttribute> extSystemAttrConfig = create(modelManager, new Key<>(ExtSystemAttribute.class), "ExtSystemAttr", true);
+		extSystemAttrConfig.addChild(mdmAttrConfig);
+		entityConfigRepository.register(extSystemAttrConfig);
+		// The external systems themselves
+		EntityConfig<ExtSystem> extSystemConfig = create(modelManager, new Key<>(ExtSystem.class), "ExtSystem", false);
+		entityConfigRepository.register(extSystemConfig);
+
+		LOGGER.debug("Entity configurations loaded in {} ms.", System.currentTimeMillis() - start);
+		return entityConfigRepository;
+	}
+
+	/**
+	 * Loads the {@link EntityConfig}s required for {@link ContextRoot} with given
+	 * {@link ContextType}.
+	 *
+	 * @param contextType The {@code ContextType}.
+	 */
+	private void registerContextRoot(ODSModelManager modelManager, ContextType contextType) {
+		EntityConfig<ContextRoot> contextRootConfig = create(modelManager, new Key<>(ContextRoot.class, contextType),
+				ODSUtils.CONTEXTTYPES.get(contextType), true);
+		contextRootConfig.addMandatory(entityConfigRepository.findRoot(new Key<>(TemplateRoot.class, contextType)));
+		for (Relation contextComponentRelation : contextRootConfig.getEntityType().getChildRelations()) {
+			EntityType contextComponentEntityType = contextComponentRelation.getTarget();
+			EntityConfig<ContextComponent> contextComponentConfig = create(modelManager,
+					new Key<>(ContextComponent.class, contextType), contextComponentEntityType.getName(), true);
+			contextComponentConfig
+					.addInherited(entityConfigRepository.findImplicit(new Key<>(TemplateComponent.class, contextType)));
+			contextRootConfig.addChild(contextComponentConfig);
+			if (contextType.isTestEquipment()) {
+				for (Relation contextSensorRelation : contextComponentEntityType.getChildRelations()) {
+					EntityType contextSensorEntityType = contextSensorRelation.getTarget();
+					EntityConfig<ContextSensor> contextSensorConfig = create(modelManager,
+							new Key<>(ContextSensor.class), contextSensorEntityType.getName(), true);
+					contextSensorConfig
+							.addInherited(entityConfigRepository.findImplicit(new Key<>(TemplateSensor.class)));
+					contextComponentConfig.addChild(contextSensorConfig);
+				}
+			}
+		}
+		entityConfigRepository.register(contextRootConfig);
+	}
+
+	/**
+	 * Loads the {@link EntityConfig}s required for {@link TemplateRoot} with given
+	 * {@link ContextType}.
+	 *
+	 * @param contextType The {@code ContextType}.
+	 */
+	private void registerTemplateRoot(ODSModelManager modelManager, ContextType contextType) {
+		String odsName = ODSUtils.CONTEXTTYPES.get(contextType);
+		EntityConfig<TemplateAttribute> templateAttributeConfig = create(modelManager,
+				new Key<>(TemplateAttribute.class, contextType), "Tpl" + odsName + "Attr", true);
+		templateAttributeConfig
+				.addInherited(entityConfigRepository.findImplicit(new Key<>(CatalogAttribute.class, contextType)));
+		templateAttributeConfig.setComparator(TemplateAttribute.COMPARATOR);
+		EntityConfig<TemplateComponent> templateComponentConfig = create(modelManager,
+				new Key<>(TemplateComponent.class, contextType), "Tpl" + odsName + "Comp", true);
+		templateComponentConfig.addChild(templateAttributeConfig);
+		templateComponentConfig
+				.addMandatory(entityConfigRepository.findRoot(new Key<>(CatalogComponent.class, contextType)));
+		templateComponentConfig.addChild(templateComponentConfig);
+		templateComponentConfig.setComparator(Sortable.COMPARATOR);
+		if (contextType.isTestEquipment()) {
+			EntityConfig<TemplateAttribute> templateSensorAttributeConfig = create(modelManager,
+					new Key<>(TemplateAttribute.class), "TplSensorAttr", true);
+			templateSensorAttributeConfig.setComparator(TemplateAttribute.COMPARATOR);
+			templateSensorAttributeConfig
+					.addInherited(entityConfigRepository.findImplicit(new Key<>(CatalogAttribute.class)));
+			EntityConfig<TemplateSensor> templateSensorConfig = create(modelManager, new Key<>(TemplateSensor.class),
+					"TplSensor", true);
+			templateSensorConfig.addChild(templateSensorAttributeConfig);
+			templateSensorConfig.addMandatory(entityConfigRepository.findRoot(new Key<>(Quantity.class)));
+			templateSensorConfig.addInherited(entityConfigRepository.findImplicit(new Key<>(CatalogSensor.class)));
+			templateSensorConfig.setComparator(Sortable.COMPARATOR);
+			templateComponentConfig.addChild(templateSensorConfig);
+		}
+		EntityConfig<TemplateRoot> templateRootConfig = create(modelManager, new Key<>(TemplateRoot.class, contextType),
+				"Tpl" + odsName + "Root", true);
+		templateRootConfig.addChild(templateComponentConfig);
+		templateRootConfig.setComparator(Versionable.COMPARATOR);
+		entityConfigRepository.register(templateRootConfig);
+	}
+
+	/**
+	 * Loads the {@link EntityConfig}s required for {@link CatalogComponent} with
+	 * given {@link ContextType}.
+	 *
+	 * @param contextType The {@code ContextType}.
+	 */
+	private void registerCatalogComponent(ODSModelManager modelManager, ContextType contextType) {
+		String odsName = ODSUtils.CONTEXTTYPES.get(contextType);
+		EntityConfig<CatalogAttribute> catalogAttributeConfig = create(modelManager,
+				new Key<>(CatalogAttribute.class, contextType), "Cat" + odsName + "Attr", true);
+		catalogAttributeConfig.addOptional(entityConfigRepository.findRoot(new Key<>(ValueList.class)));
+		catalogAttributeConfig.setComparator(Sortable.COMPARATOR);
+		EntityConfig<CatalogComponent> catalogComponentConfig = create(modelManager,
+				new Key<>(CatalogComponent.class, contextType), "Cat" + odsName + "Comp", true);
+		catalogComponentConfig.addChild(catalogAttributeConfig);
+		if (contextType.isTestEquipment()) {
+			EntityConfig<CatalogAttribute> catalogSensorAttributeConfig = create(modelManager,
+					new Key<>(CatalogAttribute.class), "CatSensorAttr", true);
+			catalogSensorAttributeConfig.addOptional(entityConfigRepository.findRoot(new Key<>(ValueList.class)));
+			EntityConfig<CatalogSensor> catalogSensorConfig = create(modelManager, new Key<>(CatalogSensor.class),
+					"CatSensor", true);
+			catalogSensorConfig.addChild(catalogSensorAttributeConfig);
+			catalogComponentConfig.addChild(catalogSensorConfig);
+		}
+		entityConfigRepository.register(catalogComponentConfig);
+	}
+
+	/**
+	 * Creates a new {@link EntityConfig}.
+	 *
+	 * @param            <T> The entity type.
+	 * @param key        Used as identifier.
+	 * @param typeName   Name of the associated {@link EntityType}.
+	 * @param appendName Flag indicates whether to append the entity types base name
+	 *                   to the MIME type.
+	 * @return The created {@code EntityConfig} is returned.
+	 */
+	private <T extends Entity> EntityConfig<T> create(ODSModelManager modelManager, Key<T> key, String typeName,
+			boolean appendName) {
+		EntityConfig<T> entityConfig = new EntityConfig<>(key);
+		ODSEntityType entityType = (ODSEntityType) modelManager.getEntityType(typeName);
+		entityConfig.setEntityType(entityType);
+		entityConfig.setMimeType(buildDefaultMimeType(entityType, appendName));
+		return entityConfig;
+	}
+
+	/**
+	 * Creates a default MIME type for given {@link EntityType}.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param appendName Flag indicates whether to append the entity types base name
+	 *                   to the MIME type.
+	 * @return The created MIME type {@code String} is returned.
+	 */
+	private String buildDefaultMimeType(ODSEntityType entityType, boolean appendName) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("application/x-asam.");
+		sb.append(entityType.getBaseName().toLowerCase(Locale.ROOT));
+		if (appendName) {
+			sb.append('.').append(entityType.getName().toLowerCase(Locale.ROOT));
+		}
+		return sb.toString();
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfig.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfig.java
new file mode 100644
index 0000000..ec95b36
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfig.java
@@ -0,0 +1,372 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup.config;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+
+/**
+ * Describes the composition of an {@link Entity} with its mandatory, optional
+ * and child relations.
+ *
+ * @param <T> The entity type.
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class EntityConfig<T extends Entity> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final List<EntityConfig<? extends Deletable>> childConfigs = new ArrayList<>();
+
+	private final List<EntityConfig<?>> inheritedConfigs = new ArrayList<>();
+	private final List<EntityConfig<?>> mandatoryConfigs = new ArrayList<>();
+	private final List<EntityConfig<?>> optionalConfigs = new ArrayList<>();
+
+	private Comparator<? super T> comparator = Entity.COMPARATOR;
+
+	private final Key<T> key;
+
+	private EntityType entityType;
+
+	private boolean reflexive;
+	private String mimeType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param key The {@link Key} this entity config is bound to.
+	 */
+	public EntityConfig(Key<T> key) {
+		this.key = key;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link Key} this entity config is bound to.
+	 *
+	 * @return The {@code Key} is returned.
+	 */
+	public Key<T> getKey() {
+		return key;
+	}
+
+	/**
+	 * Returns the {@link Entity} class.
+	 *
+	 * @return The {@code Entity} class is returned.
+	 */
+	public Class<T> getEntityClass() {
+		return key.entityClass;
+	}
+
+	/**
+	 * Returns the {@link StatusAttachable} class.
+	 *
+	 * @return Optional is empty if {@code StatusAttachable} is undefined.
+	 */
+	public Optional<Class<? extends StatusAttachable>> getStatusAttachableClass() {
+		return Optional.ofNullable(key.statusAttachableClass);
+	}
+
+	/**
+	 * Returns the {@link ContextType}.
+	 *
+	 * @return Optional is empty {@code ContextType} is undefined.
+	 */
+	public Optional<ContextType> getContextType() {
+		return Optional.ofNullable(key.contextType);
+	}
+
+	/**
+	 * Returns the {@link Comparator} for {@link Entity}s associated with this
+	 * entity config.
+	 *
+	 * @return The {@code Comparator} is returned.
+	 */
+	public Comparator<? super T> getComparator() {
+		return comparator;
+	}
+
+	/**
+	 * Returns the {@link EntityType} of this entity config.
+	 *
+	 * @return The {@code EntityType} is returned.
+	 */
+	public EntityType getEntityType() {
+		return entityType;
+	}
+
+	/**
+	 * Returns the default MIME type for a newly created {@link Entity} associated
+	 * with this entity config.
+	 *
+	 * @return The default MIME type is returned.
+	 */
+	public String getMimeType() {
+		return mimeType;
+	}
+
+	/**
+	 * Returns all related child configs.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<EntityConfig<? extends Deletable>> getChildConfigs() {
+		return Collections.unmodifiableList(childConfigs);
+	}
+
+	/**
+	 * Returns all related inherited configs.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<EntityConfig<?>> getInheritedConfigs() {
+		return Collections.unmodifiableList(inheritedConfigs);
+	}
+
+	/**
+	 * Returns all related mandatory configs.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<EntityConfig<?>> getMandatoryConfigs() {
+		return Collections.unmodifiableList(mandatoryConfigs);
+	}
+
+	/**
+	 * Returns all related optional configs.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<EntityConfig<?>> getOptionalConfigs() {
+		return Collections.unmodifiableList(optionalConfigs);
+	}
+
+	/**
+	 * Checks whether {@link Entity}s associated with this entity config may have
+	 * children of the same type.
+	 *
+	 * @return Returns {@code true} if this entity config is reflexive.
+	 */
+	public boolean isReflexive() {
+		return reflexive;
+	}
+
+	/**
+	 * Sets a new {@link Comparator} for this entity config.
+	 *
+	 * @param comparator The new {@code Comparator}.
+	 */
+	public void setComparator(Comparator<? super T> comparator) {
+		this.comparator = comparator;
+	}
+
+	/**
+	 * Sets the {@link EntityType} for this entity config.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @throws IllegalStateException Thrown if {@link EntityType} is already
+	 *                               defined.
+	 */
+	public void setEntityType(EntityType entityType) {
+		if (this.entityType != null) {
+			throw new IllegalStateException("It is not allowed to override the entity type.");
+		}
+
+		this.entityType = entityType;
+	}
+
+	/**
+	 * Sets the default MIME type for newly created {@link Entity}s associated with
+	 * this entity config.
+	 *
+	 * @param mimeType The default MIME type.
+	 * @throws IllegalStateException Thrown if default MIME type is already defined.
+	 */
+	public void setMimeType(String mimeType) {
+		if (this.mimeType != null && !this.mimeType.isEmpty()) {
+			throw new IllegalStateException("It is not allowed to override the default MIME type.");
+		}
+
+		this.mimeType = mimeType;
+	}
+
+	/**
+	 * Adds a related inherited {@link EntityConfig}.
+	 *
+	 * @param entityConfig The {@code EntityConfig}.
+	 */
+	public void addInherited(EntityConfig<?> entityConfig) {
+		inheritedConfigs.add(entityConfig);
+	}
+
+	/**
+	 * Adds a related mandatory {@link EntityConfig}.
+	 *
+	 * @param entityConfig The {@code EntityConfig}.
+	 */
+	public void addMandatory(EntityConfig<?> entityConfig) {
+		mandatoryConfigs.add(entityConfig);
+	}
+
+	/**
+	 * Adds a related optional {@link EntityConfig}.
+	 *
+	 * @param entityConfig The {@code EntityConfig}.
+	 */
+	public void addOptional(EntityConfig<?> entityConfig) {
+		optionalConfigs.add(entityConfig);
+	}
+
+	/**
+	 * Adds a related child {@link EntityConfig}.
+	 *
+	 * @param childConfig The {@code EntityConfig}.
+	 */
+	public void addChild(EntityConfig<? extends Deletable> childConfig) {
+		if (this == childConfig) {
+			reflexive = true;
+		} else {
+			childConfigs.add(childConfig);
+		}
+	}
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * Used as an identifier for {@link EntityConfig}s.
+	 *
+	 * @param <T> The entity type.
+	 */
+	public static final class Key<T extends Entity> {
+
+		// ======================================================================
+		// Instance variables
+		// ======================================================================
+
+		final Class<? extends StatusAttachable> statusAttachableClass;
+		final Class<T> entityClass;
+		final ContextType contextType;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param entityClass The {@link Entity} class.
+		 */
+		public Key(Class<T> entityClass) {
+			this.entityClass = entityClass;
+			statusAttachableClass = null;
+			contextType = null;
+		}
+
+		/**
+		 * Constructor.
+		 *
+		 * @param entityClass           The {@link Entity} class.
+		 * @param statusAttachableClass The {@link StatusAttachable} class.
+		 */
+		public Key(Class<T> entityClass, Class<? extends StatusAttachable> statusAttachableClass) {
+			this.statusAttachableClass = statusAttachableClass;
+			this.entityClass = entityClass;
+			contextType = null;
+		}
+
+		/**
+		 * Constructor.
+		 *
+		 * @param entityClass The {@link Entity} class.
+		 * @param contextType The {@link ContextType}.
+		 */
+		public Key(Class<T> entityClass, ContextType contextType) {
+			this.entityClass = entityClass;
+			this.contextType = contextType;
+			statusAttachableClass = null;
+		}
+
+		// ======================================================================
+		// Public methods
+		// ======================================================================
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public int hashCode() {
+			return Objects.hash(entityClass, statusAttachableClass, contextType);
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public boolean equals(Object object) {
+			// reference check (this == object) omitted
+			if (object instanceof Key) {
+				Key<?> other = (Key<?>) object;
+				return Objects.equals(entityClass, other.entityClass)
+						&& Objects.equals(statusAttachableClass, other.statusAttachableClass)
+						&& Objects.equals(contextType, other.contextType);
+			}
+
+			return false;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public String toString() {
+			StringBuilder sb = new StringBuilder(entityClass.getSimpleName());
+
+			if (statusAttachableClass != null) {
+				sb.append('_').append(statusAttachableClass.getSimpleName());
+			}
+
+			if (contextType != null) {
+				sb.append('_').append(contextType);
+			}
+
+			return sb.toString();
+		}
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
new file mode 100644
index 0000000..dad79c4
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepository.java
@@ -0,0 +1,198 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+
+/**
+ * Repository for {@link EntityConfig}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class EntityConfigRepository {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	// root types
+	private final Map<Key<?>, EntityConfig<?>> entityConfigs = new HashMap<>();
+
+	// child types (implicit load only!)
+	private final Map<Key<?>, EntityConfig<?>> childConfigs = new HashMap<>();
+	private final Map<String, EntityConfig<?>> contextConfigs = new HashMap<>();
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link EntityConfig} associated with given {@link Key}. This
+	 * method tries to find the associated {@code EntityConfig} in the root
+	 * configurations. If it is not found there, then it tries to find it in the
+	 * child {@code EntityConfig}s.
+	 *
+	 * @param <T> The entity type.
+	 * @param key Used as identifier.
+	 * @return The {@code EntityConfig} is returned.
+	 * @throws IllegalArgumentException Thrown if unable to find associated
+	 *                                  {@code EntityConfig}.
+	 */
+	public <T extends Entity> EntityConfig<T> find(Key<T> key) {
+		Optional<EntityConfig<T>> entityConfig = get(entityConfigs, key);
+		if (entityConfig.isPresent()) {
+			return entityConfig.get();
+		}
+
+		return get(childConfigs, key)
+				.orElseThrow(() -> new IllegalArgumentException("Entity configuration not found."));
+	}
+
+	/**
+	 * Returns the {@link EntityConfig} associated with given {@link Key}. This
+	 * method tries to find the associated {@code EntityConfig} in the root
+	 * configurations.
+	 *
+	 * @param <T> The entity type.
+	 * @param key Used as identifier.
+	 * @return The {@code EntityConfig} is returned.
+	 * @throws IllegalArgumentException Thrown if unable to find associated
+	 *                                  {@code EntityConfig}.
+	 */
+	public <T extends Entity> EntityConfig<T> findRoot(Key<T> key) {
+		return get(entityConfigs, key)
+				.orElseThrow(() -> new IllegalArgumentException("Entity configuration not found."));
+	}
+
+	/**
+	 * Returns the {@link EntityConfig} associated with given {@link Key}. This
+	 * method tries to find the associated {@code EntityConfig} in the child
+	 * configurations.
+	 *
+	 * @param <T> The entity type.
+	 * @param key Used as identifier.
+	 * @return The {@code EntityConfig} is returned.
+	 * @throws IllegalArgumentException Thrown if unable to find associated
+	 *                                  {@code EntityConfig}.
+	 */
+	public <T extends Entity> EntityConfig<T> findImplicit(Key<T> key) {
+		return get(childConfigs, key)
+				.orElseThrow(() -> new IllegalArgumentException("Entity configuration not found."));
+	}
+
+	/**
+	 * Returns the {@link EntityConfig} associated with given {@link EntityType}.
+	 *
+	 * @param entityType Its name is used as identifier.
+	 * @return The {@code EntityConfig} is returned.
+	 * @throws IllegalArgumentException Thrown if unable to find associated
+	 *                                  {@code EntityConfig}.
+	 */
+	public EntityConfig<?> find(EntityType entityType) {
+		Optional<EntityConfig<?>> entityConfig = entityConfigs.values().stream()
+				.filter(ec -> ec.getEntityType().equals(entityType)).findFirst();
+		if (entityConfig.isPresent()) {
+			// entity config is a root type
+			return entityConfig.get();
+		}
+
+		entityConfig = childConfigs.values().stream().filter(ec -> ec.getEntityType().equals(entityType)).findFirst();
+		if (entityConfig.isPresent()) {
+			// entity config is an implicitly loaded child type
+			return entityConfig.get();
+		}
+
+		EntityConfig<?> config = contextConfigs.get(entityType.getName());
+		if (config == null) {
+			throw new IllegalArgumentException("Entity configuration for type '" + entityType + "' not found.");
+		}
+
+		// config is either a context component or context sensor type
+		return config;
+	}
+
+	/**
+	 * Stores given {@link EntityConfig} in this repository.
+	 *
+	 * @param entityConfig The {@code EntityConfig}.
+	 * @throws IllegalArgumentException Thrown if an attempt to overwrite an
+	 *                                  existing {@code EntityConfig} is recorded.
+	 */
+	public void register(EntityConfig<?> entityConfig) {
+		registerChildConfigs(entityConfig);
+
+		EntityConfig<?> currentByClass = entityConfigs.put(entityConfig.getKey(), entityConfig);
+		if (currentByClass != null) {
+			throw new IllegalArgumentException("It is not allowed to overwrite existing configurations.");
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Recursively registers all child configurations of given {@link EntityConfig}.
+	 *
+	 * @param entityConfig The {@code EntityConfig}.
+	 * @throws IllegalArgumentException Thrown if an attempt to overwrite an
+	 *                                  existing {@code EntityConfig} is recorded.
+	 */
+	private void registerChildConfigs(EntityConfig<?> entityConfig) {
+		Class<? extends Entity> entityClass = entityConfig.getEntityClass();
+		if (ContextRoot.class.equals(entityClass) || ContextComponent.class.equals(entityClass)) {
+			for (EntityConfig<?> childConfig : entityConfig.getChildConfigs()) {
+				if (contextConfigs.put(childConfig.getEntityType().getName(), childConfig) != null) {
+					throw new IllegalArgumentException("It is not allowed to overwrite existing configurations.");
+				}
+
+				registerChildConfigs(childConfig);
+			}
+
+			return;
+		}
+		for (EntityConfig<?> childConfig : entityConfig.getChildConfigs()) {
+			if (childConfigs.put(childConfig.getKey(), childConfig) != null) {
+				throw new IllegalArgumentException("It is not allowed to overwrite existing configurations.");
+			}
+
+			registerChildConfigs(childConfig);
+		}
+	}
+
+	/**
+	 * Retrieves the {@link EntityConfig} associated with given {@link Key} from
+	 * given {@code Map}.
+	 *
+	 * @param <T>           The entity type.
+	 * @param entityConfigs Used to retrieve requested {@code EntityConfig}.
+	 * @param key           Used as identifier.
+	 * @return {@code Optional} is empty if {@code EntityConfig} not found.
+	 */
+	@SuppressWarnings("unchecked")
+	private static <T extends Entity> Optional<EntityConfig<T>> get(Map<Key<?>, EntityConfig<?>> entityConfigs,
+			Key<T> key) {
+		return Optional.ofNullable((EntityConfig<T>) entityConfigs.get(key));
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepositoryLoader.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepositoryLoader.java
new file mode 100644
index 0000000..4dc521a
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/lookup/config/EntityConfigRepositoryLoader.java
@@ -0,0 +1,27 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.lookup.config;
+
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+
+public interface EntityConfigRepositoryLoader {
+
+	/**
+	 * Loads the {@link EntityConfigRepository}.
+	 * 
+	 * @return
+	 */
+	EntityConfigRepository loadEntityConfigurations(ODSModelManager modelManager);
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
new file mode 100644
index 0000000..4935288
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/NotificationEntityLoader.java
@@ -0,0 +1,220 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextDescribable;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.JoinType;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NotificationEntityLoader {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(NotificationEntityLoader.class);
+
+	private final ODSModelManager modelManager;
+	private final QueryService queryService;
+	private final EntityLoader loader;
+
+	private boolean loadContextDescribable;
+
+	public NotificationEntityLoader(ODSModelManager modelManager, QueryService queryService,
+			boolean loadContextDescribable) {
+		this.modelManager = modelManager;
+		this.queryService = queryService;
+		this.loader = new EntityLoader(modelManager, queryService);
+		this.loadContextDescribable = loadContextDescribable;
+	}
+
+	public <T extends Entity> T load(Key<T> key, String userId) throws DataAccessException {
+		return loader.load(key, userId);
+	}
+
+	public List<? extends Entity> loadEntities(String aid, List<String> ids) throws DataAccessException {
+		return loadEntities(modelManager.getEntityType(aid), ids);
+	}
+
+	/**
+	 * @param entityType entity type of the entities to load.
+	 * @param ids        IDs of the entities to load.
+	 * @return loaded entities.
+	 * @throws DataAccessException Throw if the entities cannot be loaded.
+	 */
+	public List<? extends Entity> loadEntities(EntityType entityType, List<String> ids) throws DataAccessException {
+
+		if (ids.isEmpty()) {
+			return Collections.emptyList();
+		}
+
+		EntityConfig<?> config = getEntityConfig(entityType);
+
+		if (config == null || isLoadContextDescribable(config)) {
+			// entityType not modelled in MDM, try to load its
+			// ContextDescribable if it is a ContextRoot/ContextComponent
+			final EntityType testStep = modelManager.getEntityType(TestStep.class);
+			final EntityType measurement = modelManager.getEntityType(Measurement.class);
+
+			if (hasRelationTo(entityType, testStep, measurement)) {
+				return loadEntityForContextRoot(entityType, ids);
+			} else if (hasRelationTo(entityType, modelManager.getEntityType("UnitUnderTest"),
+					modelManager.getEntityType("TestSequence"), modelManager.getEntityType("TestEquipment"))) {
+				return loadEntityForContextComponent(entityType, ids);
+			} else {
+				LOGGER.debug("Cannot load entitis for entityType " + entityType + " and ids " + ids);
+				return Collections.emptyList();
+			}
+		} else {
+			return loader.loadAll(config.getKey(), ids);
+		}
+	}
+
+	/**
+	 * Loads the ContextDescribables to the given context root instances
+	 * 
+	 * @param contextRoot entityType of the context root
+	 * @param ids         IDs of the context roots.
+	 * @return the loaded ContextDescribables
+	 * @throws DataAccessException Throw if the ContextDescribables cannot be
+	 *                             loaded.
+	 */
+	private List<ContextDescribable> loadEntityForContextRoot(EntityType contextRoot, List<String> ids)
+			throws DataAccessException {
+
+		final EntityType testStep = modelManager.getEntityType(TestStep.class);
+		final EntityType measurement = modelManager.getEntityType(Measurement.class);
+
+		List<String> testStepIDs = queryService.createQuery().selectID(testStep)
+				.join(testStep.getRelation(contextRoot), JoinType.OUTER)
+				.fetch(Filter.and().add(
+						ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids.toArray(new String[0]))))
+				.stream().map(r -> r.getRecord(testStep)).map(Record::getID).collect(Collectors.toList());
+
+		List<String> measurementIDs = queryService.createQuery().selectID(measurement)
+				.join(measurement.getRelation(contextRoot), JoinType.OUTER)
+				.fetch(Filter.and().add(
+						ComparisonOperator.IN_SET.create(contextRoot.getIDAttribute(), ids.toArray(new String[0]))))
+				.stream().map(r -> r.getRecord(measurement)).map(Record::getID).collect(Collectors.toList());
+
+		List<ContextDescribable> list = new ArrayList<>();
+		list.addAll(loader.loadAll(new Key<>(TestStep.class), testStepIDs));
+		list.addAll(loader.loadAll(new Key<>(Measurement.class), measurementIDs));
+
+		return list;
+	}
+
+	/**
+	 * Loads the ContextDescribables to the given context component instances
+	 * 
+	 * @param contextComponent entityType of the context component
+	 * @param ids              IDs of the contextComponents to load.
+	 * @return the loaded ContextDescribables
+	 * @throws DataAccessException Throw if the ContextDescribables cannot be
+	 *                             loaded.
+	 */
+	private List<ContextDescribable> loadEntityForContextComponent(EntityType contextComponent, List<String> ids)
+			throws DataAccessException {
+
+		// ContextComponent can only have one parent
+		final EntityType contextRoot = contextComponent.getParentRelations().get(0).getTarget();
+
+		final EntityType testStep = modelManager.getEntityType(TestStep.class);
+		final EntityType measurement = modelManager.getEntityType(Measurement.class);
+
+		List<String> testStepIDs = queryService.createQuery().selectID(testStep)
+				.join(testStep.getRelation(contextRoot), JoinType.OUTER)
+				.join(contextRoot.getRelation(contextComponent), JoinType.OUTER)
+				.fetch(Filter.and()
+						.add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(),
+								ids.toArray(new String[0]))))
+				.stream().map(r -> r.getRecord(testStep)).map(Record::getID).collect(Collectors.toList());
+
+		List<String> measurementIDs = queryService.createQuery().selectID(measurement)
+				.join(measurement.getRelation(contextRoot), JoinType.OUTER)
+				.join(contextRoot.getRelation(contextComponent), JoinType.OUTER)
+				.fetch(Filter.and()
+						.add(ComparisonOperator.IN_SET.create(contextComponent.getIDAttribute(),
+								ids.toArray(new String[0]))))
+				.stream().map(r -> r.getRecord(measurement)).map(Record::getID).collect(Collectors.toList());
+
+		List<ContextDescribable> list = new ArrayList<>();
+		list.addAll(loader.loadAll(new Key<>(TestStep.class), testStepIDs));
+		list.addAll(loader.loadAll(new Key<>(Measurement.class), measurementIDs));
+		return list;
+	}
+
+	/**
+	 * @param entityConfig
+	 * @return true, if the entityConfig belongs to a context root or context
+	 *         component and the option loadContextDescribable
+	 */
+	private boolean isLoadContextDescribable(EntityConfig<?> entityConfig) {
+		return loadContextDescribable && (entityConfig.getEntityClass().isAssignableFrom(ContextRoot.class)
+				|| entityConfig.getEntityClass().isAssignableFrom(ContextComponent.class));
+	}
+
+	/**
+	 * Checks if a relation between sourceEntityType and at least one entity type in
+	 * targetEntityType exists.
+	 * 
+	 * @param sourceEntityType  source entity type.
+	 * @param targetEntityTypes list of target enitity types.
+	 * @return true, if relation between source entity type and at least one target
+	 *         entity type exists.
+	 */
+	private boolean hasRelationTo(EntityType sourceEntityType, EntityType... targetEntityTypes) {
+		for (EntityType e : targetEntityTypes) {
+			try {
+				sourceEntityType.getRelation(e);
+				return true;
+			} catch (IllegalArgumentException ex) {
+				return false;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * @param entityType entity type the {@link EntityConfig} is requested for
+	 * @return {@link EntityConfig} or null if not config was found for the
+	 *         specified entity type
+	 */
+	private EntityConfig<?> getEntityConfig(EntityType entityType) {
+		try {
+			return modelManager.getEntityConfig(entityType);
+		} catch (IllegalArgumentException e) {
+			return null;
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java
new file mode 100644
index 0000000..d6a30a5
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/ODSNotificationServiceFactory.java
@@ -0,0 +1,111 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification;
+
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.notification.NotificationException;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.odsadapter.ODSContextFactory;
+import org.eclipse.mdm.api.odsadapter.notification.avalon.AvalonNotificationManager;
+import org.eclipse.mdm.api.odsadapter.notification.peak.PeakNotificationManager;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory for creating a notification service.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+public class ODSNotificationServiceFactory {
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSNotificationServiceFactory.class);
+
+	public static final String PARAM_SERVER_TYPE = "freetext.notificationType";
+	public static final String PARAM_URL = "freetext.notificationUrl";
+	public static final String PARAM_POLLING_INTERVAL = "freetext.pollingInterval";
+
+	public static final String SERVER_TYPE_PEAK = "peak";
+	public static final String SERVER_TYPE_AVALON = "avalon";
+
+	public static final String PARAM_NAMESERVICE_URL = "nameserviceURL";
+
+	public NotificationService create(ApplicationContext context, Map<String, String> parameters)
+			throws ConnectionException {
+		String type = getParameter(parameters, PARAM_SERVER_TYPE);
+
+		ModelManager mm = context.getModelManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+
+		QueryService queryService = context.getQueryService()
+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+
+		if (!ODSModelManager.class.isInstance(mm)) {
+			throw new ConnectionException("ModelManager is not a ODSModelManager!");
+		}
+
+		if (SERVER_TYPE_PEAK.equalsIgnoreCase(type)) {
+			String url = getParameter(parameters, PARAM_URL);
+
+			LOGGER.info("Connecting to Peak Notification Server ...");
+			LOGGER.info("URL: {}", url);
+
+			try {
+				return new PeakNotificationManager((ODSModelManager) mm, queryService, url, true);
+			} catch (NotificationException e) {
+				throw new ConnectionException("Could not connect to notification service!", e);
+			}
+		} else if (SERVER_TYPE_AVALON.equalsIgnoreCase(type)) {
+
+			String serviceName = getParameter(parameters, ODSContextFactory.PARAM_SERVICENAME);
+			serviceName = serviceName.replace(".ASAM-ODS", "");
+			String nameServiceURL = getParameter(parameters, ODSContextFactory.PARAM_NAMESERVICE);
+
+			LOGGER.info("Connecting to Avalon Notification Server ...");
+			LOGGER.info("Name service URL: {}", nameServiceURL);
+			LOGGER.info("Service name: {}", serviceName);
+
+			long pollingInterval = 500L;
+			try {
+				pollingInterval = Long.parseLong(getParameter(parameters, PARAM_POLLING_INTERVAL));
+			} catch (NumberFormatException | ConnectionException e) {
+				LOGGER.warn("Could not parse parse parameter pollingInterval. Using default value: " + pollingInterval,
+						e);
+			}
+
+			return new AvalonNotificationManager((ODSModelManager) mm, queryService, serviceName, nameServiceURL, true,
+					pollingInterval);
+		} else {
+			throw new ConnectionException("Invalid server type. Expected on of: 'peak'");
+		}
+
+	}
+
+	private String getParameter(Map<String, String> parameters, String name) throws ConnectionException {
+		String value = parameters.get(name);
+		if (value == null || value.isEmpty()) {
+			throw new ConnectionException("Connection parameter with name '" + name + "' is either missing or empty.");
+		}
+
+		return value;
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
new file mode 100644
index 0000000..85f51ab
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/AvalonNotificationManager.java
@@ -0,0 +1,191 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification.avalon;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextDescribable;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.notification.NotificationException;
+import org.eclipse.mdm.api.base.notification.NotificationFilter;
+import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
+import org.eclipse.mdm.api.base.notification.NotificationListener;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.notification.NotificationEntityLoader;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.omg.CORBA.ORB;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.highqsoft.avalonCorbaNotification.notification.MODE_DELETE;
+import com.highqsoft.avalonCorbaNotification.notification.MODE_INSERT;
+import com.highqsoft.avalonCorbaNotification.notification.MODE_MODIFYRIGHTS;
+import com.highqsoft.avalonCorbaNotification.notification.MODE_REPLACE;
+
+/**
+ * Notification manager for handling notifications from the Avalon Notification
+ * Service
+ * 
+ * ModificationType.MODEL_MODIFIED is not supported!
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+public class AvalonNotificationManager implements NotificationService {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(AvalonNotificationManager.class);
+
+	private final Map<String, EventProcessor> eventProcessors = new HashMap<>();
+
+	private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+
+	private final ODSModelManager modelManager;
+	private final String serviceName;
+	private final String nameServiceURL;
+	private long pollingInterval = 500L;
+	private final NotificationEntityLoader loader;
+
+	private final ORB orb = ORB.init(new String[] {}, System.getProperties());
+
+	/**
+	 * Creates a new AvalonNotificationManager.
+	 * 
+	 * @param modelManager           ODSModelManager used to laod entities.
+	 * @param serviceName            name of the notification service.
+	 * @param nameServiceURL         URL of the name service.
+	 * @param loadContextDescribable if true, notifications for {@link ContextRoot}
+	 *                               and {@link ContextComponent} will load their
+	 *                               parent {@link ContextDescribable}.
+	 * @param pollingInterval        polling interval in milleseconds
+	 */
+	public AvalonNotificationManager(ODSModelManager modelManager, QueryService queryService, String serviceName,
+			String nameServiceURL, boolean loadContextDescribable, long pollingInterval) {
+		this.modelManager = modelManager;
+		this.serviceName = serviceName;
+		this.nameServiceURL = nameServiceURL;
+		this.pollingInterval = pollingInterval;
+		loader = new NotificationEntityLoader(modelManager, queryService, loadContextDescribable);
+	}
+
+	@Override
+	public void register(String registration, NotificationFilter filter, final NotificationListener listener)
+			throws NotificationException {
+		try {
+			EventProcessor consumer = new EventProcessor(orb, listener, this, nameServiceURL, serviceName);
+
+			List<String> aids = filter.getEntityTypes().stream().map(e -> e.getId()).collect(Collectors.toList());
+
+			Set<ModificationType> modes = filter.getTypes().stream()
+					.filter(m -> !ModificationType.MODEL_MODIFIED.equals(m)).collect(Collectors.toSet());
+
+			consumer.connect();
+			consumer.setFilter(aids, modes);
+
+			ScheduledFuture<?> future = executor.scheduleAtFixedRate(consumer, 0, pollingInterval,
+					TimeUnit.MILLISECONDS);
+			consumer.setFuture(future);
+
+			eventProcessors.put(registration, consumer);
+		} catch (Exception e) {
+			throw new NotificationException("Exception creating notification listener registration!", e);
+		}
+	}
+
+	@Override
+	public void deregister(String registration) {
+		EventProcessor processor = eventProcessors.get(registration);
+		if (processor != null) {
+			processor.disconnect();
+			eventProcessors.remove(registration);
+		}
+	}
+
+	@Override
+	public void close(boolean isDeregisterAll) throws NotificationException {
+		LOGGER.info("Closing NotificationManager...");
+
+		for (String registration : eventProcessors.keySet()) {
+			LOGGER.debug("Disconnecting registration '" + registration + "'.");
+			deregister(registration);
+		}
+
+		try {
+			executor.shutdown();
+			boolean terminated = executor.awaitTermination(10, TimeUnit.SECONDS);
+			if (!terminated) {
+				throw new NotificationException("Could not close all registrations!");
+			}
+		} catch (InterruptedException e) {
+			throw new NotificationException("Could not close all registrations!", e);
+		}
+	}
+
+	void processException(Exception e) {
+		LOGGER.error("Exception during notification processing!", e);
+	}
+
+	void processNotification(short mode, T_LONGLONG aeId, T_LONGLONG ieId, T_LONGLONG userId, String timestamp,
+			NotificationListener notificationListener) {
+
+		try {
+			User user = loader.load(new Key<>(User.class), Long.toString(ODSConverter.fromODSLong(userId)));
+			LOGGER.debug("User loaded");
+
+			EntityType entityType = modelManager.getEntityTypeById(Long.toString(ODSConverter.fromODSLong(aeId)));
+			List<String> ids = Arrays.asList(Long.toString(ODSConverter.fromODSLong(ieId)));
+
+			if (LOGGER.isTraceEnabled()) {
+				LOGGER.trace("Notification event with: entityType=" + entityType + ", user=" + user);
+			}
+
+			switch (mode) {
+			case MODE_INSERT.value:
+				notificationListener.instanceCreated(loader.loadEntities(entityType, ids), user);
+				break;
+			case MODE_REPLACE.value:
+				notificationListener.instanceModified(loader.loadEntities(entityType, ids), user);
+				break;
+			case MODE_DELETE.value:
+				notificationListener.instanceDeleted(entityType, ids, user);
+				break;
+			case MODE_MODIFYRIGHTS.value:
+				notificationListener.securityModified(entityType, ids, user);
+				break;
+			default:
+				processException(new NotificationException("Invalid notification type!"));
+			}
+		} catch (DataAccessException e) {
+			processException(new NotificationException("Cannot load data for notification!", e));
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/EventProcessor.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/EventProcessor.java
new file mode 100644
index 0000000..78e3424
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/avalon/EventProcessor.java
@@ -0,0 +1,272 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification.avalon;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ScheduledFuture;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.notification.NotificationException;
+import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
+import org.eclipse.mdm.api.base.notification.NotificationListener;
+import org.omg.CORBA.ORB;
+import org.omg.CosNaming.NamingContextExt;
+import org.omg.CosNaming.NamingContextExtHelper;
+import org.omg.CosNotification.StructuredEvent;
+import org.omg.CosNotification._EventType;
+import org.omg.CosNotifyChannelAdmin.ClientType;
+import org.omg.CosNotifyChannelAdmin.EventChannel;
+import org.omg.CosNotifyChannelAdmin.EventChannelHelper;
+import org.omg.CosNotifyChannelAdmin.StructuredProxyPullSupplier;
+import org.omg.CosNotifyChannelAdmin.StructuredProxyPullSupplierHelper;
+import org.omg.CosNotifyComm.InvalidEventType;
+import org.omg.CosNotifyComm.StructuredPullConsumerPOA;
+import org.omg.CosNotifyFilter.ConstraintExp;
+import org.omg.CosNotifyFilter.Filter;
+import org.omg.CosNotifyFilter.FilterFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEvent;
+import com.highqsoft.avalonCorbaNotification.notification.AvalonNotificationCorbaEventHelper;
+
+/**
+ * Event processor responsible for receiving avalon events from the notification
+ * service and redirect them to the manager.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+public class EventProcessor extends StructuredPullConsumerPOA implements Runnable {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(EventProcessor.class);
+
+	private static final String eventDomainName = "AVALON";
+
+	private final ORB orb;
+	private final NotificationListener listener;
+	private final AvalonNotificationManager manager;
+	private final String nameserviceUrl;
+	private final String serviceName;
+
+	private EventChannel eventChannel;
+	private StructuredProxyPullSupplier proxyPullSupplier;
+
+	private boolean connected = false;
+
+	private ScheduledFuture<?> future;
+
+	/**
+	 * Creates a new event processor.
+	 * 
+	 * @param orb         CORBA orb to use
+	 * @param listener    notification listener consuming the received events
+	 * @param manager     notification manager responsible for processing the events
+	 * @param serviceName service name of the CORBA notification service
+	 */
+	public EventProcessor(ORB orb, NotificationListener listener, AvalonNotificationManager manager,
+			String nameserviceUrl, String serviceName) {
+		this.orb = orb;
+		this.nameserviceUrl = nameserviceUrl;
+		this.listener = listener;
+		this.manager = manager;
+		this.serviceName = String.format("com/highqsoft/avalon/notification/%s.Notification", serviceName);
+	}
+
+	/**
+	 * Connect the event processor to the notification service.
+	 * 
+	 * @throws NotificationException in case the notification service cannot be
+	 *                               connected.
+	 */
+	public synchronized void connect() throws NotificationException {
+		if (isConnected()) {
+			return;
+		}
+
+		try {
+			NamingContextExt nc = NamingContextExtHelper.narrow(orb.string_to_object(nameserviceUrl));
+
+			eventChannel = EventChannelHelper.narrow(nc.resolve(nc.to_name(serviceName)));
+
+			proxyPullSupplier = StructuredProxyPullSupplierHelper.narrow(eventChannel.default_consumer_admin()
+					.obtain_notification_pull_supplier(ClientType.STRUCTURED_EVENT, new org.omg.CORBA.IntHolder()));
+
+			proxyPullSupplier.connect_structured_pull_consumer(this._this(orb));
+			connected = true;
+		} catch (Exception e) {
+			throw new NotificationException("Cannot connect to notification service!", e);
+		}
+	}
+
+	/**
+	 * Disconnect the event processor from the notification service.
+	 */
+	public synchronized void disconnect() {
+		if (isConnected()) {
+			if (future != null) {
+				future.cancel(false);
+			}
+
+			proxyPullSupplier = null;
+
+			eventChannel._release();
+			eventChannel = null;
+
+			connected = false;
+		}
+	}
+
+	/**
+	 * @return true if the event processor is connected to the notification service
+	 */
+	public synchronized boolean isConnected() {
+		return connected;
+	}
+
+	/**
+	 * Sets the event filter.
+	 * 
+	 * @param aids              List with application element IDs to filter for.
+	 *                          Empty list means no all.
+	 * @param modificationTypes Collection of modification types to filter for.
+	 * @throws NotificationException if the filter cannot be set
+	 */
+	public void setFilter(List<String> aids, Set<ModificationType> modificationTypes) throws NotificationException {
+		if (!isConnected()) {
+			throw new IllegalStateException("Cannot set filter when disconnected. Please connect first.");
+		}
+
+		try {
+			FilterFactory filterFactory = eventChannel.default_filter_factory();
+			if (filterFactory == null) {
+				throw new NotificationException("No default filter factory found!");
+			}
+
+			Filter filter = filterFactory.create_filter("EXTENDED_TCL");
+			filter.add_constraints(new ConstraintExp[] {
+					new ConstraintExp(getEventTypes(modificationTypes), getConstraintFilter(aids)) });
+			proxyPullSupplier.add_filter(filter);
+		} catch (Exception e) {
+			throw new NotificationException("Exception when creating filter.", e);
+		}
+	}
+
+	/**
+	 * Sets the ScheduledFuture that will be used to stop the event processor task.
+	 * 
+	 * @param future ScheduledFuture
+	 */
+	public void setFuture(ScheduledFuture<?> future) {
+		this.future = future;
+	}
+
+	@Override
+	public synchronized void run() {
+		if (isConnected()) {
+			org.omg.CORBA.BooleanHolder bh = new org.omg.CORBA.BooleanHolder();
+
+			try {
+				LOGGER.trace("Looking for structured events....");
+				// try to pull an event
+				StructuredEvent event = proxyPullSupplier.try_pull_structured_event(bh);
+				if (bh.value) {
+					AvalonNotificationCorbaEvent ev = AvalonNotificationCorbaEventHelper
+							.extract(event.remainder_of_body);
+					manager.processNotification(ev.mode, ev.aeId, ev.ieId, ev.userId, ev.timestamp, listener);
+				} else {
+					LOGGER.trace("No structured events found.");
+				}
+			} catch (Exception e) {
+				manager.processException(e);
+			}
+		} else {
+			LOGGER.warn("Disconnected.");
+			manager.processException(new NotificationException("Not connected"));
+			if (future != null) {
+				future.cancel(false);
+			}
+		}
+	}
+
+	@Override
+	public void disconnect_structured_pull_consumer() {
+		LOGGER.info("Disconnected!");
+		connected = false;
+	}
+
+	@Override
+	public void offer_change(_EventType[] added, _EventType[] removed) throws InvalidEventType {
+		// TODO Auto-generated method stub
+
+	}
+
+	/**
+	 * Constructs a constraint filter.
+	 * 
+	 * @param aids Application Element IDs used for filtering. Empty list means no
+	 *             filter.
+	 * @return Constraint filter containing the given aids
+	 */
+	private String getConstraintFilter(List<String> aids) {
+		if (aids.isEmpty()) {
+			return "TRUE";
+		} else {
+			return aids.stream().map(aid -> String.format("$.filterable_data(%s) == %s", "ApplicationElement", aid))
+					.collect(Collectors.joining(" or "));
+		}
+	}
+
+	/**
+	 * Converts ModificationTypes in EventTypes.
+	 * 
+	 * @param modificationTypes
+	 * @return Array with EventTypes
+	 */
+	private _EventType[] getEventTypes(Set<ModificationType> modificationTypes) {
+		if (modificationTypes.isEmpty()) {
+			return new _EventType[0];
+		} else {
+			return modificationTypes.stream().map(s -> new _EventType(eventDomainName, toAvalonString(s)))
+					.collect(Collectors.toList()).toArray(new _EventType[0]);
+		}
+	}
+
+	/**
+	 * Converts a {@link ModificationType} enum value to a event type name for the
+	 * CORBA notification service.
+	 * 
+	 * @param t a modification type
+	 * @return event type name
+	 */
+	private String toAvalonString(ModificationType t) {
+		switch (t) {
+		case INSTANCE_CREATED:
+			return "INSERT";
+		case INSTANCE_MODIFIED:
+			return "REPLACE";
+		case INSTANCE_DELETED:
+			return "DELETE";
+		case SECURITY_MODIFIED:
+			return "MODIFYRIGHTS";
+		case MODEL_MODIFIED:
+			throw new IllegalArgumentException(t.name() + " not supported!");
+		default:
+			throw new IllegalArgumentException("Invalid enum value!");
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/EventProcessor.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/EventProcessor.java
new file mode 100644
index 0000000..312cf2b
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/EventProcessor.java
@@ -0,0 +1,103 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification.peak;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.mdm.api.base.notification.NotificationException;
+import org.eclipse.mdm.api.base.notification.NotificationListener;
+import org.glassfish.jersey.media.sse.EventInput;
+import org.glassfish.jersey.media.sse.InboundEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.peaksolution.ods.notification.protobuf.NotificationProtos.Notification;
+
+/**
+ * Event processor responsible for receiving notification events from the
+ * notification server and redirect them to the manager.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+public class EventProcessor implements Runnable {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(EventProcessor.class);
+
+	private EventInput eventInput;
+	private NotificationListener listener;
+	private PeakNotificationManager odsNotificationManager;
+	private MediaType eventMediaType;
+	private boolean closeInvoked = false;
+	private boolean disconnected = false;
+
+	public EventProcessor(EventInput eventInput, NotificationListener listener,
+			PeakNotificationManager odsNotificationManager, MediaType eventMediaType) {
+		this.eventInput = eventInput;
+		this.listener = listener;
+		this.odsNotificationManager = odsNotificationManager;
+		this.eventMediaType = eventMediaType;
+	}
+
+	@Override
+	public void run() {
+
+		while (!eventInput.isClosed()) {
+
+			final InboundEvent inboundEvent = eventInput.read();
+
+			if (inboundEvent == null) {
+				if (!closeInvoked) {
+					odsNotificationManager
+							.processException(new NotificationException("Inbound event input stream closed!"));
+				}
+				disconnected = true;
+				return;
+			}
+
+			try {
+				if (LOGGER.isDebugEnabled()) {
+					LOGGER.trace("Received event: " + inboundEvent);
+				}
+				Notification n = inboundEvent.readData(Notification.class, eventMediaType);
+				odsNotificationManager.processNotification(n, getListener());
+			} catch (ProcessingException e) {
+				odsNotificationManager
+						.processException(new NotificationException("Cannot deserialize notification event!", e));
+				disconnected = true;
+				return;
+			}
+		}
+
+		disconnected = true;
+	}
+
+	public boolean isDisconnected() {
+		return disconnected;
+	}
+
+	public void stop() {
+		closeInvoked = true;
+		// EventInput is closed by the server side after invoking DELETE
+		// /events/{registrationName}. Otherwise we run into a deadlock with
+		// eventInput#read()
+	}
+
+	public NotificationListener getListener() {
+		return listener;
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/JsonMessageBodyProvider.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/JsonMessageBodyProvider.java
new file mode 100644
index 0000000..c29405c
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/JsonMessageBodyProvider.java
@@ -0,0 +1,96 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification.peak;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import com.google.common.base.Charsets;
+import com.google.protobuf.GeneratedMessageV3;
+import com.google.protobuf.Message;
+import com.google.protobuf.util.JsonFormat;
+import com.google.protobuf.util.JsonFormat.Parser;
+import com.google.protobuf.util.JsonFormat.Printer;
+
+/**
+ * MessageBodyProvider for handling json payloads.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+@Provider
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class JsonMessageBodyProvider implements MessageBodyReader<Message>, MessageBodyWriter<Message> {
+
+	private static final Charset charset = Charsets.UTF_8;
+	private Printer jsonPrinter = JsonFormat.printer();
+	private Parser jsonParser = JsonFormat.parser();
+
+	@Override
+	public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+			final MediaType mediaType) {
+		return Message.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public Message readFrom(final Class<Message> type, final Type genericType, final Annotation[] annotations,
+			final MediaType mediaType, final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream)
+			throws IOException {
+		try {
+			final Method newBuilder = type.getMethod("newBuilder");
+			final GeneratedMessageV3.Builder<?> builder = (GeneratedMessageV3.Builder<?>) newBuilder.invoke(type);
+			jsonParser.merge(new InputStreamReader(entityStream, charset), builder);
+			return builder.build();
+		} catch (Exception e) {
+			throw new WebApplicationException(e);
+		}
+	}
+
+	@Override
+	public long getSize(final Message m, final Class<?> type, final Type genericType, final Annotation[] annotations,
+			final MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+			final MediaType mediaType) {
+		return Message.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public void writeTo(final Message m, final Class<?> type, final Type genericType, final Annotation[] annotations,
+			final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders,
+			final OutputStream entityStream) throws IOException {
+		entityStream.write(jsonPrinter.print(m).getBytes(charset));
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationManager.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationManager.java
new file mode 100644
index 0000000..72d1e45
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationManager.java
@@ -0,0 +1,277 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification.peak;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.notification.NotificationException;
+import org.eclipse.mdm.api.base.notification.NotificationFilter;
+import org.eclipse.mdm.api.base.notification.NotificationListener;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.notification.NotificationEntityLoader;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+import org.glassfish.jersey.media.sse.EventInput;
+import org.glassfish.jersey.media.sse.SseFeature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.peaksolution.ods.notification.protobuf.NotificationProtos.Notification;
+
+/**
+ * Notification manager for handling notifications from the Peak ODS Server
+ * Notification Plugin
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+public class PeakNotificationManager implements NotificationService {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(PeakNotificationManager.class);
+
+	private final Client client;
+	private final WebTarget endpoint;
+
+	private final Map<String, EventProcessor> processors = new HashMap<>();
+
+	private final ExecutorService executor = Executors.newCachedThreadPool();
+
+	private final ODSModelManager modelManager;
+
+	private final NotificationEntityLoader loader;
+
+	/**
+	 * @param modelManager
+	 * @param url                    URL of the notification plugin
+	 * @param loadContextDescribable if true, the corresponding context describable
+	 *                               is loaded if a notification for a context root
+	 *                               or context component is received.
+	 * @throws NotificationException Thrown if the manager cannot connect to the
+	 *                               notification server.
+	 */
+	public PeakNotificationManager(ODSModelManager modelManager, QueryService queryService, String url,
+			boolean loadContextDescribable) throws NotificationException {
+		this.modelManager = modelManager;
+		loader = new NotificationEntityLoader(modelManager, queryService, loadContextDescribable);
+
+		try {
+			client = ClientBuilder.newBuilder().register(SseFeature.class).register(JsonMessageBodyProvider.class)
+					.build();
+
+			endpoint = client.target(url).path("events");
+
+			Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> reconnect(), 10, 10, TimeUnit.SECONDS);
+		} catch (Exception e) {
+			throw new NotificationException("Could not create " + PeakNotificationManager.class.getName() + "!", e);
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.mdm.api.base.notification.NotificationManager#register(java.
+	 * lang.String, org.eclipse.mdm.api.base.notification.NotificationFilter,
+	 * org.eclipse.mdm.api.base.notification.NotificationListener)
+	 */
+	@Override
+	public void register(String registration, NotificationFilter filter, NotificationListener listener)
+			throws NotificationException {
+		LOGGER.info("Starting registration for with name: {}", registration);
+
+		Response response = endpoint.path(registration).request().post(
+				javax.ws.rs.client.Entity.entity(ProtobufConverter.from(filter), MediaType.APPLICATION_JSON_TYPE));
+
+		if (response.getStatusInfo().getStatusCode() == Status.CONFLICT.getStatusCode()) {
+			if (LOGGER.isInfoEnabled()) {
+				LOGGER.info("A registration with the name already exists: {}", response.readEntity(String.class));
+				LOGGER.info("Trying to reregister...");
+			}
+			deregister(registration);
+			LOGGER.info("Deregisteration successful.");
+			register(registration, filter, listener);
+			return;
+		}
+
+		if (response.getStatusInfo().getStatusCode() != Status.OK.getStatusCode()) {
+			throw new NotificationException(
+					"Could not create registration at notification service: " + response.readEntity(String.class));
+		}
+
+		recreateEventStream(registration, listener);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.eclipse.mdm.api.base.notification.NotificationManager#deregister(java
+	 * .lang.String)
+	 */
+	@Override
+	public void deregister(String registration) {
+		if (processors.containsKey(registration)) {
+			close(registration);
+		}
+
+		endpoint.path(registration).request().delete();
+	}
+
+	@Override
+	public void close(boolean isDeregisterAll) throws NotificationException {
+		LOGGER.info("Closing NotificationManager...");
+
+		for (String registration : processors.keySet()) {
+			if (isDeregisterAll) {
+				LOGGER.debug("Deregistering '{}'.", registration);
+				deregister(registration);
+			} else {
+				LOGGER.debug("Disconnecting '{}'.", registration);
+				close(registration);
+			}
+		}
+	}
+
+	/**
+	 * Recreates the {@link EventInput}, attaches an {@link EventProcessor} to it
+	 * and stores the {@link EventProcessor} in the processors map.
+	 * 
+	 * @param registration
+	 * @param listener
+	 * @throws NotificationException
+	 */
+	private void recreateEventStream(String registration, NotificationListener listener) throws NotificationException {
+		try {
+			LOGGER.info("Requesting event input for {}", registration);
+			EventInput eventInput = endpoint.path(registration).request(SseFeature.SERVER_SENT_EVENTS_TYPE)
+					.get(EventInput.class);
+
+			LOGGER.info("Received event input, starting event processor.");
+			EventProcessor processor = new EventProcessor(eventInput, listener, this, MediaType.APPLICATION_JSON_TYPE);
+
+			executor.submit(processor);
+
+			processors.put(registration, processor);
+			LOGGER.info("Event processor started.");
+		} catch (Exception e) {
+			try {
+				deregister(registration);
+			} catch (Exception ex) {
+				LOGGER.error("Exception upon deregistering!");
+			}
+			throw new NotificationException("Could not create event input stream!", e);
+		}
+	}
+
+	/**
+	 * Checks if any registered event processor got disconnected and tries to
+	 * recreate the event stream, if necessary.
+	 */
+	private void reconnect() {
+
+		for (Map.Entry<String, EventProcessor> entry : processors.entrySet()) {
+			if (entry.getValue().isDisconnected()) {
+				try {
+					LOGGER.trace("Registration '{}' was disconnected and will be recreated.", entry.getKey());
+					recreateEventStream(entry.getKey(), entry.getValue().getListener());
+				} catch (NotificationException e) {
+					LOGGER.warn("Cannot recreate event stream for registration " + entry.getKey(), e);
+				}
+			}
+		}
+	}
+
+	private void close(String registration) {
+		if (processors.containsKey(registration)) {
+			EventProcessor processor = processors.get(registration);
+			processor.stop();
+			processors.remove(registration);
+		}
+	}
+
+	/**
+	 * Handler for Exceptions during event processing.
+	 * 
+	 * @param e Exception which occured during event processing.
+	 */
+	void processException(Exception e) {
+		LOGGER.error("Exception during notification processing!", e);
+	}
+
+	/**
+	 * Handler for notifications.
+	 * 
+	 * @param n                    notification to process.
+	 * @param notificationListener notification listener for handling the
+	 *                             notification.
+	 */
+	void processNotification(Notification n, NotificationListener notificationListener) {
+		if (LOGGER.isDebugEnabled()) {
+			LOGGER.debug("Processing notification event: " + n);
+		}
+
+		try {
+			User user = loader.load(new Key<>(User.class), Long.toString(n.getUserId()));
+
+			EntityType entityType = modelManager.getEntityTypeById(Long.toString(n.getAid()));
+
+			if (LOGGER.isTraceEnabled()) {
+				LOGGER.trace("Notification event with: entityType=" + entityType + ", user=" + user);
+			}
+			switch (n.getType()) {
+			case NEW:
+				notificationListener.instanceCreated(loader.loadEntities(entityType, n.getIidList().stream()
+						.map(id -> id.toString()).filter(ODSUtils::isValidID).collect(Collectors.toList())), user);
+				break;
+			case MODIFY:
+				notificationListener.instanceModified(loader.loadEntities(entityType, n.getIidList().stream()
+						.map(id -> id.toString()).filter(ODSUtils::isValidID).collect(Collectors.toList())), user);
+				break;
+			case DELETE:
+				notificationListener.instanceDeleted(entityType, n.getIidList().stream().map(id -> id.toString())
+						.filter(ODSUtils::isValidID).collect(Collectors.toList()), user);
+				break;
+			case MODEL:
+				notificationListener.modelModified(entityType, user);
+				break;
+			case SECURITY:
+				notificationListener.securityModified(entityType, n.getIidList().stream().map(id -> id.toString())
+						.filter(ODSUtils::isValidID).collect(Collectors.toList()), user);
+				break;
+			default:
+				processException(new NotificationException("Invalid notification type!"));
+			}
+		} catch (Exception e) {
+			processException(new NotificationException("Could not process notification!", e));
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/ProtobufConverter.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/ProtobufConverter.java
new file mode 100644
index 0000000..509a6a8
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/notification/peak/ProtobufConverter.java
@@ -0,0 +1,91 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification.peak;
+
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.notification.NotificationFilter;
+import org.eclipse.mdm.api.base.notification.NotificationFilter.ModificationType;
+
+import com.peaksolution.ods.notification.protobuf.NotificationProtos.Registration;
+import com.peaksolution.ods.notification.protobuf.NotificationProtos.Registration.NotificationMode;
+
+/**
+ * Helper class for converting between protobuf and mdm types.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+public class ProtobufConverter {
+
+	/**
+	 * Convert a notification filter to a registration.
+	 * 
+	 * @param filter notification filter.
+	 * @return registration corresponding to the given filter.
+	 */
+	public static Registration from(NotificationFilter filter) {
+		return Registration.newBuilder().setMode(NotificationMode.PUSH)
+				.addAllAid(
+						filter.getEntityTypes().stream().map(e -> Long.valueOf(e.getId())).collect(Collectors.toList()))
+				.addAllType(filter.getTypes().stream().map(t -> ProtobufConverter.from(t)).collect(Collectors.toList()))
+				.build();
+	}
+
+	/**
+	 * @param t mdm modification type.
+	 * @return protobuf notification type.
+	 */
+	public static com.peaksolution.ods.notification.protobuf.NotificationProtos.ModificationType from(
+			ModificationType t) {
+		switch (t) {
+		case INSTANCE_CREATED:
+			return com.peaksolution.ods.notification.protobuf.NotificationProtos.ModificationType.NEW;
+		case INSTANCE_MODIFIED:
+			return com.peaksolution.ods.notification.protobuf.NotificationProtos.ModificationType.MODIFY;
+		case INSTANCE_DELETED:
+			return com.peaksolution.ods.notification.protobuf.NotificationProtos.ModificationType.DELETE;
+		case MODEL_MODIFIED:
+			return com.peaksolution.ods.notification.protobuf.NotificationProtos.ModificationType.MODEL;
+		case SECURITY_MODIFIED:
+			return com.peaksolution.ods.notification.protobuf.NotificationProtos.ModificationType.SECURITY;
+		default:
+			throw new IllegalArgumentException("Invalid enum value!"); // TODO
+		}
+	}
+
+	/**
+	 * @param t protobuf notification type
+	 * @return mdm notification type
+	 */
+	public static ModificationType to(
+			com.peaksolution.ods.notification.protobuf.NotificationProtos.ModificationType t) {
+		switch (t) {
+		case NEW:
+			return ModificationType.INSTANCE_CREATED;
+		case MODIFY:
+			return ModificationType.INSTANCE_MODIFIED;
+		case DELETE:
+			return ModificationType.INSTANCE_DELETED;
+		case MODEL:
+			return ModificationType.MODEL_MODIFIED;
+		case SECURITY:
+			return ModificationType.SECURITY_MODIFIED;
+		default:
+			throw new IllegalArgumentException("Invalid enum value!"); // TODO
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSAttribute.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSAttribute.java
new file mode 100644
index 0000000..abe4edf
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSAttribute.java
@@ -0,0 +1,201 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.query;
+
+import java.util.Objects;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+
+import org.asam.ods.ApplAttr;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+
+/**
+ * ODS implementation of the {@link Attribute} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ODSAttribute implements Attribute {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Enumeration<?> enumObj;
+	private final String name;
+	private final String unit;
+	private final EntityType entityType;
+	private final ValueType<?> valueType;
+	private final boolean isIdAttribute;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param entityType The parent {@link EntityType}.
+	 * @param applAttr   The ODS meta data for this attribute.
+	 * @param unit       The unit name.
+	 * @param enumObj    The enumeration class, may be null.
+	 */
+	ODSAttribute(EntityType entityType, ApplAttr applAttr, String unit, Enumeration<?> enumObj) {
+		this.entityType = entityType;
+		name = applAttr.aaName;
+		this.unit = unit == null ? "" : unit;
+
+		if (isIDAttribute(entityType, applAttr)) {
+			valueType = ValueType.STRING;
+			isIdAttribute = true;
+		} else {
+			valueType = ODSUtils.VALUETYPES.inverse().get(applAttr.dType);
+			isIdAttribute = false;
+		}
+
+		if (valueType.isEnumerationType() && enumObj == null) {
+			throw new IllegalStateException(
+					"A modeled attribute with an enumeration value type must have an " + "enumeration definition.");
+		}
+
+		this.enumObj = enumObj;
+	}
+
+	private boolean isIDAttribute(EntityType entityType, ApplAttr applAttr) {
+		for (Relation r : entityType.getRelations()) {
+			if (applAttr.aaName.equalsIgnoreCase(r.getName())) {
+				return true;
+			}
+		}
+		return "id".equalsIgnoreCase(applAttr.baName);
+	}
+
+	public boolean isIdAttribute() {
+		return isIdAttribute;
+	}
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getUnit() {
+		return unit;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityType getEntityType() {
+		return entityType;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public ValueType<?> getValueType() {
+		return valueType;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Enumeration<?> getEnumObj() {
+		if (getValueType().isEnumerationType()) {
+			return enumObj;
+		}
+
+		throw new IllegalStateException("The value type of this attribute is not an enumeration type.");
+	}
+
+	@Override
+	public Value createValue(String unit, boolean valid, Object input) {
+		return Attribute.super.createValue(unit, valid, convertInputForIdAttribute(input));
+	}
+
+	@Override
+	public Value createValueSeq(String unit, Object input) {
+		return Attribute.super.createValueSeq(unit, convertInputForIdAttribute(input));
+	}
+
+	/**
+	 * Converts the input object from long/long-array/int/int-array to a
+	 * String/String-array
+	 * 
+	 * @param input The input to convert
+	 * @return The converted input
+	 */
+	private Object convertInputForIdAttribute(Object input) {
+		if (isIdAttribute) {
+			if (input instanceof Long || input instanceof Integer) {
+				return input.toString();
+			} else if (input instanceof long[]) {
+				return LongStream.of((long[]) input).mapToObj(Long::toString).toArray(String[]::new);
+			} else if (input instanceof int[]) {
+				return IntStream.of((int[]) input).mapToObj(Integer::toString).toArray(String[]::new);
+			}
+		}
+
+		return input;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(getEntityType(), getName());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (object instanceof ODSAttribute) {
+			Attribute attribute = (Attribute) object;
+			return getEntityType().equals(attribute.getEntityType()) && getName().equals(attribute.getName());
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java
new file mode 100644
index 0000000..41abfc2
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityFactory.java
@@ -0,0 +1,259 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.query;
+
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_ENUMERATION_NAME;
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SCALAR_TYPE;
+import static org.eclipse.mdm.api.dflt.model.CatalogAttribute.VATTR_SEQUENCE;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.DefaultCore;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.EnumerationValue;
+import org.eclipse.mdm.api.base.model.Interpolation;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+import org.eclipse.mdm.api.base.model.TypeSpecification;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.model.VersionState;
+import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+
+/**
+ * ODS implementation of the {@link EntityFactory}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class ODSEntityFactory extends EntityFactory {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final Set<Class<? extends EnumerationValue>> ENUM_CLASSES = new HashSet<>();
+
+	static {
+		ENUM_CLASSES.add(ScalarType.class);
+		ENUM_CLASSES.add(VersionState.class);
+		ENUM_CLASSES.add(Interpolation.class);
+		ENUM_CLASSES.add(AxisType.class);
+		ENUM_CLASSES.add(SequenceRepresentation.class);
+		ENUM_CLASSES.add(TypeSpecification.class);
+	}
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ODSModelManager modelManager;
+	private final Optional<User> loggedInUser;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to create {@link Core}s.
+	 * @param loggedInUser The logged in {@link User}.
+	 */
+	public ODSEntityFactory(ODSModelManager modelManager, Optional<User> loggedInUser) {
+		this.modelManager = modelManager;
+		this.loggedInUser = loggedInUser;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Extracts the {@link Core} from an {@link Entity} instance. This method
+	 * effectively makes access to the Core of a BaseEntity publicly available (by
+	 * calling the corresponding protected method of BaseEntityFactory, which is
+	 * this class's superclass) to users of ODSEntityFactory.
+	 * 
+	 * @param entity The {@link Entity} from which to extract the {@link Core}.
+	 * @return The entity's {@link Core}.
+	 */
+	public static Core extract(Entity entity) {
+		if (entity instanceof BaseEntity) {
+			return getCore((BaseEntity) entity);
+		} else {
+			throw new IllegalArgumentException("Entity of type '" + entity.getClass().getSimpleName()
+					+ "' does not extend '" + BaseEntity.class.getName() + "'");
+		}
+	}
+
+	/**
+	 * Create an instance of a class implementing the {@link Entity} interface with
+	 * core as the instance's {@link Core}. This method effectively makes the
+	 * protected BaseEntity constructor publicly available (by calling the
+	 * corresponding protected method of BaseEntityFactory, which is this class's
+	 * superclass) to users of ODSEntityFactory.
+	 * 
+	 * @param clazz The class to instantiate, must implement the {@link Entity}
+	 *              interface.
+	 * @param core  The {@link Core} to use for the newly created instance.
+	 * @return The newly created instance.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Entity> T createEntity(Class<T> clazz, Core core) {
+		if (BaseEntity.class.isAssignableFrom(clazz)) {
+			return (T) createBaseEntity(clazz.asSubclass(BaseEntity.class), core);
+		} else {
+			throw new IllegalArgumentException(
+					"Class '" + clazz.getSimpleName() + "' does not extend '" + BaseEntity.class.getName() + "'");
+		}
+
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected Optional<User> getLoggedInUser() {
+		return loggedInUser;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected <T extends Entity> Core createCore(Class<T> entityClass) {
+		return createCore(new Key<>(entityClass));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected <T extends Entity> Core createCore(Class<T> entityClass, ContextType contextType) {
+		return createCore(new Key<>(entityClass, contextType));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public static final EntityStore getMutableStore(BaseEntity entity) {
+		return EntityFactory.getMutableStore(entity);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public static final EntityStore getPermanentStore(BaseEntity entity) {
+		return EntityFactory.getPermanentStore(entity);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public static final ChildrenStore getChildrenStore(BaseEntity entity) {
+		return EntityFactory.getChildrenStore(entity);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected <T extends Entity> Core createCore(String name, Class<T> entityClass) {
+		EntityConfig<?> entityConfig = modelManager.getEntityConfig(modelManager.getEntityType(name));
+		if (!entityClass.equals(entityConfig.getEntityClass())) {
+			throw new IllegalArgumentException("Incompatible entity class expected '" + entityClass.getName()
+					+ "' but got '" + entityConfig.getEntityClass().getName() + "'");
+		}
+		Core core = new DefaultCore(entityConfig.getEntityType());
+		core.getValues().get(Entity.ATTR_MIMETYPE).set(entityConfig.getMimeType());
+
+		return core;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void validateEnum(Enumeration<?> enumerationObj) {
+		EnumRegistry er = EnumRegistry.getInstance();
+		// check if enum is properly registered
+		if (er.get(enumerationObj.getName()) == null) {
+			throw new IllegalArgumentException("Given enum class '" + enumerationObj.getName() + "' is not supported.");
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected <T extends BaseEntity> T createBaseEntity(Class<T> clazz, Core core) {
+		try {
+			Constructor<T> constructor = clazz.getDeclaredConstructor(Core.class);
+			try {
+				return constructor.newInstance(core);
+			} catch (IllegalAccessException exc) {
+				return super.createBaseEntity(clazz, core);
+			}
+		} catch (NoSuchMethodException | InvocationTargetException | InstantiationException exc) {
+			throw new IllegalStateException(exc.getMessage(), exc);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Creates a configured {@link Core} for given {@link Key}.
+	 *
+	 * @param <T> The entity type.
+	 * @param key Used as identifier to resolve the {@link EntityConfig}.
+	 * @return The created {@code Core} is returned.
+	 */
+	private <T extends Entity> Core createCore(Key<T> key) {
+		EntityConfig<T> entityConfig = modelManager.findEntityConfig(key);
+		Core core = new DefaultCore(entityConfig.getEntityType());
+		core.getValues().get(Entity.ATTR_MIMETYPE).set(entityConfig.getMimeType());
+
+		if (CatalogAttribute.class.equals(entityConfig.getEntityClass())) {
+			core.getValues().put(VATTR_ENUMERATION_NAME, ValueType.STRING.create(VATTR_ENUMERATION_NAME));
+			core.getValues().put(VATTR_SCALAR_TYPE,
+					ValueType.ENUMERATION.create(EnumRegistry.getInstance().get("ScalarType"), VATTR_SCALAR_TYPE));
+			core.getValues().put(VATTR_SEQUENCE, ValueType.BOOLEAN.create(VATTR_SEQUENCE));
+		}
+
+		return core;
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityType.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityType.java
new file mode 100644
index 0000000..dee3a4c
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSEntityType.java
@@ -0,0 +1,320 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.query;
+
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toMap;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.asam.ods.ApplElem;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+
+/**
+ * ODS implementation of the {@link EntityType} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class ODSEntityType implements EntityType {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<EntityType, Map<String, Relation>> relationsByEntityName = new HashMap<>();
+	private final Map<EntityType, Relation> relationsByEntity = new HashMap<>();
+
+	private final Map<RelationType, List<Relation>> relationsByType = new EnumMap<>(RelationType.class);
+	private final List<Relation> relations = new ArrayList<>();
+
+	private final Map<String, Attribute> attributeByName;
+
+	private final String sourceName;
+	private final T_LONGLONG odsID;
+	private final String baseName;
+	private final String name;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param sourceName  Name of the data source.
+	 * @param applElem    The ODS meta data for this entity type.
+	 * @param units       The unit {@code Map} for unit mapping of attributes.
+	 * @param enumClasses The enumeration class {@code Map} for enum mapping of
+	 *                    attributes.
+	 */
+
+	ODSEntityType(String sourceName, ApplElem applElem, Map<String, String> units,
+			Map<String, Enumeration<?>> enumObjs) {
+		this.sourceName = sourceName;
+		baseName = applElem.beName;
+		name = applElem.aeName;
+		odsID = applElem.aid;
+
+		attributeByName = Arrays
+				.stream(applElem.attributes).map(a -> new ODSAttribute(this, a,
+						units.get(Long.toString(ODSConverter.fromODSLong(a.unitId))), enumObjs.get(a.aaName)))
+				.collect(toMap(Attribute::getName, Function.identity()));
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getSourceName() {
+		return sourceName;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the ODS base name this entity type is derived from.
+	 *
+	 * @return The base name is returned.
+	 */
+	public String getBaseName() {
+		return baseName;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Attribute> getAttributes() {
+		return new ArrayList<>(attributeByName.values());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute getAttribute(String name) {
+		Attribute attribute = attributeByName.get(name);
+		if (attribute == null) {
+			Optional<Relation> relation = getRelations().stream().filter(r -> r.getName().equals(name)).findAny();
+			return relation.map(Relation::getAttribute).orElseThrow(() -> new IllegalArgumentException(
+					"Attribute with name '" + name + "' not found at entity type '" + getName() + "'."));
+		}
+		return attribute;
+	}
+
+	/**
+	 * Returns the ODS type ID of this entity type.
+	 *
+	 * @return The ODS type ID is returned.
+	 */
+	public T_LONGLONG getODSID() {
+		return odsID;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getId() {
+		return Long.toString(ODSConverter.fromODSLong(odsID));
+	}
+
+	@Override
+	public List<Relation> getRelations() {
+		return Collections.unmodifiableList(relations);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Relation> getParentRelations() {
+		return getRelations(RelationType.FATHER_CHILD).stream()
+				.filter(r -> ((ODSRelation) r).isOutgoing(RelationType.FATHER_CHILD)).collect(Collectors.toList());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Relation> getChildRelations() {
+		return getRelations(RelationType.FATHER_CHILD).stream()
+				.filter(r -> ((ODSRelation) r).isIncoming(RelationType.FATHER_CHILD)).collect(Collectors.toList());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Relation> getInfoRelations() {
+		return getRelations(RelationType.INFO).stream().filter(r -> ((ODSRelation) r).isOutgoing(RelationType.INFO))
+				.collect(Collectors.toList());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Relation> getRelations(RelationType relationType) {
+		List<Relation> result = relationsByType.get(relationType);
+		return result == null ? Collections.emptyList() : Collections.unmodifiableList(result);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Relation getRelation(EntityType target) {
+		Relation relation = relationsByEntity.get(target);
+		if (relation == null) {
+			// multiple relations to target exist, try to use a default
+			Map<String, Relation> relationsByName = relationsByEntityName.get(target);
+			if (relationsByName == null) {
+				throw new IllegalArgumentException("Relations to '" + target + "' not found!");
+			}
+
+			relation = relationsByName.get(target.getName());
+		}
+		return relation == null ? getParentRelation(target) : relation;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Relation getRelation(EntityType target, String name) {
+		Map<String, Relation> relationsByName = relationsByEntityName.get(target);
+		if (relationsByName == null) {
+			throw new IllegalArgumentException("Relations to '" + target + "' not found!");
+		}
+
+		Relation relation = relationsByName.get(name);
+		if (relation == null) {
+			throw new IllegalArgumentException("Relation to '" + target + "' with name '" + name + "' not found!");
+		}
+		return relation;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		return getName().hashCode();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (object instanceof ODSEntityType) {
+			return getName().equals(((EntityType) object).getName());
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@link Relation}s.
+	 *
+	 * @param relations {@code Relation}s which will be added.
+	 */
+	void setRelations(List<Relation> relations) {
+		Map<EntityType, List<Relation>> entityRelationsByTarget = relations.stream().distinct()
+				.filter(r -> equals(r.getSource())).collect(groupingBy(Relation::getTarget));
+
+		for (Entry<EntityType, List<Relation>> entry : entityRelationsByTarget.entrySet()) {
+			List<Relation> entityTypeRelations = entry.getValue();
+			EntityType target = entry.getKey();
+
+			entityTypeRelations.forEach(this::addRelation);
+
+			if (entityTypeRelations.size() > 1) {
+				relationsByEntityName.put(target,
+						entityTypeRelations.stream().collect(toMap(Relation::getName, identity())));
+			} else {
+				relationsByEntity.put(target, entityTypeRelations.get(0));
+			}
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Tries to find a parent {@link Relation} to given target {@link EntityType}.
+	 *
+	 * @param target The target {@code EntityType}.
+	 * @return The requested parent {@code Relation} is returned.
+	 * @throws IllegalArgumentException Thrown if no such {@code Relation} exists.
+	 */
+	private Relation getParentRelation(EntityType target) {
+		return getParentRelations().stream().filter(et -> et.getTarget().equals(target)).findAny().orElseThrow(
+				() -> new IllegalArgumentException("Relation to entity type '" + target + "' does not exist."));
+	}
+
+	/**
+	 * Adds given {@link Relation}.
+	 *
+	 * @param relation {@code Relation} which will be added.
+	 */
+	private void addRelation(Relation relation) {
+		relationsByType.computeIfAbsent(relation.getRelationType(), k -> new ArrayList<>()).add(relation);
+		relations.add(relation);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
new file mode 100644
index 0000000..50f9917
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSModelManager.java
@@ -0,0 +1,447 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.query;
+
+import static java.util.stream.Collectors.groupingBy;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Stream;
+
+import org.asam.ods.AIDName;
+import org.asam.ods.AggrFunc;
+import org.asam.ods.AoException;
+import org.asam.ods.AoSession;
+import org.asam.ods.ApplElem;
+import org.asam.ods.ApplElemAccess;
+import org.asam.ods.ApplRel;
+import org.asam.ods.ApplicationStructureValue;
+import org.asam.ods.ElemResultSetExt;
+import org.asam.ods.EnumerationAttributeStructure;
+import org.asam.ods.EnumerationItemStructure;
+import org.asam.ods.EnumerationStructure;
+import org.asam.ods.JoinDef;
+import org.asam.ods.QueryStructureExt;
+import org.asam.ods.SelAIDNameUnitId;
+import org.asam.ods.SelItem;
+import org.asam.ods.SelOrder;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.odsadapter.lookup.config.DefaultEntityConfigRepositoryLoader;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfigRepository;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfigRepositoryLoader;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.eclipse.mdm.api.odsadapter.utils.ODSEnum;
+import org.eclipse.mdm.api.odsadapter.utils.ODSEnumerations;
+import org.omg.CORBA.ORB;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ODS implementation of the {@link ModelManager} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ODSModelManager implements ModelManager {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSModelManager.class);
+
+	private final Map<String, EntityType> entityTypesByName = new HashMap<>();
+
+	private final ORB orb;
+
+	private final Lock write;
+	private final Lock read;
+
+	private EntityConfigRepository entityConfigRepository;
+	private EntityConfigRepositoryLoader entityConfigRepositoryLoader;
+
+	private ApplElemAccess applElemAccess;
+	private AoSession aoSession;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param orb       Used to activate CORBA service objects.
+	 * @param aoSession The underlying ODS session.
+	 * @throws AoException Thrown on errors.
+	 */
+	public ODSModelManager(ORB orb, AoSession aoSession) throws AoException {
+		this(orb, aoSession, new DefaultEntityConfigRepositoryLoader());
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param orb       Used to activate CORBA service objects.
+	 * @param aoSession The underlying ODS session.
+	 * @throws AoException Thrown on errors.
+	 */
+	public ODSModelManager(ORB orb, AoSession aoSession, EntityConfigRepositoryLoader entityConfigRepositoryLoader)
+			throws AoException {
+		this.aoSession = aoSession;
+		this.orb = orb;
+		applElemAccess = aoSession.getApplElemAccess();
+		this.entityConfigRepositoryLoader = entityConfigRepositoryLoader;
+
+		// setup locks
+		ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
+		write = reentrantReadWriteLock.writeLock();
+		read = reentrantReadWriteLock.readLock();
+
+		initialize();
+	}
+
+	/**
+	 * Returns the {@link ORB}.
+	 *
+	 * @return The {@code ORB} is returned.
+	 */
+	public ORB getORB() {
+		return orb;
+	}
+
+	/**
+	 * Returns the non root {@link EntityConfig} for given {@link Key}.
+	 *
+	 * @param <T> The concrete entity type.
+	 * @param key Used as identifier.
+	 * @return The non root {@code EntityConfig} is returned.
+	 */
+	public <T extends Entity> EntityConfig<T> findEntityConfig(Key<T> key) {
+		read.lock();
+
+		try {
+			return entityConfigRepository.find(key);
+		} finally {
+			read.unlock();
+		}
+	}
+
+	/**
+	 * Returns the root {@link EntityConfig} for given {@link Key}.
+	 *
+	 * @param <T> The concrete entity type.
+	 * @param key Used as identifier.
+	 * @return The root {@code EntityConfig} is returned.
+	 */
+	public <T extends Entity> EntityConfig<T> getEntityConfig(Key<T> key) {
+		read.lock();
+
+		try {
+			return entityConfigRepository.findRoot(key);
+		} finally {
+			read.unlock();
+		}
+	}
+
+	/**
+	 * Returns the {@link EntityConfig} associated with given {@link EntityType}.
+	 *
+	 * @param entityType Used as identifier.
+	 * @return The {@code EntityConfig} is returned.
+	 */
+	public EntityConfig<?> getEntityConfig(EntityType entityType) {
+		read.lock();
+
+		try {
+			return entityConfigRepository.find(entityType);
+		} finally {
+			read.unlock();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<EntityType> listEntityTypes() {
+		read.lock();
+
+		try {
+			return Collections.unmodifiableList(new ArrayList<>(entityTypesByName.values()));
+		} finally {
+			read.unlock();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityType getEntityType(Class<? extends Entity> entityClass) {
+		read.lock();
+
+		try {
+			return getEntityConfig(new Key<>(entityClass)).getEntityType();
+		} finally {
+			read.unlock();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityType getEntityType(Class<? extends Entity> entityClass, ContextType contextType) {
+		read.lock();
+
+		try {
+			return getEntityConfig(new Key<>(entityClass, contextType)).getEntityType();
+		} finally {
+			read.unlock();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityType getEntityType(String name) {
+		read.lock();
+
+		try {
+			EntityType entityType = entityTypesByName.get(name);
+			if (entityType == null) {
+				throw new IllegalArgumentException("Entity with name '" + name + "' not found.");
+			}
+
+			return entityType;
+		} finally {
+			read.unlock();
+		}
+	}
+
+	@Override
+	public EntityType getEntityTypeById(String id) {
+		Optional<EntityType> entityType = listEntityTypes().stream().filter(et -> et.getId().equals(id)).findFirst();
+		if (!entityType.isPresent()) {
+			throw new IllegalArgumentException("Entity with id '" + id + "' not found.");
+		}
+
+		return entityType.get();
+	}
+
+	/**
+	 * Returns the {@link AoSession} of this model manager.
+	 *
+	 * @return The {@code AoSession} is returned.
+	 */
+	public AoSession getAoSession() {
+		write.lock();
+
+		try {
+			return aoSession;
+		} finally {
+			write.unlock();
+		}
+	}
+
+	/**
+	 * Returns the {@link ApplElemAccess} of this model manager.
+	 *
+	 * @return The {@code ApplElemAccess} is returned.
+	 */
+	public ApplElemAccess getApplElemAccess() {
+		read.lock();
+
+		try {
+			return applElemAccess;
+		} finally {
+			read.unlock();
+		}
+	}
+
+	/**
+	 * Closes the ODS connection.
+	 *
+	 * @throws AoException Thrown on errors.
+	 */
+	public void close() throws AoException {
+		read.lock();
+
+		try {
+			applElemAccess._release();
+			aoSession.close();
+		} finally {
+			read.unlock();
+			aoSession._release();
+		}
+	}
+
+	/**
+	 * Reloads the complete session context.
+	 */
+	public void reloadApplicationModel() {
+		write.lock();
+
+		AoSession aoSessionOld = aoSession;
+		ApplElemAccess applElemAccessOld = applElemAccess;
+		try {
+			entityTypesByName.clear();
+
+			aoSession = aoSession.createCoSession();
+			applElemAccess = aoSession.getApplElemAccess();
+			initialize();
+		} catch (AoException e) {
+			LOGGER.error("Unable to reload the application model due to: " + e.reason, e);
+		} finally {
+			write.unlock();
+		}
+
+		try {
+			applElemAccessOld._release();
+			aoSessionOld.close();
+		} catch (AoException e) {
+			LOGGER.debug("Unable to close replaced session due to: " + e.reason, e);
+		} finally {
+			aoSessionOld._release();
+		}
+	}
+
+	/**
+	 * Initializes this model manager by caching the application model and loading
+	 * the {@link EntityConfig}s.
+	 *
+	 * @throws AoException Thrown on errors.
+	 */
+	private void initialize() throws AoException {
+		loadApplicationModel();
+		entityConfigRepository = entityConfigRepositoryLoader.loadEntityConfigurations(this);
+	}
+
+	/**
+	 * Caches the whole application model as provided by the ODS session.
+	 *
+	 * @throws AoException Thrown on errors.
+	 */
+	private void loadApplicationModel() throws AoException {
+		LOGGER.debug("Reading the application model...");
+
+		Map<String, Map<String, Enumeration<?>>> enumClassMap = loadODSEnumerations();
+
+		long start = System.currentTimeMillis();
+		ApplicationStructureValue applicationStructureValue = aoSession.getApplicationStructureValue();
+		Map<String, String> units = getUnitMapping(applicationStructureValue.applElems);
+
+		// create entity types (incl. attributes)
+		Map<String, ODSEntityType> entityTypesByID = new HashMap<>();
+		String sourceName = aoSession.getName();
+		for (ApplElem applElem : applicationStructureValue.applElems) {
+			String odsID = Long.toString(ODSConverter.fromODSLong(applElem.aid));
+			Map<String, Enumeration<?>> entityEnumMap = enumClassMap.getOrDefault(odsID, new HashMap<>());
+
+			ODSEntityType entityType = new ODSEntityType(sourceName, applElem, units, entityEnumMap);
+			entityTypesByName.put(applElem.aeName, entityType);
+			entityTypesByID.put(odsID, entityType);
+		}
+
+		// create relations
+		List<Relation> relations = new ArrayList<>();
+		for (ApplRel applRel : applicationStructureValue.applRels) {
+			EntityType source = entityTypesByID.get(Long.toString(ODSConverter.fromODSLong(applRel.elem1)));
+			EntityType target = entityTypesByID.get(Long.toString(ODSConverter.fromODSLong(applRel.elem2)));
+			relations.add(new ODSRelation(applRel, source, target));
+		}
+
+		// assign relations to their source entity types
+		relations.stream().collect(groupingBy(Relation::getSource))
+				.forEach((e, r) -> ((ODSEntityType) e).setRelations(r));
+
+		long stop = System.currentTimeMillis();
+		LOGGER.debug("{} entity types with {} relations found in {} ms.", entityTypesByName.size(), relations.size(),
+				stop - start);
+	}
+
+	private Map<String, Map<String, Enumeration<?>>> loadODSEnumerations() throws AoException {
+		LOGGER.debug("Loading ODS enumerations...");
+		long t1 = System.currentTimeMillis();
+
+		// enumeration mappings (aeID -> (aaName -> enumClass))
+		Map<String, Map<String, Enumeration<?>>> enumClassMap = new HashMap<>();
+		EnumRegistry er = EnumRegistry.getInstance();
+
+		Map<String, EnumerationItemStructure[]> map = new HashMap<>();
+		for (EnumerationStructure es : aoSession.getEnumerationStructure()) {
+			map.put(es.enumName, es.items);
+		}
+
+		for (EnumerationAttributeStructure eas : aoSession.getEnumerationAttributes()) {
+
+			// make sure the enumeration is found
+			if (ODSEnumerations.getEnumObj(eas.enumName) == null) {
+				Enumeration<ODSEnum> enumdyn = new Enumeration<>(ODSEnum.class, eas.enumName);
+				for (EnumerationItemStructure enumItemStruct : map.get(eas.enumName)) {
+					LOGGER.trace("{}:{}:{}", eas.enumName, enumItemStruct.itemName, enumItemStruct.index);
+					enumdyn.addValue(new ODSEnum(enumItemStruct.itemName, enumItemStruct.index));
+				}
+				er.add(eas.enumName, enumdyn);
+			}
+
+			enumClassMap.computeIfAbsent(Long.toString(ODSConverter.fromODSLong(eas.aid)), k -> new HashMap<>())
+					.put(eas.aaName, ODSEnumerations.getEnumObj(eas.enumName));
+		}
+		LOGGER.debug("Loading enumerations took {}ms", System.currentTimeMillis() - t1);
+		return enumClassMap;
+	}
+
+	/**
+	 * Loads all available {@link Unit} names mapped by their instance IDs.
+	 *
+	 * @param applElems The application element meta data instances.
+	 * @return The unit names mapped by the corresponding instance IDs.
+	 * @throws AoException Thrown if unable to load the unit mappings.
+	 */
+	private Map<String, String> getUnitMapping(ApplElem[] applElems) throws AoException {
+		ApplElem unitElem = Stream.of(applElems).filter(ae -> ae.beName.equals("AoUnit")).findAny()
+				.orElseThrow(() -> new IllegalStateException("Application element 'Unit' is not defined."));
+
+		QueryStructureExt qse = new QueryStructureExt();
+		qse.anuSeq = new SelAIDNameUnitId[] {
+				new SelAIDNameUnitId(new AIDName(unitElem.aid, "Id"), new T_LONGLONG(), AggrFunc.NONE),
+				new SelAIDNameUnitId(new AIDName(unitElem.aid, "Name"), new T_LONGLONG(), AggrFunc.NONE) };
+		qse.condSeq = new SelItem[0];
+		qse.groupBy = new AIDName[0];
+		qse.joinSeq = new JoinDef[0];
+		qse.orderBy = new SelOrder[0];
+
+		Map<String, String> units = new HashMap<>();
+		ElemResultSetExt unitResultSetExt = getApplElemAccess().getInstancesExt(qse, 0)[0].firstElems[0];
+		for (int i = 0; i < unitResultSetExt.values[0].value.flag.length; i++) {
+			String unitID = Long
+					.toString(ODSConverter.fromODSLong(unitResultSetExt.values[0].value.u.longlongVal()[i]));
+			String unitName = unitResultSetExt.values[1].value.u.stringVal()[i];
+			units.put(unitID, unitName);
+		}
+
+		return units;
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
new file mode 100644
index 0000000..b2f5d03
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQuery.java
@@ -0,0 +1,558 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.query;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.asam.ods.AIDName;
+import org.asam.ods.AIDNameUnitId;
+import org.asam.ods.AoException;
+import org.asam.ods.ApplElemAccess;
+import org.asam.ods.ElemResultSetExt;
+import org.asam.ods.JoinDef;
+import org.asam.ods.NameValueSeqUnitId;
+import org.asam.ods.QueryStructureExt;
+import org.asam.ods.ResultSetExt;
+import org.asam.ods.SelAIDNameUnitId;
+import org.asam.ods.SelItem;
+import org.asam.ods.SelOrder;
+import org.asam.ods.SelValueExt;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.base.query.Condition;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.FilterItem;
+import org.eclipse.mdm.api.base.query.JoinType;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+
+/**
+ * ODS implementation of the {@link Query} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ODSQuery implements Query {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSQuery.class);
+
+	private static final String GROUP_NAME = "name";
+	private static final String GROUP_AGGRFUNC = "aggrfunc";
+	private static final Pattern AGGREGATION_NAME_PATTERN = Pattern
+			.compile("(?<" + GROUP_AGGRFUNC + ">\\S+)\\((?<" + GROUP_NAME + ">\\S+)\\)");
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<String, EntityType> entityTypesByID = new HashMap<>();
+	private final Set<EntityType> queriedEntityTypes = new HashSet<>();
+	private final List<SelAIDNameUnitId> anuSeq = new ArrayList<>();
+	private final List<JoinDef> joinSeq = new ArrayList<>();
+	private final List<AIDName> groupBy = new ArrayList<>();
+	private final List<SelOrder> orderBy = new ArrayList<>();
+
+	private final ApplElemAccess applElemAccess;
+
+	private int limit;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param applElemAccess Used to execute the query.
+	 */
+	ODSQuery(ApplElemAccess applElemAccess) {
+		this.applElemAccess = applElemAccess;
+		limit = 0;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean isQueried(EntityType entityType) {
+		return queriedEntityTypes.contains(entityType);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Query limit(int limit) {
+		this.limit = limit;
+		return this;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Query select(Attribute attribute, Aggregation aggregation) {
+		EntityType entityType = attribute.getEntityType();
+		entityTypesByID.put(Long.toString(ODSConverter.fromODSLong(((ODSEntityType) entityType).getODSID())),
+				entityType);
+		queriedEntityTypes.add(entityType);
+		anuSeq.add(createSelect(attribute, aggregation));
+		return this;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Query join(Relation relation, JoinType join) {
+		queriedEntityTypes.add(relation.getSource());
+		queriedEntityTypes.add(relation.getTarget());
+		joinSeq.add(createJoin(relation, join));
+		return this;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Query group(List<Attribute> attributes) {
+		for (Attribute attribute : attributes) {
+			group(attribute);
+		}
+		return this;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Query group(Attribute attribute) {
+		groupBy.add(createAIDName(attribute));
+		return this;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Query order(Attribute attribute, boolean ascending) {
+		orderBy.add(createOrderBy(attribute, ascending));
+		return this;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Optional<Result> fetchSingleton(Filter filter) throws DataAccessException {
+		List<Result> results = fetch(filter);
+		if (results.isEmpty()) {
+			return Optional.empty();
+		} else if (results.size() > 1) {
+			throw new DataAccessException("Multiple results found after executing the singleton query!");
+		}
+
+		return Optional.of(results.get(0));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Result> fetch(Filter filter) throws DataAccessException {
+		try {
+
+			List<SelItem> condSeq = new ArrayList<>();
+			int condCount = 0;
+			for (FilterItem conditionItem : filter) {
+				SelItem selItem = new SelItem();
+				if (conditionItem.isCondition()) {
+					selItem.value(createCondition(conditionItem.getCondition()));
+				} else if (conditionItem.isBracketOperator()) {
+					selItem._operator(ODSUtils.BRACKETOPERATORS.get(conditionItem.getBracketOperator()));
+				} else if (conditionItem.isBooleanOperator()) {
+					selItem._operator(ODSUtils.OPERATORS.get(conditionItem.getBooleanOperator()));
+					condCount++;
+				} else {
+					throw new IllegalArgumentException("Passed filter item is neither an operator nor a condition.");
+				}
+
+				condSeq.add(selItem);
+			}
+
+			QueryStructureExt qse = new QueryStructureExt();
+			qse.anuSeq = anuSeq.toArray(new SelAIDNameUnitId[anuSeq.size()]);
+			qse.condSeq = condSeq.toArray(new SelItem[condSeq.size()]);
+			qse.groupBy = groupBy.toArray(new AIDName[groupBy.size()]);
+			qse.joinSeq = joinSeq.toArray(new JoinDef[joinSeq.size()]);
+			qse.orderBy = orderBy.toArray(new SelOrder[orderBy.size()]);
+
+			List<Result> results = new ArrayList<>();
+			long start = System.currentTimeMillis();
+			for (Result result : new ResultFactory(entityTypesByID, applElemAccess.getInstancesExt(qse, limit)[0])) {
+				results.add(result);
+			}
+			long stop = System.currentTimeMillis();
+
+			LOGGER.debug("Query executed in {} ms and retrieved {} result rows ({} selections, {} conditions, "
+					+ "{} joins).", stop - start, results.size(), anuSeq.size(), condCount, joinSeq.size());
+			return results;
+		} catch (AoException aoe) {
+			throw new DataAccessException(aoe.reason, aoe);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Converts given {@link Attribute} and {@link Aggregation} to an ODS
+	 * {@link SelAIDNameUnitId}.
+	 *
+	 * @param attribute   The {@code Attribute}.
+	 * @param aggregation The {@code Aggregation}.
+	 * @return The corresponding {@code SelAIDNameUnitId} is returned.
+	 */
+	private SelAIDNameUnitId createSelect(Attribute attribute, Aggregation aggregation) {
+		SelAIDNameUnitId sanu = new SelAIDNameUnitId();
+
+		sanu.aggregate = ODSUtils.AGGREGATIONS.get(aggregation);
+		sanu.attr = createAIDName(attribute);
+		sanu.unitId = new T_LONGLONG();
+
+		return sanu;
+	}
+
+	/**
+	 * Converts given {@link Condition} to an ODS {@link SelValueExt}.
+	 *
+	 * @param condition The {@code Condition}.
+	 * @return The corresponding {@code SelValueExt} is returned.
+	 * @throws DataAccessException Thrown in case of errors.
+	 */
+	private SelValueExt createCondition(Condition condition) throws DataAccessException {
+		SelValueExt sve = new SelValueExt();
+
+		sve.oper = ODSUtils.OPERATIONS.get(condition.getComparisonOperator());
+		sve.attr = new AIDNameUnitId();
+		sve.attr.unitId = new T_LONGLONG();
+		sve.attr.attr = createAIDName(condition.getAttribute());
+		sve.value = ODSConverter.toODSValue(condition.getAttribute(), condition.getValue());
+
+		return sve;
+	}
+
+	/**
+	 * Converts given {@link Relation} and {@link JoinType} to an ODS
+	 * {@link JoinDef}.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param join     The {@code JoinType}.
+	 * @return The corresponding {@code JoinDef} is returned.
+	 */
+	private JoinDef createJoin(Relation relation, JoinType join) {
+		JoinDef joinDef = new JoinDef();
+
+		joinDef.fromAID = ((ODSEntityType) relation.getSource()).getODSID();
+		joinDef.toAID = ((ODSEntityType) relation.getTarget()).getODSID();
+		joinDef.refName = relation.getName();
+		joinDef.joiningType = ODSUtils.JOINS.get(join);
+
+		return joinDef;
+	}
+
+	/**
+	 * Converts given {@link Attribute} and sort order flag to an ODS
+	 * {@link SelOrder}.
+	 *
+	 * @param attribute The {@code Attribute}.
+	 * @param ascending The sort order.
+	 * @return The corresponding {@code SelOrder} is returned.
+	 */
+	private SelOrder createOrderBy(Attribute attribute, boolean ascending) {
+		SelOrder selOrder = new SelOrder();
+
+		selOrder.attr = createAIDName(attribute);
+		selOrder.ascending = ascending;
+
+		return selOrder;
+	}
+
+	/**
+	 * Converts given {@link Attribute} to an ODS {@link AIDName}.
+	 *
+	 * @param attribute The {@code Attribute}.
+	 * @return The corresponding {@code AIDName} is returned.
+	 */
+	private AIDName createAIDName(Attribute attribute) {
+		AIDName aidName = new AIDName();
+
+		aidName.aid = ((ODSEntityType) attribute.getEntityType()).getODSID();
+		aidName.aaName = attribute.getName();
+
+		return aidName;
+	}
+
+	private static Aggregation getAggregation(String odsAggrFunc) {
+		switch (Strings.nullToEmpty(odsAggrFunc).trim().toUpperCase()) {
+		case "COUNT":
+			return Aggregation.COUNT;
+		case "DCOUNT":
+			return Aggregation.DISTINCT_COUNT;
+		case "MIN":
+			return Aggregation.MINIMUM;
+		case "MAX":
+			return Aggregation.MAXIMUM;
+		case "AVG":
+			return Aggregation.AVERAGE;
+		case "STDDEV":
+			return Aggregation.DEVIATION;
+		case "SUM":
+			return Aggregation.SUM;
+		case "DISTINCT":
+			return Aggregation.DISTINCT;
+		default:
+			throw new IllegalArgumentException(
+					"Unsupported aggregate function '" + Strings.nullToEmpty(odsAggrFunc).trim().toUpperCase() + "'!");
+		}
+
+	}
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * Traverses the ODS {@link ResultSetExt} and creates a {@link Result} for each
+	 * row.
+	 */
+	private static final class ResultFactory implements Iterable<Result>, Iterator<Result> {
+
+		// ======================================================================
+		// Instance variables
+		// ======================================================================
+
+		private final List<RecordFactory> recordFactories = new ArrayList<>();
+		private final int length;
+		private int index;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param entityTypes  Used to access {@link EntityType} by its ODS ID.
+		 * @param resultSetExt The ODS values sequence containers.
+		 * @throws DataAccessException Thrown on conversion errors.
+		 */
+		public ResultFactory(Map<String, EntityType> entityTypes, ResultSetExt resultSetExt)
+				throws DataAccessException {
+			for (ElemResultSetExt elemResultSetExt : resultSetExt.firstElems) {
+				EntityType entityType = entityTypes.get(Long.toString(ODSConverter.fromODSLong(elemResultSetExt.aid)));
+				recordFactories.add(new RecordFactory(entityType, elemResultSetExt.values));
+			}
+
+			length = recordFactories.isEmpty() ? 0 : recordFactories.get(0).getLength();
+		}
+
+		// ======================================================================
+		// Public methods
+		// ======================================================================
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public boolean hasNext() {
+			return index < length;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public Result next() {
+			if (!hasNext()) {
+				throw new NoSuchElementException("No such element available.");
+			}
+			Result result = new Result();
+
+			for (RecordFactory recordFactory : recordFactories) {
+				result.addRecord(recordFactory.createRecord(index));
+			}
+
+			index++;
+			return result;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public Iterator<Result> iterator() {
+			return this;
+		}
+
+	}
+
+	/**
+	 * Creates a {@link Record} for given index from the original ODS values
+	 * sequence for a given {@link EntityType}.
+	 */
+	private static final class RecordFactory {
+
+		// ======================================================================
+		// Instance variables
+		// ======================================================================
+
+		private final List<ValueFactory> valueFactories = new ArrayList<>();
+		private final EntityType entityType;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param entityType The associated {@link EntityType}.
+		 * @param nvsuis     The ODS value sequence containers.
+		 * @throws DataAccessException Thrown on conversion errors.
+		 */
+		private RecordFactory(EntityType entityType, NameValueSeqUnitId[] nvsuis) throws DataAccessException {
+			this.entityType = entityType;
+			for (NameValueSeqUnitId nvsui : nvsuis) {
+				String attributeName = nvsui.valName;
+				Aggregation aggregation = Aggregation.NONE;
+				Matcher matcher = AGGREGATION_NAME_PATTERN.matcher(nvsui.valName);
+				if (matcher.matches()) {
+					attributeName = matcher.group(GROUP_NAME);
+					aggregation = ODSQuery.getAggregation(matcher.group(GROUP_AGGRFUNC));
+				}
+
+				valueFactories.add(new ValueFactory(entityType.getAttribute(attributeName), aggregation, nvsui));
+			}
+		}
+
+		// ======================================================================
+		// Private methods
+		// ======================================================================
+
+		private int getLength() {
+			return valueFactories.isEmpty() ? 0 : valueFactories.get(0).getLength();
+		}
+
+		private Record createRecord(int index) {
+			Record record = new Record(entityType);
+			for (ValueFactory valueFactory : valueFactories) {
+				record.addValue(valueFactory.createValue(index));
+			}
+
+			return record;
+		}
+
+	}
+
+	/**
+	 * Creates a {@link Value} container for given index from the original ODS value
+	 * sequence for a given {@link Attribute}.
+	 */
+	private static final class ValueFactory {
+
+		// ======================================================================
+		// Instance variables
+		// ======================================================================
+
+		private final List<Value> values;
+		private final String unit;
+		private final int length;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param attribute The associated {@link Attribute}.
+		 * @param nvsui     The ODS value sequence container.
+		 * @throws DataAccessException Thrown on conversion errors.
+		 */
+		private ValueFactory(Attribute attribute, Aggregation aggregation, NameValueSeqUnitId nvsui)
+				throws DataAccessException {
+			length = nvsui.value.flag.length;
+			unit = attribute.getUnit();
+			values = ODSConverter.fromODSValueSeq(attribute, aggregation, unit, nvsui.value);
+		}
+
+		// ======================================================================
+		// Private methods
+		// ======================================================================
+
+		/**
+		 * Returns the length of the sequence.
+		 *
+		 * @return Length of the sequence is returned.
+		 */
+		private int getLength() {
+			return length;
+		}
+
+		/**
+		 * Returns the {@link Value} for given index.
+		 *
+		 * @param index Index within the sequence.
+		 * @return The corresponding {@code Value} is returned.
+		 */
+		private Value createValue(int index) {
+			return values.get(index);
+		}
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQueryService.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQueryService.java
new file mode 100644
index 0000000..e226a3e
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSQueryService.java
@@ -0,0 +1,35 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.query;
+
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
+
+public class ODSQueryService implements QueryService {
+
+	private ODSModelManager modelManager;
+
+	public ODSQueryService(ODSModelManager modelManager) {
+		this.modelManager = modelManager;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Query createQuery() {
+		return new ODSQuery(modelManager.getApplElemAccess());
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSRelation.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSRelation.java
new file mode 100644
index 0000000..e57cb39
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/query/ODSRelation.java
@@ -0,0 +1,169 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.query;
+
+import java.util.Objects;
+
+import org.asam.ods.ApplAttr;
+import org.asam.ods.ApplRel;
+import org.asam.ods.DataType;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+
+/**
+ * ODS implementation of the {@link Relation} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class ODSRelation implements Relation {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final RelationType relationType;
+	private final EntityType source;
+	private final EntityType target;
+	private final String name;
+
+	private final int rangeMax;
+	private final int invRangeMax;
+	private Attribute attribute;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param applRel The ODS meta data for this relation.
+	 * @param source  The source {@link EntityType}.
+	 * @param target  The target {@code EntityType}.
+	 */
+	ODSRelation(ApplRel applRel, EntityType source, EntityType target) {
+		this.source = source;
+		this.target = target;
+		name = applRel.arName;
+		relationType = ODSUtils.RELATIONSHIPS.inverse().get(applRel.arRelationType);
+		rangeMax = applRel.arRelationRange.max;
+		invRangeMax = applRel.invRelationRange.max;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityType getSource() {
+		return source;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityType getTarget() {
+		return target;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public RelationType getRelationType() {
+		return relationType;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Attribute getAttribute() {
+		if (attribute == null) {
+			attribute = new ODSAttribute(getSource(),
+					new ApplAttr(getName(), "", DataType.DT_LONGLONG, 0, true, false, null), null, null);
+		}
+
+		return attribute;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(getSource(), getTarget(), getName());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (object instanceof ODSRelation) {
+			Relation relation = (Relation) object;
+			return getSource().equals(relation.getSource()) && getTarget().equals(relation.getTarget())
+					&& getName().equals(relation.getName());
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean isOutgoing(RelationType relationType) {
+		return relationType.equals(getRelationType()) && rangeMax == 1;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean isIncoming(RelationType relationType) {
+		return relationType.equals(getRelationType()) && rangeMax == -1;
+	}
+
+	@Override
+	public boolean isNtoM() {
+		return relationType == RelationType.INFO && rangeMax == -1 && invRangeMax == -1;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/BaseEntitySearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/BaseEntitySearchQuery.java
new file mode 100644
index 0000000..effa0dc
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/BaseEntitySearchQuery.java
@@ -0,0 +1,279 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.reducing;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.FilterItem;
+import org.eclipse.mdm.api.base.query.JoinType;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.Searchable;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinNode;
+
+/**
+ * Base implementation for entity {@link SearchQuery}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+abstract class BaseEntitySearchQuery implements SearchQuery {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Class<? extends Entity> rootEntityClass;
+	private final JoinTree joinTree = new JoinTree();
+	private final Class<? extends Entity> entityClass;
+
+	private final ODSModelManager modelManager;
+	private final QueryService queryService;
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager    Used to load {@link EntityType}s.
+	 * @param entityClass     The source entity class of this search query.
+	 * @param rootEntityClass The root entity class of this search query.
+	 */
+	protected BaseEntitySearchQuery(ODSModelManager modelManager, QueryService queryService,
+			Class<? extends Entity> entityClass, Class<? extends Entity> rootEntityClass) {
+		this.modelManager = modelManager;
+		this.queryService = queryService;
+		this.entityClass = entityClass;
+		this.rootEntityClass = rootEntityClass;
+
+		EntityConfig<?> entityConfig = modelManager.getEntityConfig(new Key<>(entityClass));
+		EntityType source = entityConfig.getEntityType();
+
+		entityConfig.getOptionalConfigs().stream().map(EntityConfig::getEntityType)
+				.filter(et -> !"Classification".equals(et.getName())).forEach(entityType -> {
+					joinTree.addNode(source, entityType, true, JoinType.OUTER);
+				});
+
+		entityConfig.getMandatoryConfigs().stream().map(EntityConfig::getEntityType).forEach(entityType -> {
+			joinTree.addNode(source, entityType, true, JoinType.INNER);
+		});
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final List<EntityType> listEntityTypes() {
+		return joinTree.getNodeNames().stream().map(modelManager::getEntityType).collect(Collectors.toList());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final Searchable getSearchableRoot() {
+		Function<String, SearchableNode> factory = k -> {
+			return new SearchableNode(modelManager.getEntityType(k));
+		};
+
+		Map<String, SearchableNode> nodes = new HashMap<>();
+		for (Entry<String, List<String>> entry : joinTree.getTree().entrySet()) {
+			SearchableNode parent = nodes.computeIfAbsent(entry.getKey(), factory);
+
+			for (String childName : entry.getValue()) {
+				parent.addRelated(nodes.computeIfAbsent(childName, factory));
+			}
+		}
+
+		return nodes.get(modelManager.getEntityType(rootEntityClass).getName());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final List<Value> getFilterValues(Attribute attribute, Filter filter) throws DataAccessException {
+		Query query = queryService.createQuery().select(attribute, Aggregation.DISTINCT).group(attribute);
+
+		// add required joins
+		filter.stream().filter(FilterItem::isCondition).map(FilterItem::getCondition).forEach(c -> {
+			addJoins(query, c.getAttribute().getEntityType());
+		});
+
+		return query.fetch(filter).stream().map(r -> r.getValue(attribute)).collect(Collectors.toList());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final List<Result> fetchComplete(List<EntityType> entityTypes, Filter filter) throws DataAccessException {
+		Query query = queryService.createQuery().selectID(modelManager.getEntityType(entityClass));
+
+		// add required joins
+		entityTypes.stream().forEach(entityType -> {
+			addJoins(query, entityType);
+			query.selectAll(entityType);
+		});
+
+		return fetch(query, filter);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final List<Result> fetch(List<Attribute> attributes, Filter filter) throws DataAccessException {
+		Query query = queryService.createQuery().selectID(modelManager.getEntityType(entityClass));
+
+		// add required joins
+		attributes.stream().forEach(attribute -> {
+			addJoins(query, attribute.getEntityType());
+			query.select(attribute);
+		});
+
+		return fetch(query, filter);
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@link JoinConfig} to the internally managed {@link JoinTree}.
+	 *
+	 * @param joinConfig Will be added.
+	 */
+	protected final void addJoinConfig(JoinConfig joinConfig) {
+		EntityConfig<?> targetEntityConfig = modelManager.getEntityConfig(new Key<>(joinConfig.target));
+		EntityType target = targetEntityConfig.getEntityType();
+
+		// add dependency source to target
+		joinTree.addNode(modelManager.getEntityType(joinConfig.source), target, joinConfig.viaParent, JoinType.INNER);
+
+		// add target's optional dependencies
+		targetEntityConfig.getOptionalConfigs().stream().map(EntityConfig::getEntityType)
+				.filter(et -> !"Classification".equals(et.getName())).forEach(entityType -> {
+					joinTree.addNode(target, entityType, true, JoinType.OUTER);
+				});
+
+		// add target's mandatory dependencies
+		targetEntityConfig.getMandatoryConfigs().stream().map(EntityConfig::getEntityType).forEach(entityType -> {
+			joinTree.addNode(target, entityType, true, JoinType.INNER);
+		});
+	}
+
+	/**
+	 * Adds joins to context data according to the given {@link ContextState}.
+	 *
+	 * @param contextState The {@code ContextState}.
+	 */
+	protected final void addJoinConfig(ContextState contextState) {
+		if (contextState == null) {
+			// nothing to do
+			return;
+		}
+
+		Class<? extends Entity> source = contextState.isOrdered() ? TestStep.class : Measurement.class;
+		for (ContextType contextType : ContextType.values()) {
+			EntityType rootEntityType = modelManager.getEntityType(ContextRoot.class, contextType);
+			for (Relation componentRelation : rootEntityType.getChildRelations()) {
+				joinTree.addNode(componentRelation.getSource(), componentRelation.getTarget(), true, JoinType.OUTER);
+
+				for (Relation sensorRelation : componentRelation.getTarget().getChildRelations()) {
+					joinTree.addNode(sensorRelation.getSource(), sensorRelation.getTarget(), true, JoinType.OUTER);
+				}
+			}
+
+			joinTree.addNode(modelManager.getEntityType(source), rootEntityType, true, JoinType.OUTER);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Executes given {@link Query} using given {@link Filter}. Joins required for
+	 * the given {@code Filter} will be implicitly added as needed.
+	 *
+	 * @param query  Will be executed.
+	 * @param filter The query filtering sequence.
+	 * @return Returns the {@link Result}s in a {@code List}.
+	 * @throws DataAccessException Thrown if failed to execute given {@code Query}.
+	 */
+	private List<Result> fetch(Query query, Filter filter) throws DataAccessException {
+		filter.stream().filter(FilterItem::isCondition).map(FilterItem::getCondition)
+				.forEach(c -> addJoins(query, c.getAttribute().getEntityType()));
+
+		EntityType entityType = modelManager.getEntityType(entityClass);
+		return query.order(entityType.getIDAttribute()).fetch(filter).stream()
+				// group by instance ID and merge grouped results
+				.collect(groupingBy(r -> r.getRecord(entityType).getID(), reducing(Result::merge)))
+				// collect merged results
+				.values().stream().filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
+	}
+
+	/**
+	 * Adds join statements to given target {@link EntityType} as needed to be able
+	 * to execute given {@code Query}.
+	 *
+	 * @param query      The {@link Query}.
+	 * @param entityType The target {@link EntityType}.
+	 */
+	private void addJoins(Query query, EntityType entityType) {
+		if (query.isQueried(entityType)) {
+			return;
+		}
+
+		JoinNode joinNode = joinTree.getJoinNode(entityType.getName());
+		EntityType sourceEntityType = modelManager.getEntityType(joinNode.source);
+		addJoins(query, sourceEntityType);
+		query.join(sourceEntityType.getRelation(entityType), joinNode.joinType);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelGroupSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelGroupSearchQuery.java
new file mode 100644
index 0000000..fbd9edf
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelGroupSearchQuery.java
@@ -0,0 +1,60 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * {@link SearchQuery} implementation for {@link ChannelGroup} as source entity
+ * type.
+ *
+ * @since 1.0.0
+ * @author
+ */
+final class ChannelGroupSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	ChannelGroupSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, ChannelGroup.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+		addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+		addJoinConfig(JoinConfig.up(TestStep.class, Test.class));
+		addJoinConfig(JoinConfig.up(Measurement.class, TestStep.class));
+		addJoinConfig(JoinConfig.up(ChannelGroup.class, Measurement.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+
+		// context
+		addJoinConfig(contextState);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelSearchQuery.java
new file mode 100644
index 0000000..27facac
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ChannelSearchQuery.java
@@ -0,0 +1,63 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * {@link SearchQuery} implementation for {@link Channel} as source entity type.
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+final class ChannelSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	ChannelSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Channel.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+		addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+		addJoinConfig(JoinConfig.up(TestStep.class, Test.class));
+		addJoinConfig(JoinConfig.up(Measurement.class, TestStep.class));
+		addJoinConfig(JoinConfig.up(Channel.class, Measurement.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+
+		// context
+		addJoinConfig(contextState);
+
+		// TODO join to sensor tables.... || this will break the joins to
+		// context data
+		// multiple outer join to the same table...
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ContextState.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ContextState.java
new file mode 100644
index 0000000..d68dbe9
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ContextState.java
@@ -0,0 +1,65 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.TestStep;
+
+/**
+ * Context state enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+enum ContextState {
+
+	// ======================================================================
+	// Enum constants
+	// ======================================================================
+
+	/**
+	 * References {@link ContextRoot}s of {@link TestStep}s.
+	 */
+	ORDERED,
+
+	/**
+	 * References {@link ContextRoot}s of {@link Measurement}s.
+	 */
+	MEASURED;
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Checks whether this context state is {@link #ORDERED}.
+	 *
+	 * @return Returns {@code true} if this instance is {@link #ORDERED}.
+	 */
+	public boolean isOrdered() {
+		return ORDERED == this;
+	}
+
+	/**
+	 * Checks whether this context state is {@link #MEASURED}.
+	 *
+	 * @return Returns {@code true} if this instance is {@link #MEASURED}.
+	 */
+	public boolean isMeasured() {
+		return MEASURED == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/JoinTree.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/JoinTree.java
new file mode 100644
index 0000000..e12b6f9
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/JoinTree.java
@@ -0,0 +1,212 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+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.Set;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.JoinType;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+
+/**
+ * This class spans a dependency tree for conditional join statements is
+ * {@link SearchQuery}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class JoinTree {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<String, List<String>> tree = new HashMap<>();
+	private final Map<String, JoinNode> joinNodes = new HashMap<>();
+	private final Set<String> nodeNames = new HashSet<>();
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the tree configuration. It mapps a source entity type names to
+	 * supported target entity type names.
+	 *
+	 * @return The returned {@code Map} is unmodifiable.
+	 */
+	public Map<String, List<String>> getTree() {
+		return Collections.unmodifiableMap(tree);
+	}
+
+	/**
+	 * Returns a {@code List} with distinct entity type names covered by this join
+	 * tree.
+	 *
+	 * @return Returned {@code List} is unmodifiable.
+	 */
+	public Set<String> getNodeNames() {
+		return Collections.unmodifiableSet(nodeNames);
+	}
+
+	/**
+	 * Returns the {@link JoinNode} for given target entity type name.
+	 *
+	 * @param target The target entity type name.
+	 * @return The {@code JoinNode} for given target entity type name is returned.
+	 * @throws IllegalArgumentException Thrown if no such {@code JoinNode} exists.
+	 */
+	public JoinNode getJoinNode(String target) {
+		JoinNode joinNode = joinNodes.get(target);
+		if (joinNode == null) {
+			throw new IllegalArgumentException("Relation to '" + target + "' not possible.");
+		}
+
+		return joinNode;
+	}
+
+	/**
+	 * Adds given dependency setup to this join tree.
+	 *
+	 * @param source    The source entity type name.
+	 * @param target    The target entity type name.
+	 * @param viaParent If true, then source is the considered parent of the target.
+	 * @param joinType  Either inner or outer joinType.
+	 * @throws IllegalArgumentException Thrown if given setup overrides an existing
+	 *                                  one (a target entity type is allowed to be
+	 *                                  joined only once).
+	 */
+	public void addNode(EntityType source, EntityType target, boolean viaParent, JoinType joinType) {
+		String sourceName = source.getName();
+		String targetName = target.getName();
+
+		if (joinNodes.put(targetName, new JoinNode(sourceName, targetName, joinType)) != null) {
+			throw new IllegalArgumentException("It is not allowed to override join nodes.");
+		}
+
+		if (viaParent) {
+			tree.computeIfAbsent(sourceName, k -> new ArrayList<>()).add(targetName);
+		} else {
+			tree.computeIfAbsent(targetName, k -> new ArrayList<>()).add(sourceName);
+		}
+
+		nodeNames.add(sourceName);
+		nodeNames.add(targetName);
+	}
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * A simple joinType node setup.
+	 */
+	static final class JoinNode {
+
+		// ======================================================================
+		// Instance variables
+		// ======================================================================
+
+		final String source;
+		final String target;
+		final JoinType joinType;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param source   The source entity type name.
+		 * @param target   The target entity type name.
+		 * @param joinType Either inner or outer {@link JoinType}.
+		 */
+		private JoinNode(String source, String target, JoinType joinType) {
+			this.source = source;
+			this.target = target;
+			this.joinType = joinType;
+		}
+
+	}
+
+	/**
+	 * A simple joinType configuration setup.
+	 */
+	static final class JoinConfig {
+
+		// ======================================================================
+		// Instance variables
+		// ======================================================================
+
+		final Class<? extends Entity> source;
+		final Class<? extends Entity> target;
+		final boolean viaParent;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param source    The source entity type name.
+		 * @param target    The target entity type name.
+		 * @param viaParent If true, then source is the considered parent of the target.
+		 */
+		private JoinConfig(Class<? extends Entity> source, Class<? extends Entity> target, boolean viaParent) {
+			this.source = source;
+			this.target = target;
+			this.viaParent = viaParent;
+		}
+
+		// ======================================================================
+		// Package methods
+		// ======================================================================
+
+		/**
+		 * Creates a new {@link JoinConfig} where given source is considered as the
+		 * child of given target.
+		 *
+		 * @param source The source entity type name.
+		 * @param target The target entity type name.
+		 * @return The created {@code JoinConfig} is returned.
+		 */
+		static JoinConfig up(Class<? extends Entity> source, Class<? extends Entity> target) {
+			return new JoinConfig(source, target, false);
+		}
+
+		/**
+		 * Creates a new {@link JoinConfig} where given source is considered as the
+		 * parent of given target.
+		 *
+		 * @param source The source entity type name.
+		 * @param target The target entity type name.
+		 * @return The created {@code JoinConfig} is returned.
+		 */
+		static JoinConfig down(Class<? extends Entity> source, Class<? extends Entity> target) {
+			return new JoinConfig(source, target, true);
+		}
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/MeasurementSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/MeasurementSearchQuery.java
new file mode 100644
index 0000000..cb162e5
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/MeasurementSearchQuery.java
@@ -0,0 +1,60 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * {@link SearchQuery} implementation for {@link Measurement} as source entity
+ * type.
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+final class MeasurementSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	MeasurementSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Measurement.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+		addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+		addJoinConfig(JoinConfig.up(TestStep.class, Test.class));
+		addJoinConfig(JoinConfig.up(Measurement.class, TestStep.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+
+		// context
+		addJoinConfig(contextState);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/MergedSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/MergedSearchQuery.java
new file mode 100644
index 0000000..1505c50
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/MergedSearchQuery.java
@@ -0,0 +1,135 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.reducing;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.Searchable;
+
+/**
+ * Merges 2 distinct search queries, where one queries context data as ordered
+ * and the other context as measured.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class MergedSearchQuery implements SearchQuery {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final EntityType entityType;
+
+	private final BaseEntitySearchQuery byResult;
+	private final BaseEntitySearchQuery byOrder;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	MergedSearchQuery(EntityType entityType, Function<ContextState, BaseEntitySearchQuery> factory) {
+		this.entityType = entityType;
+
+		byResult = factory.apply(ContextState.MEASURED);
+		byOrder = factory.apply(ContextState.ORDERED);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<EntityType> listEntityTypes() {
+		return byOrder.listEntityTypes();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Searchable getSearchableRoot() {
+		return byOrder.getSearchableRoot();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Value> getFilterValues(Attribute attribute, Filter filter) throws DataAccessException {
+		List<Value> orderValues = byOrder.getFilterValues(attribute, filter);
+		List<Value> resultValues = byResult.getFilterValues(attribute, filter);
+
+		return Stream.concat(orderValues.stream(), resultValues.stream())
+				// group by value and merge values
+				.collect(groupingBy(v -> v.extract(), reducing((v1, v2) -> v1)))
+				// collect merged results
+				.values().stream().filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Result> fetchComplete(List<EntityType> entityTypes, Filter filter) throws DataAccessException {
+		return mergeResults(byOrder.fetchComplete(entityTypes, filter), byResult.fetchComplete(entityTypes, filter));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Result> fetch(List<Attribute> attributes, Filter filter) throws DataAccessException {
+		return mergeResults(byOrder.fetch(attributes, filter), byResult.fetch(attributes, filter));
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Merges given {@link Result}s to one using the root entity type of this search
+	 * query.
+	 *
+	 * @param results1 The first {@code Result}.
+	 * @param results2 The second {@code Result}.
+	 * @return The merged {@link Result} is returned.
+	 */
+	private List<Result> mergeResults(List<Result> results1, List<Result> results2) {
+		return Stream.concat(results1.stream(), results2.stream())
+				// group by instance ID and merge grouped results
+				.collect(groupingBy(r -> r.getRecord(entityType).getID(), reducing(Result::merge)))
+				// collect merged results
+				.values().stream().filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearch.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearch.java
new file mode 100644
index 0000000..6a15f28
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearch.java
@@ -0,0 +1,287 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.text.StringEscapeUtils;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+/**
+ * This class handles the requests which are sent to the FreeTextSearch
+ * 
+ * @author Christian Weyermann
+ *
+ */
+public class ODSFreeTextSearch {
+
+	/**
+	 * This is the payload which needs to be added to the post to add a
+	 */
+	private static final String ES_POSTDATA = "{\"_source\": [\"source\", \"type\", \"id\"], \"query\":{\"simple_query_string\":{\"query\":\"%s\",\"default_operator\":\"or\",\"lenient\":\"true\"}}}";
+
+	/**
+	 * mainly logs requests on INFO
+	 */
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSFreeTextSearch.class);
+
+	/**
+	 * Used to finally load the Entites
+	 */
+	private EntityLoader loader;
+
+	/**
+	 * The URL is hard coded
+	 */
+	private URI url;
+
+	/**
+	 * The client is created once and reused
+	 */
+	private HttpClient client;
+
+	/**
+	 * This will start up the FreeText Search. No upfron querries are done. Thus
+	 * this can be called as often as desired without any major performance loss
+	 * 
+	 * @param entityLoader
+	 * @param sourceName
+	 * @throws DataAccessException
+	 */
+	public ODSFreeTextSearch(EntityLoader entityLoader, String sourceName, String host) throws DataAccessException {
+		this.loader = entityLoader;
+
+		url = URI.create(host).resolve(sourceName.toLowerCase()).resolve("/_search");
+
+		client = new HttpClient();
+	}
+
+	/**
+	 * A search which is compatible to the Search as defined in the rest of the API.
+	 * 
+	 * @param inputQuery
+	 * @return never null, but maybe empty
+	 */
+	public Map<Class<? extends Entity>, List<Entity>> search(String inputQuery) {
+		Map<Class<? extends Entity>, List<Entity>> result = new HashMap<>();
+
+		Map<Class<? extends Entity>, List<String>> instances = searchIds(inputQuery);
+		instances.keySet().forEach(type -> convertIds2Entities(result, instances, type));
+		return result;
+	}
+
+	/**
+	 * A search which is compatible to the Search as defined in the rest of the API.
+	 * 
+	 * @param inputQuery
+	 * @return never null, but maybe empty
+	 */
+	public Map<Class<? extends Entity>, List<String>> searchIds(String inputQuery) {
+		Map<Class<? extends Entity>, List<String>> instanceIds = new HashMap<>();
+
+		JsonElement root = queryElasticSearch(inputQuery);
+		if (root != null) {
+			JsonArray hits = root.getAsJsonObject().get("hits").getAsJsonObject().get("hits").getAsJsonArray();
+
+			hits.forEach(e -> put(e, instanceIds));
+
+		}
+		return instanceIds;
+	}
+
+	/**
+	 * Converts all instances to entities
+	 * 
+	 * @param convertedMap it will
+	 * @param map
+	 * @param type
+	 */
+	private void convertIds2Entities(Map<Class<? extends Entity>, List<Entity>> convertedMap,
+			Map<Class<? extends Entity>, List<String>> map, Class<? extends Entity> type) {
+		try {
+			List<Entity> list = new ArrayList<>();
+			list.addAll(loader.loadAll(new Key<>(type), map.get(type)));
+
+			convertedMap.put(type, list);
+		} catch (DataAccessException e) {
+			throw new IllegalStateException("Cannot load ids from ODS. This means no results are available", e);
+		}
+
+	}
+
+	/**
+	 * Puts all the hits in elasticsearch
+	 * 
+	 * @param hit a hit as given from ElasticSearch
+	 * @param map the map of all ids for the class of the entity
+	 */
+	private void put(JsonElement hit, Map<Class<? extends Entity>, List<String>> map) {
+		JsonObject object = hit.getAsJsonObject().get("_source").getAsJsonObject();
+
+		String type = object.get("type").getAsString();
+		Class<? extends Entity> clazz = getClass4Type(type);
+
+		if (clazz != null) {
+			if (!map.containsKey(clazz)) {
+				List<String> list = new ArrayList<>();
+				map.put(clazz, list);
+			}
+
+			List<String> list = map.get(clazz);
+			list.add((String) object.get("id").getAsString());
+		}
+	}
+
+	/**
+	 * 
+	 * @param type the type as given by elasticsearch
+	 * @return the class of each element
+	 */
+	private Class<? extends Entity> getClass4Type(String type) {
+		Class<? extends Entity> clazz;
+		switch (type) {
+		case "Project":
+			clazz = Project.class;
+			break;
+		case "Pool":
+			clazz = Pool.class;
+			break;
+		case "Test":
+			clazz = Test.class;
+			break;
+		case "TestStep":
+			clazz = TestStep.class;
+			break;
+		case "Measurement":
+			clazz = Measurement.class;
+			break;
+
+		default:
+			clazz = null;
+		}
+		return clazz;
+	}
+
+	/**
+	 * This method actually querries ElasticSearch.
+	 * 
+	 * @param inputQuery
+	 * @return
+	 */
+	private JsonElement queryElasticSearch(String inputQuery) {
+		PostMethod post = new PostMethod(url.toString());
+
+		String requestJson = buildRequestJson(inputQuery);
+
+		LOGGER.info("POST: " + url);
+		LOGGER.info("Asking: " + requestJson);
+		byte[] json = requestJson.getBytes();
+		post.setRequestEntity(new ByteArrayRequestEntity(json, "application/json"));
+
+		JsonElement result = execute(post);
+		LOGGER.info("Answered:" + result);
+
+		return result;
+	}
+
+	/**
+	 * Actually builds the json
+	 * 
+	 * @param inputQuery
+	 * @return
+	 */
+	private String buildRequestJson(String inputQuery) {
+		String query = StringEscapeUtils.escapeJson(inputQuery);
+		return String.format(ES_POSTDATA, query);
+	}
+
+	/**
+	 * Executes the HTTP method and expects a json in the return payload, which is
+	 * then returned
+	 * 
+	 * @param method
+	 * @return
+	 */
+	private JsonElement execute(HttpMethod method) {
+		try {
+			int status = client.executeMethod(method);
+			if (status == 404) {
+				return null;
+			}
+
+			checkError(status);
+			return buildResponseJson(method);
+		} catch (IOException e) {
+			throw new IllegalStateException("Problems querying ElasticSearch.", e);
+		}
+	}
+
+	/**
+	 * Reads out the http method and builds the JSON via GSON
+	 * 
+	 * @param method
+	 * @return
+	 * @throws IOException
+	 */
+	private JsonElement buildResponseJson(HttpMethod method) throws IOException {
+		JsonElement res = null;
+
+		InputStream in = method.getResponseBodyAsStream();
+		try (InputStreamReader reader = new InputStreamReader(in)) {
+			res = new JsonParser().parse(reader);
+		}
+
+		return res;
+	}
+
+	/**
+	 * If an error occured an appropriate exception is thrown.
+	 * 
+	 * @param status
+	 */
+	private void checkError(int status) {
+		String text = String.format("ElasticSearch answered %d. ", status);
+
+		if (status / 100 != 2) {
+			throw new IllegalStateException(text);
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchService.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchService.java
new file mode 100644
index 0000000..64edfea
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchService.java
@@ -0,0 +1,319 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Environment;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.base.search.Searchable;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
+import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+/**
+ * ODS implementation of the {@link SearchService} interface.
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+public class ODSSearchService implements SearchService {
+
+	private final Map<Class<? extends Entity>, SearchQuery> searchQueries = new HashMap<>();
+
+	private final ODSContext context;
+	private final EntityLoader entityLoader;
+	private final String esHost;
+	private ODSFreeTextSearch freeTextSearch;
+
+	public static final String PARAM_ELASTIC_SEARCH_URL = "elasticsearch.url";
+
+	/**
+	 * Constructor.
+	 *
+	 * @param context      Used to retrieve {@link ODSModelManager}.
+	 * @param entityLoader Used to load complete {@link Entity}s.
+	 */
+	public ODSSearchService(ODSContext context, QueryService queryService, EntityLoader entityLoader) {
+		this.context = context;
+		this.entityLoader = entityLoader;
+		esHost = context.getParameters().get(PARAM_ELASTIC_SEARCH_URL);
+
+		registerMergedSearchQuery(Project.class,
+				c -> new ProjectSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Pool.class, c -> new PoolSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Test.class, c -> new TestSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(TestStep.class,
+				c -> new TestStepSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Measurement.class,
+				c -> new MeasurementSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(ChannelGroup.class,
+				c -> new ChannelGroupSearchQuery(context.getODSModelManager(), queryService, c));
+		registerMergedSearchQuery(Channel.class,
+				c -> new ChannelSearchQuery(context.getODSModelManager(), queryService, c));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Class<? extends Entity>> listSearchableTypes() {
+		return new ArrayList<>(searchQueries.keySet());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<EntityType> listEntityTypes(Class<? extends Entity> entityClass) {
+		return findSearchQuery(entityClass).listEntityTypes();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Searchable getSearchableRoot(Class<? extends Entity> entityClass) {
+		return findSearchQuery(entityClass).getSearchableRoot();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Value> getFilterValues(Class<? extends Entity> entityClass, Attribute attribute, Filter filter)
+			throws DataAccessException {
+		return findSearchQuery(entityClass).getFilterValues(attribute, filter);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> List<T> fetchComplete(Class<T> entityClass, List<EntityType> entityTypes, Filter filter)
+			throws DataAccessException {
+		return createResult(entityClass, findSearchQuery(entityClass).fetchComplete(entityTypes, filter));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public <T extends Entity> List<T> fetch(Class<T> entityClass, List<Attribute> attributes, Filter filter)
+			throws DataAccessException {
+		return createResult(entityClass, findSearchQuery(entityClass).fetch(attributes, filter));
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Result> fetchResults(Class<? extends Entity> entityClass, List<Attribute> attributes, Filter filter,
+			String query) throws DataAccessException {
+		Filter mergedFilter = getMergedFilter(filter, query);
+		if (mergedFilter.isEmtpty()) {
+			return Collections.emptyList();
+		}
+
+		EntityType entityType = context.getODSModelManager().getEntityType(entityClass);
+		Map<String, Result> recordsByEntityID = new HashMap<>();
+		for (Result result : findSearchQuery(entityClass).fetch(attributes, mergedFilter)) {
+			recordsByEntityID.put(result.getRecord(entityType).getID(), result);
+		}
+
+		return new ArrayList<>(recordsByEntityID.values());
+	}
+
+	@Override
+	public Map<Class<? extends Entity>, List<Entity>> fetch(String query) throws DataAccessException {
+		if (freeTextSearch == null) {
+			initFreetextSearch();
+		}
+
+		return freeTextSearch.search(query);
+	}
+
+	@Override
+	public boolean isTextSearchAvailable() {
+		return true;
+	}
+
+	/**
+	 * Returns a filter merged from an existing filter and a filter resulting from a
+	 * freetext search result.
+	 * 
+	 * @param filter first filter to merge
+	 * @param query  freetext query, which returns the ids to generate the second
+	 *               filter to merge
+	 * @return conjunction of the first and second filter
+	 * @throws DataAccessException Thrown if {@link ODSFreeTextSearch} is
+	 *                             unavailable or cannot execute the query.
+	 */
+	protected Filter getMergedFilter(Filter filter, String query) throws DataAccessException {
+		Preconditions.checkNotNull(filter, "Filter cannot be null!");
+
+		Filter freetextIdsFilter = getFilterForFreetextQuery(query);
+		// If freetext search query is provided but yields no results, return empty
+		// filter for compatibility with previous behaviour:
+		if (null == freetextIdsFilter) {
+			return Filter.or();
+		} else if (filter.isEmtpty()) {
+			return freetextIdsFilter;
+		} else if (Strings.isNullOrEmpty(query) && freetextIdsFilter.isEmtpty()) {
+			return filter;
+		} else {
+			return Filter.and().merge(filter, freetextIdsFilter);
+		}
+	}
+
+	/**
+	 * Executes a free text search and returns the IDs of the matching entities.
+	 * 
+	 * @param query search query
+	 * @return found entity IDs grouped by entity.
+	 * @throws DataAccessException Thrown if {@link ODSFreeTextSearch} is
+	 *                             unavailable or cannot execute the query.
+	 */
+	protected Map<Class<? extends Entity>, List<String>> fetchIds(String query) throws DataAccessException {
+		if (Strings.isNullOrEmpty(query)) {
+			return Collections.emptyMap();
+		}
+
+		if (freeTextSearch == null) {
+			initFreetextSearch();
+		}
+
+		return freeTextSearch.searchIds(query);
+	}
+
+	/**
+	 * Delegates to {@link ODSFreeTextSearch} to retrieve a map of all entity IDs
+	 * found by the given query. With the results a filter is generated, which can
+	 * be used to query the entity instances of result of the free text query.
+	 * 
+	 * @param query fulltext search query
+	 * @return A map with the found entity IDs grouped by {@link Entity} class or
+	 *         null if a query was provided but yielded no results.
+	 * @throws DataAccessException Thrown if {@link ODSFreeTextSearch} is
+	 *                             unavailable or cannot execute the query.
+	 */
+	protected Filter getFilterForFreetextQuery(String query) throws DataAccessException {
+
+		if (Strings.isNullOrEmpty(query)) {
+			// No query provided => return empty filter for merging with other filters:
+			return Filter.or();
+		}
+
+		Filter freeTextResultsFilter = null;
+		for (Map.Entry<Class<? extends Entity>, List<String>> entry : fetchIds(query).entrySet()) {
+			if (!entry.getValue().isEmpty()) {
+				if (null == freeTextResultsFilter) {
+					freeTextResultsFilter = Filter.or();
+				}
+
+				freeTextResultsFilter.ids(context.getODSModelManager().getEntityType(entry.getKey()), entry.getValue());
+			}
+		}
+
+		return freeTextResultsFilter; // null if query yielded no results
+	}
+
+	/**
+	 * Loads {@link Entity}s of given entity class for given {@link Result}s.
+	 *
+	 * @param <T>         The entity type.
+	 * @param entityClass Entity class of the loaded {@code Entity}s.
+	 * @param results     The queried {@code Result}s.
+	 * @return All loaded entities are returned as a {@link List}.
+	 * @throws DataAccessException Thrown if unable to load the {@code Entity}s.
+	 */
+	private <T extends Entity> List<T> createResult(Class<T> entityClass, List<Result> results)
+			throws DataAccessException {
+		EntityType entityType = context.getODSModelManager().getEntityType(entityClass);
+		Map<String, Result> recordsByEntityID = new HashMap<>();
+		for (Result result : results) {
+			recordsByEntityID.put(result.getRecord(entityType).getID(), result);
+		}
+
+		Map<T, Result> resultsByEntity = new HashMap<>();
+		for (T entity : entityLoader.loadAll(new Key<>(entityClass), recordsByEntityID.keySet())) {
+			resultsByEntity.put(entity, recordsByEntityID.get(entity.getID()));
+		}
+
+		return new ArrayList<>(resultsByEntity.keySet());
+	}
+
+	/**
+	 * Returns the {@link SearchQuery} for given entity class.
+	 *
+	 * @param entityClass Used as identifier.
+	 * @return The {@link SearchQuery}
+	 */
+	private SearchQuery findSearchQuery(Class<? extends Entity> entityClass) {
+		SearchQuery searchQuery = searchQueries.get(entityClass);
+		if (searchQuery == null) {
+			throw new IllegalArgumentException(
+					"Search query for type '" + entityClass.getSimpleName() + "' not found.");
+		}
+
+		return searchQuery;
+	}
+
+	/**
+	 * Registers a {@link SearchQuery} for given entity class.
+	 *
+	 * @param entityClass The entity class produced by using this query.
+	 * @param factory     The {@code SearchQuery} factory.
+	 */
+	private void registerMergedSearchQuery(Class<? extends Entity> entityClass,
+			Function<ContextState, BaseEntitySearchQuery> factory) {
+		searchQueries.put(entityClass,
+				new MergedSearchQuery(context.getODSModelManager().getEntityType(entityClass), factory));
+	}
+
+	private void initFreetextSearch() throws DataAccessException {
+		List<Environment> all = entityLoader.loadAll(new Key<>(Environment.class), "*");
+		if (all.isEmpty()) {
+			throw new DataAccessException("No environment loaded. So the Search does not know where to search");
+		}
+		String sourceName = all.get(0).getSourceName();
+		freeTextSearch = new ODSFreeTextSearch(entityLoader, sourceName, esHost);
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/PoolSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/PoolSearchQuery.java
new file mode 100644
index 0000000..b8a8d03
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/PoolSearchQuery.java
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * {@link SearchQuery} implementation for {@link Pool} as source entity type.
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+final class PoolSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	PoolSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Pool.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+		addJoinConfig(JoinConfig.down(Pool.class, Test.class));
+		addJoinConfig(JoinConfig.down(Test.class, TestStep.class));
+		addJoinConfig(JoinConfig.down(TestStep.class, Measurement.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+
+		// context
+		addJoinConfig(contextState);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ProjectSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ProjectSearchQuery.java
new file mode 100644
index 0000000..e5b79d1
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/ProjectSearchQuery.java
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * {@link SearchQuery} implementation for {@link Project} as source entity type.
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+final class ProjectSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	ProjectSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Project.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.down(Project.class, Pool.class));
+		addJoinConfig(JoinConfig.down(Pool.class, Test.class));
+		addJoinConfig(JoinConfig.down(Test.class, TestStep.class));
+		addJoinConfig(JoinConfig.down(TestStep.class, Measurement.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+
+		// context
+		addJoinConfig(contextState);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/SearchableNode.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/SearchableNode.java
new file mode 100644
index 0000000..6c8b452
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/SearchableNode.java
@@ -0,0 +1,102 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.search.Searchable;
+
+/**
+ * Implementation of the {@link Searchable} interface for use in search queries
+ * derived from {@link BaseEntitySearchQuery}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class SearchableNode implements Searchable {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final List<Searchable> relatedSearchables = new ArrayList<>();
+	private final EntityType entityType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param entityType The associated {@link EntityType}.
+	 */
+	SearchableNode(EntityType entityType) {
+		this.entityType = entityType;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<Searchable> getRelatedSearchables() {
+		return Collections.unmodifiableList(relatedSearchables);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityType getEntityType() {
+		return entityType;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("Searchable(").append("EntityType = ").append(entityType);
+
+		if (!isLeaf()) {
+			sb.append(", relatedSearchables = ")
+					.append(relatedSearchables.stream().map(Searchable::getEntityType).collect(Collectors.toList()));
+		}
+
+		return sb.append(')').toString();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@link Searchable} as a child to this searchable.
+	 *
+	 * @param searchable Will be added a child.
+	 */
+	void addRelated(Searchable searchable) {
+		relatedSearchables.add(searchable);
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestSearchQuery.java
new file mode 100644
index 0000000..fbc2feb
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestSearchQuery.java
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * {@link SearchQuery} implementation for {@link Test} as source entity type.
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+final class TestSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	TestSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, Test.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+		addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+		addJoinConfig(JoinConfig.down(Test.class, TestStep.class));
+		addJoinConfig(JoinConfig.down(TestStep.class, Measurement.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+
+		// context
+		addJoinConfig(contextState);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestStepSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestStepSearchQuery.java
new file mode 100644
index 0000000..0f632d9
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/search/TestStepSearchQuery.java
@@ -0,0 +1,60 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * {@link SearchQuery} implementation for {@link TestStep} as source entity
+ * type.
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+final class TestStepSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	TestStepSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+		super(modelManager, queryService, TestStep.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+		addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+		addJoinConfig(JoinConfig.up(TestStep.class, Test.class));
+		addJoinConfig(JoinConfig.down(TestStep.class, Measurement.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+
+		// context
+		addJoinConfig(contextState);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/BaseStatement.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/BaseStatement.java
new file mode 100644
index 0000000..3d9326a
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/BaseStatement.java
@@ -0,0 +1,125 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.asam.ods.AoException;
+import org.asam.ods.ApplElemAccess;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+
+/**
+ * A base implementation for execution statements (CREATE, UPDATE, DELETE).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+abstract class BaseStatement {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ODSTransaction transaction;
+	private final ODSEntityType entityType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param transaction The owning {@link ODSTransaction}.
+	 * @param entityType  The associated {@link EntityType}.
+	 */
+	protected BaseStatement(ODSTransaction transaction, EntityType entityType) {
+		this.transaction = transaction;
+		this.entityType = (ODSEntityType) entityType;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Executes this statement for given {@link Entity}s.
+	 *
+	 * @param entities The processed {@code Entity}s.
+	 * @throws AoException         Thrown if the execution fails.
+	 * @throws DataAccessException Thrown if the execution fails.
+	 * @throws IOException         Thrown if a file transfer operation fails.
+	 */
+	public abstract void execute(Collection<Entity> entities) throws AoException, DataAccessException, IOException;
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ODSTransaction}.
+	 *
+	 * @return The {@code ODSTransaction} is returned.
+	 */
+	protected ODSTransaction getTransaction() {
+		return transaction;
+	}
+
+	/**
+	 * Returns the {@link ODSModelManager}.
+	 *
+	 * @return The {@code ODSModelManager} is returned.
+	 */
+	protected ODSModelManager getModelManager() {
+		return transaction.getModelManager();
+	}
+
+	/**
+	 * Returns the {@link QueryService}.
+	 *
+	 * @return The {@code QueryService} is returned.
+	 */
+	protected QueryService getQueryService() {
+		return transaction.getContext().getQueryService()
+				.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+	}
+
+	/**
+	 * Returns the {@link ApplElemAccess}.
+	 *
+	 * @return The {@code ApplElemAccess} is returned.
+	 * @throws AoException Thrown in case of errors.
+	 */
+	protected ApplElemAccess getApplElemAccess() throws AoException {
+		return transaction.getContext().getODSModelManager().getApplElemAccess();
+	}
+
+	/**
+	 * Returns the associated {@link EntityType}.
+	 *
+	 * @return The associated {@code EntityType} is returned.
+	 */
+	protected ODSEntityType getEntityType() {
+		return entityType;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/CatalogManager.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/CatalogManager.java
new file mode 100644
index 0000000..8421b6a
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/CatalogManager.java
@@ -0,0 +1,565 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.asam.ods.AoException;
+import org.asam.ods.ApplicationAttribute;
+import org.asam.ods.ApplicationElement;
+import org.asam.ods.ApplicationRelation;
+import org.asam.ods.ApplicationStructure;
+import org.asam.ods.BaseAttribute;
+import org.asam.ods.BaseElement;
+import org.asam.ods.BaseStructure;
+import org.asam.ods.DataType;
+import org.asam.ods.RelationRange;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
+import org.eclipse.mdm.api.dflt.model.CatalogComponent;
+import org.eclipse.mdm.api.dflt.model.CatalogSensor;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.eclipse.mdm.api.odsadapter.utils.ODSEnumerations;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+
+/**
+ * Used to create, update or delete {@link CatalogComponent},
+ * {@link CatalogSensor} and {@link CatalogAttribute} entities. Modifications of
+ * the listed types results in modifications of the application model.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class CatalogManager {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ODSTransaction transaction;
+
+	private ApplicationStructure applicationStructure;
+	private BaseStructure baseStructure;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param transaction The {@link ODSTransaction}.
+	 */
+	CatalogManager(ODSTransaction transaction) {
+		this.transaction = transaction;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates for each given {@link CatalogComponent} a corresponding application
+	 * element including all required application relations.
+	 *
+	 * @param catalogComponents The {@code CatalogComponent}s.
+	 * @throws AoException Thrown in case of errors.
+	 */
+	public void createCatalogComponents(Collection<CatalogComponent> catalogComponents) throws AoException {
+		Map<ContextType, List<CatalogComponent>> catalogComponentsByContextType = catalogComponents.stream()
+				.collect(Collectors.groupingBy(CatalogComponent::getContextType));
+
+		for (Entry<ContextType, List<CatalogComponent>> entry : catalogComponentsByContextType.entrySet()) {
+			String odsContextTypeName = ODSUtils.CONTEXTTYPES.get(entry.getKey());
+			ApplicationElement contextRootApplicationElement = getApplicationStructure()
+					.getElementByName(odsContextTypeName);
+			BaseElement contextRootBaseElement = contextRootApplicationElement.getBaseElement();
+			ApplicationElement contextTemplateComponentApplicationElement = getApplicationStructure()
+					.getElementByName("Tpl" + odsContextTypeName + "Comp");
+			BaseElement baseElement = getBaseStructure().getElementByType("Ao" + odsContextTypeName + "Part");
+
+			for (CatalogComponent catalogComponent : entry.getValue()) {
+				ApplicationElement applicationElement = createApplicationElement(catalogComponent.getName(),
+						baseElement);
+
+				// relation context root to context component
+				ApplicationRelation applicationRelation = getApplicationStructure().createRelation();
+				applicationRelation.setElem1(contextRootApplicationElement);
+				applicationRelation.setElem2(applicationElement);
+				applicationRelation.setRelationName(catalogComponent.getName());
+				applicationRelation.setInverseRelationName(odsContextTypeName);
+				applicationRelation
+						.setBaseRelation(getBaseStructure().getRelation(contextRootBaseElement, baseElement));
+				applicationRelation._release();
+
+				// relation template component to context component
+				applicationRelation = getApplicationStructure().createRelation();
+				applicationRelation.setElem1(contextTemplateComponentApplicationElement);
+				applicationRelation.setElem2(applicationElement);
+				applicationRelation.setRelationName(catalogComponent.getName());
+				applicationRelation.setInverseRelationName("Tpl" + odsContextTypeName + "Comp");
+				applicationRelation.setRelationRange(new RelationRange((short) 0, (short) -1));
+				applicationRelation.setInverseRelationRange(new RelationRange((short) 1, (short) 1));
+
+				// release resources
+				applicationElement._release();
+				applicationRelation._release();
+			}
+
+			// release resources
+			contextTemplateComponentApplicationElement._release();
+			contextRootApplicationElement._release();
+			contextRootBaseElement._release();
+			baseElement._release();
+		}
+	}
+
+	/**
+	 * Creates for each given {@link CatalogSensor} a corresponding application
+	 * element including all required application relations.
+	 *
+	 * @param catalogSensors The {@code CatalogSensor}s.
+	 * @throws AoException Thrown in case of errors.
+	 */
+	public void createCatalogSensors(Collection<CatalogSensor> catalogSensors) throws AoException {
+		Map<String, List<CatalogSensor>> catalogSensorsByCatalogComponent = catalogSensors.stream()
+				.collect(Collectors.groupingBy(cs -> cs.getCatalogComponent().getName()));
+
+		ApplicationElement channelApplicationElement = getApplicationStructure().getElementByName("MeaQuantity");
+		BaseElement channelBaseElement = channelApplicationElement.getBaseElement();
+
+		for (Entry<String, List<CatalogSensor>> entry : catalogSensorsByCatalogComponent.entrySet()) {
+			ApplicationElement contextComponentApplicationElement = getApplicationStructure()
+					.getElementByName(entry.getKey());
+			BaseElement contextComponentBaseElement = contextComponentApplicationElement.getBaseElement();
+			ApplicationElement contextTemplateSensorApplicationElement = getApplicationStructure()
+					.getElementByName("TplSensor");
+			BaseElement baseElement = getBaseStructure().getElementByType("AoTestEquipmentPart");
+
+			for (CatalogSensor catalogSensor : entry.getValue()) {
+				ApplicationElement applicationElement = createApplicationElement(catalogSensor.getName(), baseElement);
+
+				// relation context component to context sensor
+				ApplicationRelation applicationRelation = getApplicationStructure().createRelation();
+				applicationRelation.setElem1(contextComponentApplicationElement);
+				applicationRelation.setElem2(applicationElement);
+				applicationRelation.setRelationName(catalogSensor.getName());
+				applicationRelation.setInverseRelationName(entry.getKey());
+				applicationRelation
+						.setBaseRelation(getBaseStructure().getRelation(contextComponentBaseElement, baseElement));
+				applicationRelation._release();
+
+				// relation template sensor to context sensor
+				applicationRelation = getApplicationStructure().createRelation();
+				applicationRelation.setElem1(contextTemplateSensorApplicationElement);
+				applicationRelation.setElem2(applicationElement);
+				applicationRelation.setRelationName(catalogSensor.getName());
+				applicationRelation.setInverseRelationName("TplSensor");
+				applicationRelation.setRelationRange(new RelationRange((short) 0, (short) -1));
+				applicationRelation.setInverseRelationRange(new RelationRange((short) 1, (short) 1));
+				applicationRelation._release();
+
+				// relation channel to context sensor
+				applicationRelation = getApplicationStructure().createRelation();
+				applicationRelation.setElem1(channelApplicationElement);
+				applicationRelation.setElem2(applicationElement);
+				applicationRelation.setRelationName(catalogSensor.getName());
+				applicationRelation.setInverseRelationName("MeaQuantity");
+				applicationRelation.setBaseRelation(getBaseStructure().getRelation(channelBaseElement, baseElement));
+
+				// release resources
+				applicationElement._release();
+				applicationRelation._release();
+			}
+
+			// release resources
+			contextComponentApplicationElement._release();
+			contextTemplateSensorApplicationElement._release();
+			contextComponentBaseElement._release();
+			baseElement._release();
+		}
+
+		// release resources
+		channelApplicationElement._release();
+		channelBaseElement._release();
+	}
+
+	/**
+	 * Creates for each given {@link CatalogAttribute} a corresponding application
+	 * attribute.
+	 *
+	 * @param catalogAttributes The {@code CatalogAttribute}s.
+	 * @throws AoException Thrown in case of errors.
+	 */
+	public void createCatalogAttributes(Collection<CatalogAttribute> catalogAttributes) throws AoException {
+		Map<String, List<CatalogAttribute>> catalogAttributesByCatalogComponent = catalogAttributes.stream()
+				.collect(Collectors.groupingBy(CatalogManager::getParentName));
+
+		for (Entry<String, List<CatalogAttribute>> entry : catalogAttributesByCatalogComponent.entrySet()) {
+			ApplicationElement applicationElement = getApplicationStructure().getElementByName(entry.getKey());
+
+			for (CatalogAttribute catalogAttribute : entry.getValue()) {
+
+				ApplicationAttribute applicationAttribute = applicationElement.createAttribute();
+				DataType dataType = ODSUtils.VALUETYPES.get(catalogAttribute.getValueType());
+				applicationAttribute.setDataType(dataType);
+				applicationAttribute.setName(catalogAttribute.getName());
+				if (dataType == DataType.DT_ENUM) {
+					applicationAttribute.setEnumerationDefinition(getApplicationStructure().getEnumerationDefinition(
+							ODSEnumerations.getEnumName(catalogAttribute.getEnumerationObject())));
+				}
+				Optional<Unit> unit = catalogAttribute.getUnit();
+				if (unit.isPresent()) {
+					applicationAttribute.setUnit(ODSConverter.toODSID(unit.get().getID()));
+				}
+
+				// release resources
+				applicationAttribute._release();
+			}
+
+			// release resources
+			applicationElement._release();
+		}
+	}
+
+	/**
+	 * Updates the application attribute for each given {@link CatalogAttribute}.
+	 *
+	 * @param catalogAttributes The {@code CatalogAttribute}s.
+	 * @throws AoException Thrown in case of errors.
+	 */
+	public void updateCatalogAttributes(List<CatalogAttribute> catalogAttributes) throws AoException {
+		Map<String, List<CatalogAttribute>> catalogAttributesByCatalogComponent = catalogAttributes.stream()
+				.collect(Collectors.groupingBy(CatalogManager::getParentName));
+
+		for (Entry<String, List<CatalogAttribute>> entry : catalogAttributesByCatalogComponent.entrySet()) {
+			ApplicationElement applicationElement = getApplicationStructure().getElementByName(entry.getKey());
+
+			for (CatalogAttribute catalogAttribute : entry.getValue()) {
+
+				ApplicationAttribute applicationAttribute = applicationElement
+						.getAttributeByName(catalogAttribute.getName());
+
+				Optional<Unit> unit = catalogAttribute.getUnit();
+				if (unit.isPresent()) {
+					applicationAttribute.setUnit(ODSConverter.toODSID(unit.get().getID()));
+				}
+
+				// release resources
+				applicationAttribute._release();
+			}
+
+			// release resources
+			applicationElement._release();
+		}
+	}
+
+	/**
+	 * Deletes the corresponding application element for each given
+	 * {@link CatalogComponent}. Deleting a {@code CatalogComponent} is only allowed
+	 * if it is not used in templates and all of its children could be deleted. So
+	 * at first it is tried to delete its {@link CatalogAttribute}s and
+	 * {@link CatalogSensor}s. On success it is ensured none of the given {@code
+	 * CatalogComponent}s is used in templates. Finally the corresponding
+	 * application elements are deleted.
+	 *
+	 * @param catalogComponents The {@code CatalogComponent}s.
+	 * @throws AoException         Thrown in case of errors.
+	 * @throws DataAccessException Thrown in case of errors.
+	 */
+	public void deleteCatalogComponents(Collection<CatalogComponent> catalogComponents)
+			throws AoException, DataAccessException {
+		List<CatalogAttribute> attributes = new ArrayList<>();
+		List<CatalogSensor> sensors = new ArrayList<>();
+		for (CatalogComponent catalogComponent : catalogComponents) {
+			attributes.addAll(catalogComponent.getCatalogAttributes());
+			sensors.addAll(catalogComponent.getCatalogSensors());
+		}
+		transaction.delete(sensors);
+		transaction.delete(attributes);
+
+		if (areReferencedInTemplates(catalogComponents)) {
+			throw new DataAccessException(
+					"Unable to delete given catalog components since at least " + "one is used in templates.");
+		}
+
+		for (CatalogComponent catalogComponent : catalogComponents) {
+			ApplicationElement applicationElement = getApplicationStructure()
+					.getElementByName(catalogComponent.getName());
+			for (ApplicationRelation applicationRelation : applicationElement.getAllRelations()) {
+				getApplicationStructure().removeRelation(applicationRelation);
+
+				// release resources
+				applicationRelation._release();
+			}
+			getApplicationStructure().removeElement(applicationElement);
+
+			// release resources
+			applicationElement._release();
+		}
+	}
+
+	/**
+	 * Deletes the corresponding application element for each given
+	 * {@link CatalogSensor}. Deleting a {@code CatalogSensor} is only allowed if it
+	 * is not used in templates and all of its children could be deleted. So at
+	 * first it is tried to delete its {@link CatalogAttribute}s. On success it is
+	 * ensured none of the given {@code CatalogSensor}s is used in templates.
+	 * Finally the corresponding application elements are deleted.
+	 *
+	 * @param catalogSensors The {@code CatalogSensor}s.
+	 * @throws AoException         Thrown in case of errors.
+	 * @throws DataAccessException Thrown in case of errors.
+	 */
+	public void deleteCatalogSensors(Collection<CatalogSensor> catalogSensors) throws AoException, DataAccessException {
+		List<CatalogAttribute> attributes = new ArrayList<>();
+		for (CatalogSensor catalogSensor : catalogSensors) {
+			attributes.addAll(catalogSensor.getCatalogAttributes());
+		}
+		transaction.delete(attributes);
+
+		if (areReferencedInTemplates(catalogSensors)) {
+			throw new DataAccessException(
+					"Unable to delete given catalog sensors since at " + "least one is used in templates.");
+		}
+
+		for (CatalogSensor catalogSensor : catalogSensors) {
+			ApplicationElement applicationElement = getApplicationStructure().getElementByName(catalogSensor.getName());
+			for (ApplicationRelation applicationRelation : applicationElement.getAllRelations()) {
+				getApplicationStructure().removeRelation(applicationRelation);
+
+				// release resources
+				applicationRelation._release();
+			}
+			getApplicationStructure().removeElement(applicationElement);
+
+			// release resources
+			applicationElement._release();
+		}
+
+	}
+
+	/**
+	 * Deletes the corresponding application attributes for each given
+	 * {@link CatalogAttribute}. Deleting a {@code CatalogAttribute} is only allowed
+	 * if it is not used in templates. So at first it is ensured none of the given
+	 * {@code CatalogAttribute}s is used in templates and finally the corresponding
+	 * application attributes are deleted.
+	 *
+	 * @param catalogAttributes The {@code CatalogAttribute}s.
+	 * @throws AoException         Thrown in case of errors.
+	 * @throws DataAccessException Thrown in case of errors.
+	 */
+	public void deleteCatalogAttributes(Collection<CatalogAttribute> catalogAttributes)
+			throws AoException, DataAccessException {
+		if (areReferencedInTemplates(catalogAttributes)) {
+			throw new DataAccessException(
+					"Unable to delete given catalog attributes since at least " + "one is used in templates.");
+		}
+
+		Map<String, List<CatalogAttribute>> catalogAttributesByParent = catalogAttributes.stream()
+				.collect(Collectors.groupingBy(CatalogManager::getParentName));
+
+		for (Entry<String, List<CatalogAttribute>> entry : catalogAttributesByParent.entrySet()) {
+			ApplicationElement applicationElement = getApplicationStructure().getElementByName(entry.getKey());
+
+			for (CatalogAttribute catalogAttribute : entry.getValue()) {
+				ApplicationAttribute applicationAttribute = applicationElement
+						.getAttributeByName(catalogAttribute.getName());
+				applicationElement.removeAttribute(applicationAttribute);
+
+				// release resources
+				applicationAttribute._release();
+			}
+
+			// release resources
+			applicationElement._release();
+		}
+	}
+
+	/**
+	 * Releases cached resources.
+	 */
+	public void clear() {
+		if (applicationStructure != null) {
+			applicationStructure._release();
+		}
+
+		if (baseStructure != null) {
+			baseStructure._release();
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link ApplicationElement} with given name and
+	 * {@link BaseElement}. The returned {@code ApplicationElement} will be created
+	 * with the three mandatory {@link ApplicationAttribute}s for 'Id', 'Name' and
+	 * 'MimeType'.
+	 *
+	 * @param name        The name of the application element.
+	 * @param baseElement The {@code BaseElement} the created {@code
+	 * 		ApplicationElement} will be derived from.
+	 * @return The created {@code ApplicationElement} is returned.
+	 * @throws AoException Thrown in case of errors.
+	 */
+	private ApplicationElement createApplicationElement(String name, BaseElement baseElement) throws AoException {
+		ApplicationElement applicationElement = getApplicationStructure().createElement(baseElement);
+		applicationElement.setName(name);
+
+		// Id
+		ApplicationAttribute idApplicationAttribute = applicationElement.getAttributeByBaseName("id");
+		idApplicationAttribute.setName("Id");
+		idApplicationAttribute.setDataType(DataType.DT_LONGLONG);
+		idApplicationAttribute.setIsAutogenerated(true);
+
+		// Name
+		ApplicationAttribute nameApplicationAttribute = applicationElement.getAttributeByBaseName("name");
+		nameApplicationAttribute.setName("Name");
+		nameApplicationAttribute.setLength(50);
+
+		// MimeType
+		BaseAttribute mimeTypeBaseAttribute = baseElement.getAttributes("mime_type")[0];
+		ApplicationAttribute mimeTypeApplicationAttribute = applicationElement.createAttribute();
+		mimeTypeApplicationAttribute.setBaseAttribute(mimeTypeBaseAttribute);
+		mimeTypeApplicationAttribute.setName("MimeType");
+		mimeTypeApplicationAttribute.setDataType(DataType.DT_STRING);
+		mimeTypeApplicationAttribute.setLength(256);
+		mimeTypeApplicationAttribute.setIsObligatory(true);
+
+		// release resources
+		idApplicationAttribute._release();
+		nameApplicationAttribute._release();
+		mimeTypeApplicationAttribute._release();
+		mimeTypeBaseAttribute._release();
+
+		return applicationElement;
+	}
+
+	/**
+	 * Returns the cached {@link ApplicationStructure}.
+	 *
+	 * @return The {@code ApplicationStructure} is returned.
+	 * @throws AoException Thrown if unable to access the {@code
+	 * 		ApplicationStructure}.
+	 */
+	private ApplicationStructure getApplicationStructure() throws AoException {
+		if (applicationStructure == null) {
+			applicationStructure = transaction.getModelManager().getAoSession().getApplicationStructure();
+		}
+
+		return applicationStructure;
+	}
+
+	/**
+	 * Returns the cached {@link BaseStructure}.
+	 *
+	 * @return The {@code BaseStructure} is returned.
+	 * @throws AoException Thrown if unable to access the {@code
+	 * 		BaseStructure}.
+	 */
+	private BaseStructure getBaseStructure() throws AoException {
+		if (baseStructure == null) {
+			baseStructure = transaction.getModelManager().getAoSession().getBaseStructure();
+		}
+
+		return baseStructure;
+	}
+
+	/**
+	 * Checks whether given {@link Entity}s are referenced in templates.
+	 *
+	 * @param entities The checked entities ({@link CatalogComponent},
+	 *                 {@link CatalogSensor} or {@link CatalogAttribute}).
+	 * @return Returns {@code true} if at least one entity is referenced in a
+	 *         template.
+	 * @throws AoException         Thrown on errors.
+	 * @throws DataAccessException Thrown on errors.
+	 */
+	private boolean areReferencedInTemplates(Collection<? extends Entity> entities)
+			throws AoException, DataAccessException {
+		Map<EntityType, List<Entity>> entitiesByEntityType = entities.stream()
+				.collect(Collectors.groupingBy(transaction.getModelManager()::getEntityType));
+
+		for (Entry<EntityType, List<Entity>> entry : entitiesByEntityType.entrySet()) {
+			EntityType source = entry.getKey();
+			EntityType target = transaction.getModelManager().getEntityType(source.getName().replace("Cat", "Tpl"));
+
+			Query query = transaction.getContext().getQueryService()
+					.orElseThrow(() -> new ServiceNotProvidedException(QueryService.class)).createQuery()
+					.selectID(target).join(source, target);
+
+			List<Result> results = query.fetch(Filter.and().add(
+					ComparisonOperator.IN_SET.create(source.getIDAttribute(), collectInstanceIDs(entry.getValue()))));
+			if (results.size() > 0) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Collect the instance IDs of all given {@link Entity}s.
+	 *
+	 * @param entities The {@link Entity}s.
+	 * @return The instance IDs a {@code String[]} are turned.
+	 */
+	private static String[] collectInstanceIDs(List<Entity> entities) {
+		String[] ids = new String[entities.size()];
+
+		for (int i = 0; i < ids.length; i++) {
+			ids[i] = entities.get(i).getID();
+		}
+
+		return ids;
+	}
+
+	/**
+	 * Returns the parent name for given {@link CatalogAttribute}.
+	 *
+	 * @param catalogAttribute The {@code CatalogAttribute}.
+	 * @return The parent name is returned.
+	 */
+	private static String getParentName(CatalogAttribute catalogAttribute) {
+		Optional<CatalogComponent> catalogComponent = catalogAttribute.getCatalogComponent();
+		if (catalogComponent.isPresent()) {
+			return catalogComponent.get().getName();
+		}
+
+		return catalogAttribute.getCatalogSensor()
+				.orElseThrow(() -> new IllegalStateException("Parent entity is unknown.")).getName();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/DeleteStatement.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/DeleteStatement.java
new file mode 100644
index 0000000..f521967
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/DeleteStatement.java
@@ -0,0 +1,260 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+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 java.util.stream.Collectors;
+
+import org.asam.ods.AoException;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.FilesAttachable;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.ParameterSet;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.JoinType;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Delete statement is used to delete entities with their children.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class DeleteStatement extends BaseStatement {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final List<String> AUTO_DELETABLE = Arrays.asList("MeaQuantity", "SubMatrix", "LocalColumn",
+			"ExternalComponent");
+	private static final Logger LOGGER = LoggerFactory.getLogger(DeleteStatement.class);
+
+	private final boolean useAutoDelete;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param transaction   The owning {@link ODSTransaction}.
+	 * @param entityType    The associated {@link EntityType}.
+	 * @param useAutoDelete If {@code true} child relations of {@link Measurement}
+	 *                      entities are not followed.
+	 */
+	DeleteStatement(ODSTransaction transaction, EntityType entityType, boolean useAutoDelete) {
+		super(transaction, entityType);
+		this.useAutoDelete = useAutoDelete;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void execute(Collection<Entity> entities) throws AoException, DataAccessException {
+		if (entities.stream().filter(e -> !e.getTypeName().equals(getEntityType().getName())).findAny().isPresent()) {
+			throw new IllegalArgumentException("At least one given entity is of incompatible type.");
+		}
+
+		long start = System.currentTimeMillis();
+		int amount = delete(getEntityType(), entities.stream().map(Entity::getID).collect(Collectors.toSet()), false);
+		LOGGER.debug("{} instances deleted in {} ms.", amount, System.currentTimeMillis() - start);
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Recursively follows child relations of given entities and deletes all child
+	 * entities before deleting parent entities.
+	 *
+	 * @param entityType     {@link EntityType} of the deleted entities.
+	 * @param instanceIDs    Instance IDs of entities which have to be deleted.
+	 * @param ignoreSiblings Is it required to check whether {@link Measurement}
+	 *                       siblings share a common {@link ContextRoot}s.
+	 * @return Returns the total number of deleted instances.
+	 * @throws AoException         Thrown if unable to delete entities.
+	 * @throws DataAccessException Thrown if unable to query child entities.
+	 */
+	private int delete(EntityType entityType, Collection<String> instanceIDs, boolean ignoreSiblings)
+			throws AoException, DataAccessException {
+		if (instanceIDs.isEmpty()) {
+			return 0;
+		}
+
+		Query query = getQueryService().createQuery().selectID(entityType);
+		for (Relation relation : entityType.getChildRelations()) {
+			if (useAutoDelete && AUTO_DELETABLE.contains(relation.getTarget().getName())) {
+				continue;
+			}
+
+			if (!relation.getTarget().equals(relation.getSource())) {
+				query.join(relation, JoinType.OUTER).selectID(relation.getTarget());
+			}
+		}
+
+		// select attributes containing file links only for entity types
+		// implementing FilesAttachable
+		EntityConfig<?> entityConfig = getModelManager().getEntityConfig(entityType);
+		if (FilesAttachable.class.isAssignableFrom(entityConfig.getEntityClass())) {
+			entityType.getAttributes().stream().filter(a -> a.getValueType().isFileLinkType()).forEach(query::select);
+		}
+
+		EntityType testStep = getModelManager().getEntityType(TestStep.class);
+		EntityType measurement = getModelManager().getEntityType(Measurement.class);
+		EntityType channel = getModelManager().getEntityType(Channel.class);
+
+		EntityType unitUnderTest = getModelManager().getEntityType(ContextRoot.class, ContextType.UNITUNDERTEST);
+		EntityType testSequence = getModelManager().getEntityType(ContextRoot.class, ContextType.TESTSEQUENCE);
+		EntityType testEquipment = getModelManager().getEntityType(ContextRoot.class, ContextType.TESTEQUIPMENT);
+
+		// type in this list must be deleted AFTER this this instances have been
+		// deleted
+		// informative relation is considered as a child relation
+		List<EntityType> delayedDelete = new ArrayList<>();
+
+		// join context roots
+		if (measurement.equals(entityType) || testStep.equals(entityType)) {
+			query.join(entityType.getRelation(unitUnderTest), JoinType.OUTER).selectID(unitUnderTest);
+			query.join(entityType.getRelation(testSequence), JoinType.OUTER).selectID(testSequence);
+			query.join(entityType.getRelation(testEquipment), JoinType.OUTER).selectID(testEquipment);
+			delayedDelete.addAll(Arrays.asList(unitUnderTest, testSequence, testEquipment));
+		}
+
+		// join parameter sets
+		if (measurement.equals(entityType) || channel.equals(entityType)) {
+			EntityType parameterSet = getModelManager().getEntityType(ParameterSet.class);
+			query.join(entityType.getRelation(parameterSet), JoinType.OUTER).selectID(parameterSet);
+		}
+
+		Filter filter = Filter.or().ids(entityType, instanceIDs);
+		entityType.getParentRelations().stream().filter(r -> r.getTarget().equals(entityType))
+				.forEach(relation -> filter.ids(relation, instanceIDs));
+
+		// query child IDs
+		Map<EntityType, Set<String>> children = new HashMap<>();
+		for (Result result : query.fetch(filter)) {
+			// load children of other types
+			result.stream().filter(r -> r.getID() != null && r.getID().length() > 0).forEach(r -> {
+				children.computeIfAbsent(r.getEntityType(), k -> new HashSet<>()).add(r.getID());
+			});
+
+			// collect file links to remove
+			List<FileLink> fileLinks = new ArrayList<>();
+			for (Value value : result.getRecord(entityType).getValues().values()) {
+				if (value.getValueType().isFileLink()) {
+					fileLinks.add(value.extract());
+				} else if (value.getValueType().isFileLinkSequence()) {
+					fileLinks.addAll(Arrays.asList((FileLink[]) value.extract()));
+				}
+			}
+
+			if (!fileLinks.isEmpty()) {
+				getTransaction().getUploadService().addToRemove(fileLinks);
+			}
+		}
+
+		// omit context roots with references to not removed measurements
+		if (!ignoreSiblings && measurement.equals(entityType)) {
+			for (EntityType contextRoot : Arrays.asList(unitUnderTest, testSequence, testEquipment)) {
+				Set<String> contextRootIDs = children.getOrDefault(contextRoot, Collections.emptySet());
+				if (contextRootIDs.isEmpty()) {
+					continue;
+				}
+
+				Query contextQuery = getQueryService().createQuery();
+				contextQuery.selectID(contextRoot, measurement);
+				contextQuery.join(contextRoot, measurement);
+
+				for (Result result : contextQuery.fetch(Filter.idsOnly(contextRoot, contextRootIDs))) {
+					if (instanceIDs.contains(result.getRecord(measurement).getID())) {
+						continue;
+					}
+
+					// context root references a not removed measurement
+					contextRootIDs.remove(result.getRecord(contextRoot).getID());
+				}
+			}
+		}
+
+		int amount = 0;
+		// delete real children
+		List<Entry<EntityType, Set<String>>> consideredChildren = new ArrayList<>();
+		for (Entry<EntityType, Set<String>> entry : children.entrySet()) {
+			EntityType childType = entry.getKey();
+			Set<String> childInstanceIDs = entry.getValue();
+			if (entityType.equals(childType)) {
+				childInstanceIDs.removeAll(instanceIDs);
+			} else if (delayedDelete.contains(entry.getKey())) {
+				consideredChildren.add(entry);
+				continue;
+			}
+			amount += delete(entry.getKey(), childInstanceIDs, true);
+		}
+
+		getApplElemAccess().deleteInstances(((ODSEntityType) entityType).getODSID(), toODSIDs(instanceIDs));
+
+		// delete considered children (informative relation)
+		for (Entry<EntityType, Set<String>> entry : consideredChildren) {
+			amount += delete(entry.getKey(), entry.getValue(), true);
+		}
+
+		return amount + instanceIDs.size();
+	}
+
+	/**
+	 * Converts given {@code Collection} of instance IDs to ODS a {@link T_LONGLONG}
+	 * array.
+	 *
+	 * @param instanceIDs The instance IDs.
+	 * @return The corresponding ODS {@code T_LONGLONG[]} is returned.
+	 */
+	private T_LONGLONG[] toODSIDs(Collection<String> instanceIDs) {
+		return instanceIDs.stream().map(ODSConverter::toODSID).toArray(T_LONGLONG[]::new);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/InsertStatement.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/InsertStatement.java
new file mode 100644
index 0000000..2a54ac5
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/InsertStatement.java
@@ -0,0 +1,282 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.asam.ods.AIDName;
+import org.asam.ods.AIDNameValueSeqUnitId;
+import org.asam.ods.AoException;
+import org.asam.ods.ElemId;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Query;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Insert statement is used to write new entities and their children.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class InsertStatement extends BaseStatement {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(InsertStatement.class);
+
+	private final Map<Class<? extends Entity>, List<Entity>> childrenMap = new HashMap<>();
+	private final List<Core> cores = new ArrayList<>();
+	private final Map<String, List<Value>> insertMap = new HashMap<>();
+
+	private final List<FileLink> fileLinkToUpload = new ArrayList<>();
+
+	private final Map<String, SortIndexTestSteps> sortIndexTestSteps = new HashMap<>();
+	private boolean loadSortIndex;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param transaction The owning {@link ODSTransaction}.
+	 * @param entityType  The associated {@link EntityType}.
+	 */
+	InsertStatement(ODSTransaction transaction, EntityType entityType) {
+		super(transaction, entityType);
+
+		loadSortIndex = getModelManager().getEntityType(TestStep.class).equals(getEntityType());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void execute(Collection<Entity> entities) throws AoException, DataAccessException, IOException {
+		entities.stream().map(ODSEntityFactory::extract).forEach(this::readEntityCore);
+		execute();
+	}
+
+	/**
+	 * Executes this statement for given {@link Core}s.
+	 *
+	 * @param cores The processed {@code Core}s.
+	 * @throws AoException         Thrown if the execution fails.
+	 * @throws DataAccessException Thrown if the execution fails.
+	 * @throws IOException         Thrown if a file transfer operation fails.
+	 */
+	public void executeWithCores(Collection<Core> cores) throws AoException, DataAccessException, IOException {
+		cores.forEach(this::readEntityCore);
+		execute();
+	}
+
+	/**
+	 * Uploads new {@link FileLink}s, adjusts sort indices for new {@link TestStep}
+	 * entities and writes collected insertion data at once. Once new entities are
+	 * written their children are created by delegation to the
+	 * {@link ODSTransaction}.
+	 *
+	 * @throws AoException         Thrown if the execution fails.
+	 * @throws DataAccessException Thrown if the execution fails.
+	 * @throws IOException         Thrown if a file transfer operation fails.
+	 */
+	private void execute() throws AoException, DataAccessException, IOException {
+		List<AIDNameValueSeqUnitId> anvsuList = new ArrayList<>();
+		T_LONGLONG aID = getEntityType().getODSID();
+
+		// TODO tracing progress in this method...
+
+		if (loadSortIndex && !sortIndexTestSteps.isEmpty()) {
+			adjustMissingSortIndices();
+		}
+
+		if (!fileLinkToUpload.isEmpty()) {
+			getTransaction().getUploadService().uploadParallel(fileLinkToUpload, null);
+		}
+
+		for (Entry<String, List<Value>> entry : insertMap.entrySet()) {
+			Attribute attribute = getEntityType().getAttribute(entry.getKey());
+
+			AIDNameValueSeqUnitId anvsu = new AIDNameValueSeqUnitId();
+			anvsu.attr = new AIDName(aID, entry.getKey());
+			anvsu.unitId = ODSConverter.toODSLong(0);
+			anvsu.values = ODSConverter.toODSValueSeq(attribute, entry.getValue());
+			anvsuList.add(anvsu);
+		}
+
+		long start = System.currentTimeMillis();
+		ElemId[] elemIds = getApplElemAccess()
+				.insertInstances(anvsuList.toArray(new AIDNameValueSeqUnitId[anvsuList.size()]));
+		for (int i = 0; i < elemIds.length; i++) {
+			cores.get(i).setID(Long.toString(ODSConverter.fromODSLong(elemIds[i].iid)));
+		}
+		long stop = System.currentTimeMillis();
+
+		LOGGER.debug("{} " + getEntityType() + " instances created in {} ms.", elemIds.length, stop - start);
+
+		for (List<Entity> children : childrenMap.values()) {
+			getTransaction().create(children);
+		}
+	}
+
+	/**
+	 * Reads given {@link Core} and prepares its data to be written:
+	 *
+	 * <ul>
+	 * <li>collect new {@link FileLink}s</li>
+	 * <li>trace missing sort indices of TestSteps</li>
+	 * <li>collect property {@link Value}s</li>
+	 * <li>collect foreign key {@code Value}s</li>
+	 * <li>collect child entities for recursive creation</li>
+	 * </ul>
+	 *
+	 * @param core The {@code Core}.
+	 */
+	private void readEntityCore(Core core) {
+		if (!core.getTypeName().equals(getEntityType().getName())) {
+			throw new IllegalArgumentException("Entity core '" + core.getTypeName()
+					+ "' is incompatible with current insert statement for entity type '" + getEntityType() + "'.");
+		}
+
+		cores.add(core);
+
+		if (loadSortIndex) {
+			if ((Integer) core.getValues().get(Sortable.ATTR_SORT_INDEX).extract() < 0) {
+				sortIndexTestSteps.computeIfAbsent(core.getPermanentStore().get(Test.class).getID(),
+						k -> new SortIndexTestSteps()).testStepCores.add(core);
+			}
+		}
+
+		// add all entity values
+		for (Value value : core.getAllValues().values()) {
+			insertMap.computeIfAbsent(value.getName(), k -> new ArrayList<>()).add(value);
+		}
+
+		// collect file links
+		fileLinkToUpload.addAll(core.getAddedFileLinks());
+
+		// define "empty" values for informative relations
+		for (Relation relation : getEntityType().getInfoRelations()) {
+			insertMap.computeIfAbsent(relation.getName(), k -> new ArrayList<>()).add(relation.createValue());
+		}
+
+		// define "empty" values for parent relations
+		for (Relation relation : getEntityType().getParentRelations()) {
+			insertMap.computeIfAbsent(relation.getName(), k -> new ArrayList<>()).add(relation.createValue());
+		}
+
+		// replace "empty" relation values with corresponding instance IDs
+		setRelationIDs(core.getMutableStore().getCurrent());
+		setRelationIDs(core.getPermanentStore().getCurrent());
+
+		for (Entry<Class<? extends Deletable>, List<? extends Deletable>> entry : core.getChildrenStore().getCurrent()
+				.entrySet()) {
+			childrenMap.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).addAll(entry.getValue());
+		}
+
+		getTransaction().addModified(core);
+		getTransaction().addCreated(core);
+	}
+
+	/**
+	 * Overwrites empty foreign key {@link Value} containers.
+	 *
+	 * @param relatedEntities The related {@link Entity}s.
+	 */
+	private void setRelationIDs(Collection<Entity> relatedEntities) {
+		for (Entity relatedEntity : relatedEntities) {
+			if (!ODSUtils.isValidID(relatedEntity.getID())) {
+				throw new IllegalArgumentException("Related entity must be a persited entity.");
+			}
+
+			Relation relation = getEntityType().getRelation(getModelManager().getEntityType(relatedEntity));
+			List<Value> relationValues = insertMap.get(relation.getName());
+			if (relationValues == null) {
+				throw new IllegalStateException("Relation '" + relation + "' is incompatible with insert statement "
+						+ "for entity type '" + getEntityType() + "'");
+			}
+			relationValues.get(relationValues.size() - 1).set(relatedEntity.getID());
+		}
+	}
+
+	/**
+	 * Adjusts missing sort indices for {@link TestStep}s by querying last used max
+	 * sort index.
+	 *
+	 * @throws DataAccessException Thrown if unable to query used sort indices.
+	 */
+	private void adjustMissingSortIndices() throws DataAccessException {
+		EntityType testStep = getEntityType();
+		EntityType test = getModelManager().getEntityType(Test.class);
+		Relation parentRelation = testStep.getRelation(test);
+
+		Attribute attrSortIndex = testStep.getAttribute(Sortable.ATTR_SORT_INDEX);
+		Query query = getQueryService().createQuery().select(parentRelation.getAttribute())
+				.select(attrSortIndex, Aggregation.MAXIMUM).group(parentRelation.getAttribute());
+
+		Filter filter = Filter.idsOnly(parentRelation, sortIndexTestSteps.keySet());
+		for (Result result : query.fetch(filter)) {
+			Record record = result.getRecord(testStep);
+			int sortIndex = result.getValue(attrSortIndex, Aggregation.MAXIMUM).extract();
+			sortIndexTestSteps.remove(record.getID(parentRelation).get()).setIndices(sortIndex + 1);
+		}
+
+		// start at 1 for all remaining
+		sortIndexTestSteps.values().forEach(tss -> tss.setIndices(0));
+	}
+
+	/**
+	 * Utility class to write missing sort index of new {@link TestStep}s.
+	 */
+	private static final class SortIndexTestSteps {
+
+		private List<Core> testStepCores = new ArrayList<>();
+
+		/**
+		 * Assigns sort indices to {@link Core}s starting at given index.
+		 *
+		 * @param startIndex The start index.
+		 */
+		private void setIndices(int startIndex) {
+			int index = startIndex;
+			for (Core core : testStepCores) {
+				core.getValues().get(Sortable.ATTR_SORT_INDEX).set(index++);
+			}
+		}
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
new file mode 100644
index 0000000..94825b7
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/ODSTransaction.java
@@ -0,0 +1,548 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.asam.ods.AoException;
+import org.asam.ods.ElemId;
+import org.asam.ods.SetType;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.model.CatalogAttribute;
+import org.eclipse.mdm.api.dflt.model.CatalogComponent;
+import org.eclipse.mdm.api.dflt.model.CatalogSensor;
+import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
+import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityType;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ODS implementation of the {@link Transaction} interface.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class ODSTransaction implements Transaction {
+
+	// TODO: it should be possible to a attach a progress listener
+	// -> progress notification updates while uploading files
+	// -> any other useful informations?!
+	// -> splitting of tasks into subtasks may be required...
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSTransaction.class);
+
+	// this one is stored in case of application model modifications
+	private final ODSContext parentContext;
+
+	// this one is used to access the application model and execute queries
+	// instance is decoupled from its parent
+	private final ODSContext context;
+
+	// only for logging
+	private final String id = UUID.randomUUID().toString();
+
+	// need to write version == instanceID -> update after create
+	private final List<ContextRoot> contextRoots = new ArrayList<>();
+
+	// reset instance IDs on abort
+	private final List<Core> created = new ArrayList<>();
+
+	// apply changes
+	private final List<Core> modified = new ArrayList<>();
+
+	private final Entity entity;
+	private final Transfer transfer;
+
+	private UploadService uploadService;
+
+	private CatalogManager catalogManager;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param parentModelManager Used to access the persistence.
+	 * @param entity             Used for security checks
+	 * @param transfer           The file transfer type.
+	 * @throws AoException Thrown if unable to start a co-session.
+	 */
+	public ODSTransaction(ODSContext parentContext, Entity entity, Transfer transfer) throws AoException {
+		this.parentContext = parentContext;
+		this.entity = entity;
+		this.transfer = transfer;
+		context = parentContext.newContext();
+		context.getAoSession().startTransaction();
+		LOGGER.debug("Transaction '{}' started.", id);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	@SuppressWarnings("unchecked")
+	public <T extends Entity> void create(Collection<T> entities) throws DataAccessException {
+		if (entities.isEmpty()) {
+			return;
+		} else if (entities.stream().filter(e -> ODSUtils.isValidID(e.getID())).findAny().isPresent()) {
+			throw new IllegalArgumentException("At least one given entity is already persisted.");
+		}
+
+		try {
+			Map<Class<?>, List<T>> entitiesByClassType = entities.stream()
+					.collect(Collectors.groupingBy(e -> e.getClass()));
+
+			List<CatalogComponent> catalogComponents = (List<CatalogComponent>) entitiesByClassType
+					.get(CatalogComponent.class);
+			if (catalogComponents != null) {
+				getCatalogManager().createCatalogComponents(catalogComponents);
+			}
+
+			List<CatalogSensor> catalogSensors = (List<CatalogSensor>) entitiesByClassType.get(CatalogSensor.class);
+			if (catalogSensors != null) {
+				// TODO anehmer on 2017-11-16: avalon 4.3b throws an exception in
+				// AoSession.commitTransaction() if multiple
+				// catalog sensors have been deleted and leaves the application
+				// model in a broken state. This is also stated in the documentation. This
+				// comment should be removed later.
+				getCatalogManager().createCatalogSensors(catalogSensors);
+			}
+
+			List<CatalogAttribute> catalogAttributes = (List<CatalogAttribute>) entitiesByClassType
+					.get(CatalogAttribute.class);
+			if (catalogAttributes != null) {
+				getCatalogManager().createCatalogAttributes(catalogAttributes);
+			}
+
+			List<TemplateAttribute> templateAttributes = (List<TemplateAttribute>) entitiesByClassType
+					.get(TemplateAttribute.class);
+			if (templateAttributes != null) {
+				List<TemplateAttribute> filtered = getFileLinkTemplateAttributes(templateAttributes);
+				if (!filtered.isEmpty()) {
+					getUploadService().upload(filtered, null);
+				}
+			}
+
+			List<TestStep> testSteps = (List<TestStep>) entitiesByClassType.get(TestStep.class);
+			if (testSteps != null) {
+				create(testSteps.stream().map(ContextRoot::of).collect(ArrayList::new, List::addAll, List::addAll));
+			}
+
+			List<Measurement> measurements = (List<Measurement>) entitiesByClassType.get(Measurement.class);
+			if (measurements != null) {
+				// Use set here, since measurement siblings point to the same
+				// context roots. Only create those ContextRoots that haven't been created yet:
+				create(measurements.stream().map(ContextRoot::of)
+						.collect(HashSet<ContextRoot>::new, Set<ContextRoot>::addAll, Set<ContextRoot>::addAll).stream()
+						.filter(cr -> !ODSUtils.isValidID(cr.getID())).collect(Collectors.toSet()));
+			}
+
+			executeStatements(et -> new InsertStatement(this, et), entities);
+			processNtoMRelations(entities);
+
+			List<ContextRoot> roots = (List<ContextRoot>) entitiesByClassType.get(ContextRoot.class);
+			if (roots != null) {
+				roots.forEach(contextRoot -> {
+					contextRoot.setVersion(contextRoot.getID().toString());
+				});
+
+				// this will restore the ASAM path of each context root
+				executeStatements(et -> new UpdateStatement(this, et, true), roots);
+				contextRoots.addAll(roots);
+			}
+		} catch (AoException e) {
+			throw new DataAccessException("Unable to write new entities due to: " + e.reason, e);
+		} catch (IOException e) {
+			throw new DataAccessException("Unable to write new entities due to: " + e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	@SuppressWarnings("unchecked")
+	public <T extends Entity> void update(Collection<T> entities) throws DataAccessException {
+		if (entities.isEmpty()) {
+			return;
+		} else if (entities.stream().filter(e -> !ODSUtils.isValidID(e.getID())).findAny().isPresent()) {
+			throw new IllegalArgumentException("At least one given entity is not yet persisted.");
+		}
+
+		try {
+			Map<Class<?>, List<T>> entitiesByClassType = entities.stream()
+					.collect(Collectors.groupingBy(e -> e.getClass()));
+			List<CatalogAttribute> catalogAttributes = (List<CatalogAttribute>) entitiesByClassType
+					.get(CatalogAttribute.class);
+			if (catalogAttributes != null) {
+				getCatalogManager().updateCatalogAttributes(catalogAttributes);
+			}
+
+			List<TemplateAttribute> templateAttributes = (List<TemplateAttribute>) entitiesByClassType
+					.get(TemplateAttribute.class);
+			if (templateAttributes != null) {
+				List<TemplateAttribute> filtered = getFileLinkTemplateAttributes(templateAttributes);
+				if (!filtered.isEmpty()) {
+					getUploadService().upload(filtered, null);
+				}
+			}
+			executeStatements(et -> new UpdateStatement(this, et, false), entities);
+			processNtoMRelations(entities);
+		} catch (AoException e) {
+			throw new DataAccessException("Unable to update entities due to: " + e.reason, e);
+		} catch (IOException e) {
+			throw new DataAccessException("Unable to update entities due to: " + e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> void delete(Collection<T> entities) throws DataAccessException {
+		if (entities.isEmpty()) {
+			return;
+		}
+
+		List<T> filteredEntities = entities.stream().filter(e -> ODSUtils.isValidID(e.getID()))
+				.collect(Collectors.toList());
+
+		try {
+			Map<Class<?>, List<T>> entitiesByClassType = filteredEntities.stream()
+					.collect(Collectors.groupingBy(e -> e.getClass()));
+
+			List<CatalogComponent> catalogComponents = (List<CatalogComponent>) entitiesByClassType
+					.get(CatalogComponent.class);
+			if (catalogComponents != null) {
+				getCatalogManager().deleteCatalogComponents(catalogComponents);
+			}
+
+			List<CatalogSensor> catalogSensors = (List<CatalogSensor>) entitiesByClassType.get(CatalogSensor.class);
+			if (catalogSensors != null) {
+				// TODO anehmer on 2017-11-16: avalon 4.3b throws an exception in
+				// AoSession.commitTransaction() if multiple
+				// catalog sensors have been deleted and leaves the application
+				// model in a broken state. This is also stated in the documentation. This
+				// comment should be removed later.
+				getCatalogManager().deleteCatalogSensors(catalogSensors);
+			}
+
+			List<CatalogAttribute> catalogAttributes = (List<CatalogAttribute>) entitiesByClassType
+					.get(CatalogAttribute.class);
+			if (catalogAttributes != null) {
+				getCatalogManager().deleteCatalogAttributes(catalogAttributes);
+			}
+
+			/*
+			 * TODO: for any template that has to be deleted it is required to ensure there
+			 * are no links to it...
+			 */
+
+			executeStatements(et -> new DeleteStatement(this, et, true), filteredEntities);
+		} catch (AoException e) {
+			throw new DataAccessException("Unable to delete entities due to: " + e.reason, e);
+		} catch (IOException e) {
+			throw new DataAccessException("Unable to delete entities due to: " + e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void writeMeasuredValues(Collection<WriteRequest> writeRequests) throws DataAccessException {
+		if (writeRequests.isEmpty()) {
+			return;
+		}
+
+		try {
+			Map<ScalarType, List<WriteRequest>> writeRequestsByRawType = writeRequests.stream()
+					.collect(Collectors.groupingBy(WriteRequest::getRawScalarType));
+
+			for (List<WriteRequest> writeRequestGroup : writeRequestsByRawType.values()) {
+				WriteRequestHandler writeRequestHandler = new WriteRequestHandler(this);
+				List<Channel> channels = new ArrayList<>();
+
+				for (WriteRequest writeRequest : writeRequestGroup) {
+					Channel channel = writeRequest.getChannel();
+					channel.setScalarType(writeRequest.getCalculatedScalarType());
+					// TODO it might be required to change relation to another
+					// unit?!??
+					channels.add(channel);
+					writeRequestHandler.addRequest(writeRequest);
+				}
+
+				update(channels);
+				writeRequestHandler.execute();
+			}
+		} catch (AoException e) {
+			throw new DataAccessException("Unable to write measured values due to: " + e.reason, e);
+		} catch (IOException e) {
+			throw new DataAccessException("Unable to write measured values due to: " + e.getMessage(), e);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void commit() throws DataAccessException {
+		try {
+			context.getAoSession().commitTransaction();
+
+			// commit succeed -> apply changes in entity cores
+			modified.forEach(Core::apply);
+
+			// remove deleted remote files
+			if (uploadService != null) {
+				uploadService.commit();
+			}
+
+			if (catalogManager != null) {
+				// application model has been modified -> reload
+				parentContext.getODSModelManager().reloadApplicationModel();
+			}
+
+			LOGGER.debug("Transaction '{}' committed.", id);
+			closeSession();
+		} catch (AoException e) {
+			throw new DataAccessException("Unable to commit transaction '" + id + "' due to: " + e.reason, e);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void abort() {
+		try {
+			if (uploadService != null) {
+				uploadService.abort();
+			}
+
+			// reset version, since creation failed or was aborted
+			contextRoots.forEach(cr -> cr.setVersion(null));
+
+			// reset instance IDs
+			String virtualID = "0";
+			created.forEach(c -> c.setID(virtualID));
+
+			context.getAoSession().abortTransaction();
+
+			LOGGER.debug("Transaction '{}' aborted.", id);
+		} catch (AoException e) {
+			LOGGER.error("Unable to abort transaction '" + id + "' due to: " + e.reason, e);
+		} finally {
+			closeSession();
+		}
+	}
+
+	/**
+	 * Once {@link #abort()} is called instance ID of given {@link Core} will be
+	 * reset to {@code 0} which indicates a virtual {@link Entity}, not yet
+	 * persisted, entity.
+	 *
+	 * @param core The {@code Core} of a newly written {@code Entity}.
+	 */
+	void addCreated(Core core) {
+		created.add(core);
+	}
+
+	/**
+	 * Once {@link #commit()} is {@link Core#apply()} will be called to apply
+	 * modified {@link Value} contents and removed related entities.
+	 *
+	 * @param core The {@code Core} of an updated {@code Entity}.
+	 */
+	void addModified(Core core) {
+		modified.add(core);
+	}
+
+	/**
+	 * Returns the {@link ODSContext}.
+	 *
+	 * @return The {@code ODSContext} is returned.
+	 */
+	ODSContext getContext() {
+		return context;
+	}
+
+	/**
+	 * Returns the {@link ODSModelManager}.
+	 *
+	 * @return The {@code ODSModelManager} is returned.
+	 */
+	ODSModelManager getModelManager() {
+		return context.getODSModelManager();
+	}
+
+	/**
+	 * Returns the {@link UploadService}.
+	 *
+	 * @return The {@code UploadService} is returned.
+	 * @throws DataAccessException Thrown if file transfer is not possible.
+	 */
+	UploadService getUploadService() throws DataAccessException {
+		if (uploadService == null) {
+			if (context.getFileServer() == null) {
+				throw new DataAccessException("CORBA file server is not available.");
+			}
+
+			// upload service starts a periodic session refresh task -> lazy
+			// instantiation
+			uploadService = new UploadService(context, entity, transfer);
+		}
+
+		return uploadService;
+	}
+
+	/**
+	 * Returns the {@link CatalogManager}.
+	 *
+	 * @return The {@code CatalogManager} is returned.
+	 */
+	private CatalogManager getCatalogManager() {
+		if (catalogManager == null) {
+			catalogManager = new CatalogManager(this);
+		}
+
+		return catalogManager;
+	}
+
+	/**
+	 * Collects {@link TemplateAttribute}s with a valid default {@link Value} of
+	 * type {@link ValueType#FILE_LINK} or {@link ValueType#FILE_LINK_SEQUENCE}.
+	 *
+	 * @param templateAttributes The processed {@code TemplateAttribute}s.
+	 * @return Returns {@link TemplateAttribute} which have {@link FileLink}s stored
+	 *         as default {@code Value}.
+	 */
+	private List<TemplateAttribute> getFileLinkTemplateAttributes(List<TemplateAttribute> templateAttributes) {
+		return templateAttributes.stream().filter(ta -> {
+			Value value = ta.getDefaultValue();
+			return value.getValueType().isFileLinkType() && value.isValid();
+		}).collect(Collectors.toList());
+	}
+
+	/**
+	 * Executes statements for given entities by using given statement factory.
+	 *
+	 * @param <T>              The entity type.
+	 * @param statementFactory Used to create a new statement for a given
+	 *                         {@link EntityType}.
+	 * @param entities         The processed {@code Entity}s.
+	 * @throws AoException         Thrown if the execution fails.
+	 * @throws DataAccessException Thrown if the execution fails.
+	 * @throws IOException         Thrown if a file transfer operation fails.
+	 */
+	private <T extends Entity> void executeStatements(Function<EntityType, BaseStatement> statementFactory,
+			Collection<T> entities) throws AoException, DataAccessException, IOException {
+		Map<EntityType, List<Entity>> entitiesByType = entities.stream()
+				.collect(Collectors.groupingBy(context.getODSModelManager()::getEntityType));
+		for (Entry<EntityType, List<Entity>> entry : entitiesByType.entrySet()) {
+			statementFactory.apply(entry.getKey()).execute(entry.getValue());
+		}
+	}
+
+	/**
+	 * Processes N-to-M relations for the given entities
+	 * 
+	 * @param entities The processed {@code Entity}s.
+	 * @throws DataAccessException Thrown if the execution fails.
+	 */
+	private <T extends Entity> void processNtoMRelations(Collection<T> entities) {
+		for (Entity e : entities) {
+			context.getODSModelManager().getEntityType(e).getRelations().stream().filter(Relation::isNtoM)
+					.forEach(r -> processMtoMRelation(e, r));
+		}
+	}
+
+	private void processMtoMRelation(Entity entity, Relation relation) {
+
+		List<? extends Deletable> removedRelatedEntities = ODSEntityFactory.extract(entity).getNtoMStore().getRemoved()
+				.getOrDefault(relation.getName(), Collections.emptyList());
+		List<? extends Deletable> addedRelatedEntities = ODSEntityFactory.extract(entity).getNtoMStore().getAdded()
+				.getOrDefault(relation.getName(), Collections.emptyList());
+
+		T_LONGLONG[] removedInstIds = removedRelatedEntities.stream().map(Entity::getID).map(ODSConverter::toODSID)
+				.toArray(T_LONGLONG[]::new);
+
+		T_LONGLONG[] addedInstIds = addedRelatedEntities.stream().map(Entity::getID).map(ODSConverter::toODSID)
+				.toArray(T_LONGLONG[]::new);
+
+		try {
+			if (removedInstIds.length > 0) {
+				ODSEntityType entityType = ((ODSEntityType) context.getODSModelManager().getEntityType(entity));
+				ElemId elemId = new ElemId(entityType.getODSID(), ODSConverter.toODSID(entity.getID()));
+				context.getAoSession().getApplElemAccess().setRelInst(elemId, relation.getName(), removedInstIds,
+						SetType.REMOVE);
+			}
+
+			if (addedInstIds.length > 0) {
+				ODSEntityType entityType = ((ODSEntityType) context.getODSModelManager().getEntityType(entity));
+				ElemId elemId = new ElemId(entityType.getODSID(), ODSConverter.toODSID(entity.getID()));
+				context.getAoSession().getApplElemAccess().setRelInst(elemId, relation.getName(), addedInstIds,
+						SetType.APPEND);
+			}
+		} catch (AoException e) {
+			throw new DataAccessException("" + e.reason, e); // TODO
+		}
+	}
+
+	/**
+	 * Closes the co-session of this transaction.
+	 */
+	private void closeSession() {
+		if (catalogManager != null) {
+			catalogManager.clear();
+		}
+
+		context.close();
+		LOGGER.debug("Transaction '{}' closed.", id);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
new file mode 100644
index 0000000..85622b5
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UpdateStatement.java
@@ -0,0 +1,269 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import org.asam.ods.AIDName;
+import org.asam.ods.AIDNameValueSeqUnitId;
+import org.asam.ods.AoException;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.FilesAttachable;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.model.Role;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.eclipse.mdm.api.odsadapter.utils.ODSUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Insert statement is used to update entities and their children.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class UpdateStatement extends BaseStatement {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(UpdateStatement.class);
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<Class<? extends Entity>, List<Entity>> childrenToCreate = new HashMap<>();
+	private final Map<Class<? extends Entity>, List<Entity>> childrenToUpdate = new HashMap<>();
+	private final Map<Class<? extends Deletable>, List<Deletable>> childrenToRemove = new HashMap<>();
+	private Map<String, List<Value>> updateMap = new HashMap<>();
+
+	private final List<FileLink> fileLinkToUpload = new ArrayList<>();
+	private final List<String> nonUpdatableRelationNames;
+	private final boolean ignoreChildren;
+	private final boolean isFilesAttachable;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param transaction    The owning {@link ODSTransaction}.
+	 * @param entityType     The associated {@link EntityType}.
+	 * @param ignoreChildren If {@code true}, then child entities won't be
+	 *                       processed.
+	 */
+	UpdateStatement(ODSTransaction transaction, EntityType entityType, boolean ignoreChildren) {
+		super(transaction, entityType);
+
+		nonUpdatableRelationNames = entityType.getInfoRelations().stream().map(Relation::getName)
+				.collect(Collectors.toList());
+		this.ignoreChildren = ignoreChildren;
+
+		EntityConfig<?> entityConfig = getModelManager().getEntityConfig(getEntityType());
+		isFilesAttachable = FilesAttachable.class.isAssignableFrom(entityConfig.getEntityClass());
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void execute(Collection<Entity> entities) throws AoException, DataAccessException, IOException {
+		for (Entity entity : entities) {
+			readEntityCore(ODSEntityFactory.extract(entity));
+		}
+
+		// TODO tracing progress in this method...
+
+		List<AIDNameValueSeqUnitId> anvsuList = new ArrayList<>();
+		T_LONGLONG aID = getEntityType().getODSID();
+
+		if (!fileLinkToUpload.isEmpty()) {
+			getTransaction().getUploadService().uploadParallel(fileLinkToUpload, null);
+		}
+
+		for (Entry<String, List<Value>> entry : updateMap.entrySet()) {
+			if (nonUpdatableRelationNames.contains(entry.getKey())) {
+				// skip "empty" informative relation sequence
+				continue;
+			}
+			if (entry.getKey().equalsIgnoreCase(Role.ATTR_SUPERUSER_FLAG)) {
+				// skip superuser flag as it cannot be written through the ODS API
+				continue;
+			}
+
+			Attribute attribute = getEntityType().getAttribute(entry.getKey());
+
+			AIDNameValueSeqUnitId anvsu = new AIDNameValueSeqUnitId();
+			anvsu.attr = new AIDName(aID, entry.getKey());
+			anvsu.unitId = ODSConverter.toODSLong(0);
+			anvsu.values = ODSConverter.toODSValueSeq(attribute, entry.getValue());
+			anvsuList.add(anvsu);
+		}
+
+		long start = System.currentTimeMillis();
+		getApplElemAccess().updateInstances(anvsuList.toArray(new AIDNameValueSeqUnitId[anvsuList.size()]));
+		long stop = System.currentTimeMillis();
+
+		LOGGER.debug("{} " + getEntityType() + " instances updated in {} ms.", entities.size(), stop - start);
+
+		// delete first to make sure naming collisions do not occur!
+		for (List<Deletable> children : childrenToRemove.values()) {
+			getTransaction().delete(children);
+		}
+		for (List<Entity> children : childrenToCreate.values()) {
+			getTransaction().create(children);
+		}
+		for (List<Entity> children : childrenToUpdate.values()) {
+			getTransaction().update(children);
+		}
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Reads given {@link Core} and prepares its data to be written:
+	 *
+	 * <ul>
+	 * <li>collect new and removed {@link FileLink}s</li>
+	 * <li>collect property {@link Value}s</li>
+	 * <li>collect foreign key {@code Value}s</li>
+	 * <li>collect child entities for recursive create/update/delete</li>
+	 * </ul>
+	 *
+	 * @param core The {@code Core}.
+	 * @throws DataAccessException Thrown in case of errors.
+	 */
+	private void readEntityCore(Core core) throws DataAccessException {
+		if (!core.getTypeName().equals(getEntityType().getName())) {
+			throw new IllegalArgumentException("Entity core '" + core.getTypeName()
+					+ "' is incompatible with current update statement for entity type '" + getEntityType() + "'.");
+		}
+
+		// add all entity values
+		for (Value value : core.getAllValues().values()) {
+			updateMap.computeIfAbsent(value.getName(), k -> new ArrayList<>()).add(value);
+		}
+
+		// collect file links
+		fileLinkToUpload.addAll(core.getAddedFileLinks());
+		List<FileLink> fileLinksToRemove = core.getRemovedFileLinks();
+		if (isFilesAttachable && !fileLinksToRemove.isEmpty()) {
+			getTransaction().getUploadService().addToRemove(fileLinksToRemove);
+		}
+
+		updateMap.computeIfAbsent(getEntityType().getIDAttribute().getName(), k -> new ArrayList<>())
+				.add(getEntityType().getIDAttribute().createValue(core.getID()));
+
+		// define "empty" values for ALL informative relations
+		for (Relation relation : getEntityType().getInfoRelations()) {
+			updateMap.computeIfAbsent(relation.getName(), k -> new ArrayList<>()).add(relation.createValue());
+		}
+
+		// preserve "empty" relation values for removed related entities
+		EntityStore mutableStore = core.getMutableStore();
+		mutableStore.getRemoved().stream().map(e -> getModelManager().getEntityType(e))
+				.map(getEntityType()::getRelation).map(Relation::getName).forEach(nonUpdatableRelationNames::remove);
+
+		// replace "empty" relation values with corresponding instance IDs
+		setRelationIDs(mutableStore.getCurrent());
+
+		collectChildEntities(core);
+
+		getTransaction().addModified(core);
+	}
+
+	/**
+	 * Collects child entities for recursive processing.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	private void collectChildEntities(Core core) {
+		if (ignoreChildren) {
+			return;
+		}
+
+		for (Entry<Class<? extends Deletable>, List<? extends Deletable>> entry : core.getChildrenStore().getCurrent()
+				.entrySet()) {
+			Map<Boolean, List<Entity>> partition = entry.getValue().stream()
+					.collect(Collectors.partitioningBy(e -> ODSUtils.isValidID(e.getID())));
+			List<Entity> virtualEntities = partition.get(Boolean.FALSE);
+			if (virtualEntities != null && !virtualEntities.isEmpty()) {
+				childrenToCreate.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).addAll(virtualEntities);
+			}
+			List<Entity> existingEntities = partition.get(Boolean.TRUE);
+			if (existingEntities != null && !existingEntities.isEmpty()) {
+				childrenToUpdate.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).addAll(existingEntities);
+			}
+		}
+
+		for (Entry<Class<? extends Deletable>, List<? extends Deletable>> entry : core.getChildrenStore().getRemoved()
+				.entrySet()) {
+			List<Deletable> toDelete = entry.getValue().stream().filter(e -> ODSUtils.isValidID(e.getID()))
+					.collect(Collectors.toList());
+			childrenToRemove.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).addAll(toDelete);
+		}
+	}
+
+	/**
+	 * Overwrites empty foreign key {@link Value} containers.
+	 *
+	 * @param relatedEntities The related {@link Entity}s.
+	 */
+	private void setRelationIDs(Collection<Entity> relatedEntities) {
+		for (Entity relatedEntity : relatedEntities) {
+			if (!ODSUtils.isValidID(relatedEntity.getID())) {
+				throw new IllegalArgumentException("Related entity must be a persited entity.");
+			}
+
+			Relation relation = getEntityType().getRelation(getModelManager().getEntityType(relatedEntity));
+			List<Value> relationValues = updateMap.get(relation.getName());
+			if (relationValues == null) {
+				throw new IllegalStateException("Relation '" + relation
+						+ "' is incompatible with update statement for entity type '" + getEntityType() + "'");
+			}
+			relationValues.get(relationValues.size() - 1).set(relatedEntity.getID());
+			nonUpdatableRelationNames.remove(relation.getName());
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UploadService.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UploadService.java
new file mode 100644
index 0000000..5748049
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/UploadService.java
@@ -0,0 +1,204 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+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.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.asam.ods.AoException;
+import org.eclipse.mdm.api.base.file.FileService.ProgressListener;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
+import org.eclipse.mdm.api.odsadapter.filetransfer.CORBAFileService;
+import org.eclipse.mdm.api.odsadapter.filetransfer.Transfer;
+
+/**
+ * Manages new or removed externally linked files.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+final class UploadService {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+
+	private final Map<TemplateAttribute, Value> templateAttributeFileLinks = new HashMap<>();
+	private final List<FileLink> uploaded = new ArrayList<>();
+	private final Map<InputStream, String> remotePaths = new HashMap<>();
+	private final List<FileLink> toRemove = new ArrayList<>();
+
+	private final CORBAFileService fileService;
+	private final Entity entity;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param context  Used for setup.
+	 * @param entity   Used for security checks.
+	 * @param transfer The transfer type.
+	 */
+	UploadService(ODSContext context, Entity entity, Transfer transfer) {
+		fileService = new CORBAFileService(context, transfer);
+		this.entity = entity;
+
+		scheduler.scheduleAtFixedRate(() -> {
+			try {
+				context.getAoSession().getName();
+			} catch (AoException e) {
+				/*
+				 * NOTE: This is done to keep the parent transaction's session alive till its
+				 * commit or abort method is called. If this session refresh results in an
+				 * error, then any running file transfer will abort with a proper error,
+				 * therefore any exception here is completely ignored and explicitly NOT logged!
+				 */
+			}
+		}, 5, 5, TimeUnit.MINUTES);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Uploads new externally linked files stored in given
+	 * {@link TemplateAttribute}s. The upload progress may be traced with a progress
+	 * listener.
+	 *
+	 * @param templateAttributes The {@link TemplateAttribute}s.
+	 * @param progressListener   The progress listener.
+	 * @throws IOException Thrown if unable to upload files.
+	 */
+	public void upload(Collection<TemplateAttribute> templateAttributes, ProgressListener progressListener)
+			throws IOException {
+		List<FileLink> fileLinks = new ArrayList<>();
+		for (TemplateAttribute templateAttribute : templateAttributes) {
+			Value defaultValue = templateAttribute.getDefaultValue();
+			if (!defaultValue.isValid()) {
+				continue;
+			}
+
+			if (defaultValue.getValueType().isFileLink()) {
+				fileLinks.add(defaultValue.extract());
+			} else if (defaultValue.getValueType().isFileLinkSequence()) {
+				fileLinks.addAll(Arrays.asList((FileLink[]) defaultValue.extract()));
+			} else {
+				throw new IllegalStateException("Template attribute's value type is not of type file link.");
+			}
+
+			templateAttributeFileLinks.put(templateAttribute, defaultValue);
+		}
+
+		if (!fileLinks.isEmpty()) {
+			uploadParallel(fileLinks, progressListener);
+			// remote paths available -> update template attribute
+			templateAttributeFileLinks.forEach((ta, v) -> ta.setDefaultValue(v.extract()));
+		}
+	}
+
+	/**
+	 * Parallel upload of given {@link FileLink}s. Local {@link Path}s linked
+	 * multiple times are uploaded only once. The upload progress may be traced with
+	 * a progress listener.
+	 *
+	 * @param fileLinks        Collection of {@code FileLink}s to upload.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to upload files.
+	 */
+	public void uploadParallel(Collection<FileLink> fileLinks, ProgressListener progressListener) throws IOException {
+		List<FileLink> filtered = retainForUpload(fileLinks);
+		try {
+			fileService.uploadParallel(entity, filtered, progressListener);
+		} finally {
+			filtered.stream().filter(FileLink::isRemote).forEach(fl -> {
+				remotePaths.put(fl.getLocalStream(), fl.getRemotePath());
+				uploaded.add(fl);
+			});
+		}
+	}
+
+	/**
+	 * Once {@link #commit()} is called given {@link FileLink}s will be deleted from
+	 * the remote storage.
+	 *
+	 * @param fileLinks Collection of {@code FileLink}s to delete.
+	 */
+	public void addToRemove(Collection<FileLink> fileLinks) {
+		toRemove.addAll(fileLinks);
+	}
+
+	/**
+	 * Commits modifications of externally linked files.
+	 */
+	public void commit() {
+		fileService.delete(entity, toRemove);
+		scheduler.shutdown();
+	}
+
+	/**
+	 * Aborts modifications of externally linked files.
+	 */
+	public void abort() {
+		fileService.delete(entity, uploaded);
+		uploaded.forEach(fl -> fl.setRemotePath(null));
+		templateAttributeFileLinks.forEach((ta, v) -> ta.setDefaultValue(v.extract()));
+		scheduler.shutdown();
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Filters given {@link FileLink}s by removing already uploaded ones.
+	 *
+	 * @param fileLinks Will be filtered.
+	 * @return Returns {@code FileLink}s which have to be uploaded.
+	 */
+	private List<FileLink> retainForUpload(Collection<FileLink> fileLinks) {
+		List<FileLink> filtered = new ArrayList<>(fileLinks);
+		for (FileLink fileLink : fileLinks) {
+			String remotePath = remotePaths.get(fileLink.getLocalStream());
+			if (remotePath != null && !remotePath.isEmpty()) {
+				fileLink.setRemotePath(remotePath);
+				filtered.remove(fileLink);
+				uploaded.add(fileLink);
+			}
+		}
+
+		return filtered;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/WriteRequestHandler.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/WriteRequestHandler.java
new file mode 100644
index 0000000..912af56
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/transaction/WriteRequestHandler.java
@@ -0,0 +1,168 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.transaction;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.IntStream;
+
+import org.asam.ods.AoException;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.DefaultCore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+
+/**
+ * Writes mass data specified in {@link WriteRequest}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class WriteRequestHandler {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final String AE_LC_ATTR_INDEPENDENT = "IndependentFlag";
+	private static final String AE_LC_ATTR_REPRESENTATION = "SequenceRepresentation";
+	private static final String AE_LC_ATTR_PARAMETERS = "GenerationParameters";
+	private static final String AE_LC_ATTR_RAWDATATYPE = "RawDatatype";
+	private static final String AE_LC_ATTR_AXISTYPE = "axistype";
+	private static final String AE_LC_ATTR_VALUES = "Values";
+	private static final String AE_LC_ATTR_FLAGS = "Flags";
+	private static final String AE_LC_ATTR_GLOBAL_FLAG = "GlobalFlag";
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final List<Core> cores = new ArrayList<>();
+	private final EntityType localColumnEntityType;
+	private final InsertStatement insertStatement;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param transaction The owning {@link ODSTransaction}.
+	 */
+	public WriteRequestHandler(ODSTransaction transaction) {
+		localColumnEntityType = transaction.getModelManager().getEntityType("LocalColumn");
+		insertStatement = new InsertStatement(transaction, localColumnEntityType);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@link WriteRequest} to be processed.
+	 *
+	 * @param writeRequest The {@code WriteRequest}.
+	 */
+	public void addRequest(WriteRequest writeRequest) {
+		cores.add(createCore(writeRequest));
+	}
+
+	/**
+	 * Imports given mass data configurations.
+	 *
+	 * @throws AoException         Thrown if the execution fails.
+	 * @throws DataAccessException Thrown if the execution fails.
+	 * @throws IOException         Thrown if a file transfer operation fails.
+	 */
+	public void execute() throws AoException, DataAccessException, IOException {
+		insertStatement.executeWithCores(cores);
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Reads given {@link WriteRequest} and prepares a corresponding {@link Core}
+	 * for import.
+	 *
+	 * @param writeRequest The mass data configuration.
+	 * @return The created {@code Core} is returned.
+	 */
+	private Core createCore(WriteRequest writeRequest) {
+		Core core = new DefaultCore(localColumnEntityType);
+
+		core.getPermanentStore().set(writeRequest.getChannelGroup());
+		core.getMutableStore().set(writeRequest.getChannel());
+
+		Map<String, Value> values = core.getValues();
+		values.get(Entity.ATTR_NAME).set(writeRequest.getChannel().getName());
+		values.get(Entity.ATTR_MIMETYPE).set("application/x-asam.aolocalcolumn");
+		values.get(AE_LC_ATTR_INDEPENDENT).set((short) (writeRequest.isIndependent() ? 1 : 0));
+		values.get(AE_LC_ATTR_RAWDATATYPE).set(writeRequest.getRawScalarType());
+		values.get(AE_LC_ATTR_REPRESENTATION).set(writeRequest.getSequenceRepresentation());
+		values.get(AE_LC_ATTR_AXISTYPE).set(writeRequest.getAxisType());
+		values.get(AE_LC_ATTR_PARAMETERS).set(writeRequest.getGenerationParameters());
+
+		if (writeRequest.hasValues()) {
+			ValueType<?> valueType = writeRequest.getRawScalarType().toValueType();
+			String unitName = writeRequest.getChannel().getUnit().getName();
+			values.put(AE_LC_ATTR_VALUES,
+					valueType.create(AE_LC_ATTR_VALUES, unitName, true, writeRequest.getValues()));
+
+			// OpenATFX issue: For "implicit" columns, if no value for the
+			// GenerationParameters attribute is present,
+			// it is attempted to transfer the local column values (through which the
+			// generation parameters are
+			// available in these cases) to the GenerationParameters attribute without
+			// converting them to the
+			// correct DS_DOUBLE data type first (unless it is a DOUBLE or LONG column),
+			// resulting in an exception.
+			// Hence, supply correctly converted generation parameters as a workaround:
+			if (writeRequest.getSequenceRepresentation().isImplicit()) {
+				Object genParamValues = writeRequest.getValues();
+				double[] genParamD = new double[Array.getLength(genParamValues)];
+				IntStream.range(0, genParamD.length)
+						.forEach(i -> genParamD[i] = ((Number) Array.get(genParamValues, i)).doubleValue());
+				values.get(AE_LC_ATTR_PARAMETERS).set(genParamD);
+			}
+
+			// flags
+			if (writeRequest.areAllValid()) {
+				values.get(AE_LC_ATTR_GLOBAL_FLAG).set((short) 15);
+			} else {
+				short[] flags = ODSConverter.toODSValidFlagSeq(writeRequest.getFlags());
+				values.get(AE_LC_ATTR_FLAGS).set(flags);
+			}
+		} else if (writeRequest.hasExternalComponents()) {
+			// TODO
+			throw new UnsupportedOperationException("NOT YET IMPLEMENTED.");
+		} else {
+			throw new IllegalStateException("Given write request neither has measured values nor external components");
+		}
+
+		return core;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
new file mode 100644
index 0000000..53273e9
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverter.java
@@ -0,0 +1,1207 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.utils;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.asam.ods.Blob;
+import org.asam.ods.DataType;
+import org.asam.ods.NameValueSeqUnit;
+import org.asam.ods.TS_Union;
+import org.asam.ods.TS_UnionSeq;
+import org.asam.ods.TS_Value;
+import org.asam.ods.TS_ValueSeq;
+import org.asam.ods.T_COMPLEX;
+import org.asam.ods.T_DCOMPLEX;
+import org.asam.ods.T_ExternalReference;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.model.DoubleComplex;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.FloatComplex;
+import org.eclipse.mdm.api.base.model.MeasuredValues;
+import org.eclipse.mdm.api.base.model.MimeType;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.odsadapter.ReadRequestHandler;
+import org.eclipse.mdm.api.odsadapter.query.ODSAttribute;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Utility class for value conversions from/to ODS types.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class ODSConverter {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final Map<Integer, DateTimeFormatter> ODS_DATE_FORMATTERS = new HashMap<>();
+
+	static {
+		ODS_DATE_FORMATTERS.put(4,
+				new DateTimeFormatterBuilder().appendPattern("yyyy").parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
+						.parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter());
+		ODS_DATE_FORMATTERS.put(6, new DateTimeFormatterBuilder().appendPattern("yyyyMM")
+				.parseDefaulting(ChronoField.DAY_OF_MONTH, 1).toFormatter());
+		ODS_DATE_FORMATTERS.put(8, DateTimeFormatter.ofPattern("yyyyMMdd"));
+		ODS_DATE_FORMATTERS.put(10, DateTimeFormatter.ofPattern("yyyyMMddHH"));
+		ODS_DATE_FORMATTERS.put(12, DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
+		ODS_DATE_FORMATTERS.put(14, DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
+		/*
+		 * JDK-8031085: DateTimeFormatter won't parse dates with custom format
+		 * "yyyyMMddHHmmssSSS"
+		 * 
+		 * @see http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8031085
+		 */
+		ODS_DATE_FORMATTERS.put(17, new DateTimeFormatterBuilder().appendPattern("yyyyMMddHHmmss")
+				.appendValue(ChronoField.MILLI_OF_SECOND, 3).toFormatter());
+	}
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 */
+	private ODSConverter() {
+	}
+
+	// ======================================================================
+	// Conversion methods
+	// ======================================================================
+
+	/**
+	 * Converts given {@link TS_ValueSeq} to {@link Value}s.
+	 *
+	 * @param attribute   The {@link Attribute}.
+	 * @param aggregation The {@link Aggregation} used when the values were
+	 *                    obtained.
+	 * @param unit        The unit name.
+	 * @param odsValueSeq The {@code TS_ValueSeq}.
+	 * @return The converted {@code Value}s are returned.
+	 * @throws DataAccessException Thrown on conversion errors.
+	 */
+	public static List<Value> fromODSValueSeq(Attribute attribute, Aggregation aggregation, String unit,
+			TS_ValueSeq odsValueSeq) throws DataAccessException {
+		DataType dataType = odsValueSeq.u.discriminator();
+		short[] flags = odsValueSeq.flag;
+		List<Value> values = new ArrayList<>(flags.length);
+
+		if (((ODSAttribute) attribute).isIdAttribute() && Sets
+				.immutableEnumSet(Aggregation.MINIMUM, Aggregation.MAXIMUM, Aggregation.DISTINCT, Aggregation.NONE)
+				.contains(aggregation)) {
+			if (DataType.DT_LONGLONG == dataType) {
+				T_LONGLONG[] odsValues = odsValueSeq.u.longlongVal();
+				for (int i = 0; i < flags.length; i++) {
+					values.add(createValue(attribute, aggregation, DataType.DT_STRING, unit, flags[i] == 15,
+							Long.toString(fromODSLong(odsValues[i]))));
+				}
+				return values;
+			} else if (DataType.DS_LONGLONG == dataType) {
+				T_LONGLONG[][] odsValues = odsValueSeq.u.longlongSeq();
+				for (int i = 0; i < flags.length; i++) {
+					values.add(createValue(attribute, aggregation, DataType.DS_STRING, unit, flags[i] == 15,
+							toString(odsValues[i])));
+				}
+				return values;
+			} else if (DataType.DT_LONG == dataType) {
+				int[] odsValues = odsValueSeq.u.longVal();
+				for (int i = 0; i < flags.length; i++) {
+					values.add(createValue(attribute, aggregation, DataType.DT_STRING, unit, flags[i] == 15,
+							Integer.toString(odsValues[i])));
+				}
+				return values;
+			} else if (DataType.DS_LONG == dataType) {
+				int[][] odsValues = odsValueSeq.u.longSeq();
+				for (int i = 0; i < flags.length; i++) {
+					values.add(createValue(attribute, aggregation, DataType.DS_STRING, unit, flags[i] == 15,
+							toString(odsValues[i])));
+				}
+				return values;
+			}
+		}
+
+		if (DataType.DT_STRING == dataType) {
+			String[] odsValues = odsValueSeq.u.stringVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_STRING == dataType) {
+			String[][] odsValues = odsValueSeq.u.stringSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_DATE == dataType) {
+			String[] odsValues = odsValueSeq.u.dateVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(
+						createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSDate(odsValues[i])));
+			}
+		} else if (DataType.DS_DATE == dataType) {
+			String[][] odsValues = odsValueSeq.u.dateSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSDateSeq(odsValues[i])));
+			}
+		} else if (DataType.DT_BOOLEAN == dataType) {
+			boolean[] odsValues = odsValueSeq.u.booleanVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_BOOLEAN == dataType) {
+			boolean[][] odsValues = odsValueSeq.u.booleanSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_BYTE == dataType) {
+			byte[] odsValues = odsValueSeq.u.byteVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_BYTE == dataType) {
+			byte[][] odsValues = odsValueSeq.u.byteSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_SHORT == dataType) {
+			short[] odsValues = odsValueSeq.u.shortVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_SHORT == dataType) {
+			short[][] odsValues = odsValueSeq.u.shortSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_LONG == dataType) {
+			int[] odsValues = odsValueSeq.u.longVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_LONG == dataType) {
+			int[][] odsValues = odsValueSeq.u.longSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_LONGLONG == dataType) {
+			T_LONGLONG[] odsValues = odsValueSeq.u.longlongVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(
+						createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSLong(odsValues[i])));
+			}
+		} else if (DataType.DS_LONGLONG == dataType) {
+			T_LONGLONG[][] odsValues = odsValueSeq.u.longlongSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSLongSeq(odsValues[i])));
+			}
+		} else if (DataType.DT_FLOAT == dataType) {
+			float[] odsValues = odsValueSeq.u.floatVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_FLOAT == dataType) {
+			float[][] odsValues = odsValueSeq.u.floatSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_DOUBLE == dataType) {
+			double[] odsValues = odsValueSeq.u.doubleVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_DOUBLE == dataType) {
+			double[][] odsValues = odsValueSeq.u.doubleSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_BYTESTR == dataType) {
+			byte[][] odsValues = odsValueSeq.u.bytestrVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DS_BYTESTR == dataType) {
+			byte[][][] odsValues = odsValueSeq.u.bytestrSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15, odsValues[i]));
+			}
+		} else if (DataType.DT_COMPLEX == dataType) {
+			T_COMPLEX[] odsValues = odsValueSeq.u.complexVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSFloatComplex(odsValues[i])));
+			}
+		} else if (DataType.DS_COMPLEX == dataType) {
+			T_COMPLEX[][] odsValues = odsValueSeq.u.complexSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSFloatComplexSeq(odsValues[i])));
+			}
+		} else if (DataType.DT_DCOMPLEX == dataType) {
+			T_DCOMPLEX[] odsValues = odsValueSeq.u.dcomplexVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSDoubleComplex(odsValues[i])));
+			}
+		} else if (DataType.DS_DCOMPLEX == dataType) {
+			T_DCOMPLEX[][] odsValues = odsValueSeq.u.dcomplexSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSDoubleComplexSeq(odsValues[i])));
+			}
+		} else if (DataType.DT_ENUM == dataType) {
+			int[] odsValues = odsValueSeq.u.enumVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						ODSEnumerations.fromODSEnum(attribute.getEnumObj(), odsValues[i])));
+			}
+		} else if (DataType.DS_ENUM == dataType) {
+			int[][] odsValues = odsValueSeq.u.enumSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						ODSEnumerations.fromODSEnumSeq(attribute.getEnumObj(), odsValues[i])));
+			}
+		} else if (DataType.DT_EXTERNALREFERENCE == dataType) {
+			T_ExternalReference[] odsValues = odsValueSeq.u.extRefVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSExternalReference(odsValues[i])));
+			}
+		} else if (DataType.DS_EXTERNALREFERENCE == dataType) {
+			T_ExternalReference[][] odsValues = odsValueSeq.u.extRefSeq();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(createValue(attribute, aggregation, dataType, unit, flags[i] == 15,
+						fromODSExternalReferenceSeq(odsValues[i])));
+			}
+		} else if (DataType.DT_BLOB == dataType) {
+			Blob[] odsValues = odsValueSeq.u.blobVal();
+			for (int i = 0; i < flags.length; i++) {
+				values.add(
+						createValue(attribute, aggregation, dataType, unit, flags[i] == 15, fromODSBlob(odsValues[i])));
+			}
+		} else {
+			throw new DataAccessException("Conversion for ODS data type '" + dataType.toString() + "' does not exist.");
+		}
+
+		return values;
+	}
+
+	/**
+	 * Creates a {@link Value} from the input.
+	 * 
+	 * @param attribute   The {@link Attribute}
+	 * @param aggregation The {@link Aggregation} used when the input values were
+	 *                    obtained
+	 * @param dataType    The {@link DataType} associated with the input value,
+	 *                    evaluated only if aggregation != {@code Aggregation.NONE},
+	 *                    otherwise that of the attribute is used
+	 * @param unit        The unit of the input value
+	 * @param valid       The validity flag of the input value
+	 * @param input       The input value
+	 * @return The {@link Value} created.
+	 */
+	private static Value createValue(Attribute attribute, Aggregation aggregation, DataType dataType, String unit,
+			boolean valid, Object input) {
+		if (Aggregation.NONE == aggregation) {
+			return attribute.createValue(unit, valid, input);
+		} else {
+			ValueType<?> valueType = ODSUtils.VALUETYPES.inverse().get(dataType);
+			if (valueType.isEnumerationType() && attribute.getValueType().isEnumerationType()
+					&& Sets.immutableEnumSet(Aggregation.MINIMUM, Aggregation.MAXIMUM, Aggregation.DISTINCT)
+							.contains(aggregation)) {
+				return valueType.create(getColumnName(attribute, aggregation), unit, valid, input,
+						attribute.getEnumObj().getName());
+			} else {
+				return valueType.create(getColumnName(attribute, aggregation), unit, valid, input);
+			}
+		}
+	}
+
+	/**
+	 * Returns the name of the attribute with its applied aggregation as returned by
+	 * the ODS Server, for example: MAXIMUM(sortIndex)
+	 * 
+	 * @param attribute
+	 * @param aggregation
+	 * @return the name of the attribute with the applied aggragation
+	 */
+	public static String getColumnName(Attribute attribute, Aggregation aggregation) {
+		return String.format("%s(%s)", aggregation.name(), attribute.getName());
+	}
+
+	private static String[] toString(int[] odsValues) {
+		return IntStream.of(odsValues).mapToObj(Integer::toString).toArray(String[]::new);
+	}
+
+	private static String[] toString(T_LONGLONG[] odsValues) {
+		return Stream.of(odsValues).map(l -> Long.toString(fromODSLong(l))).toArray(String[]::new);
+	}
+
+	/**
+	 * Converts given {@link Value}s to {@link TS_ValueSeq}.
+	 *
+	 * @param values The {@code Value}s.
+	 * @return The converted {@code TS_ValueSeq} is returned.
+	 * @throws DataAccessException Thrown on conversion errors.
+	 */
+	public static TS_ValueSeq toODSValueSeq(Attribute attribute, List<Value> values) throws DataAccessException {
+		int size = values == null ? 0 : values.size();
+		short[] flags = new short[size];
+
+		TS_ValueSeq odsValueSeq = new TS_ValueSeq(new TS_UnionSeq(), flags);
+		if (values == null || size < 1) {
+			odsValueSeq.u._default();
+			return odsValueSeq;
+		}
+
+		ValueType<?> type = values.get(0).getValueType();
+		if (ValueType.STRING == type) {
+			String[] odsValues = new String[size];
+			for (int i = 0; i < size; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			if (((ODSAttribute) attribute).isIdAttribute()) {
+				odsValueSeq.u.longlongVal(toLongLong(odsValues));
+			} else {
+				odsValueSeq.u.stringVal(odsValues);
+			}
+		} else if (ValueType.STRING_SEQUENCE == type) {
+			String[][] odsValues = new String[size][];
+			for (int i = 0; i < size; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			if (((ODSAttribute) attribute).isIdAttribute()) {
+				odsValueSeq.u.longlongSeq(toLongLongSeq(odsValues));
+			} else {
+				odsValueSeq.u.stringSeq(odsValues);
+			}
+
+		} else if (ValueType.DATE == type) {
+			String[] odsValues = new String[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSDate(value.extract());
+			}
+			odsValueSeq.u.dateVal(odsValues);
+		} else if (ValueType.DATE_SEQUENCE == type) {
+			String[][] odsValues = new String[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSDateSeq(value.extract());
+			}
+			odsValueSeq.u.dateSeq(odsValues);
+		} else if (ValueType.BOOLEAN == type) {
+			boolean[] odsValues = new boolean[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.booleanVal(odsValues);
+		} else if (ValueType.BOOLEAN_SEQUENCE == type) {
+			boolean[][] odsValues = new boolean[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.booleanSeq(odsValues);
+		} else if (ValueType.BYTE == type) {
+			byte[] odsValues = new byte[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.byteVal(odsValues);
+		} else if (ValueType.BYTE_SEQUENCE == type) {
+			byte[][] odsValues = new byte[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.byteSeq(odsValues);
+		} else if (ValueType.SHORT == type) {
+			short[] odsValues = new short[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.shortVal(odsValues);
+		} else if (ValueType.SHORT_SEQUENCE == type) {
+			short[][] odsValues = new short[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.shortSeq(odsValues);
+		} else if (ValueType.INTEGER == type) {
+			int[] odsValues = new int[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.longVal(odsValues);
+		} else if (ValueType.INTEGER_SEQUENCE == type) {
+			int[][] odsValues = new int[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.longSeq(odsValues);
+		} else if (ValueType.LONG == type) {
+			T_LONGLONG[] odsValues = new T_LONGLONG[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSLong(value.extract());
+			}
+			odsValueSeq.u.longlongVal(odsValues);
+		} else if (ValueType.LONG_SEQUENCE == type) {
+			T_LONGLONG[][] odsValues = new T_LONGLONG[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSLongSeq(value.extract());
+			}
+			odsValueSeq.u.longlongSeq(odsValues);
+		} else if (ValueType.FLOAT == type) {
+			float[] odsValues = new float[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.floatVal(odsValues);
+		} else if (ValueType.FLOAT_SEQUENCE == type) {
+			float[][] odsValues = new float[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.floatSeq(odsValues);
+		} else if (ValueType.DOUBLE == type) {
+			double[] odsValues = new double[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.doubleVal(odsValues);
+		} else if (ValueType.DOUBLE_SEQUENCE == type) {
+			double[][] odsValues = new double[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.doubleSeq(odsValues);
+		} else if (ValueType.BYTE_STREAM == type) {
+			byte[][] odsValues = new byte[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.bytestrVal(odsValues);
+		} else if (ValueType.BYTE_STREAM_SEQUENCE == type) {
+			byte[][][] odsValues = new byte[size][][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = value.extract();
+			}
+			odsValueSeq.u.bytestrSeq(odsValues);
+		} else if (ValueType.FLOAT_COMPLEX == type) {
+			T_COMPLEX[] odsValues = new T_COMPLEX[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSFloatComplex(value.extract());
+			}
+			odsValueSeq.u.complexVal(odsValues);
+		} else if (ValueType.FLOAT_COMPLEX_SEQUENCE == type) {
+			T_COMPLEX[][] odsValues = new T_COMPLEX[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSFloatComplexSeq(value.extract());
+			}
+			odsValueSeq.u.complexSeq(odsValues);
+		} else if (ValueType.DOUBLE_COMPLEX == type) {
+			T_DCOMPLEX[] odsValues = new T_DCOMPLEX[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSDoubleComplex(value.extract());
+			}
+			odsValueSeq.u.dcomplexVal(odsValues);
+		} else if (ValueType.DOUBLE_COMPLEX_SEQUENCE == type) {
+			T_DCOMPLEX[][] odsValues = new T_DCOMPLEX[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSDoubleComplexSeq(value.extract());
+			}
+			odsValueSeq.u.dcomplexSeq(odsValues);
+		} else if (ValueType.ENUMERATION == type) {
+			int[] odsValues = new int[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = ODSEnumerations.toODSEnum(value.extract());
+			}
+			odsValueSeq.u.enumVal(odsValues);
+		} else if (ValueType.ENUMERATION_SEQUENCE == type) {
+			int[][] odsValues = new int[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = ODSEnumerations.toODSEnumSeq(value.extract());
+			}
+			odsValueSeq.u.enumSeq(odsValues);
+		} else if (ValueType.FILE_LINK == type) {
+			T_ExternalReference[] odsValues = new T_ExternalReference[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSExternalReference(value.extract());
+			}
+			odsValueSeq.u.extRefVal(odsValues);
+		} else if (ValueType.FILE_LINK_SEQUENCE == type) {
+			T_ExternalReference[][] odsValues = new T_ExternalReference[size][];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSExternalReferenceSeq(value.extract());
+			}
+			odsValueSeq.u.extRefSeq(odsValues);
+		} else if (ValueType.BLOB == type) {
+			Blob[] odsValues = new Blob[size];
+			for (int i = 0; i < flags.length; i++) {
+				Value value = values.get(i);
+				flags[i] = toODSValidFlag(value.isValid());
+				odsValues[i] = toODSBlob(value.extract());
+			}
+			odsValueSeq.u.blobVal(odsValues);
+		} else {
+			throw new DataAccessException("Mapping for value type '" + type + "' does not exist.");
+		}
+
+		return odsValueSeq;
+	}
+
+	/**
+	 * Converts given two dimensional String array to two dimensional
+	 * {@link T_LONGLONG} array.
+	 * 
+	 * @param value The String array.
+	 * @return The converted {@link T_LONGLONG} array.
+	 */
+	private static T_LONGLONG[][] toLongLongSeq(String[][] value) {
+
+		return Stream.of(value).map(ODSConverter::toLongLong).toArray(T_LONGLONG[][]::new);
+	}
+
+	/**
+	 * Converts given String array to {@link T_LONGLONG} array.
+	 * 
+	 * @param value The String array.
+	 * @return The converted {@link T_LONGLONG} array.
+	 */
+	private static T_LONGLONG[] toLongLong(String[] value) {
+		return Stream.of(value).map(s -> toODSID(s)).toArray(T_LONGLONG[]::new);
+	}
+
+	/**
+	 * Converts given {@link NameValueSeqUnit[]} to {@link MeasuredValues}s.
+	 *
+	 * @param odsMeasuredValuesSeq The {@code NameValueSeqUnit}s.
+	 * @return The converted {@code MeasuredValues}s are returned.
+	 * @throws DataAccessException Thrown on conversion errors.
+	 */
+	public static List<MeasuredValues> fromODSMeasuredValuesSeq(NameValueSeqUnit[] odsMeasuredValuesSeq,
+			ReadRequestHandler.ColumnAttributes[] columnAttributesArray) throws DataAccessException {
+		List<MeasuredValues> measuredValues = new ArrayList<>(odsMeasuredValuesSeq.length);
+
+		Map<String, ReadRequestHandler.ColumnAttributes> mapColumnAttributes = new HashMap<>();
+		if (null != columnAttributesArray) {
+			Arrays.stream(columnAttributesArray).forEach(ca -> mapColumnAttributes.put(ca.getName(), ca));
+		}
+
+		for (NameValueSeqUnit odsMeasuredValues : odsMeasuredValuesSeq) {
+			measuredValues
+					.add(fromODSMeasuredValues(odsMeasuredValues, mapColumnAttributes.get(odsMeasuredValues.valName)));
+		}
+
+		return measuredValues;
+	}
+
+	/**
+	 * Converts given {@link NameValueSeqUnit} to {@link MeasuredValues}.
+	 *
+	 * @param odsMeasuredValues The {@code NameValueSeqUnit}.
+	 * @return The converted {@code MeasuredValues} is returned.
+	 * @throws DataAccessException Thrown on conversion errors.
+	 */
+	private static MeasuredValues fromODSMeasuredValues(NameValueSeqUnit odsMeasuredValues,
+			ReadRequestHandler.ColumnAttributes columnAttributes) throws DataAccessException {
+		TS_ValueSeq odsValueSeq = odsMeasuredValues.value;
+		DataType dataType = odsValueSeq.u.discriminator();
+		ScalarType scalarType;
+		Object values;
+
+		if (DataType.DT_STRING == dataType) {
+			scalarType = ScalarType.STRING;
+			values = odsValueSeq.u.stringVal();
+		} else if (DataType.DT_DATE == dataType) {
+			scalarType = ScalarType.DATE;
+			values = fromODSDateSeq(odsValueSeq.u.dateVal());
+		} else if (DataType.DT_BOOLEAN == dataType) {
+			scalarType = ScalarType.BOOLEAN;
+			values = odsValueSeq.u.booleanVal();
+		} else if (DataType.DT_BYTE == dataType) {
+			scalarType = ScalarType.BYTE;
+			values = odsValueSeq.u.byteVal();
+		} else if (DataType.DT_SHORT == dataType) {
+			scalarType = ScalarType.SHORT;
+			values = odsValueSeq.u.shortVal();
+		} else if (DataType.DT_LONG == dataType) {
+			scalarType = ScalarType.INTEGER;
+			values = odsValueSeq.u.longVal();
+		} else if (DataType.DT_LONGLONG == dataType) {
+			scalarType = ScalarType.LONG;
+			values = fromODSLongSeq(odsValueSeq.u.longlongVal());
+		} else if (DataType.DT_FLOAT == dataType) {
+			scalarType = ScalarType.FLOAT;
+			values = odsValueSeq.u.floatVal();
+		} else if (DataType.DT_DOUBLE == dataType) {
+			scalarType = ScalarType.DOUBLE;
+			values = odsValueSeq.u.doubleVal();
+		} else if (DataType.DT_BYTESTR == dataType) {
+			scalarType = ScalarType.BYTE_STREAM;
+			values = odsValueSeq.u.bytestrVal();
+		} else if (DataType.DT_COMPLEX == dataType) {
+			scalarType = ScalarType.FLOAT_COMPLEX;
+			values = fromODSFloatComplexSeq(odsValueSeq.u.complexVal());
+		} else if (DataType.DT_DCOMPLEX == dataType) {
+			scalarType = ScalarType.DOUBLE_COMPLEX;
+			values = fromODSDoubleComplexSeq(odsValueSeq.u.dcomplexVal());
+		} else if (DataType.DT_EXTERNALREFERENCE == dataType) {
+			scalarType = ScalarType.FILE_LINK;
+			values = fromODSExternalReferenceSeq(odsValueSeq.u.extRefVal());
+		} else {
+			throw new DataAccessException(
+					"Conversion for ODS measured points of type '" + dataType.toString() + "' does not exist.");
+		}
+
+		if (null == columnAttributes) {
+			columnAttributes = new ReadRequestHandler.ColumnAttributes("", null, new double[0], false, null);
+		}
+
+		return scalarType.createMeasuredValues(odsMeasuredValues.valName, odsMeasuredValues.unit,
+				columnAttributes.getSequenceRepresentation(), columnAttributes.getGenerationParameters(),
+				columnAttributes.isIndependentColumn(), columnAttributes.getAxisType(), values,
+				fromODSValidFlagSeq(odsValueSeq.flag));
+	}
+
+	/**
+	 * Converts given {@link Value} to {@link TS_Value}.
+	 *
+	 * @param value The {@code Value}.
+	 * @return The converted {@code TS_Value} is returned.
+	 * @throws DataAccessException Thrown on conversion errors.
+	 */
+	public static TS_Value toODSValue(Attribute attribute, Value value) throws DataAccessException {
+		TS_Value odsValue = new TS_Value(new TS_Union(), toODSValidFlag(value.isValid()));
+		ValueType<?> type = value.getValueType();
+
+		if (ValueType.STRING == type) {
+			if (((ODSAttribute) attribute).isIdAttribute()) {
+				odsValue.u.longlongVal(ODSConverter.toODSID(value.extract()));
+			} else {
+				odsValue.u.stringVal(value.extract());
+			}
+		} else if (ValueType.STRING_SEQUENCE == type) {
+			if (((ODSAttribute) attribute).isIdAttribute()) {
+				odsValue.u.longlongSeq(
+						Stream.of((String[]) value.extract()).map(ODSConverter::toODSID).toArray(T_LONGLONG[]::new));
+			} else {
+				odsValue.u.stringSeq(value.extract());
+			}
+		} else if (ValueType.DATE == type) {
+			odsValue.u.dateVal(toODSDate(value.extract()));
+		} else if (ValueType.DATE_SEQUENCE == type) {
+			odsValue.u.dateSeq(toODSDateSeq(value.extract()));
+		} else if (ValueType.BOOLEAN == type) {
+			odsValue.u.booleanVal(value.extract());
+		} else if (ValueType.BOOLEAN_SEQUENCE == type) {
+			odsValue.u.booleanVal(value.extract());
+		} else if (ValueType.BYTE == type) {
+			odsValue.u.byteVal(value.extract());
+		} else if (ValueType.BYTE_SEQUENCE == type) {
+			odsValue.u.byteSeq(value.extract());
+		} else if (ValueType.SHORT == type) {
+			odsValue.u.shortVal(value.extract());
+		} else if (ValueType.SHORT_SEQUENCE == type) {
+			odsValue.u.shortSeq(value.extract());
+		} else if (ValueType.INTEGER == type) {
+			odsValue.u.longVal(value.extract());
+		} else if (ValueType.INTEGER_SEQUENCE == type) {
+			odsValue.u.longSeq(value.extract());
+		} else if (ValueType.LONG == type) {
+			odsValue.u.longlongVal(toODSLong(value.extract()));
+		} else if (ValueType.LONG_SEQUENCE == type) {
+			odsValue.u.longlongSeq(toODSLongSeq(value.extract()));
+		} else if (ValueType.FLOAT == type) {
+			odsValue.u.floatVal(value.extract());
+		} else if (ValueType.FLOAT_SEQUENCE == type) {
+			odsValue.u.floatSeq(value.extract());
+		} else if (ValueType.DOUBLE == type) {
+			odsValue.u.doubleVal(value.extract());
+		} else if (ValueType.DOUBLE_SEQUENCE == type) {
+			odsValue.u.doubleSeq(value.extract());
+		} else if (ValueType.BYTE_STREAM == type) {
+			odsValue.u.bytestrVal(value.extract());
+		} else if (ValueType.BYTE_STREAM_SEQUENCE == type) {
+			odsValue.u.bytestrSeq(value.extract());
+		} else if (ValueType.FLOAT_COMPLEX == type) {
+			odsValue.u.complexVal(toODSFloatComplex(value.extract()));
+		} else if (ValueType.FLOAT_COMPLEX_SEQUENCE == type) {
+			odsValue.u.complexSeq(toODSFloatComplexSeq(value.extract()));
+		} else if (ValueType.DOUBLE_COMPLEX == type) {
+			odsValue.u.dcomplexVal(toODSDoubleComplex(value.extract()));
+		} else if (ValueType.DOUBLE_COMPLEX_SEQUENCE == type) {
+			odsValue.u.dcomplexSeq(toODSDoubleComplexSeq(value.extract()));
+		} else if (ValueType.ENUMERATION == type) {
+			odsValue.u.enumVal(ODSEnumerations.toODSEnum(value.extract()));
+		} else if (ValueType.ENUMERATION_SEQUENCE == type) {
+			odsValue.u.enumSeq(ODSEnumerations.toODSEnumSeq(value.extract()));
+		} else if (ValueType.FILE_LINK == type) {
+			odsValue.u.extRefVal(toODSExternalReference(value.extract()));
+		} else if (ValueType.FILE_LINK_SEQUENCE == type) {
+			odsValue.u.extRefSeq(toODSExternalReferenceSeq(value.extract()));
+		} else if (ValueType.BLOB == type) {
+			odsValue.u.blobVal(toODSBlob(value.extract()));
+		} else {
+			throw new DataAccessException("Mapping for value type '" + type + "' does not exist.");
+		}
+
+		return odsValue;
+	}
+
+	/**
+	 * Converts given {@link short[]} to {@link boolean[]}.
+	 *
+	 * @param input The {@code short}s.
+	 * @return The converted {@code boolean}s are returned.
+	 */
+	private static boolean[] fromODSValidFlagSeq(short[] input) {
+		boolean[] result = new boolean[input.length];
+		for (int i = 0; i < result.length; i++) {
+			result[i] = fromODSValidFlag(input[i]);
+		}
+
+		return result;
+	}
+
+	/**
+	 * Converts given {@link short} to {@link boolean}.
+	 *
+	 * @param input The {@code short}.
+	 * @return The converted {@code boolean} is returned.
+	 */
+	private static boolean fromODSValidFlag(short input) {
+		return input == 15;
+	}
+
+	/**
+	 * Converts given {@link boolean[]} to {@link short[]}.
+	 *
+	 * @param input The {@code boolean}s.
+	 * @return The converted {@code short}s are returned.
+	 */
+	public static short[] toODSValidFlagSeq(boolean[] input) {
+		short[] result = new short[input.length];
+		for (int i = 0; i < result.length; i++) {
+			result[i] = toODSValidFlag(input[i]);
+		}
+
+		return result;
+	}
+
+	/**
+	 * Converts given {@link boolean} to {@link short}.
+	 *
+	 * @param input The {@code boolean}.
+	 * @return The converted {@code short} is returned.
+	 */
+	public static short toODSValidFlag(boolean input) {
+		return (short) (input ? 15 : 0);
+	}
+
+	/**
+	 * Converts given {@link T_LONGLONG[]} to {@link long[]}.
+	 *
+	 * @param input The {@code T_LONGLONG}s.
+	 * @return The converted {@code long}s are returned.
+	 */
+	private static long[] fromODSLongSeq(T_LONGLONG[] input) {
+		long[] result = new long[input.length];
+		for (int i = 0; i < result.length; i++) {
+			result[i] = fromODSLong(input[i]);
+		}
+
+		return result;
+	}
+
+	/**
+	 * Converts given {@link T_LONGLONG} to {@link long}.
+	 *
+	 * @param input The {@code T_LONGLONG}.
+	 * @return The converted {@code long} is returned.
+	 */
+	public static long fromODSLong(T_LONGLONG input) {
+		T_LONGLONG value = input == null ? new T_LONGLONG() : input;
+		return (value.high + (value.low >= 0 ? 0 : 1)) * 0x100000000L + value.low;
+	}
+
+	/**
+	 * Converts given {@link long[]} to {@link T_LONGLONG[]}.
+	 *
+	 * @param input The {@code long}s.
+	 * @return The converted {@code T_LONGLONG}s are returned.
+	 */
+	private static T_LONGLONG[] toODSLongSeq(long[] input) {
+		List<T_LONGLONG> result = new ArrayList<>(input.length);
+		for (long value : input) {
+			result.add(toODSLong(value));
+		}
+
+		return result.toArray(new T_LONGLONG[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link long} to {@link T_LONGLONG}.
+	 *
+	 * @param input The {@code long}.
+	 * @return The converted {@code T_LONGLONG} is returned.
+	 */
+	public static T_LONGLONG toODSLong(long input) {
+		return new T_LONGLONG((int) (input >> 32 & 0xffffffffL), (int) (input & 0xffffffffL));
+	}
+
+	/**
+	 * Converts a given MDM ID string to {@link T_LONGLONG}.
+	 * 
+	 * @param input The MDM ID string.
+	 * @return The converted {@code T_LONGLONG} is returned.
+	 */
+	public static T_LONGLONG toODSID(String input) {
+		try {
+			return toODSLong(Long.valueOf(input));
+		} catch (NumberFormatException e) {
+			return new T_LONGLONG();
+		}
+	}
+
+	/**
+	 * Converts given {@link String[]} to {@link LocalDateTime[]}.
+	 *
+	 * @param input The {@code String}s.
+	 * @return The converted {@code LocalDateTime}s are returned.
+	 */
+	private static LocalDateTime[] fromODSDateSeq(String[] input) {
+		List<LocalDateTime> result = new ArrayList<>();
+		if (input != null) {
+			for (String value : input) {
+				result.add(fromODSDate(value));
+			}
+		}
+
+		return result.toArray(new LocalDateTime[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link String} to {@link LocalDateTime}.
+	 *
+	 * @param input The {@code T_COMPLEX}.
+	 * @return The converted {@code String} is returned.
+	 */
+	private static LocalDateTime fromODSDate(String input) {
+		if (input == null || input.isEmpty()) {
+			return null;
+		}
+
+		DateTimeFormatter formatter = ODS_DATE_FORMATTERS.get(input.length());
+		if (formatter == null) {
+			throw new IllegalArgumentException("Invalid ODS date: " + input);
+		}
+
+		try {
+			if (input.length() <= 8) {
+				// Java does not accept a bare date as DateTime, so we are using LocalDate
+				// instead of LocalDateTime
+				return LocalDate.parse(input, formatter).atStartOfDay();
+			} else {
+				return LocalDateTime.parse(input, formatter);
+			}
+		} catch (DateTimeParseException e) {
+			throw new IllegalArgumentException("Invalid ODS date: " + input, e);
+		}
+	}
+
+	/**
+	 * Converts given {@link LocalDateTime[]} to {@link String[]}.
+	 *
+	 * @param input The {@code LocalDateTime}s.
+	 * @return The converted {@code String}s are returned.
+	 */
+	private static String[] toODSDateSeq(LocalDateTime[] input) {
+		List<String> result = new ArrayList<>(input.length);
+		for (LocalDateTime value : input) {
+			result.add(toODSDate(value));
+		}
+
+		return result.toArray(new String[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link LocalDateTime} to {@link String}.
+	 *
+	 * @param input The {@code LocalDateTime}.
+	 * @return The converted {@code String} is returned.
+	 */
+	private static String toODSDate(LocalDateTime input) {
+		return input == null ? "" : input.format(ODS_DATE_FORMATTERS.get(14));
+	}
+
+	/**
+	 * Converts given {@link T_COMPLEX[]} to {@link FloatComplex[]}.
+	 *
+	 * @param input The {@code T_COMPLEX}s.
+	 * @return The converted {@code FloatComplex}s are returned.
+	 */
+	private static FloatComplex[] fromODSFloatComplexSeq(T_COMPLEX[] input) {
+		List<FloatComplex> result = new ArrayList<>();
+		if (input != null) {
+			for (T_COMPLEX value : input) {
+				result.add(fromODSFloatComplex(value));
+			}
+		}
+
+		return result.toArray(new FloatComplex[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link T_COMPLEX} to {@link FloatComplex}.
+	 *
+	 * @param input The {@code T_COMPLEX}.
+	 * @return The converted {@code FloatComplex} is returned.
+	 */
+	private static FloatComplex fromODSFloatComplex(T_COMPLEX input) {
+		return input == null ? null : new FloatComplex(input.r, input.i);
+	}
+
+	/**
+	 * Converts given {@link FloatComplex[]} to {@link T_COMPLEX[]}.
+	 *
+	 * @param input The {@code FloatComplex}s.
+	 * @return The converted {@code T_COMPLEX}s are returned.
+	 */
+	private static T_COMPLEX[] toODSFloatComplexSeq(FloatComplex[] input) {
+		List<T_COMPLEX> result = new ArrayList<>(input.length);
+		for (FloatComplex value : input) {
+			result.add(toODSFloatComplex(value));
+		}
+
+		return result.toArray(new T_COMPLEX[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link FloatComplex} to {@link T_COMPLEX}.
+	 *
+	 * @param input The {@code FloatComplex}.
+	 * @return The converted {@code T_COMPLEX} is returned.
+	 */
+	private static T_COMPLEX toODSFloatComplex(FloatComplex input) {
+		return input == null ? null : new T_COMPLEX(input.real(), input.imaginary());
+	}
+
+	/**
+	 * Converts given {@link T_DCOMPLEX[]} to {@link DoubleComplex[]}.
+	 *
+	 * @param input The {@code T_DCOMPLEX}s.
+	 * @return The converted {@code DoubleComplex}s are returned.
+	 */
+	private static DoubleComplex[] fromODSDoubleComplexSeq(T_DCOMPLEX[] input) {
+		List<DoubleComplex> result = new ArrayList<>();
+		if (input != null) {
+			for (T_DCOMPLEX value : input) {
+				result.add(fromODSDoubleComplex(value));
+			}
+		}
+
+		return result.toArray(new DoubleComplex[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link T_DCOMPLEX} to {@link DoubleComplex}.
+	 *
+	 * @param input The {@code T_DCOMPLEX}.
+	 * @return The converted {@code DoubleComplex} is returned.
+	 */
+	private static DoubleComplex fromODSDoubleComplex(T_DCOMPLEX input) {
+		return input == null ? null : new DoubleComplex(input.r, input.i);
+	}
+
+	/**
+	 * Converts given {@link DoubleComplex[]} to {@link T_DCOMPLEX[]}.
+	 *
+	 * @param input The {@code DoubleComplex}s.
+	 * @return The converted {@code T_DCOMPLEX}s are returned.
+	 */
+	private static T_DCOMPLEX[] toODSDoubleComplexSeq(DoubleComplex[] input) {
+		List<T_DCOMPLEX> result = new ArrayList<>(input.length);
+		for (DoubleComplex value : input) {
+			result.add(toODSDoubleComplex(value));
+		}
+
+		return result.toArray(new T_DCOMPLEX[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link DoubleComplex} to {@link T_DCOMPLEX}.
+	 *
+	 * @param input The {@code DoubleComplex}.
+	 * @return The converted {@code T_DCOMPLEX} is returned.
+	 */
+	private static T_DCOMPLEX toODSDoubleComplex(DoubleComplex input) {
+		return input == null ? null : new T_DCOMPLEX(input.real(), input.imaginary());
+	}
+
+	/**
+	 * Converts given {@link T_ExternalReference[]} to {@link FileLink[]}.
+	 *
+	 * @param input The {@code T_ExternalReference}s.
+	 * @return The converted {@code FileLink}s are returned.
+	 */
+	private static FileLink[] fromODSExternalReferenceSeq(T_ExternalReference[] input) {
+		List<FileLink> result = new ArrayList<>();
+		if (input != null) {
+			for (T_ExternalReference value : input) {
+				result.add(fromODSExternalReference(value));
+			}
+		}
+
+		return result.toArray(new FileLink[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link T_ExternalReference} to {@link FileLink}.
+	 *
+	 * @param input The {@code T_ExternalReference}.
+	 * @return The converted {@code FileLink} is returned.
+	 */
+	private static FileLink fromODSExternalReference(T_ExternalReference input) {
+		if (input == null) {
+			return null;
+		}
+		return FileLink.newRemote(input.location, new MimeType(input.mimeType), input.description);
+	}
+
+	/**
+	 * Converts given {@link FileLink[]} to {@link T_ExternalReference[]}.
+	 *
+	 * @param input The {@code FileLink}s.
+	 * @return The converted {@code T_ExternalReference}s are returned.
+	 */
+	private static T_ExternalReference[] toODSExternalReferenceSeq(FileLink[] input) {
+		List<T_ExternalReference> result = new ArrayList<>(input.length);
+		for (FileLink value : input) {
+			result.add(toODSExternalReference(value));
+		}
+
+		return result.toArray(new T_ExternalReference[result.size()]);
+	}
+
+	/**
+	 * Converts given {@link FileLink} to {@link T_ExternalReference}.
+	 *
+	 * @param input The {@code FileLink}.
+	 * @return The converted {@code T_ExternalReference} is returned.
+	 */
+	private static T_ExternalReference toODSExternalReference(FileLink input) {
+		if (input == null) {
+			return new T_ExternalReference("", "", "");
+		}
+		String remotePath = input.isRemote() ? input.getRemotePath() : "";
+		return new T_ExternalReference(input.getDescription(), input.getMimeType().toString(), remotePath);
+	}
+
+	/**
+	 * Converts given {@link Blob} to {@link Object}.
+	 *
+	 * @param input The {@code Blob}
+	 * @return The converted {@code Object} is returned.
+	 */
+	private static Object fromODSBlob(Blob input) {
+		throw new UnsupportedOperationException("NOT YET IMPLEMENTED");
+	}
+
+	/**
+	 * Converts given object to {@link Blob}.
+	 *
+	 * @param input The object.
+	 * @return The converted {@code Blob} is returned.
+	 */
+	private static Blob toODSBlob(Object input) {
+		throw new UnsupportedOperationException("NOT YET IMPLEMENTED");
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSEnum.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSEnum.java
new file mode 100755
index 0000000..2bf11d9
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSEnum.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.utils;
+
+import org.eclipse.mdm.api.base.model.EnumerationValue;
+
+/**
+ * Special enumeration class for ODS enumerations
+ *
+ */
+public class ODSEnum extends EnumerationValue {
+	/**
+	 * Constructor
+	 * 
+	 * @param name:    the text representation of the enumeration value
+	 * @param ordinal: the numeric representation of the enumeration value
+	 */
+	public ODSEnum(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSEnumerations.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSEnumerations.java
new file mode 100644
index 0000000..76cc4d5
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSEnumerations.java
@@ -0,0 +1,465 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.utils;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.EnumerationValue;
+import org.eclipse.mdm.api.base.model.Interpolation;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+import org.eclipse.mdm.api.base.model.TypeSpecification;
+import org.eclipse.mdm.api.base.model.VersionState;
+
+/**
+ * Utility class for enumeration constant conversions from/to ODS types.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class ODSEnumerations {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final String SCALAR_TYPE_NAME = "datatype_enum";
+	private static final String STATE_NAME = "valid_enum";
+	private static final String INTERPOLATION_NAME = "interpolation_enum";
+	private static final String AXIS_TYPE_NAME = "axistype";
+	private static final String TYPE_SPECIFICATION_NAME = "typespec_enum";
+	private static final String SEQUENCE_REPRESENTATION_NAME = "seq_rep_enum";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 */
+	private ODSEnumerations() {
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the enumeration class identified by given name.
+	 *
+	 * @param <E>  The enumeration type.
+	 * @param name The ODS name of the requested enumeration class.
+	 * @return The corresponding enumeration class is returned.
+	 * @throws IllegalArgumentException Thrown if ODS enumeration name is unknown.
+	 */
+	// FIXME (Florian Schmitt): can we do this simpler?
+	public static Enumeration<? extends EnumerationValue> getEnumObj(String name) {
+		EnumRegistry er = EnumRegistry.getInstance();
+		if (SCALAR_TYPE_NAME.equals(name)) {
+			return (er.get(EnumRegistry.SCALAR_TYPE));
+		} else if (STATE_NAME.equals(name)) {
+			return (er.get(EnumRegistry.VERSION_STATE));
+		} else if (INTERPOLATION_NAME.equals(name)) {
+			return (er.get(EnumRegistry.INTERPOLATION));
+		} else if (AXIS_TYPE_NAME.equals(name)) {
+			return (er.get(EnumRegistry.AXIS_TYPE));
+		} else if (TYPE_SPECIFICATION_NAME.equals(name)) {
+			return (er.get(EnumRegistry.TYPE_SPECIFICATION));
+		} else if (SEQUENCE_REPRESENTATION_NAME.equals(name)) {
+			return (er.get(EnumRegistry.SEQUENCE_REPRESENTATION));
+		} else {
+			return er.get(name);
+		}
+	}
+
+	/**
+	 * Returns the ODS enumeration name for given enumeration class.
+	 *
+	 * @param enumObj The enumeration object.
+	 * @return The corresponding ODS enumeration name is returned.
+	 * @throws IllegalArgumentException Thrown if enumeration class is unknown.
+	 */
+	public static String getEnumName(Enumeration<?> enumObj) {
+		if (enumObj == null) {
+			throw new IllegalArgumentException("EnumerationValue class is not allowed to be null.");
+		} else if (EnumRegistry.SCALAR_TYPE.equals(enumObj.getName())) {
+			return SCALAR_TYPE_NAME;
+		} else if (EnumRegistry.VERSION_STATE.equals(enumObj.getName())) {
+			return STATE_NAME;
+		} else if (EnumRegistry.INTERPOLATION.equals(enumObj.getName())) {
+			return INTERPOLATION_NAME;
+		} else if (EnumRegistry.AXIS_TYPE.equals(enumObj.getName())) {
+			return AXIS_TYPE_NAME;
+		} else if (EnumRegistry.TYPE_SPECIFICATION.equals(enumObj.getName())) {
+			return TYPE_SPECIFICATION_NAME;
+		} else if (EnumRegistry.SEQUENCE_REPRESENTATION.equals(enumObj.getName())) {
+			return SEQUENCE_REPRESENTATION_NAME;
+		} else {
+			return enumObj.getName();
+		}
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Converts given ODS enumeration value using given enumeration class to the
+	 * corresponding enumeration constant.
+	 *
+	 * @param <E>       The enumeration type.
+	 * @param enumClass The enumeration class.
+	 * @param value     The ODS enumeration value.
+	 * @return The corresponding enumeration constant is returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	@SuppressWarnings("unchecked")
+	// FIXME: cant we have this easier?
+	static <E extends EnumerationValue> E fromODSEnum(Enumeration<E> enumObj, int value) {
+		if (enumObj == null) {
+			throw new IllegalArgumentException("EnumerationValue class is not allowed to be null.");
+		} else if (EnumRegistry.SCALAR_TYPE.equals(enumObj.getName())) {
+			return (E) fromODSScalarType(value);
+		} else if (EnumRegistry.SEQUENCE_REPRESENTATION.equals(enumObj.getName())) {
+			return (E) fromODSSequenceRepresentation(value);
+		} else {
+			return (E) fromODSEnumByOrdinal(enumObj, value);
+		}
+	}
+
+	/**
+	 * Converts given ODS enumeration values using given enumeration class to the
+	 * corresponding enumeration constants.
+	 *
+	 * @param <E>       The enumeration type.
+	 * @param enumClass The enumeration class.
+	 * @param values    The ODS enumeration values.
+	 * @return The corresponding enumeration constants are returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	@SuppressWarnings("unchecked")
+	static <E extends EnumerationValue> E[] fromODSEnumSeq(Enumeration<?> enumObj, int[] values) {
+		if (enumObj == null) {
+			throw new IllegalArgumentException("EnumerationValue class is not allowed to be null.");
+		} else if (EnumRegistry.SCALAR_TYPE.equals(enumObj.getName())) {
+			List<E> scalarTypes = new ArrayList<>(values.length);
+			for (int value : values) {
+				scalarTypes.add((E) fromODSScalarType(value));
+			}
+			return (E[]) scalarTypes.toArray(new ScalarType[values.length]);
+		} else if (EnumRegistry.SEQUENCE_REPRESENTATION.equals(enumObj.getName())) {
+			List<E> sequenceRepresentations = new ArrayList<>(values.length);
+			for (int value : values) {
+				sequenceRepresentations.add((E) fromODSSequenceRepresentation(value));
+			}
+			return (E[]) sequenceRepresentations.toArray(new SequenceRepresentation[values.length]);
+		} else {
+			return (E[]) fromODSEnumSeqByOrdinal(enumObj, values);
+		}
+	}
+
+	/**
+	 * Converts given enumeration constant to the corresponding ODS enumeration
+	 * value.
+	 *
+	 * @param <E>      The enumeration type.
+	 * @param constant The enumeration constant.
+	 * @return The corresponding ODS enumeration value is returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	static <E extends EnumerationValue> int toODSEnum(E constant) {
+		if (constant == null) {
+			return 0;
+		} else if (constant instanceof ScalarType) {
+			return toODSScalarType((ScalarType) constant);
+		} else if (constant instanceof VersionState || constant instanceof Interpolation || constant instanceof AxisType
+				|| constant instanceof TypeSpecification) {
+			// NOTE: Ordinal numbers map directly to the corresponding ODS
+			// enumeration constant value.
+			return constant.ordinal();
+		} else if (constant instanceof SequenceRepresentation) {
+			return toODSSequenceRepresentation((SequenceRepresentation) constant);
+		}
+
+		throw new IllegalArgumentException(
+				"EnumerationValue mapping for type '" + constant.getClass().getSimpleName() + "' does not exist.");
+	}
+
+	/**
+	 * Converts given enumeration constants to the corresponding ODS enumeration
+	 * values.
+	 *
+	 * @param <E>       The enumeration type.
+	 * @param constants The enumeration constants.
+	 * @return The corresponding ODS enumeration values are returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	static <E extends EnumerationValue> int[] toODSEnumSeq(E[] constants) {
+		if (constants == null) {
+			return new int[0];
+		}
+
+		int[] values = new int[constants.length];
+		if (constants instanceof ScalarType[]) {
+			for (int i = 0; i < values.length; i++) {
+				values[i] = toODSScalarType((ScalarType) constants[i]);
+			}
+		} else if (constants instanceof VersionState[] || constants instanceof Interpolation[]
+				|| constants instanceof AxisType[] || constants instanceof TypeSpecification[]) {
+			for (int i = 0; i < values.length; i++) {
+				// NOTE: Ordinal numbers directly map to the corresponding ODS
+				// enumeration constant value.
+				// FIXME: do we really want this?
+				values[i] = ((EnumerationValue) constants[i]).ordinal();
+			}
+		} else if (constants instanceof SequenceRepresentation[]) {
+			for (int i = 0; i < values.length; i++) {
+				values[i] = toODSSequenceRepresentation((SequenceRepresentation) constants[i]);
+			}
+		} else {
+			throw new IllegalArgumentException("EnumerationValue mapping for type '"
+					+ constants.getClass().getComponentType().getSimpleName() + "' does not exist.");
+		}
+
+		return values;
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Converts given ODS enumeration value to the corresponding {@link ScalarType}
+	 * constant.
+	 *
+	 * @param value The ODS enumeration value.
+	 * @return The corresponding {@code ScalarType} constant is returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	private static ScalarType fromODSScalarType(int value) {
+		if (value == 0) {
+			return ScalarType.UNKNOWN;
+		} else if (value == 1) {
+			return ScalarType.STRING;
+		} else if (value == 2) {
+			return ScalarType.SHORT;
+		} else if (value == 3) {
+			return ScalarType.FLOAT;
+		} else if (value == 4) {
+			return ScalarType.BOOLEAN;
+		} else if (value == 5) {
+			return ScalarType.BYTE;
+		} else if (value == 6) {
+			return ScalarType.INTEGER;
+		} else if (value == 7) {
+			return ScalarType.DOUBLE;
+		} else if (value == 8) {
+			return ScalarType.LONG;
+		} else if (value == 10) {
+			return ScalarType.DATE;
+		} else if (value == 11) {
+			return ScalarType.BYTE_STREAM;
+		} else if (value == 12) {
+			return ScalarType.BLOB;
+		} else if (value == 13) {
+			return ScalarType.FLOAT_COMPLEX;
+		} else if (value == 14) {
+			return ScalarType.DOUBLE_COMPLEX;
+		} else if (value == 28) {
+			return ScalarType.FILE_LINK;
+		} else if (value == 30) {
+			return ScalarType.ENUMERATION;
+		}
+
+		throw new IllegalArgumentException("Unable to map ODS enumeration vaue '" + value + "' to constant of type '"
+				+ ScalarType.class.getSimpleName() + "'.");
+	}
+
+	/**
+	 * Converts given {@link ScalarType} to the corresponding ODS enumeration value.
+	 *
+	 * @param scalarType The {@code ScalarType}.
+	 * @return The corresponding ODS enumeration value is returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	private static int toODSScalarType(ScalarType scalarType) {
+		if (ScalarType.UNKNOWN == scalarType) {
+			return 0;
+		} else if (ScalarType.STRING == scalarType) {
+			return 1;
+		} else if (ScalarType.SHORT == scalarType) {
+			return 2;
+		} else if (ScalarType.FLOAT == scalarType) {
+			return 3;
+		} else if (ScalarType.BOOLEAN == scalarType) {
+			return 4;
+		} else if (ScalarType.BYTE == scalarType) {
+			return 5;
+		} else if (ScalarType.INTEGER == scalarType) {
+			return 6;
+		} else if (ScalarType.DOUBLE == scalarType) {
+			return 7;
+		} else if (ScalarType.LONG == scalarType) {
+			return 8;
+		} else if (ScalarType.DATE == scalarType) {
+			return 10;
+		} else if (ScalarType.BYTE_STREAM == scalarType) {
+			return 11;
+		} else if (ScalarType.BLOB == scalarType) {
+			return 12;
+		} else if (ScalarType.FLOAT_COMPLEX == scalarType) {
+			return 13;
+		} else if (ScalarType.DOUBLE_COMPLEX == scalarType) {
+			return 14;
+		} else if (ScalarType.FILE_LINK == scalarType) {
+			return 28;
+		} else if (ScalarType.ENUMERATION == scalarType) {
+			return 30;
+		}
+
+		throw new IllegalArgumentException("Unable to map enumeration constant '" + scalarType + "' of type '"
+				+ ScalarType.class.getSimpleName() + "' to ODS enumeration value.");
+	}
+
+	/**
+	 * Converts given ODS enumeration value to the corresponding
+	 * {@link SequenceRepresentation} constant.
+	 *
+	 * @param value The ODS enumeration value.
+	 * @return The corresponding {@code SequenceRepresentation} constant is
+	 *         returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	private static SequenceRepresentation fromODSSequenceRepresentation(int value) {
+		if (value == 0) {
+			return SequenceRepresentation.EXPLICIT;
+		} else if (value == 1) {
+			return SequenceRepresentation.IMPLICIT_CONSTANT;
+		} else if (value == 2) {
+			return SequenceRepresentation.IMPLICIT_LINEAR;
+		} else if (value == 3) {
+			return SequenceRepresentation.IMPLICIT_SAW;
+		} else if (value == 4) {
+			return SequenceRepresentation.RAW_LINEAR;
+		} else if (value == 5) {
+			return SequenceRepresentation.RAW_POLYNOMIAL;
+		} else if (value == 7) {
+			return SequenceRepresentation.EXPLICIT_EXTERNAL;
+		} else if (value == 8) {
+			return SequenceRepresentation.RAW_LINEAR_EXTERNAL;
+		} else if (value == 9) {
+			return SequenceRepresentation.RAW_POLYNOMIAL_EXTERNAL;
+		} else if (value == 10) {
+			return SequenceRepresentation.RAW_LINEAR_CALIBRATED;
+		} else if (value == 11) {
+			return SequenceRepresentation.RAW_LINEAR_CALIBRATED_EXTERNAL;
+		}
+
+		throw new IllegalArgumentException("Unable to map ODS enumeration vaue '" + value + "' to constant of type '"
+				+ SequenceRepresentation.class.getSimpleName() + "'.");
+	}
+
+	/**
+	 * Converts given {@link SequenceRepresentation} to the corresponding ODS
+	 * enumeration value.
+	 *
+	 * @param sequenceRepresentation The {@code SequenceRepresentation}.
+	 * @return The corresponding ODS enumeration value is returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	private static int toODSSequenceRepresentation(SequenceRepresentation sequenceRepresentation) {
+		if (SequenceRepresentation.EXPLICIT == sequenceRepresentation) {
+			return 0;
+		} else if (SequenceRepresentation.IMPLICIT_CONSTANT == sequenceRepresentation) {
+			return 1;
+		} else if (SequenceRepresentation.IMPLICIT_LINEAR == sequenceRepresentation) {
+			return 2;
+		} else if (SequenceRepresentation.IMPLICIT_SAW == sequenceRepresentation) {
+			return 3;
+		} else if (SequenceRepresentation.RAW_LINEAR == sequenceRepresentation) {
+			return 4;
+		} else if (SequenceRepresentation.RAW_POLYNOMIAL == sequenceRepresentation) {
+			return 5;
+		} else if (SequenceRepresentation.EXPLICIT_EXTERNAL == sequenceRepresentation) {
+			return 7;
+		} else if (SequenceRepresentation.RAW_LINEAR_EXTERNAL == sequenceRepresentation) {
+			return 8;
+		} else if (SequenceRepresentation.RAW_POLYNOMIAL_EXTERNAL == sequenceRepresentation) {
+			return 9;
+		} else if (SequenceRepresentation.RAW_LINEAR_CALIBRATED == sequenceRepresentation) {
+			return 10;
+		} else if (SequenceRepresentation.RAW_LINEAR_CALIBRATED_EXTERNAL == sequenceRepresentation) {
+			return 11;
+		}
+
+		throw new IllegalArgumentException("Unable to map enumeration constant '" + sequenceRepresentation
+				+ "' of type '" + SequenceRepresentation.class.getSimpleName() + "' to ODS enumeration value.");
+	}
+
+	/**
+	 * Converts given ODS enumeration value to the corresponding enumeration
+	 * constant. The ODS enumeration value is used as the ordinal number of the
+	 * requested enumeration constant.
+	 *
+	 * @param <E>       The enumeration type.
+	 * @param enumClass The enumeration class.
+	 * @param value     The ODS enumeration value.
+	 * @return The corresponding enumeration constant is returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	private static <E extends EnumerationValue> E fromODSEnumByOrdinal(Enumeration<E> enumObj, int value) {
+		// NOTE: Ordinal numbers directly map to the corresponding ODS
+		// enumeration constant value.
+		E enumvalue = enumObj.valueOf(value);
+		if (enumvalue == null) {
+			throw new IllegalArgumentException();
+		}
+		return enumvalue;
+	}
+
+	/**
+	 * Converts given ODS enumeration values to the corresponding enumeration
+	 * constants. The ODS enumeration values are used as the ordinal numbers of the
+	 * requested enumeration constants.
+	 *
+	 * @param <E>       The enumeration type.
+	 * @param enumClass The enumeration class.
+	 * @param values    The ODS enumeration values.
+	 * @return The corresponding enumeration constants are returned.
+	 * @throws IllegalArgumentException Thrown if conversion not possible.
+	 */
+	@SuppressWarnings("unchecked")
+	private static <E extends EnumerationValue> E[] fromODSEnumSeqByOrdinal(Enumeration<E> enumObj, int[] values) {
+		List<E> enumValues = new ArrayList<>(values.length);
+
+		for (int value : values) {
+			// NOTE: Ordinal numbers directly map to the corresponding ODS
+			// enumeration constant value.
+			E enumvalue = enumObj.valueOf(value);
+			if (enumvalue == null) {
+				throw new IllegalArgumentException();
+			}
+			enumValues.add(enumvalue);
+		}
+
+		return enumValues.toArray((E[]) Array.newInstance(enumObj.getClass(), values.length));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSUtils.java b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSUtils.java
new file mode 100644
index 0000000..8cd50f3
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/java/org/eclipse/mdm/api/odsadapter/utils/ODSUtils.java
@@ -0,0 +1,138 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.utils;
+
+import org.asam.ods.AggrFunc;
+import org.asam.ods.DataType;
+import org.asam.ods.SelOpcode;
+import org.asam.ods.SelOperator;
+import org.eclipse.mdm.api.base.adapter.RelationType;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.base.query.BooleanOperator;
+import org.eclipse.mdm.api.base.query.BracketOperator;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.JoinType;
+
+import com.google.common.collect.ImmutableBiMap;
+
+/**
+ * Utility class provides bidirectional mappings for ODS types
+ *
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @since 1.0.0
+ */
+public abstract class ODSUtils {
+	/**
+	 * Maps {@link RelationType} to the corresponding ODS {@link RelationType}.
+	 */
+	public static final ImmutableBiMap<RelationType, org.asam.ods.RelationType> RELATIONSHIPS = ImmutableBiMap.<RelationType, org.asam.ods.RelationType>builder()
+			.put(RelationType.FATHER_CHILD, org.asam.ods.RelationType.FATHER_CHILD)
+			.put(RelationType.INFO, org.asam.ods.RelationType.INFO)
+			.put(RelationType.INHERITANCE, org.asam.ods.RelationType.INHERITANCE).build();
+
+	/**
+	 * Maps {@link Aggregation} to the corresponding ODS {@link AggrFunc}.
+	 */
+	public static final ImmutableBiMap<Aggregation, AggrFunc> AGGREGATIONS = ImmutableBiMap
+			.<Aggregation, AggrFunc>builder().put(Aggregation.NONE, AggrFunc.NONE)
+			.put(Aggregation.COUNT, AggrFunc.COUNT).put(Aggregation.DISTINCT_COUNT, AggrFunc.DCOUNT)
+			.put(Aggregation.MINIMUM, AggrFunc.MIN).put(Aggregation.MAXIMUM, AggrFunc.MAX)
+			.put(Aggregation.AVERAGE, AggrFunc.AVG).put(Aggregation.DEVIATION, AggrFunc.STDDEV)
+			.put(Aggregation.SUM, AggrFunc.SUM).put(Aggregation.DISTINCT, AggrFunc.DISTINCT).build();
+
+	/**
+	 * Maps {@link ContextType} to the corresponding ODS {@link String}.
+	 */
+	public static final ImmutableBiMap<ContextType, String> CONTEXTTYPES = ImmutableBiMap.<ContextType, String>builder()
+			.put(ContextType.UNITUNDERTEST, "UnitUnderTest").put(ContextType.TESTSEQUENCE, "TestSequence")
+			.put(ContextType.TESTEQUIPMENT, "TestEquipment").build();
+
+	/**
+	 * Maps {@link ComparisonOperator} to the corresponding ODS {@link SelOpcode}.
+	 */
+	public static final ImmutableBiMap<ComparisonOperator, SelOpcode> OPERATIONS = ImmutableBiMap
+			.<ComparisonOperator, SelOpcode>builder().put(ComparisonOperator.LIKE, SelOpcode.LIKE)
+			.put(ComparisonOperator.CASE_INSENSITIVE_LIKE, SelOpcode.CI_LIKE)
+			.put(ComparisonOperator.NOT_LIKE, SelOpcode.NOTLIKE)
+			.put(ComparisonOperator.CASE_INSENSITIVE_NOT_LIKE, SelOpcode.CI_NOTLIKE)
+			.put(ComparisonOperator.EQUAL, SelOpcode.EQ).put(ComparisonOperator.CASE_INSENSITIVE_EQUAL, SelOpcode.CI_EQ)
+			.put(ComparisonOperator.NOT_EQUAL, SelOpcode.NEQ)
+			.put(ComparisonOperator.CASE_INSENSITIVE_NOT_EQUAL, SelOpcode.CI_NEQ)
+			.put(ComparisonOperator.GREATER_THAN, SelOpcode.GT)
+			.put(ComparisonOperator.CASE_INSENSITIVE_GREATER_THAN, SelOpcode.CI_GT)
+			.put(ComparisonOperator.GREATER_THAN_OR_EQUAL, SelOpcode.GTE)
+			.put(ComparisonOperator.CASE_INSENSITIVE_GREATER_THAN_OR_EQUAL, SelOpcode.CI_GTE)
+			.put(ComparisonOperator.LESS_THAN, SelOpcode.LT)
+			.put(ComparisonOperator.CASE_INSENSITIVE_LESS_THAN, SelOpcode.CI_LT)
+			.put(ComparisonOperator.LESS_THAN_OR_EQUAL, SelOpcode.LTE)
+			.put(ComparisonOperator.CASE_INSENSITIVE_LESS_THAN_OR_EQUAL, SelOpcode.CI_LTE)
+			.put(ComparisonOperator.IS_NULL, SelOpcode.IS_NULL)
+			.put(ComparisonOperator.IS_NOT_NULL, SelOpcode.IS_NOT_NULL).put(ComparisonOperator.IN_SET, SelOpcode.INSET)
+			.put(ComparisonOperator.CASE_INSENSITIVE_IN_SET, SelOpcode.CI_INSET)
+			.put(ComparisonOperator.NOT_IN_SET, SelOpcode.NOTINSET)
+			.put(ComparisonOperator.CASE_INSENSITIVE_NOT_IN_SET, SelOpcode.CI_NOTINSET)
+			.put(ComparisonOperator.BETWEEN, SelOpcode.BETWEEN).build();
+
+	/**
+	 * Maps {@link BooleanOperator} to the corresponding ODS {@link SelOperator}.
+	 */
+	public static final ImmutableBiMap<BooleanOperator, SelOperator> OPERATORS = ImmutableBiMap
+			.<BooleanOperator, SelOperator>builder().put(BooleanOperator.AND, SelOperator.AND)
+			.put(BooleanOperator.OR, SelOperator.OR).put(BooleanOperator.NOT, SelOperator.NOT).build();
+
+	/**
+	 * Maps {@link BracketOperator} to the corresponding ODS {@link SelOperator}.
+	 */
+	public static final ImmutableBiMap<BracketOperator, SelOperator> BRACKETOPERATORS = ImmutableBiMap
+			.<BracketOperator, SelOperator>builder().put(BracketOperator.OPEN, SelOperator.OPEN)
+			.put(BracketOperator.CLOSE, SelOperator.CLOSE).build();
+
+	/**
+	 * Maps {@link ValueType} to the corresponding ODS {@link DataType}.
+	 */
+	public static final ImmutableBiMap<ValueType<?>, DataType> VALUETYPES = ImmutableBiMap
+			.<ValueType<?>, DataType>builder().put(ValueType.UNKNOWN, DataType.DT_UNKNOWN)
+			.put(ValueType.STRING, DataType.DT_STRING).put(ValueType.STRING_SEQUENCE, DataType.DS_STRING)
+			.put(ValueType.DATE, DataType.DT_DATE).put(ValueType.DATE_SEQUENCE, DataType.DS_DATE)
+			.put(ValueType.BOOLEAN, DataType.DT_BOOLEAN).put(ValueType.BOOLEAN_SEQUENCE, DataType.DS_BOOLEAN)
+			.put(ValueType.BYTE, DataType.DT_BYTE).put(ValueType.BYTE_SEQUENCE, DataType.DS_BYTE)
+			.put(ValueType.SHORT, DataType.DT_SHORT).put(ValueType.SHORT_SEQUENCE, DataType.DS_SHORT)
+			.put(ValueType.INTEGER, DataType.DT_LONG).put(ValueType.INTEGER_SEQUENCE, DataType.DS_LONG)
+			.put(ValueType.LONG, DataType.DT_LONGLONG).put(ValueType.LONG_SEQUENCE, DataType.DS_LONGLONG)
+			.put(ValueType.FLOAT, DataType.DT_FLOAT).put(ValueType.FLOAT_SEQUENCE, DataType.DS_FLOAT)
+			.put(ValueType.DOUBLE, DataType.DT_DOUBLE).put(ValueType.DOUBLE_SEQUENCE, DataType.DS_DOUBLE)
+			.put(ValueType.BYTE_STREAM, DataType.DT_BYTESTR).put(ValueType.BYTE_STREAM_SEQUENCE, DataType.DS_BYTESTR)
+			.put(ValueType.FLOAT_COMPLEX, DataType.DT_COMPLEX)
+			.put(ValueType.FLOAT_COMPLEX_SEQUENCE, DataType.DS_COMPLEX)
+			.put(ValueType.DOUBLE_COMPLEX, DataType.DT_DCOMPLEX)
+			.put(ValueType.DOUBLE_COMPLEX_SEQUENCE, DataType.DS_DCOMPLEX).put(ValueType.ENUMERATION, DataType.DT_ENUM)
+			.put(ValueType.ENUMERATION_SEQUENCE, DataType.DS_ENUM)
+			.put(ValueType.FILE_LINK, DataType.DT_EXTERNALREFERENCE)
+			.put(ValueType.FILE_LINK_SEQUENCE, DataType.DS_EXTERNALREFERENCE).put(ValueType.BLOB, DataType.DT_BLOB)
+			.build();
+
+	/**
+	 * Maps {@link JoinType} to the corresponding ODS {@link org.asam.ods.JoinType}.
+	 */
+	public static final ImmutableBiMap<JoinType, org.asam.ods.JoinType> JOINS = ImmutableBiMap.<JoinType, org.asam.ods.JoinType>builder()
+			.put(JoinType.INNER, org.asam.ods.JoinType.JTDEFAULT).put(JoinType.OUTER, org.asam.ods.JoinType.JTOUTER)
+			.build();
+
+	public static boolean isValidID(String instanceID) {
+		return instanceID != null && !instanceID.isEmpty() && !"0".equals(instanceID);
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/main/proto/notification.proto b/org.eclipse.mdm.api.odsadapter/src/main/proto/notification.proto
new file mode 100644
index 0000000..7503205
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/main/proto/notification.proto
@@ -0,0 +1,49 @@
+/********************************************************************************

+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation

+ *

+ * See the NOTICE file(s) distributed with this work for additional

+ * information regarding copyright ownership.

+ *

+ * This program and the accompanying materials are made available under the

+ * terms of the Eclipse Public License v. 2.0 which is available at

+ * http://www.eclipse.org/legal/epl-2.0.

+ *

+ * SPDX-License-Identifier: EPL-2.0

+ *

+ ********************************************************************************/

+ 
+syntax = "proto3";
+
+package com.peaksolution.ods.notification;
+option java_package = "com.peaksolution.ods.notification.protobuf";
+option java_outer_classname = "NotificationProtos";
+
+import "google/protobuf/timestamp.proto";
+
+enum ModificationType {
+  NEW = 0;
+  MODIFY = 1;
+  DELETE = 2;
+  MODEL = 3;
+  SECURITY = 4;
+}
+	
+message Registration {
+	enum NotificationMode {
+		PUSH = 0;
+		PULL = 1;
+	}
+	
+	NotificationMode mode = 1;
+	repeated ModificationType type = 2;
+	repeated int64 aid = 3;
+}
+
+message Notification {
+	ModificationType type = 1;
+	string uuid = 2;
+	google.protobuf.Timestamp creation = 3;
+	int64 userId = 4;
+	int64 aid = 5;
+	repeated int64 iid = 6;
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/AggregationTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/AggregationTest.java
new file mode 100644
index 0000000..048089c
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/AggregationTest.java
@@ -0,0 +1,169 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+/**
+ * Aggregation test
+ *
+ * @since 1.0.0
+ * @author maf, Peak Solution GmbH
+ */
+@Ignore
+// FIXME 11.01.2018: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class AggregationTest {
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	@org.junit.Test
+	public void testQueryIdAndNameNoAggregation() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		QueryService queryService = context.getQueryService().get();
+
+		EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+		Attribute idAttribute = unitEntityType.getAttribute("Id");
+		Attribute nameAttribute = unitEntityType.getAttribute("Name");
+
+		List<Result> listRes = queryService.createQuery().select(idAttribute).select(nameAttribute).fetch();
+
+		assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+		assertThat(listRes.get(0).getValue(idAttribute).getValueType()).isEqualTo(ValueType.STRING);
+		// Test retrieving attribute value with Aggregation.NONE (should yield the same
+		// result as with no aggregation):
+		assertThat(listRes.get(0).getValue(idAttribute, Aggregation.NONE).getValueType()).isEqualTo(ValueType.STRING);
+		assertThat(listRes.get(0).getValue(nameAttribute).getValueType()).isEqualTo(ValueType.STRING);
+	}
+
+	@org.junit.Test
+	public void testQueryIdWithAggregation() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		QueryService queryService = context.getQueryService().get();
+
+		EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+		Attribute idAttribute = unitEntityType.getAttribute("Id");
+
+		List<Result> listRes = queryService.createQuery().select(idAttribute, Aggregation.MAXIMUM) // should be a string
+																									// in result, just
+																									// like
+																									// non-aggregated Id
+																									// attribute
+				.select(idAttribute, Aggregation.AVERAGE) // should be a numeric value in result
+				.fetch();
+
+		assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+		assertThat(listRes.get(0).getValue(idAttribute, Aggregation.MAXIMUM).getValueType())
+				.isEqualTo(ValueType.STRING);
+		assertThat(listRes.get(0).getValue(idAttribute, Aggregation.AVERAGE).getValueType()).isEqualTo(ValueType.LONG);
+	}
+
+	@org.junit.Test
+	public void testQueryFactorWithAggregation() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		QueryService queryService = context.getQueryService().get();
+
+		EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+		Attribute factorAttribute = unitEntityType.getAttribute("Factor");
+
+		List<Result> listRes = queryService.createQuery().select(factorAttribute, Aggregation.COUNT)
+				.group(factorAttribute).fetch();
+
+		assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+		assertThat(listRes.get(0).getValue(factorAttribute, Aggregation.COUNT).getValueType())
+				.isEqualTo(ValueType.INTEGER);
+	}
+
+	@org.junit.Test
+	public void testQueryFactorWithAndWithoutAggregation() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		QueryService queryService = context.getQueryService().get();
+
+		EntityType unitEntityType = modelManager.getEntityType(Unit.class);
+		Attribute factorAttribute = unitEntityType.getAttribute("Factor");
+
+		List<Result> listRes = queryService.createQuery().select(factorAttribute)
+				.select(factorAttribute, Aggregation.SUM).group(factorAttribute).fetch();
+
+		assertThat(listRes.size()).isGreaterThanOrEqualTo(1);
+		assertThat(listRes.get(0).getValue(factorAttribute).getValueType()).isEqualTo(ValueType.DOUBLE);
+		assertThat(listRes.get(0).getValue(factorAttribute, Aggregation.SUM).getValueType())
+				.isEqualTo(ValueType.DOUBLE);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/JoinTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/JoinTest.java
new file mode 100644
index 0000000..483b1d0
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/JoinTest.java
@@ -0,0 +1,356 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+/**
+ * JoinType test
+ *
+ * @since 1.0.0
+ * @author jst, Peak Solution GmbH
+ */
+@Ignore
+// FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class JoinTest {
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	@org.junit.Test
+	public void findTestFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "37"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "65"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "80"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "302"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "28"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "65"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Test> list = searchService.fetch(Test.class, Filter.idOnly(et, "80"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findTestStepFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<TestStep> list = searchService.fetch(TestStep.class, Filter.idOnly(et, "302"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "28"));
+
+		assertEquals(9, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "37"));
+
+		assertEquals(9, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "80"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findMeasurementFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<Measurement> list = searchService.fetch(Measurement.class, Filter.idOnly(et, "302"));
+
+		assertEquals(1, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "28"));
+
+		assertEquals(14, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "37"));
+
+		assertEquals(14, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "65"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelGroupFromChannelId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Channel.class);
+
+		List<ChannelGroup> list = searchService.fetch(ChannelGroup.class, Filter.idOnly(et, "302"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromTestId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Test.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "28"));
+
+		assertEquals(43, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromTestStepId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(TestStep.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "37"));
+
+		assertEquals(43, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromMeasurementId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(Measurement.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "65"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+	@org.junit.Test
+	public void findChannelFromChannelGroupId() throws DataAccessException {
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType et = modelManager.getEntityType(ChannelGroup.class);
+
+		List<Channel> list = searchService.fetch(Channel.class, Filter.idOnly(et, "80"));
+
+		assertEquals(2, list.size());
+		System.out.println(list.size());
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSAdapterTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSAdapterTest.java
new file mode 100644
index 0000000..6bd6241
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSAdapterTest.java
@@ -0,0 +1,442 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.massdata.WriteRequestBuilder;
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.MimeType;
+import org.eclipse.mdm.api.base.model.PhysicalDimension;
+import org.eclipse.mdm.api.base.model.Quantity;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.CatalogComponent;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.dflt.model.TemplateComponent;
+import org.eclipse.mdm.api.dflt.model.TemplateRoot;
+import org.eclipse.mdm.api.dflt.model.TemplateTest;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Ignore
+// FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class ODSAdapterTest {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default model
+	 * and any database constraint which enforces a relation of Test to a parent
+	 * entity is deactivated!
+	 */
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSAdapterTest.class);
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static EntityManager entityManager;
+	private static EntityFactory entityFactory;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+		entityManager = context.getEntityManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
+		entityFactory = context.getEntityFactory()
+				.orElseThrow(() -> new IllegalStateException("Entity manager factory not available."));
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	/*
+	 * FIXME this test requires that there is a teststep with id 2, that has a
+	 * unitundertest component called "filetest", that has an empty filelink
+	 * attribute "myextref" and a string attrinute "attr1". remove the comment at
+	 * org.junit.Test if you fulfill these requirements
+	 */
+	// @org.junit.Test
+	public void changeFile() throws Exception {
+		String idteststep = "2";
+		ModelManager modelManager = context.getModelManager().get();
+		SearchService searchService = context.getSearchService().get();
+
+		EntityType etteststep = modelManager.getEntityType(TestStep.class);
+		Transaction transaction;
+
+		transaction = entityManager.startTransaction();
+
+		try {
+			List<TestStep> mealist;
+			mealist = searchService.fetch(TestStep.class, Filter.idOnly(etteststep, idteststep));
+			assertEquals(1, mealist.size());
+			TestStep ts = mealist.get(0);
+			Map<ContextType, ContextRoot> loadContexts = ts.loadContexts(entityManager, ContextType.UNITUNDERTEST);
+			ContextRoot contextRoot = loadContexts.get(ContextType.UNITUNDERTEST);
+			Optional<ContextComponent> contextComponent = contextRoot.getContextComponent("filetest");
+			Value value = contextComponent.get().getValue("myextref");
+			contextComponent.get().getValue("attr1").set("val4711");
+			FileLink fl = FileLink.newRemote("", new MimeType(""), "");
+			FileLink fl2 = (FileLink) value.extract();
+			assertEquals(fl2, fl);
+			List<BaseEntity> toUpdate = new ArrayList<>();
+			toUpdate.add(contextComponent.get());
+			transaction.update(toUpdate);
+			transaction.commit();
+		} catch (RuntimeException e) {
+			transaction.abort();
+			throw e;
+		}
+	}
+
+	@org.junit.Test
+	public void runtTestScript() throws DataAccessException {
+		List<CatalogComponent> catalogComponents = createCatalogComponents();
+		List<TemplateRoot> templateRoots = createTemplateRoots(catalogComponents);
+		List<TemplateTestStep> templateTestSteps = createTemplateTestSteps(templateRoots);
+		TemplateTest templateTest = createTemplateTest(templateTestSteps);
+		PhysicalDimension physicalDimension = entityFactory.createPhysicalDimension("any_physical_dimension");
+		Unit unit = entityFactory.createUnit("any_unit", physicalDimension);
+		Quantity quantity = entityFactory.createQuantity("any_quantity", unit);
+
+		Transaction transaction = entityManager.startTransaction();
+		try {
+			create(transaction, "catalog components", catalogComponents);
+			create(transaction, "template roots", templateRoots);
+			create(transaction, "template test steps", templateTestSteps);
+			create(transaction, "template test", Collections.singletonList(templateTest));
+			create(transaction, "physical dimension", Collections.singletonList(physicalDimension));
+			create(transaction, "unit", Collections.singletonList(unit));
+			create(transaction, "quantity", Collections.singletonList(quantity));
+
+			transaction.commit();
+		} catch (RuntimeException e) {
+			transaction.abort();
+			e.printStackTrace();
+			fail("Unable to create test data due to: " + e.getMessage());
+		}
+
+		List<Project> projects = Collections.emptyList();
+		try {
+			projects = createTestData(templateTest, quantity);
+		} catch (RuntimeException e) {
+			e.printStackTrace();
+		}
+
+		transaction = entityManager.startTransaction();
+		try {
+			// delete in reverse order!
+			if (!projects.isEmpty()) {
+				delete(transaction, "projects and their children", projects);
+			}
+
+			delete(transaction, "quantity", Collections.singletonList(quantity));
+			delete(transaction, "unit", Collections.singletonList(unit));
+			delete(transaction, "physical dimension", Collections.singletonList(physicalDimension));
+			delete(transaction, "template test", Collections.singletonList(templateTest));
+			delete(transaction, "template test steps", templateTestSteps);
+			delete(transaction, "template roots", templateRoots);
+			delete(transaction, "catalog components", catalogComponents);
+
+			transaction.commit();
+		} catch (RuntimeException e) {
+			transaction.abort();
+			fail("Unable to delete test data due to: " + e.getMessage());
+		}
+
+		if (projects.isEmpty()) {
+			fail("Was unable to create test data.");
+		}
+	}
+
+	private List<Project> createTestData(TemplateTest templateTest, Quantity quantity) throws DataAccessException {
+
+		Project project = entityFactory.createProject("simple_project");
+		Pool pool = entityFactory.createPool("simple_pool", project);
+
+		List<Test> tests = createTests(2, pool, templateTest);
+
+		// create measurement test data
+		List<WriteRequest> writeRequests = new ArrayList<>();
+		for (Test test : tests) {
+			for (TestStep testStep : test.getCommissionedTestSteps()) {
+				Optional<TemplateTestStep> templateTestStep = TemplateTestStep.of(testStep);
+				ContextRoot[] contextRoots = new ContextRoot[0];
+				if (templateTestStep.isPresent()) {
+					contextRoots = templateTestStep.get().getTemplateRoots().stream()
+							.map(templateRoot -> entityFactory.createContextRoot(templateRoot))
+							.toArray(ContextRoot[]::new);
+				}
+				for (int i = 1; i < 3; i++) {
+					Measurement measurement = entityFactory.createMeasurement("measurement_" + i, testStep,
+							contextRoots);
+
+					// create channels
+					List<Channel> channels = new ArrayList<>();
+					for (int j = 0; j < 9; j++) {
+						channels.add(entityFactory.createChannel("channel_ " + j, measurement, quantity));
+					}
+
+					// create channel group
+					ChannelGroup channelGroup = entityFactory.createChannelGroup("group", 10, measurement);
+					writeRequests.addAll(createMeasurementData(measurement, channelGroup, channels));
+				}
+			}
+		}
+
+		Transaction transaction = entityManager.startTransaction();
+		try {
+			create(transaction, "project and pool with tests based on teamplates with measurements and mass data",
+					Collections.singleton(project));
+
+			transaction.writeMeasuredValues(writeRequests);
+			transaction.commit();
+			return Collections.singletonList(project);
+		} catch (DataAccessException e) {
+			e.printStackTrace();
+			transaction.abort();
+		}
+
+		return Collections.emptyList();
+	}
+
+	private List<WriteRequest> createMeasurementData(Measurement measurement, ChannelGroup channelGroup,
+			List<Channel> channels) {
+		// set length of the channel value sequence
+		List<WriteRequest> writeRequests = new ArrayList<>();
+
+		// populate channel value write requests - one per channel
+		Collections.sort(channels, (c1, c2) -> c1.getName().compareTo(c2.getName()));
+
+		WriteRequestBuilder wrb = WriteRequest.create(channelGroup, channels.get(0), AxisType.X_AXIS);
+		writeRequests.add(wrb.implicitLinear(ScalarType.FLOAT, 0, 1).independent().build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(1), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit()
+				.booleanValues(new boolean[] { true, true, false, true, true, false, true, false, false, false })
+				.build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(2), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit().byteValues(new byte[] { 5, 32, 42, 9, 17, 65, 13, 8, 15, 21 }).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(3), AxisType.Y_AXIS);
+		writeRequests.add(
+				wrb.explicit().integerValues(new int[] { 423, 645, 221, 111, 675, 353, 781, 582, 755, 231 }).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(4), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit()
+				.stringValues(new String[] { "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10" }).build());
+
+		LocalDateTime now = LocalDateTime.now();
+		wrb = WriteRequest.create(channelGroup, channels.get(5), AxisType.Y_AXIS);
+		writeRequests
+				.add(wrb.explicit()
+						.dateValues(new LocalDateTime[] { now, now.plusDays(1), now.plusDays(2), now.plusDays(3),
+								now.plusDays(4), now.plusDays(5), now.plusDays(6), now.plusDays(7), now.plusDays(8),
+								now.plusDays(9) })
+						.build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(6), AxisType.Y_AXIS);
+		writeRequests.add(wrb.explicit().byteStreamValues(new byte[][] { { 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 9, 10 },
+				{ 11 }, { 12, 13, 14 }, { 15, 16 }, { 17, 18, 19, 20 }, { 21, 22 }, { 23 } }).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(7), AxisType.Y_AXIS);
+		writeRequests.add(wrb.implicitConstant(ScalarType.SHORT, Short.MAX_VALUE).build());
+
+		wrb = WriteRequest.create(channelGroup, channels.get(8), AxisType.Y_AXIS);
+		writeRequests.add(wrb.implicitSaw(ScalarType.FLOAT, 0, 1, 4).build());
+
+		return writeRequests;
+	}
+
+	private static void delete(Transaction transaction, String key, Collection<? extends Deletable> entities)
+			throws DataAccessException {
+		LOGGER.info(">>>>>>>>>>>>>>>>> deleting " + key + "...");
+		long start = System.currentTimeMillis();
+		transaction.delete(entities);
+		LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " deleted in " + (System.currentTimeMillis() - start) + " ms");
+	}
+
+	private static void create(Transaction transaction, String key, Collection<? extends Entity> entities)
+			throws DataAccessException {
+		LOGGER.info(">>>>>>>>>>>>>>>>> creating " + key + "...");
+		long start = System.currentTimeMillis();
+		transaction.create(entities);
+		LOGGER.info(">>>>>>>>>>>>>>>>> " + key + " written in " + (System.currentTimeMillis() - start) + " ms");
+	}
+
+	private List<Test> createTests(int count, Pool pool, TemplateTest templateTest) {
+		return IntStream.range(1, ++count)
+				.mapToObj(i -> entityFactory.createTest("simple_test_" + i, pool, templateTest))
+				.collect(Collectors.toList());
+	}
+
+	private TemplateTest createTemplateTest(List<TemplateTestStep> templateTestSteps) {
+		TemplateTest templateTest = entityFactory.createTemplateTest("tpl_test");
+		templateTestSteps.forEach(tts -> {
+			entityFactory.createTemplateTestStepUsage(UUID.randomUUID().toString(), templateTest, tts);
+		});
+		return templateTest;
+	}
+
+	private List<TemplateTestStep> createTemplateTestSteps(List<TemplateRoot> templateRoots) {
+		// make sure each context type is given only once
+		templateRoots.stream().collect(Collectors.toMap(TemplateRoot::getContextType, Function.identity()));
+
+		List<TemplateTestStep> templateTestSteps = new ArrayList<>();
+		TemplateTestStep templateTestStep1 = entityFactory.createTemplateTestStep("tpl_test_step_1");
+		templateRoots.forEach(tr -> templateTestStep1.setTemplateRoot(tr));
+		templateTestSteps.add(templateTestStep1);
+		TemplateTestStep templateTestStep2 = entityFactory.createTemplateTestStep("tpl_test_step_2");
+		templateRoots.forEach(tr -> templateTestStep2.setTemplateRoot(tr));
+		templateTestSteps.add(templateTestStep2);
+
+		return templateTestSteps;
+	}
+
+	private List<TemplateRoot> createTemplateRoots(List<CatalogComponent> catalogComponents) {
+		Map<ContextType, List<CatalogComponent>> groups = catalogComponents.stream()
+				.collect(Collectors.groupingBy(CatalogComponent::getContextType));
+
+		List<TemplateRoot> templateRoots = new ArrayList<>();
+		groups.forEach((contextType, catalogComps) -> {
+			TemplateRoot templateRoot = entityFactory.createTemplateRoot(contextType,
+					"tpl_" + toLower(contextType.name()) + "_root");
+			// create child template components for template root
+			catalogComps.forEach(catalogComp -> {
+				TemplateComponent templateComponent = entityFactory
+						.createTemplateComponent("tpl_" + catalogComp.getName() + "_parent", templateRoot, catalogComp);
+				entityFactory.createTemplateComponent("tpl_" + catalogComp.getName() + "_child", templateComponent,
+						catalogComp);
+			});
+
+			templateRoots.add(templateRoot);
+		});
+
+		return templateRoots;
+	}
+
+	private List<CatalogComponent> createCatalogComponents() {
+		List<CatalogComponent> catalogComponents = new ArrayList<>();
+		catalogComponents.add(createCatalogComponent(ContextType.UNITUNDERTEST));
+		catalogComponents.add(createCatalogComponent(ContextType.TESTSEQUENCE));
+		catalogComponents.add(createCatalogComponent(ContextType.TESTEQUIPMENT));
+		return catalogComponents;
+	}
+
+	private CatalogComponent createCatalogComponent(ContextType contextType) {
+		CatalogComponent catalogComponent = entityFactory.createCatalogComponent(contextType,
+				toLower(contextType.name()));
+
+		entityFactory.createCatalogAttribute("string", ValueType.STRING, catalogComponent);
+		entityFactory.createCatalogAttribute("date", ValueType.DATE, catalogComponent);
+		entityFactory.createCatalogAttribute("long", ValueType.LONG, catalogComponent);
+		entityFactory.createCatalogAttribute("file_link", ValueType.FILE_LINK, catalogComponent);
+		entityFactory.createCatalogAttribute("file_link_array", ValueType.FILE_LINK_SEQUENCE, catalogComponent);
+		EnumRegistry er = EnumRegistry.getInstance();
+		entityFactory.createCatalogAttribute("scalar_type", er.get(EnumRegistry.SCALAR_TYPE), catalogComponent);
+
+		return catalogComponent;
+	}
+
+	private static String toLower(String name) {
+		return name.toLowerCase(Locale.ROOT);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSContextTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSContextTest.java
new file mode 100644
index 0000000..d0f93e5
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSContextTest.java
@@ -0,0 +1,175 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.asam.ods.AoException;
+import org.asam.ods.InstanceElement;
+import org.assertj.core.api.Condition;
+import org.assertj.core.api.Fail;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.odsadapter.utils.ODSConverter;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.mockito.Mockito;
+
+@Ignore
+//FIXME 26.01.2018: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+//Comment this in for local tests only.
+public class ODSContextTest {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default model
+	 * and any database constraint which enforces a relation of Test to a parent
+	 * entity is deactivated!
+	 */
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static EntityManager entityManager;
+
+	private static String nameServiceHost = System.getProperty("host");
+	private static String nameServicePort = System.getProperty("port");
+	private static String serviceName = System.getProperty("service");
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+		entityManager = context.getEntityManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	@org.junit.Test
+	public void testGetAdapterType() {
+		assertThat(context.getAdapterType()).isEqualTo("ods");
+	}
+
+	@org.junit.Test
+	public void testGetLink() {
+		// we assume a test with ID 4 exists.
+		Test test = entityManager.load(Test.class, "4");
+
+		Map<Entity, String> asamPaths = entityManager.getLinks(Arrays.asList(test));
+
+		assertThat(asamPaths).hasSize(1).containsOnlyKeys(test).hasEntrySatisfying(test,
+				new Condition<String>(s -> s.startsWith(getLinkPrefix()), ""));
+	}
+
+	@org.junit.Test
+	public void testGetLinkAndLoadOdsInstance() {
+		// we assume a test with ID 4 exists.
+		long testId = 4L;
+		Test test = entityManager.load(Test.class, Long.toString(testId));
+
+		Map<Entity, String> asamPaths = entityManager.getLinks(Arrays.asList(test));
+
+		assertThat(asamPaths).hasSize(1).containsOnlyKeys(test).hasEntrySatisfying(test,
+				new Condition<String>(s -> s.startsWith(getLinkPrefix()), ""));
+		// We try to load the instance from the ODS Server with the AsamPath, but
+		// without the service prefix
+		String asamPathWithoutService = asamPaths.get(test).replace(getLinkPrefix(), "");
+
+		try {
+			InstanceElement ie = ((ODSContext) context).getAoSession().getApplicationStructure()
+					.getInstanceByAsamPath(asamPathWithoutService);
+			assertThat(ODSConverter.fromODSLong(ie.getId())).isEqualTo(testId);
+		} catch (AoException e) {
+			Fail.fail(
+					"Instance with AsamPath '" + asamPathWithoutService + "' could not be loaded. Reason: " + e.reason,
+					e);
+		}
+	}
+
+	@org.junit.Test(expected = IllegalArgumentException.class)
+	public void testGetLinksWithInvalidType() {
+		// we assume a test with ID 4 exists.
+		Test test = entityManager.load(Test.class, "4");
+		BaseEntity entity = Mockito.mock(BaseEntity.class);
+		// Mock an entity with a non existing TypeName
+		when(entity.getTypeName()).thenReturn("invalidType");
+
+		entityManager.getLinks(Arrays.asList(test, entity));
+	}
+
+	@org.junit.Test
+	public void testGetLinksWithEnitityWithMissingId() {
+		// we assume a test with ID 4 exists.
+		Test test = entityManager.load(Test.class, "4");
+
+		// Mock an entity with a non existing ID
+		TestStep testStep = Mockito.mock(TestStep.class);
+		when(testStep.getID()).thenReturn("-1");
+
+		Map<Entity, String> asamPaths = entityManager.getLinks(Arrays.asList(test, testStep));
+
+		assertThat(asamPaths).hasSize(1).containsOnlyKeys(test).hasEntrySatisfying(test,
+				new Condition<String>(s -> s.startsWith(getLinkPrefix()), ""));
+	}
+
+	private String getLinkPrefix() {
+		return String.format("corbaloc::1.2@%s:%s/NameService/%s.ASAM-ODS", nameServiceHost, nameServicePort,
+				serviceName);
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSRoleTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSRoleTest.java
new file mode 100644
index 0000000..4620a5d
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/ODSRoleTest.java
@@ -0,0 +1,206 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.dflt.model.Role;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Ignore
+// FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class ODSRoleTest {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default model
+	 * and any database constraint which enforces a relation of Test to a parent
+	 * entity is deactivated!
+	 */
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ODSRoleTest.class);
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static EntityManager em;
+	private static EntityFactory entityFactory;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+		em = context.getEntityManager().orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
+		entityFactory = context.getEntityFactory()
+				.orElseThrow(() -> new IllegalStateException("Entity manager factory not available."));
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	@org.junit.Test
+	public void testLoadRelatedUsers()
+			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+		User user = em.loadAll(User.class, "sa").get(0);
+		List<Role> role = em.loadRelatedEntities(user, "users2groups", Role.class);
+
+		assertThat(role).hasSize(1).extracting(Role::getName).containsExactly("MDMSystemAdministrator");
+	}
+
+	@org.junit.Test
+	public void testLoadRelatedRoles()
+			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+		Role role = em.loadAll(Role.class, "MDMSystemAdministrator").get(0);
+		List<User> user = em.loadRelatedEntities(role, "groups2users", User.class);
+
+		assertThat(user).hasSize(1).extracting(User::getName).containsExactly("sa");
+	}
+
+	@org.junit.Test
+	public void testCreateUserAndRole()
+			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+		String userName = "CreateUserAndRole";
+		String roleName = "CreateUserAndRole";
+
+		try {
+			Transaction transaction = em.startTransaction();
+			User user = entityFactory.createUser(userName, "Test", "User");
+			Role role = entityFactory.createRole(roleName);
+			role.addUser(user);
+
+			transaction.create(Arrays.asList(user, role));
+			transaction.commit();
+
+			assertThat(em.loadRelatedEntities(role, "users2groups", User.class)).hasSize(1).extracting(User::getName)
+					.contains(userName);
+
+			assertThat(em.loadRelatedEntities(user, "groups2users", Role.class)).hasSize(1).extracting(Role::getName)
+					.contains(roleName);
+		} finally {
+			Transaction transaction = em.startTransaction();
+			List<User> users = em.loadAll(User.class, userName);
+			transaction.delete(users);
+			List<Role> roles = em.loadAll(Role.class, roleName);
+			transaction.delete(roles);
+			transaction.commit();
+		}
+	}
+
+	@org.junit.Test
+	public void testAddMultipleUsersToNewRole()
+			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+		String roleName = "AddMultipleUsersToNewRole";
+		try {
+			Transaction transaction = em.startTransaction();
+			List<User> users = em.loadAll(User.class);
+			Role role = entityFactory.createRole(roleName);
+
+			users.forEach(u -> role.addUser(u));
+			transaction.create(Arrays.asList(role));
+			transaction.commit();
+
+			assertThat(em.loadRelatedEntities(role, "users2groups", User.class)).hasSize(users.size());
+		} finally {
+			Transaction transaction = em.startTransaction();
+			List<Role> roles = em.loadAll(Role.class, roleName);
+			transaction.delete(roles);
+			transaction.commit();
+		}
+	}
+
+	@org.junit.Test
+	public void testRemoveUserFromRole()
+			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+		String userName = "RemoveUserFromRole";
+		try {
+			Transaction transaction = em.startTransaction();
+			Role role = em.load(Role.class, "1");
+			User user = entityFactory.createUser(userName, "User", "User");
+
+			role.addUser(user);
+
+			transaction.create(Arrays.asList(user));
+			transaction.update(Arrays.asList(role));
+			transaction.commit();
+
+			assertThat(em.loadRelatedEntities(role, "groups2users", User.class)).hasSize(2);
+
+			Role role2 = em.load(Role.class, "1");
+			transaction = em.startTransaction();
+			role2.removeUser(user);
+			transaction.update(Arrays.asList(role2));
+			transaction.commit();
+
+			assertThat(em.loadRelatedEntities(role2, "groups2users", User.class)).hasSize(1);
+		} finally {
+			Transaction transaction = em.startTransaction();
+			List<User> users = em.loadAll(User.class, userName);
+			transaction.delete(users);
+			transaction.commit();
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/RelationTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/RelationTest.java
new file mode 100755
index 0000000..a07b428
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/RelationTest.java
@@ -0,0 +1,185 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter;
+
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.ParameterSet;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.odsadapter.query.ODSEntityFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.RelationSearchQuery;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+
+@Ignore
+// FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class RelationTest {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default model
+	 * and any database constraint which enforces a relation of Test to a parent
+	 * entity is deactivated!
+	 */
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static EntityManager entityManager;
+	private static ModelManager modelManager;
+	private static QueryService queryService;
+	private static SearchService searchService;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+		entityManager = context.getEntityManager()
+				.orElseThrow(() -> new ServiceNotProvidedException(EntityManager.class));
+		modelManager = context.getModelManager().orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+		queryService = context.getQueryService().orElseThrow(() -> new ServiceNotProvidedException(QueryService.class));
+		searchService = context.getSearchService()
+				.orElseThrow(() -> new IllegalStateException("Search service not available."));
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	/**
+	 * changes a relation between instances. There needs to exist a MeaResult of id
+	 * 1101 and a ParameterSet of id 1102 which will be related after running this
+	 * test. If these don't exist, please leave the following line commented, or the
+	 * test will fail.
+	 * 
+	 * @throws Exception
+	 */
+	@org.junit.Test
+	public void changeRelation() throws Exception {
+		String idmea = "1101";
+		String idparamset = "1002";
+
+		EntityType etmeasurement = modelManager.getEntityType(Measurement.class);
+		EntityType etparamset = modelManager.getEntityType(ParameterSet.class);
+		Transaction transaction;
+
+		transaction = entityManager.startTransaction();
+
+		try {
+			List<Measurement> mealist;
+			// we use the searchService to fetch a measurement. Please note, that we
+			// use the per default defined method to fetch the measurement.
+			// This does not load any related ParameterSets! But
+			// we don't care at this point, because we just want to change
+			// the related ParameterSet to a new one, not look at
+			// the existing relations.
+			mealist = searchService.fetch(Measurement.class, Filter.idOnly(etmeasurement, idmea));
+			assertEquals(1, mealist.size());
+			Measurement mea = mealist.get(0);
+
+			// load the parameter set which we want to relate to our measurment.
+			// again we don't care for any preexisting relations.
+			List<ParameterSet> paramsetlist = new ArrayList<>();
+			ParameterSet paramset = entityManager.load(ParameterSet.class, idparamset);
+			paramsetlist.add(paramset);
+			// Note: we can only set relations in the mutable store (which
+			// doesn't include parent-child-relations)
+			EntityStore store = ODSEntityFactory.getMutableStore(paramset);
+			store.set(mea);
+			assertEquals(store.get(Measurement.class), mea);
+
+			transaction.update(paramsetlist);
+			transaction.commit();
+
+			// reload from database and check if relation is consistent with
+			// expectations
+			// first we need to build our own SearchQuery, because the
+			// predefined ones don't include ParameterSet as stated above.
+			RelationSearchQuery mq = new RelationSearchQuery((ODSModelManager) modelManager, queryService);
+			// the SearchQuery defines how to join measurement and parameterset,
+			// but we also have to declare that we want to fetch the related
+			// measurement
+			List<EntityType> fetchList = new ArrayList<>();
+			fetchList.add(etmeasurement);
+			List<Result> fetch = mq.fetchComplete(fetchList, Filter.idOnly(etparamset, idparamset));
+			assertEquals(fetch.size(), 1);
+
+			// now we can check that the new relation is there as expected
+			Record record = fetch.get(0).getRecord(etmeasurement);
+			assertNotNull(record);
+			assertEquals(record.getID(), idmea);
+
+		} catch (RuntimeException e) {
+			transaction.abort();
+			throw e;
+		}
+
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationTest.java
new file mode 100644
index 0000000..ca152f7
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/notification/peak/PeakNotificationTest.java
@@ -0,0 +1,332 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.notification.peak;
+
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.asam.ods.AIDName;
+import org.asam.ods.AIDNameValueSeqUnitId;
+import org.asam.ods.AoException;
+import org.asam.ods.AoSession;
+import org.asam.ods.ApplElemAccess;
+import org.asam.ods.ApplicationElement;
+import org.asam.ods.TS_UnionSeq;
+import org.asam.ods.TS_ValueSeq;
+import org.asam.ods.T_LONGLONG;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.Transaction;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.notification.NotificationException;
+import org.eclipse.mdm.api.base.notification.NotificationFilter;
+import org.eclipse.mdm.api.base.notification.NotificationListener;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.EntityManager;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.odsadapter.ODSContext;
+import org.eclipse.mdm.api.odsadapter.ODSContextFactory;
+import org.eclipse.mdm.api.odsadapter.notification.ODSNotificationServiceFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test notification service.
+ * 
+ * Needs a running ODS and Notification Server. Assumes an existing Test with
+ * name defined in {@link PeakNotificationTest#PARENT_TEST}, an UnitUnderTest
+ * with ID 11 and an UnitUnderTestPart with ID 34.
+ * 
+ * @author Matthias Koller, Peak Solution GmbH
+ *
+ */
+@Ignore
+// FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class PeakNotificationTest {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default model
+	 * and any database constraint which enforces a relation of Test to a parent
+	 * entity is deactivated!
+	 */
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(EventProcessor.class);
+
+	// TODO name service: corbaloc::1.2@<SERVER_IP>:<SERVER_PORT>/NameService
+	private static final String NAME_SERVICE = "corbaloc::1.2@127.0.0.1:2809/NameService";
+
+	// TODO service name: <SERVICE_NAME>.ASAM-ODS
+	private static final String SERVICE_NAME = "MDMNVH.ASAM-ODS";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static final String PARENT_TEST = "PBN_UNECE_R51_13022014_1349";
+
+	private static final String NOTIFICATION_URL = "http://localhost:8080/api";
+	private static final String NOTIFICATION_REGISTRATION_NAME = "mdm";
+	private static final String NOTIFICATION_USER = "sa";
+	private static final String NOTIFICATION_PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static EntityManager entityManager;
+	private static NotificationService notificationManager;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, NAME_SERVICE);
+		connectionParameters.put(PARAM_SERVICENAME, SERVICE_NAME);
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+
+		Map<String, String> notificationParameters = new HashMap<>();
+		notificationParameters.put(ODSNotificationServiceFactory.PARAM_SERVER_TYPE,
+				ODSNotificationServiceFactory.SERVER_TYPE_PEAK);
+		notificationParameters.put(ODSNotificationServiceFactory.PARAM_URL, NOTIFICATION_URL);
+		notificationParameters.put(ODSContextFactory.PARAM_USER, NOTIFICATION_USER);
+		notificationParameters.put(ODSContextFactory.PARAM_PASSWORD, NOTIFICATION_PASSWORD);
+
+		notificationManager = new ODSNotificationServiceFactory().create(context, notificationParameters);
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException, NotificationException {
+		if (context != null) {
+			context.close();
+		}
+
+		if (notificationManager != null) {
+			notificationManager.deregister(NOTIFICATION_REGISTRATION_NAME);
+			notificationManager.close(true);
+		}
+	}
+
+	@org.junit.Test
+	public void testCreateTestStep() throws NotificationException, DataAccessException, InterruptedException {
+		String testStepName = USER + "_TestStep";
+
+		NotificationListener l = Mockito.mock(NotificationListener.class);
+
+		notificationManager.register(NOTIFICATION_REGISTRATION_NAME, new NotificationFilter(), l);
+
+		try {
+			createTestStep(PARENT_TEST, testStepName);
+
+			// make sure notification has some time to be pushed
+			Thread.sleep(1000L);
+
+			@SuppressWarnings({ "unchecked", "rawtypes" })
+			ArgumentCaptor<List<TestStep>> testStepCaptor = ArgumentCaptor.forClass((Class) List.class);
+			ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
+
+			verify(l, times(1)).instanceCreated(testStepCaptor.capture(), userCaptor.capture());
+
+			assertThat(testStepCaptor.getValue().size(), is(1));
+			assertThat(testStepCaptor.getValue().get(0).getName(), is(testStepName));
+			assertThat(userCaptor.getValue().getName(), is(USER));
+		} finally {
+			notificationManager.deregister(NOTIFICATION_REGISTRATION_NAME);
+			deleteTestStep(testStepName);
+		}
+	}
+
+	@org.junit.Test
+	public void testModifyContextRoot()
+			throws NotificationException, DataAccessException, InterruptedException, IOException {
+		NotificationListener l = Mockito.mock(NotificationListener.class);
+
+		notificationManager.register(NOTIFICATION_REGISTRATION_NAME, new NotificationFilter(), l);
+
+		try {
+			updateUUT(11, "application/x-asam.aounitundertest.unitundertest");
+
+			// make sure notification has some time to be pushed
+			Thread.sleep(1000L);
+
+			@SuppressWarnings({ "unchecked", "rawtypes" })
+			ArgumentCaptor<List<Entity>> entityCaptor = ArgumentCaptor.forClass((Class) List.class);
+			ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
+
+			verify(l, times(1)).instanceModified(entityCaptor.capture(), userCaptor.capture());
+
+			assertThat(entityCaptor.getValue().size(), is(1));
+			assertThat(entityCaptor.getValue().get(0).getName(), is("PBN_UNECE_R51_Left_AccV"));
+			assertThat(userCaptor.getValue().getName(), is(USER));
+		} finally {
+			notificationManager.deregister(NOTIFICATION_REGISTRATION_NAME);
+		}
+	}
+
+	@org.junit.Test
+	public void testModifyContextComponent()
+			throws NotificationException, DataAccessException, InterruptedException, IOException {
+		NotificationListener l = Mockito.mock(NotificationListener.class);
+
+		notificationManager.register(NOTIFICATION_REGISTRATION_NAME, new NotificationFilter(), l);
+
+		try {
+			updateUUTP(34, "test");
+
+			// make sure notification has some time to be pushed
+			Thread.sleep(1000L);
+
+			@SuppressWarnings({ "unchecked", "rawtypes" })
+			ArgumentCaptor<List<Entity>> entityCaptor = ArgumentCaptor.forClass((Class) List.class);
+			ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
+
+			verify(l, times(1)).instanceModified(entityCaptor.capture(), userCaptor.capture());
+
+			assertThat(entityCaptor.getValue().size(), is(1));
+			assertThat(entityCaptor.getValue().get(0).getName(), is("PBN_UNECE_R51_Left_SteadyV"));
+			assertThat(userCaptor.getValue().getName(), is(USER));
+		} finally {
+			notificationManager.deregister(NOTIFICATION_REGISTRATION_NAME);
+		}
+	}
+
+	private void createTestStep(String parentName, String name) throws DataAccessException {
+		Transaction transaction = entityManager.startTransaction();
+
+		List<Test> tests = entityManager.loadAll(Test.class, parentName);
+
+		assertThat("Parent test not found!", !tests.isEmpty());
+
+		Optional<? extends EntityFactory> entityFactory = context.getEntityFactory();
+		if (!entityFactory.isPresent()) {
+			throw new IllegalStateException("Entity factory not present!");
+		}
+
+		TestStep testStep = entityFactory.get().createTestStep(name, tests.get(0));
+		testStep.setSortIndex(0);
+
+		transaction.create(Arrays.asList(testStep));
+
+		transaction.commit();
+	}
+
+	private void deleteTestStep(String name) throws DataAccessException {
+		Transaction transaction = entityManager.startTransaction();
+
+		List<TestStep> testSteps = entityManager.loadAll(TestStep.class, name);
+
+		transaction.delete(testSteps);
+
+		transaction.commit();
+	}
+
+	private void updateUUT(int uutId, String newValue) throws DataAccessException {
+
+		AoSession session = null;
+		try {
+			session = ((ODSContext) context).getAoSession().createCoSession();
+
+			ApplicationElement aeUUT = session.getApplicationStructure().getElementsByBaseType("AoUnitUnderTest")[0];
+
+			final ApplElemAccess aea = session.getApplElemAccess();
+
+			TS_UnionSeq uId = new TS_UnionSeq();
+			uId.longlongVal(new T_LONGLONG[] { new T_LONGLONG(0, uutId) });
+
+			TS_UnionSeq uManufacturer = new TS_UnionSeq();
+			uManufacturer.stringVal(new String[] { newValue });
+
+			AIDNameValueSeqUnitId[] val = new AIDNameValueSeqUnitId[] {
+					new AIDNameValueSeqUnitId(new AIDName(aeUUT.getId(), "Id"), new T_LONGLONG(),
+							new TS_ValueSeq(uId, new short[] { (short) 15 })),
+					new AIDNameValueSeqUnitId(new AIDName(aeUUT.getId(), "Mimetype"), new T_LONGLONG(),
+							new TS_ValueSeq(uManufacturer, new short[] { (short) 15 })) };
+			session.startTransaction();
+			aea.updateInstances(val);
+			session.commitTransaction();
+
+		} catch (AoException e) {
+			throw new DataAccessException(e.reason, e);
+		} finally {
+			if (session != null) {
+				try {
+					session.close();
+				} catch (AoException e) {
+					LOGGER.warn("Exception when closing the ods session: " + e.reason, e);
+				}
+			}
+		}
+	}
+
+	private void updateUUTP(int tyreId, String newValue) throws DataAccessException {
+
+		AoSession session = null;
+		try {
+			session = ((ODSContext) context).getAoSession().createCoSession();
+
+			ApplicationElement aeTyre = session.getApplicationStructure().getElementByName("tyre");
+
+			final ApplElemAccess aea = session.getApplElemAccess();
+
+			TS_UnionSeq uId = new TS_UnionSeq();
+			uId.longlongVal(new T_LONGLONG[] { new T_LONGLONG(0, tyreId) });
+
+			TS_UnionSeq uManufacturer = new TS_UnionSeq();
+			uManufacturer.stringVal(new String[] { newValue });
+
+			AIDNameValueSeqUnitId[] val = new AIDNameValueSeqUnitId[] {
+					new AIDNameValueSeqUnitId(new AIDName(aeTyre.getId(), "Id"), new T_LONGLONG(),
+							new TS_ValueSeq(uId, new short[] { (short) 15 })),
+					new AIDNameValueSeqUnitId(new AIDName(aeTyre.getId(), "manufacturer"), new T_LONGLONG(),
+							new TS_ValueSeq(uManufacturer, new short[] { (short) 15 })) };
+			session.startTransaction();
+			aea.updateInstances(val);
+			session.commitTransaction();
+
+		} catch (AoException e) {
+			throw new DataAccessException(e.reason, e);
+		} finally {
+			if (session != null) {
+				try {
+					session.close();
+				} catch (AoException e) {
+					LOGGER.warn("Exception when closing the ods session: " + e.reason, e);
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
new file mode 100644
index 0000000..279ba65
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSFreeTextSearchTest.java
@@ -0,0 +1,192 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.text.StringEscapeUtils;
+import org.apache.http.HttpHost;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.odsadapter.lookup.EntityLoader;
+import org.eclipse.mdm.api.odsadapter.lookup.config.EntityConfig.Key;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.RestClient;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+
+@Ignore
+//FIXME 05.02.2020: this test needs a docker to run elasticsearch and is not suitable for continous build in Jenkins.
+//Comment this in for local tests only, if docker is available
+public class ODSFreeTextSearchTest {
+
+	private EntityLoader loader;
+	private ODSFreeTextSearch fts;
+	private TestStep ts;
+
+	private RestClient client;
+
+	@ClassRule
+	public static ElasticsearchContainer elasticSearch = new ElasticsearchContainer(
+			"docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0");
+
+	@SuppressWarnings("unchecked")
+	@Before
+	public void init() throws DataAccessException {
+		ts = mock(TestStep.class);
+		loader = mock(EntityLoader.class);
+
+		when(loader.loadAll(any(Key.class), anyCollection())).thenAnswer(new Answer<List<Entity>>() {
+
+			@Override
+			public List<Entity> answer(InvocationOnMock invocation) throws Throwable {
+				Collection<Long> object = (Collection<Long>) invocation.getArguments()[1];
+
+				List<Entity> res = new ArrayList<>();
+				for (int i = 0; i < object.size(); i++) {
+					res.add(ts);
+				}
+
+				return res;
+			}
+		});
+
+		client = RestClient.builder(HttpHost.create(elasticSearch.getHttpHostAddress())).build();
+		fts = new ODSFreeTextSearch(loader, "mdm", "http://" + elasticSearch.getHttpHostAddress());
+	}
+
+	@Test
+	public void noIndex_emptyResult() throws DataAccessException {
+		ODSFreeTextSearch ftsOtherIndex = new ODSFreeTextSearch(loader, "UNKNOWN_INDEX",
+				"http://" + elasticSearch.getHttpHostAddress());
+
+		Map<Class<? extends Entity>, List<Entity>> map = ftsOtherIndex.search("VAG_002");
+		assertThat(map).isEmpty();
+	}
+
+	@Test
+	public void exampleIndex_querySuccessfull() throws Exception {
+		try {
+			createExampleIndex("mdm", "TestStep", "asdf");
+
+			assertThat(fts.search("asdf").get(TestStep.class).get(0)).isEqualTo(ts);
+		} finally {
+			deleteIndex("mdm");
+		}
+	}
+
+	@Test
+	public void specialCharacters_correctlyEscaped() throws InterruptedException {
+		try {
+			createExampleIndex("mdm", "Measurement", "hallo\"!§");
+
+			Map<Class<? extends Entity>, List<Entity>> search = fts.search("hallo\"!§");
+			assertThat(search.get(Measurement.class).get(0)).isEqualTo(ts);
+		} finally {
+			deleteIndex("mdm");
+		}
+	}
+
+	@Test
+	public void nonMdmResults_ignored() throws InterruptedException {
+		try {
+			createExampleIndex("mdm", "NONMDMStuff", "test");
+
+			Map<Class<? extends Entity>, List<Entity>> search = fts.search("test");
+			assertThat(search).isEmpty();
+		} finally {
+			deleteIndex("mdm");
+		}
+	}
+
+	@Test
+	public void twoResults_twoResultsRetuned() throws InterruptedException {
+		try {
+			createExampleIndex("mdm", "Test", "0", "unicorn ASDF");
+			createExampleIndex("mdm", "Test", "1", "unicorn XYZ");
+
+			Map<Class<? extends Entity>, List<Entity>> search = fts.search("unicorn");
+			assertThat(search.get(org.eclipse.mdm.api.base.model.Test.class)).hasSize(2);
+		} finally {
+			deleteIndex("mdm");
+		}
+	}
+
+	@Test(expected = IllegalStateException.class)
+	public void illegalLoadRequest_niceExceptionIsThrown() throws DataAccessException, InterruptedException {
+		try {
+			loader = mock(EntityLoader.class);
+			when(loader.loadAll(any(), anyCollection())).thenThrow(new DataAccessException(""));
+			createExampleIndex("mdm2", "TestStep", "asdf");
+			ODSFreeTextSearch fts2 = new ODSFreeTextSearch(loader, "mdm2",
+					"http://" + elasticSearch.getHttpHostAddress());
+
+			fts2.search("asdf");
+		} finally {
+			deleteIndex("mdm2");
+		}
+	}
+
+	private void createExampleIndex(String indexName, String type, String value) throws InterruptedException {
+		createExampleIndex(indexName, type, "0", value);
+	}
+
+	private void createExampleIndex(String indexName, String type, String id, String value)
+			throws InterruptedException {
+		ObjectMapper mapper = new ObjectMapper();
+		Map<String, String> json = new HashMap<>();
+		json.put("id", StringEscapeUtils.escapeJson(id));
+		json.put("type", StringEscapeUtils.escapeJson(type));
+		json.put("attr", StringEscapeUtils.escapeJson(value));
+
+		try {
+			Request a = new Request("PUT", indexName + "/_doc/" + type + "-" + id);
+			a.setJsonEntity(mapper.writeValueAsString(json));
+			client.performRequest(a);
+		} catch (IOException e) {
+			throw new RuntimeException("Could not index!");
+		}
+
+		Thread.sleep(1000); // let the index some time to populate
+	}
+
+	private void deleteIndex(String indexName) {
+		try {
+			client.performRequest(new Request("DELETE", indexName));
+		} catch (IOException e) {
+			throw new RuntimeException("Could not delete index!");
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceIT.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceIT.java
new file mode 100644
index 0000000..2e11dd3
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceIT.java
@@ -0,0 +1,212 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_NAMESERVICE;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_PASSWORD;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_SERVICENAME;
+import static org.eclipse.mdm.api.odsadapter.ODSContextFactory.PARAM_USER;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.assertj.core.api.iterable.Extractor;
+import org.assertj.core.groups.Tuple;
+import org.eclipse.mdm.api.base.ConnectionException;
+import org.eclipse.mdm.api.base.ServiceNotProvidedException;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.ParameterSet;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.BooleanOperator;
+import org.eclipse.mdm.api.base.query.BracketOperator;
+import org.eclipse.mdm.api.base.query.ComparisonOperator;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.FilterItem;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchService;
+import org.eclipse.mdm.api.dflt.ApplicationContext;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.ODSContextFactory;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.mockito.Mockito;
+
+import com.google.common.collect.ImmutableMap;
+
+@Ignore
+// FIXME 10.7.2017: this test needs a running ODS Server, that is not suitable for continous build in Jenkins.
+// Comment this in for local tests only.
+public class ODSSearchServiceIT {
+
+	/*
+	 * ATTENTION: ==========
+	 *
+	 * To run this test make sure the target service is running a MDM default model
+	 * and any database constraint which enforces a relation of Test to a parent
+	 * entity is deactivated!
+	 */
+
+	private static final String NAME_SERVICE = "corbaloc::1.2@%s:%s/NameService";
+
+	private static final String USER = "sa";
+	private static final String PASSWORD = "sa";
+
+	private static ApplicationContext context;
+	private static ModelManager modelManager;
+	private static SearchService searchService;
+
+	@BeforeClass
+	public static void setUpBeforeClass() throws ConnectionException {
+		String nameServiceHost = System.getProperty("host");
+		String nameServicePort = System.getProperty("port");
+		String serviceName = System.getProperty("service");
+
+		if (nameServiceHost == null || nameServiceHost.isEmpty()) {
+			throw new IllegalArgumentException("name service host is unknown: define system property 'host'");
+		}
+
+		nameServicePort = nameServicePort == null || nameServicePort.isEmpty() ? String.valueOf(2809) : nameServicePort;
+		if (nameServicePort == null || nameServicePort.isEmpty()) {
+			throw new IllegalArgumentException("name service port is unknown: define system property 'port'");
+		}
+
+		if (serviceName == null || serviceName.isEmpty()) {
+			throw new IllegalArgumentException("service name is unknown: define system property 'service'");
+		}
+
+		Map<String, String> connectionParameters = new HashMap<>();
+		connectionParameters.put(PARAM_NAMESERVICE, String.format(NAME_SERVICE, nameServiceHost, nameServicePort));
+		connectionParameters.put(PARAM_SERVICENAME, serviceName + ".ASAM-ODS");
+		connectionParameters.put(PARAM_USER, USER);
+		connectionParameters.put(PARAM_PASSWORD, PASSWORD);
+
+		context = new ODSContextFactory().connect(connectionParameters);
+		modelManager = context.getModelManager().orElseThrow(() -> new ServiceNotProvidedException(ModelManager.class));
+		searchService = context.getSearchService()
+				.orElseThrow(() -> new IllegalStateException("Search service not available."));
+	}
+
+	@AfterClass
+	public static void tearDownAfterClass() throws ConnectionException {
+		if (context != null) {
+			context.close();
+		}
+	}
+
+	final class MeasurementSearchQuery extends BaseEntitySearchQuery {
+
+		/**
+		 * Constructor.
+		 *
+		 * @param modelManager Used to load {@link EntityType}s.
+		 * @param contextState The {@link ContextState}.
+		 */
+		MeasurementSearchQuery(ODSModelManager modelManager, QueryService queryService, ContextState contextState) {
+			super(modelManager, queryService, ParameterSet.class, Project.class);
+
+			// layers
+			addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+			addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+			addJoinConfig(JoinConfig.up(TestStep.class, Test.class));
+			addJoinConfig(JoinConfig.up(Measurement.class, TestStep.class));
+			addJoinConfig(JoinConfig.up(ParameterSet.class, Measurement.class));
+			addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+			addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+
+			// context
+			addJoinConfig(contextState);
+		}
+
+	}
+
+	private Extractor<FilterItem, Tuple> filterExtractors = new Extractor<FilterItem, Tuple>() {
+
+		@Override
+		public Tuple extract(FilterItem f) {
+			return tuple(f.isBooleanOperator() ? f.getBooleanOperator() : null,
+					f.isCondition() ? f.getCondition().getAttribute().getName() : null,
+					f.isCondition() ? f.getCondition().getComparisonOperator() : null,
+					f.isCondition() ? f.getCondition().getValue().extract() : null,
+					f.isBracketOperator() ? f.getBracketOperator() : null);
+		}
+	};
+
+	@org.junit.Test
+	public void testGetMergedFilter() throws Exception {
+
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(ImmutableMap.of(TestStep.class, Arrays.asList("10"))).when(service)
+				.fetchIds(Mockito.anyString());
+
+		EntityType testStep = modelManager.getEntityType(TestStep.class);
+
+		assertThat(service.getMergedFilter(Filter.idOnly(testStep, "11"), "query")).hasSize(7)
+				.extracting(filterExtractors).containsExactly(tuple(null, null, null, null, BracketOperator.OPEN),
+						tuple(null, "Id", ComparisonOperator.EQUAL, "10"),
+						tuple(null, null, null, null, BracketOperator.CLOSE),
+						tuple(BooleanOperator.AND, null, null, null, null),
+						tuple(null, null, null, null, BracketOperator.OPEN),
+						tuple(null, "Id", ComparisonOperator.IN_SET, new String[] { "10" }, null),
+						tuple(null, null, null, null, BracketOperator.CLOSE));
+	}
+
+	@org.junit.Test
+	public void testGetMergedFilterNoAttributeFilter() throws Exception {
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(ImmutableMap.of(TestStep.class, Arrays.asList("10"))).when(service)
+				.fetchIds(Mockito.anyString());
+
+		assertThat(service.getMergedFilter(Filter.and(), "query")).extracting(filterExtractors)
+				.containsExactly(tuple(null, "Id", ComparisonOperator.IN_SET, new String[] { "10" }));
+	}
+
+	@org.junit.Test
+	public void testGetMergedFilterNoFreetextResult() throws Exception {
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(Collections.emptyMap()).when(service).fetchIds(Mockito.anyString());
+
+		EntityType testStep = modelManager.getEntityType(TestStep.class);
+
+		assertThat(service.getMergedFilter(Filter.idOnly(testStep, "11"), "")).extracting(filterExtractors)
+				.containsExactly(tuple(null, "Id", ComparisonOperator.EQUAL, "11"));
+	}
+
+	@org.junit.Test
+	public void testGetMergedFilterNoAttributeFilterAndNoFreetextResult() throws Exception {
+		ODSSearchService service = Mockito.spy((ODSSearchService) searchService);
+
+		Mockito.doReturn(Collections.emptyMap()).when(service).fetchIds(Mockito.anyString());
+
+		assertThat(service.getMergedFilter(Filter.and(), null)).isEmpty();
+
+		assertThat(service.getMergedFilter(Filter.and(), "")).isEmpty();
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java
new file mode 100644
index 0000000..2e320af
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/ODSSearchServiceTest.java
@@ -0,0 +1,74 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.junit.Test;
+
+public class ODSSearchServiceTest {
+
+	@Test
+	public void testGetMergedFilter() {
+		EntityType testEntity = mockEntityType();
+		ODSSearchService searchService = mockODSSearchService(testEntity);
+
+		// No freetext query -> original filter is returned
+		assertThat(searchService.getMergedFilter(Filter.idOnly(testEntity, "1"), ""))
+				.isEqualTo(Filter.and().id(testEntity, "1"));
+
+		// Freetext query with result -> conjuction of old filter and filter generated
+		// by freetext result
+		assertThat(searchService.getMergedFilter(Filter.idOnly(testEntity, "1"), "existing"))
+				.isEqualTo(Filter.and().id(testEntity, "1").merge(Filter.or().id(testEntity, "5")));
+
+		// Freetext query with no result -> empty filter is returned
+		assertThat(searchService.getMergedFilter(Filter.idOnly(testEntity, "1"), "not existing"))
+				.isEqualTo(Filter.or());
+
+		// No filter -> filter generated by freetext result is returned
+		assertThat(searchService.getMergedFilter(Filter.or(), "existing")).isEqualTo(Filter.or().id(testEntity, "5"));
+	}
+
+	private ODSSearchService mockODSSearchService(EntityType testEntity) {
+		ODSSearchService searchService = mock(ODSSearchService.class);
+		when(searchService.getMergedFilter(any(), any())).thenCallRealMethod();
+
+		Filter f = Filter.or().id(testEntity, "5");
+		when(searchService.getFilterForFreetextQuery("existing")).thenReturn(f);
+		when(searchService.getFilterForFreetextQuery("not existing")).thenReturn(null);
+		when(searchService.getFilterForFreetextQuery("")).thenReturn(Filter.or());
+		return searchService;
+	}
+
+	private EntityType mockEntityType() {
+		Attribute idAttribute = mock(Attribute.class);
+		when(idAttribute.getName()).thenReturn("Id");
+		when(idAttribute.createValue("", "1")).thenReturn(ValueType.STRING.create("Id", "1"));
+
+		EntityType testEntity = mock(EntityType.class);
+		when(testEntity.getName()).thenReturn("TestEntity");
+		when(testEntity.getIDAttribute()).thenReturn(idAttribute);
+		when(idAttribute.getEntityType()).thenReturn(testEntity);
+		return testEntity;
+	}
+}
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/RelationSearchQuery.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/RelationSearchQuery.java
new file mode 100755
index 0000000..5d050d2
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/search/RelationSearchQuery.java
@@ -0,0 +1,66 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.search;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.ParameterSet;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.dflt.model.Pool;
+import org.eclipse.mdm.api.dflt.model.Project;
+import org.eclipse.mdm.api.odsadapter.query.ODSModelManager;
+import org.eclipse.mdm.api.odsadapter.search.JoinTree.JoinConfig;
+
+/**
+ * This class is used as a helper to the tests in
+ * org.eclipse.mdm.api.odsadapter.RelationTest It needs to be here, because
+ * BaseEntitySearchQuery is declared as protected in the
+ * org.eclipse.mdm.api.odsadapter.search package. It makes some sense to leave
+ * it protected in that way, because implementing a BaseEntitySearchQuery
+ * requires understanding of the underlying data model which The RelationTest
+ * requires that the related parametersets to a measurement are loaded. This
+ * class provides a JoinConfig which allows this to happen by defining the way
+ * the entities in question have to be joined. If we wouldn't join the
+ * ParameterSet in, the related entities would not be loaded, and it would be
+ * impossible to determine whether there are any related ParameterSets or not.
+ *
+ */
+public final class RelationSearchQuery extends BaseEntitySearchQuery {
+
+	/**
+	 * Constructor.
+	 *
+	 * @param modelManager Used to load {@link EntityType}s.
+	 * @param contextState The {@link ContextState}.
+	 */
+	public RelationSearchQuery(ODSModelManager modelManager, QueryService queryService) {
+		super(modelManager, queryService, ParameterSet.class, Project.class);
+
+		// layers
+		addJoinConfig(JoinConfig.up(Pool.class, Project.class));
+		addJoinConfig(JoinConfig.up(Test.class, Pool.class));
+		addJoinConfig(JoinConfig.up(TestStep.class, Test.class));
+		addJoinConfig(JoinConfig.up(Measurement.class, TestStep.class));
+		addJoinConfig(JoinConfig.up(ParameterSet.class, Measurement.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, Channel.class));
+		addJoinConfig(JoinConfig.down(Measurement.class, ChannelGroup.class));
+
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java
new file mode 100644
index 0000000..d9bd991
--- /dev/null
+++ b/org.eclipse.mdm.api.odsadapter/src/test/java/org/eclipse/mdm/api/odsadapter/utils/ODSConverterTest.java
@@ -0,0 +1,113 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.odsadapter.utils;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import java.time.LocalDateTime;
+
+import org.asam.ods.TS_UnionSeq;
+import org.asam.ods.TS_ValueSeq;
+import org.eclipse.mdm.api.base.query.Aggregation;
+import org.eclipse.mdm.api.odsadapter.query.ODSAttribute;
+import org.junit.Test;
+
+public class ODSConverterTest {
+
+	@Test
+	public void testFromODSValueSeqODSDateYear() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("2017"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 1, 1, 0, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateMonth() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("201710"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 1, 0, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDate() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171004"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 0, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateHour() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("2017100412"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateMinute() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("201710041213"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateSecond() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171004121314"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13, 14, 0)));
+	}
+
+	@Test
+	public void testFromODSValueSeqODSDateMillisecond() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171004121314123"));
+
+		verify(attr).createValue(eq(""), eq(true), eq(LocalDateTime.of(2017, 10, 4, 12, 13, 14, 123_000_000)));
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testFromODSValueSeqInvalidLength() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("201710041"));
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testFromODSValueSeqInvalidMonth() throws Exception {
+		ODSAttribute attr = mock(ODSAttribute.class);
+
+		ODSConverter.fromODSValueSeq(attr, Aggregation.NONE, "", getTS_ValueSeqFromDates("20171304"));
+	}
+
+	private TS_ValueSeq getTS_ValueSeqFromDates(String... dates) {
+		TS_UnionSeq u = new TS_UnionSeq();
+		u.dateVal(dates);
+		return new TS_ValueSeq(u, new short[] { 15 });
+	}
+}