"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>
+ * {
+ * @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>
+ * {
+ * @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>
+ * {
+ * @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>
+ * {
+ * @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>
+ * {
+ * @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 ∈ [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} -> {@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#SHORT} -> {@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#INTEGER} -> {@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#LONG} -> {@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<Byte> 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
+ * ∈ [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 ∈ [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 ∈ [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 ∈ [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> = ∑
+ * 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 ∈
+ * [1, n], n is the total number of values and generation parameters
+ * p<sub>j</sub> for j ∈ [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 ∈ [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> = ∑
+ * 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 ∈
+ * [1, n], n is the total number of values and generation parameters
+ * p<sub>j</sub> for j ∈ [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 ∈ [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 ∈ [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 (<)
+ */
+ LESS_THAN,
+
+ /**
+ * Less than equal (<=)
+ */
+ LESS_THAN_OR_EQUAL,
+
+ /**
+ * Greater than (>)
+ */
+ GREATER_THAN,
+
+ /**
+ * Greater than equal (>=)
+ */
+ 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 -> 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;