"561698 - Merge 'org.eclipse.mdm.api.default/dev' into 'dev'"
Signed-off-by: Simon Skoczylas <simon.skoczylas@karakun.com>
diff --git a/org.eclipse.mdm.api.default/.gitignore b/org.eclipse.mdm.api.default/.gitignore
new file mode 100644
index 0000000..49678ad
--- /dev/null
+++ b/org.eclipse.mdm.api.default/.gitignore
@@ -0,0 +1,17 @@
+# eclipse
+.classpath
+.project
+.settings/
+bin/
+
+# gradle
+.gradle
+build/
+
+# intellij
+.idea/
+out/
+*.ipr
+*.iml
+*.iws
+/bin/
diff --git a/org.eclipse.mdm.api.default/LICENSE.txt b/org.eclipse.mdm.api.default/LICENSE.txt
new file mode 100644
index 0000000..e48e096
--- /dev/null
+++ b/org.eclipse.mdm.api.default/LICENSE.txt
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0
+
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+ PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+ OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a) in the case of the initial Contributor, the initial content
+ Distributed under this Agreement, and
+
+ b) in the case of each subsequent Contributor:
+ i) changes to the Program, and
+ ii) additions to the Program;
+ where such changes and/or additions to the Program originate from
+ and are Distributed by that particular Contributor. A Contribution
+ "originates" from a Contributor if it was added to the Program by
+ such Contributor itself or anyone acting on such Contributor's behalf.
+ Contributions do not include changes or additions to the Program that
+ are not Modified Works.
+
+"Contributor" means any person or entity that Distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which
+are necessarily infringed by the use or sale of its Contribution alone
+or when combined with the Program.
+
+"Program" means the Contributions Distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement
+or any Secondary License (as applicable), including Contributors.
+
+"Derivative Works" shall mean any work, whether in Source Code or other
+form, that is based on (or derived from) the Program and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship.
+
+"Modified Works" shall mean any work in Source Code or other form that
+results from an addition to, deletion from, or modification of the
+contents of the Program, including, for purposes of clarity any new file
+in Source Code form that contains any contents of the Program. Modified
+Works shall not include works that contain only declarations,
+interfaces, types, classes, structures, or files of the Program solely
+in each case in order to link to, bind by name, or subclass the Program
+or Modified Works thereof.
+
+"Distribute" means the acts of a) distributing or b) making available
+in any manner that enables the transfer of a copy.
+
+"Source Code" means the form of a Program preferred for making
+modifications, including but not limited to software source code,
+documentation source, and configuration files.
+
+"Secondary License" means either the GNU General Public License,
+Version 2.0, or any later versions of that license, including any
+exceptions or additional permissions as identified by the initial
+Contributor.
+
+2. GRANT OF RIGHTS
+
+ a) Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free copyright
+ license to reproduce, prepare Derivative Works of, publicly display,
+ publicly perform, Distribute and sublicense the Contribution of such
+ Contributor, if any, and such Derivative Works.
+
+ b) Subject to the terms of this Agreement, each Contributor hereby
+ grants Recipient a non-exclusive, worldwide, royalty-free patent
+ license under Licensed Patents to make, use, sell, offer to sell,
+ import and otherwise transfer the Contribution of such Contributor,
+ if any, in Source Code or other form. This patent license shall
+ apply to the combination of the Contribution and the Program if, at
+ the time the Contribution is added by the Contributor, such addition
+ of the Contribution causes such combination to be covered by the
+ Licensed Patents. The patent license shall not apply to any other
+ combinations which include the Contribution. No hardware per se is
+ licensed hereunder.
+
+ c) Recipient understands that although each Contributor grants the
+ licenses to its Contributions set forth herein, no assurances are
+ provided by any Contributor that the Program does not infringe the
+ patent or other intellectual property rights of any other entity.
+ Each Contributor disclaims any liability to Recipient for claims
+ brought by any other entity based on infringement of intellectual
+ property rights or otherwise. As a condition to exercising the
+ rights and licenses granted hereunder, each Recipient hereby
+ assumes sole responsibility to secure any other intellectual
+ property rights needed, if any. For example, if a third party
+ patent license is required to allow Recipient to Distribute the
+ Program, it is Recipient's responsibility to acquire that license
+ before distributing the Program.
+
+ d) Each Contributor represents that to its knowledge it has
+ sufficient copyright rights in its Contribution, if any, to grant
+ the copyright license set forth in this Agreement.
+
+ e) Notwithstanding the terms of any Secondary License, no
+ Contributor makes additional grants to any Recipient (other than
+ those set forth in this Agreement) as a result of such Recipient's
+ receipt of the Program under the terms of a Secondary License
+ (if permitted under the terms of Section 3).
+
+3. REQUIREMENTS
+
+3.1 If a Contributor Distributes the Program in any form, then:
+
+ a) the Program must also be made available as Source Code, in
+ accordance with section 3.2, and the Contributor must accompany
+ the Program with a statement that the Source Code for the Program
+ is available under this Agreement, and informs Recipients how to
+ obtain it in a reasonable manner on or through a medium customarily
+ used for software exchange; and
+
+ b) the Contributor may Distribute the Program under a license
+ different than this Agreement, provided that such license:
+ i) effectively disclaims on behalf of all other Contributors all
+ warranties and conditions, express and implied, including
+ warranties or conditions of title and non-infringement, and
+ implied warranties or conditions of merchantability and fitness
+ for a particular purpose;
+
+ ii) effectively excludes on behalf of all other Contributors all
+ liability for damages, including direct, indirect, special,
+ incidental and consequential damages, such as lost profits;
+
+ iii) does not attempt to limit or alter the recipients' rights
+ in the Source Code under section 3.2; and
+
+ iv) requires any subsequent distribution of the Program by any
+ party to be under a license that satisfies the requirements
+ of this section 3.
+
+3.2 When the Program is Distributed as Source Code:
+
+ a) it must be made available under this Agreement, or if the
+ Program (i) is combined with other material in a separate file or
+ files made available under a Secondary License, and (ii) the initial
+ Contributor attached to the Source Code the notice described in
+ Exhibit A of this Agreement, then the Program may be made available
+ under the terms of such Secondary Licenses, and
+
+ b) a copy of this Agreement must be included with each copy of
+ the Program.
+
+3.3 Contributors may not remove or alter any copyright, patent,
+trademark, attribution notices, disclaimers of warranty, or limitations
+of liability ("notices") contained within the Program from any copy of
+the Program which they Distribute, provided that Contributors may add
+their own appropriate notices.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While this
+license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product
+offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes
+the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every
+other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits
+and other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program
+in a commercial product offering. The obligations in this section do not
+apply to any claims or Losses relating to any actual or alleged
+intellectual property infringement. In order to qualify, an Indemnified
+Contributor must: a) promptly notify the Commercial Contributor in
+writing of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those performance
+claims and warranties, and if a court requires any other Contributor to
+pay any damages as a result, the Commercial Contributor must pay
+those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
+TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+PURPOSE. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all
+risks associated with its exercise of rights under this Agreement,
+including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs
+or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software
+or hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted and
+may only be modified in the following manner. The Agreement Steward
+reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement
+Steward has the right to modify this Agreement. The Eclipse Foundation
+is the initial Agreement Steward. The Eclipse Foundation may assign the
+responsibility to serve as the Agreement Steward to a suitable separate
+entity. Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always be
+Distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to Distribute the Program (including its
+Contributions) under the new version.
+
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted
+under this Agreement are reserved. Nothing in this Agreement is intended
+to be enforceable by any entity that is not a Contributor or Recipient.
+No third-party beneficiary rights are created under this Agreement.
+
+Exhibit A - Form of Secondary Licenses Notice
+
+"This Source Code may also be made available under the following
+Secondary Licenses when the conditions for such availability set forth
+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+version(s), and exceptions or additional permissions here}."
+
+ Simply including a copy of this Agreement, including this Exhibit A
+ is not sufficient to license the Source Code under Secondary Licenses.
+
+ If it is not possible or desirable to put the notice in a particular
+ file, then You may include the notice in a location (such as a LICENSE
+ file in a relevant directory) where a recipient would be likely to
+ look for such a notice.
+
+ You may add additional accurate notices of copyright ownership.
diff --git a/org.eclipse.mdm.api.default/NOTICE.txt b/org.eclipse.mdm.api.default/NOTICE.txt
new file mode 100644
index 0000000..56281c6
--- /dev/null
+++ b/org.eclipse.mdm.api.default/NOTICE.txt
@@ -0,0 +1,382 @@
+# Notices for Eclipse MDM|BL
+
+This content is produced and maintained by the Eclipse MDM|BL project,
+it is a project of the openMDM(R) Eclipse Working Group.
+
+* Project home: https://projects.eclipse.org/projects/technology.mdmbl
+
+## Trademarks
+
+Eclipse MDM|BL, MDM|BL and Eclipse openMDM(R) logo are registered trademarks
+of the Eclipse Foundation.
+
+## Copyright
+
+All content is the property of the following respective authors or their employers.
+For more information regarding authorship of content, please consult the listed
+source code repository logs.
+
+Copyright (c) 2016-2019 Gigatronik Ingolstadt GmbH
+Copyright (c) 2016-2020 Peak Solution GmbH
+Copyright (c) 2017-2018 science + computing AG Tuebingen (ATOS SE)
+Copyright (c) 2017-2018 Canoo Engineering AG
+Copyright (c) 2017 Florian Schmitt
+Copyright (c) 2017-2020 Angelika Wittek
+Copyright (c) 2018-2019 Elektronische Fahrwerksysteme GMBH
+Copyright (c) 2018-2020 Karakun AG
+Copyright (c) 2018-2020 Alexander Nehmer
+
+## Declared Project Licenses
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v. 2.0 which is available at
+http://www.eclipse.org/legal/epl-2.0.
+
+SPDX-License-Identifier: EPL-2.0
+
+## Source Code
+
+The project maintains the following source code repositories:
+
+org.eclipse.mdm.api.base.git - The openMDM(R) API.
+org.eclipse.mdm.api.default.git - Extension of the openMDM(R) API containing default elements.
+org.eclipse.mdm.api.odsadapter.git - ODS implementation of persistence adapter.
+org.eclipse.mdm.nucleus.git - Core building blocks for the openMDM Business Logic and Web Frontend.
+
+## Third-party Content
+
+The Content includes items that have been sourced from third parties as set out below.
+If you did not receive this Content directly from the Eclipse Foundation, the following
+is provided for informational purposes only, and you should look to
+the Redistributor's license for terms and conditions of use.
+
+antlr4-4.5.3.jar(2.5.3)
+ * License: New BSD license
+
+aopalliance-repackaged-2.5.0-b05.jar (2.5.0-b05)
+ * License: CDDL
+
+commons-codec-1.2.jar (1.2)
+ * License: Apache License, 2.0
+
+commons-httpclient-3.1.jar (3.1)
+ * License: Apache License, 2.0
+
+commons-lang3-3.8.1.jar (3.8.1)
+ * License: Apache License, 2.0
+
+commons-text-1.6.jar (1.6)
+ * License: Apache License, 2.0
+
+gson-2.7.jar (2.7)
+ * License: Apache License, 2.0
+
+Google Guava Version: 25.0-jre (25.0)
+ * License: Apache License, 2.0
+
+Gradle Wrapper (4.10.2)
+ * License: Apache License, 2.0
+
+hk2-api-2.5.0-b05.jar (2.5.0-b05)
+ * License: CDDL-1.1
+
+hk2-locator-2.5.0-b05.jar(2.5.0-b05)
+ * License: CDDL
+
+hk2-utils-2.5.0-b05.jar (2.5.0-b05)
+ * License: CDDL
+
+jackson-annotations-2.9.0.jar (2.9.0)
+ * License: Apache License, 2.0
+
+jackson-core-2.9.2.jar(2.9.2)
+ * License: Apache License, 2.0
+
+jackson-databind-2.9.2.jar (2.9.2)
+ * License: Apache License, 2.0
+
+jackson-jaxrs-base-2.9.2.jar(2.9.2)
+ * License: Apache License, 2.0
+
+jackson-jaxrs-json-provider-2.9.2.jar(2.9.2)
+ * License: Apache License, 2.0
+
+jackson-module-jaxb-annotations-2.9.2.jar (2.9.2)
+ * License: Apache License, 2.0
+
+javassist-3.20.0-GA.jar (2.20.0-GA)
+ * License: Apache 2.0
+
+jcl-over-slf4j-1.7.25.jar(1.7.25)
+ * License: MIT License
+ * Licence Path: https://www.slf4j.org/license.html
+ * Project URL: https://www.slf4j.org
+ * Source URL: https://github.com/qos-ch/slf4j
+
+jersey-client-2.23.2.jar (2.23.2)
+ * License: CDDL
+
+jersey-common-2.23.2.jar (2.23.2)
+ * License: CDDL
+
+jersey-container-servlet-2.23.2.jar (2.23.2)
+ * License: CDDL
+
+jersey-container-servlet-core-2.23.3.jar(2.23.2)
+ * License: CDDL
+
+jersey-guava-2.23.2.jar (2.23.2)
+ * License: Apache License, 2.0
+
+jersey-media-jaxb-2.23.2.jar(2.23.2)
+ * License: CDDL
+
+jersey-media-sse-2.23.2.jar (2.23.2)
+ * License: CDDL
+
+jersey-media-multipart-2.23.2.jar (2.23.2)
+ * License: CDDL
+
+jersey-server-2.23.2.jar (2.23.2)
+ * License: Apache-2.0
+
+log4j-over-slf4j-1.7.25.jar (1.7.25)
+ * License: Apache-2.0
+
+logback-classic-1.2.3.jar(1.2.3)
+ * License: Eclipse Public License 1.0
+
+logback-core-1.2.3.jar(1.2.3)
+ * License: Eclipse Public License 1.0
+
+mimepull-1.9.6.jar (1.9.4)
+ * License: CDDL
+
+openatfx-0.7.4.jar (0.7.4)
+ * License: Apache-2.0
+
+osgi-resource-locator-1.0.1.jar(1.0.1)
+ * License: CDDL
+
+protobuf-java-3.2.0.jar (3.2.0)
+ * License: New BSD license
+
+protobuf-java-util-3.2.0.jar (3.2.0)
+ * License: New BSD license
+
+swagger-annotations-2.0.8.jar (2.0.8)
+ * License: Apache-2.0
+
+swagger-ui-3.23.0.jar (3.23.0)
+ * License: Apache-2.0
+
+slf4j-api-1.7.25.jar (1.7.25)
+ * License: MIT license
+ * Licence Path: https://www.slf4j.org/license.html
+ * Project URL: https://github.com/qos-ch/slf4j
+ * Source URL: https://github.com/qos-ch/slf4j/releases/tag/v_1.7.25
+
+stax2-api-3.1.4.jar (3.1.4)
+ * License: BSD-2-Clause
+
+validation-api-1.1.0.Final.jar (1.1.0.Final)
+ * License: Apache License, 2.0
+
+vavr-0.9.1-sources.jar (0.9.1)
+ * License: Apache License, 2.0
+
+vavr-match-0.9.1.jar (0.9.1)
+ * License: Apache License, 2.0
+
+woodstox-core-asl-4.4.1.jar (4.4.1)
+ * License: Apache License, 2.0
+
+
+FFAMFAMFAM Silk Icon, Version 1.3
+ * License: Creative Commons Attribution 3.0 License
+ * Licence Path: https://creativecommons.org/licenses/by/3.0/
+ * Project: http://www.famfamfam.com/lab/icons/silk/
+ * Source: http://www.famfamfam.com/lab/icons/silk/
+
+@angular/animations:7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io/api/animations
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/cdk:7.1.1
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io/api
+ * Source: https://github.com/angular/angular/releases/tag/7.1.1
+
+
+@angular/common@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io/api/common
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4r
+
+@angular/compiler@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/core@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/forms@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/http@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser-dynamic@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/router@7.2.4
+ * License: MIT
+ * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+ * Project: https://angular.io
+ * Source: https://github.com/angular/angular/releases/tag/7.2.4
+
+bootstrap@4.1.3
+ * License: MIT
+ * Licence Path: https://github.com/twbs/bootstrap/raw/master/LICENSE
+ * Project: https://getbootstrap.com/
+ * Source: https://github.com/twbs/bootstrap
+
+class-transformer@0.1.6
+ * License: MIT
+ * Licence Path: https://github.com/typestack/class-transformer/blob/master/LICENSE
+ * Project: https://github.com/pleerock/class-transformer
+ * Source: https://github.com/pleerock/class-transformer
+
+core-js@2.6.0
+ * License: MIT
+ * Licence Path: https://github.com/zloirock/core-js/raw/master/LICENSE
+ * Project: https://github.com/zloirock/core-js
+ * Source: https://github.com/zloirock/core-js/releases/tag/v2.6.0
+
+file-saver@1.3.3
+ * License: MIT
+ * Licence Path: https://github.com/eligrey/FileSaver.js/raw/master/LICENSE.md
+ * Project: https://github.com/eligrey/FileSaver.js
+ * Source: https://github.com/eligrey/FileSaver.js
+
+font-awesome@4.7.0
+ * License: MIT
+ * Licence Path: https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt
+ * Project: https://fontawesome.com/
+ * Source: https://github.com/FortAwesome/Font-Awesome
+
+ng2-split-pane@1.3.1
+ * License: MIT
+ * Licence Path: https://github.com/wannabegeek/ng2-split-pane/raw/master/LICENSE
+ * Project: https://github.com/wannabegeek/ng2-split-pane
+ * Source: https://github.com/wannabegeek/ng2-split-pane
+
+ngx-bootstrap@3.1.2
+ * License: MIT
+ * Licence Path: https://github.com/valor-software/ngx-bootstrap/blob/v3.1.2/LICENSE
+ * Project: https://valor-software.com/ngx-bootstrap
+ * Source: https://github.com/valor-software/ngx-bootstrap/tree/v3.1.2
+
+@ngx-translate/core@11.0.1
+ * License: MIT
+ * Licence Path: https://github.com/ngx-translate/core/blob/v11.0.1/LICENSE
+ * Project URL: http://www.ngx-translate.com/
+ * Source URL: https://github.com/ngx-translate/core
+
+@ngx-translate/http-loader@4.0.0
+ * License: MIT
+ * Licence Path: https://github.com/ngx-translate/http-loader/blob/v4.0.0/LICENSE
+ * Project URL: http://www.ngx-translate.com/
+ * Source URL: https://github.com/ngx-translate/http-loader/tree/v4.0.0
+
+primeicons:1.0.0
+ * License: MIT
+ * Licence Path: https://github.com/primefaces/primeicons/blob/1.0.0/LICENSE
+ * Project: https://www.primefaces.org/primeng
+ * Source: https://github.com/primefaces/primeicons/tree/1.0.0
+
+primeng@7.0.1
+ * License: MIT
+ * Licence Path: https://github.com/primefaces/primeng/blob/7.0.1/LICENSE.md
+ * Project: https://www.primefaces.org/primeng
+ * Source: https://github.com/primefaces/primeng/tree/7.0.1
+
+rxjs@6.3.3
+ * License: Apache-2.0
+ * Project: https://rxjs-dev.firebaseapp.com/
+ * Source: https://github.com/ReactiveX/rxjs/tree/6.3.3
+
+rxjs-compat:6.3.3
+ * License: Apache-2.0
+ * Project: https://rxjs-dev.firebaseapp.com/
+ * Source: https://github.com/ReactiveX/rxjs/tree/6.3.3/compat
+
+tslib@1.9.0
+ * License: Apache-2.0
+ * Project: https://github.com/Microsoft/tslib
+ * Source: https://github.com/Microsoft/tslib/tree/1.9.0
+
+zone.js@0.8.26
+ * License: MIT
+ * Licence Path: https://github.com/angular/zone.js/raw/master/LICENSE
+ * Project: https://github.com/angular
+ * Source: https://github.com/angular/zone.js/releases/tag/v0.8.26
+
+OMG Event Service Specification (1.2)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/EVNT/1.2/
+* Source: https://www.omg.org/spec/EVNT/1.2/pdf
+
+OMG Notification Service Specification (1.1)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/NOT/
+* Source: https://www.omg.org/spec/NOT/1.1/PDF
+
+ods530.idl
+Date: Hoehenkirchen, 06/01/2016
+"The ASAM Board of Directors releases the IDL files for use under the EPL to the Eclipse IWG openMDM.
+This is valid for all versions of ASAM ODS 5.3.x.
+This permission is valid under the conditions of Eclipse will not modify the file."
+
+AvalonEvent.idl, CorbaFileServer.idl
+Date: 08/15/2016
+"Herewith, we release the generated Client-Source-Code generated from our CORBA IDLs, namely
+* CORBANotification Service (generated from „AvalonEvent.idl”)
+* CORBAFileServer (generated from „CorbaFileServer.idl“),
+Under the Eclipse Public License (EPL). This agreement does not include the „AvalonEvent.idl“ and
+„CorbaFileServer.idl“ itself, which remain protected property of HighQSoft. "
+
+## Cryptography
+
+Content may contain encryption software. The country in which you are currently
+may have restrictions on the import, possession, and use, and/or re-export to
+another country, of encryption software. BEFORE using any encryption software,
+please check the country's laws, regulations and policies concerning the import,
+possession, or use, and re-export of encryption software, to see if this is
+permitted.
diff --git a/org.eclipse.mdm.api.default/build.gradle b/org.eclipse.mdm.api.default/build.gradle
new file mode 100644
index 0000000..26035f0
--- /dev/null
+++ b/org.eclipse.mdm.api.default/build.gradle
@@ -0,0 +1,49 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+description = 'MDM API - Default Model'
+group = 'org.eclipse.mdm'
+version = '5.2.0M1-SNAPSHOT'
+
+apply plugin: 'java'
+apply plugin: 'maven'
+apply plugin: 'eclipse'
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+}
+
+dependencies {
+ compile "org.eclipse.mdm:org.eclipse.mdm.api.base:${version}"
+
+ // testing
+ testCompile 'junit:junit:4.12'
+ testCompile 'org.mockito:mockito-core:2.13.0'
+ testCompile 'org.assertj:assertj-core:3.6.2'
+}
+
+jar {
+ metaInf { from 'NOTICE.txt' }
+ metaInf { from 'LICENSE.txt' }
+}
+
+task sourcesJar(type: Jar, dependsOn: classes) {
+ classifier = 'sources'
+ from sourceSets.main.allSource
+}
+
+artifacts {
+ archives sourcesJar
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.default/gradle.properties b/org.eclipse.mdm.api.default/gradle.properties
new file mode 100644
index 0000000..2ab5436
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradle.properties
@@ -0,0 +1,16 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+sourceCompatibility=1.8
+targetCompatibility=1.8
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.jar b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.properties b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82e006
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
diff --git a/org.eclipse.mdm.api.default/gradlew b/org.eclipse.mdm.api.default/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/org.eclipse.mdm.api.default/gradlew.bat b/org.eclipse.mdm.api.default/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/org.eclipse.mdm.api.default/settings.gradle b/org.eclipse.mdm.api.default/settings.gradle
new file mode 100644
index 0000000..c7402a5
--- /dev/null
+++ b/org.eclipse.mdm.api.default/settings.gradle
@@ -0,0 +1,15 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+rootProject.name = 'org.eclipse.mdm.api.default'
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContext.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContext.java
new file mode 100644
index 0000000..2831ec9
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContext.java
@@ -0,0 +1,28 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt;
+
+import org.eclipse.mdm.api.base.BaseApplicationContext;
+import org.eclipse.mdm.api.dflt.model.EntityFactory;
+
+/**
+ * Extends the {@link BaseApplicationContext} interface to return
+ * {@link EntityFactory} and {@link EntityManager}.
+ *
+ * @since 1.0.0
+ */
+public interface ApplicationContext extends BaseApplicationContext<EntityFactory, EntityManager> {
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContextFactory.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContextFactory.java
new file mode 100644
index 0000000..2bdad67
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/ApplicationContextFactory.java
@@ -0,0 +1,27 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt;
+
+import org.eclipse.mdm.api.base.BaseApplicationContextFactory;
+
+/**
+ * Extends the {@link BaseApplicationContextFactory} interface to return an
+ * {@link ApplicationContext}.
+ *
+ * @since 1.0.0
+ */
+public interface ApplicationContextFactory extends BaseApplicationContextFactory<ApplicationContext> {
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/EntityManager.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/EntityManager.java
new file mode 100644
index 0000000..8298101
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/EntityManager.java
@@ -0,0 +1,167 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.dflt.model.Status;
+import org.eclipse.mdm.api.dflt.model.TemplateTest;
+import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
+import org.eclipse.mdm.api.dflt.model.Versionable;
+
+/**
+ * Extends the {@link BaseEntityManager} interface with additional load methods
+ * dedicated to the default application models.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface EntityManager extends BaseEntityManager {
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Loads the entity identified by given entity class, {@link ContextType} and
+ * its instance ID.
+ *
+ * @param <T> The desired type.
+ * @param entityClass Type of the returned entity.
+ * @param contextType The {@link ContextType}.
+ * @param instanceID The instance ID.
+ * @return The entity with given instance ID is returned.
+ * @throws DataAccessException Thrown if unable to retrieve the entity.
+ */
+ default <T extends Entity> T load(Class<T> entityClass, ContextType contextType, String instanceID)
+ throws DataAccessException {
+ List<T> entities = load(entityClass, contextType, Collections.singletonList(instanceID));
+ if (entities.size() != 1) {
+ throw new DataAccessException("Failed to load entity by instance ID.");
+ }
+ return entities.get(0);
+
+ }
+
+ <T extends Entity> List<T> load(Class<T> entityClass, ContextType contextType, Collection<String> instanceIDs)
+ throws DataAccessException;
+
+ /**
+ * Loads all available entities of given type.
+ *
+ * <pre>
+ * {
+ * @code
+ * List<CatalogComponent> catalogComponents = entityManager.loadAll(CatalogComponent.class, UNITUNDERTEST);
+ * }
+ * </pre>
+ *
+ * @param <T> The desired type.
+ * @param entityClass Type of the returned entities.
+ * @param contextType The {@link ContextType}.
+ * @return Entities are returned in a {@code List}.
+ * @throws DataAccessException Thrown if unable to retrieve the entities.
+ * @see #loadAll(Class, ContextType, String)
+ */
+ default <T extends Entity> List<T> loadAll(Class<T> entityClass, ContextType contextType)
+ throws DataAccessException {
+ return loadAll(entityClass, contextType, "*");
+ }
+
+ /**
+ * Loads all available entities of given type whose name fulfills the given
+ * pattern.
+ *
+ * <pre>
+ * {
+ * @code
+ * // retrieve all template roots whose name starts with 'Example'
+ * List<TemplateRoot> templateRoots = entityManager.loadAll(TemplateRoot.class, UNITUNDERTEST, "Example*");
+ * }
+ * </pre>
+ *
+ * @param <T> The desired type.
+ * @param entityClass Type of the returned entities.
+ * @param contextType The {@link ContextType}.
+ * @param pattern Is always case sensitive and may contain wildcard
+ * characters as follows: "?" for one matching character and
+ * "*" for a sequence of matching characters.
+ * @return Matched entities are returned in a {@code List}.
+ * @throws DataAccessException Thrown if unable to retrieve the entities.
+ * @see #loadAll(Class)
+ */
+ <T extends Entity> List<T> loadAll(Class<T> entityClass, ContextType contextType, String pattern)
+ throws DataAccessException;
+
+ /**
+ * Loads the latest valid {@link Versionable} entity of given type and name.
+ *
+ * @param <T> The desired type.
+ * @param entityClass Type of the returned entity.
+ * @param name The exact name of the requested entity.
+ * @return Optional is empty if no such entity was found
+ * @throws DataAccessException Thrown if unable to retrieve the entity.
+ */
+ default <T extends Versionable> Optional<T> loadLatestValid(Class<T> entityClass, String name)
+ throws DataAccessException {
+ return loadAll(entityClass, name).stream().filter(v -> v.nameEquals(name)).filter(Versionable::isValid)
+ .max(Versionable.COMPARATOR);
+ }
+
+ /**
+ * Loads the latest valid {@link Versionable} entity of given type,
+ * {@link ContextType} and name.
+ *
+ * @param <T> The desired type.
+ * @param entityClass Type of the returned entity.
+ * @param contextType The {@code ContextType}.
+ * @param name The exact name of the requested entity.
+ * @return Optional is empty if no such entity was found
+ * @throws DataAccessException Thrown if unable to retrieve the entity.
+ */
+ default <T extends Versionable> Optional<T> loadLatestValid(Class<T> entityClass, ContextType contextType,
+ String name) throws DataAccessException {
+ return loadAll(entityClass, contextType, name).stream().filter(v -> v.nameEquals(name))
+ .filter(Versionable::isValid).max(Versionable.COMPARATOR);
+ }
+
+ <T extends StatusAttachable> List<T> loadAll(Class<T> entityClass, Status status, String pattern);
+
+ /**
+ * Loads the refereced {@link TemplateTest} for a {@link Test}.
+ *
+ * @param test {@link Test} referencing the desired template
+ * @return {@link Optional} with the loaded {@link TemplateTest}
+ */
+ Optional<TemplateTest> loadTemplate(Test test);
+
+ /**
+ * Loads the referenced {@link TemplateTestStep} for a {@link TestStep}
+ *
+ * @param testStep {@link TestStep} referencing the desired template
+ * @return {@link Optional} with the loaded {@link TemplateTestStep}
+ */
+ Optional<TemplateTestStep> loadTemplate(TestStep testStep);
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogAttribute.java
new file mode 100644
index 0000000..ac6c20d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogAttribute.java
@@ -0,0 +1,321 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Unit;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Implementation of the catalog attribute entity type. A catalog attribute is a
+ * generic attribute description to store context data ("as measured", "as
+ * ordered"). It always belongs to a {@link CatalogComponent} or a
+ * {@link CatalogSensor}. Its name has to be unique within the parent and may
+ * not be changed, once written.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogComponent
+ * @see CatalogSensor
+ */
+public class CatalogAttribute extends BaseEntity implements Deletable, Describable, Sortable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The 'ValueListReference' attribute name.
+ */
+ public static final String ATTR_VALUE_LIST_REFERENCE = "ValueListRef";
+
+ /**
+ * The 'ValueCopyable' attribute name.
+ */
+ public static final String ATTR_VALUE_COPYABLE = "ValueCopyable";
+
+ /**
+ * The 'ActionRequestClassname' attribute name.
+ */
+ public static final String ATTR_ACTION_REQUEST_CLASSNAME = "ActionRequestClassname";
+
+ /**
+ * The <u>virtual</u> '{@literal @}EnumerationName' attribute name.
+ */
+ public static final String VATTR_ENUMERATION_NAME = "@EnumerationName";
+
+ /**
+ * The <u>virtual</u> '{@literal @}ScalarType' attribute name.
+ */
+ public static final String VATTR_SCALAR_TYPE = "@ScalarType";
+
+ /**
+ * The <u>virtual</u> '{@literal @}Sequence' attribute name.
+ */
+ public static final String VATTR_SEQUENCE = "@Sequence";
+
+ // ======================================================================
+ // Instance variables
+ // ======================================================================
+
+ private Enumeration<?> enumerationObj;
+ private final Value scalarTypeValue;
+ private final Value sequenceValue;
+
+ private Unit unit;
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ CatalogAttribute(Core core) {
+ super(core);
+
+ Map<String, Value> values = core.getValues();
+ EnumRegistry er = EnumRegistry.getInstance();
+ Value enumValue = values.remove(VATTR_ENUMERATION_NAME);
+ if (enumValue != null) {
+ enumerationObj = er.get(enumValue.extract(ValueType.STRING));
+ }
+ scalarTypeValue = values.remove(VATTR_SCALAR_TYPE);
+ sequenceValue = values.remove(VATTR_SEQUENCE);
+
+ unit = core.getMutableStore().get(Unit.class);
+ core.getMutableStore().remove(Unit.class);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Checks whether it is allowed to store other data than those provided via
+ * related {@link ValueList}.
+ *
+ * @return Returns {@code false} if it is allowed to store other values then
+ * those provided.
+ */
+ public Boolean isValueListReference() {
+ boolean valueListReference = getValue(ATTR_VALUE_LIST_REFERENCE).extract();
+ return valueListReference && getValueList().isPresent();
+ }
+
+ /**
+ * Sets a new value reference flag for this catalog attribute.
+ *
+ * @param valueListReference The new value list reference flag.
+ */
+ public void setValueListReference(Boolean valueListReference) {
+ getValue(ATTR_VALUE_LIST_REFERENCE).set(valueListReference);
+ }
+
+ /**
+ * Checks whether it is allowed to copy the contained value in case of an
+ * associated descriptive component is copied.
+ *
+ * @return Returns {@code true} if it allowed to copy a contained value.
+ */
+ public Boolean isValueCopyable() {
+ return getValue(ATTR_VALUE_COPYABLE).extract();
+ }
+
+ /**
+ * Sets a new value copyable flag for this catalog attribute.
+ *
+ * @param valueCopyable The new value copyable flag.
+ */
+ public void setValueCopyable(Boolean valueCopyable) {
+ getValue(ATTR_VALUE_COPYABLE).set(valueCopyable);
+ }
+
+ /**
+ * Returns the action request class name of this catalog attribute.
+ *
+ * @return The action request class name is returned.
+ */
+ public String getActionRequestClassname() {
+ return getValue(ATTR_ACTION_REQUEST_CLASSNAME).extract();
+ }
+
+ /**
+ * Sets a new action request class name for this attribute.
+ *
+ * @param actionRequestClassname The new action request class name.
+ */
+ public void setActionRequestClassname(String actionRequestClassname) {
+ getValue(ATTR_ACTION_REQUEST_CLASSNAME).set(actionRequestClassname);
+ }
+
+ /**
+ * Returns the related {@link ValueList}.
+ *
+ * @return {@code Optional} is empty if no {@code ValueList} is related.
+ */
+ public Optional<ValueList> getValueList() {
+ return Optional.ofNullable(getCore().getMutableStore().get(ValueList.class));
+ }
+
+ /**
+ * Replaces current {@link ValueList} relation with the given one.
+ *
+ * @param valueList The new {@code ValueList} may be null.
+ */
+ public void setValueList(ValueList valueList) {
+ if (valueList == null) {
+ getCore().getMutableStore().remove(ValueList.class);
+ setValueListReference(Boolean.FALSE);
+ } else {
+ getCore().getMutableStore().set(valueList);
+ }
+ }
+
+ /**
+ * Returns the parent {@link CatalogComponent}.
+ *
+ * @return {@code Optional} is empty if a {@link CatalogSensor} is parent of
+ * this catalog attribute.
+ * @see #getCatalogSensor()
+ */
+ public Optional<CatalogComponent> getCatalogComponent() {
+ return Optional.ofNullable(getCore().getPermanentStore().get(CatalogComponent.class));
+ }
+
+ /**
+ * Returns the parent {@link CatalogSensor}.
+ *
+ * @return {@code Optional} is empty if a {@link CatalogComponent} is parent of
+ * this catalog attribute.
+ * @see #getCatalogComponent()
+ */
+ public Optional<CatalogSensor> getCatalogSensor() {
+ return Optional.ofNullable(getCore().getPermanentStore().get(CatalogSensor.class));
+ }
+
+ /**
+ * Returns the virtual and unmodifiable {@link ValueType} of this catalog
+ * attribute.
+ *
+ * @return The {@code ValueType} is returned.
+ */
+ public ValueType<?> getValueType() {
+ ScalarType scalarType = scalarTypeValue.extract();
+ Boolean sequence = sequenceValue.extract();
+ return sequence.booleanValue() ? scalarType.toValueType() : scalarType.toSingleValueType();
+ }
+
+ /**
+ * Returns the virtual and unmodifiable enumeration class of this catalog
+ * attribute.
+ *
+ * @return The enumeration class is returned.
+ * @throws IllegalStateException Thrown if this catalog attribute's
+ * {@link ValueType} returns {@code true} when
+ * {@link ValueType#isEnumerationType()} is
+ * called.
+ */
+ @SuppressWarnings("rawtypes")
+ public Enumeration getEnumerationObject() {
+ if (!getValueType().isEnumerationType()) {
+ throw new IllegalStateException("Catalog attribute is not of type enumeration.");
+ }
+ return enumerationObj;
+ }
+
+ /**
+ * Returns the {@link Unit} of this catalog attribute.
+ *
+ * @return {@code Optional} is empty if no unit is defined.
+ */
+ public Optional<Unit> getUnit() {
+ return Optional.ofNullable(unit);
+ }
+
+ /**
+ * Sets a new {@link Unit} for this catalog attribute.
+ *
+ * @param unit The new {@code Unit} may be null.
+ */
+ public void setUnit(Unit unit) {
+ this.unit = unit;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+
+ ScalarType scalarType = scalarTypeValue.extract();
+ sb.append("ScalarType = ").append(scalarType);
+ if (scalarType.isEnumeration()) {
+ sb.append(", EnumerationObject = ").append(getEnumerationObject());
+ }
+
+ sb.append(", Sequence = ").append((boolean) sequenceValue.extract());
+
+ Optional<Unit> catalogUnit = getUnit();
+ if (catalogUnit.isPresent()) {
+ sb.append(", Unit = ").append(catalogUnit.get());
+ }
+
+ sb.append(", ").append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ return sb.append(')').toString();
+ }
+
+ // ======================================================================
+ // Package methods
+ // ======================================================================
+
+ /**
+ * Sets {@link ValueType} of this catalog attribute.
+ *
+ * @param valueType The {@link ValueType}.
+ */
+ void setValueType(ValueType<?> valueType) {
+ Enumeration<?> scalarTypeEnum = EnumRegistry.getInstance().get(EnumRegistry.SCALAR_TYPE);
+ scalarTypeValue.set(scalarTypeEnum.valueOf(valueType.toSingleType().name()));
+ sequenceValue.set(valueType.isSequence());
+ }
+
+ /**
+ * Sets enumeration Object of this catalog attribute.
+ *
+ * @param enumerationObj The enumeration.
+ */
+ void setEnumerationObj(Enumeration<?> enumerationObj) {
+ setValueType(ValueType.ENUMERATION);
+ this.enumerationObj = enumerationObj;
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogComponent.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogComponent.java
new file mode 100644
index 0000000..f91dc18
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogComponent.java
@@ -0,0 +1,192 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the catalog component entity type. A catalog component acts
+ * as a container to store context data ("as measured", "as ordered"). Each
+ * catalog component has a corresponding entity type whose name is equal to the
+ * name of the catalog component. Therefore the name of a catalog component has
+ * to be unique and is not allowed to be modified, once written. A catalog
+ * component consists of {@link CatalogAttribute} which describe the attributes
+ * of this container. In case of {@link ContextType#TESTEQUIPMENT} it may have
+ * {@link CatalogSensor}s which describe the available measurement sensors.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogAttribute
+ * @see CatalogSensor
+ */
+public class CatalogComponent extends BaseEntity implements Datable, Deletable, Describable {
+
+ // ======================================================================
+ // Instance variables
+ // ======================================================================
+
+ private final ContextType contextType;
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ CatalogComponent(Core core) {
+ super(core);
+
+ String typeName = core.getTypeName().toUpperCase(Locale.ROOT);
+ for (ContextType contextTypeCandidate : ContextType.values()) {
+ if (typeName.contains(contextTypeCandidate.name())) {
+ contextType = contextTypeCandidate;
+ return;
+ }
+ }
+
+ throw new IllegalStateException("Core is incompatible.");
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the {@link ContextType} of this catalog component.
+ *
+ * @return The {@code ContextType} is returned.
+ */
+ public ContextType getContextType() {
+ return contextType;
+ }
+
+ /**
+ * Returns the {@link CatalogAttribute} identified by given name.
+ *
+ * @param name The name of the {@code CatalogAttribute}.
+ * @return The {@code Optional} is empty if a {@code CatalogAttribute} with
+ * given name does not exist.
+ */
+ public Optional<CatalogAttribute> getCatalogAttribute(String name) {
+ return getCatalogAttributes().stream().filter(ca -> ca.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link CatalogAttribute}s related to this catalog
+ * component.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<CatalogAttribute> getCatalogAttributes() {
+ return getCore().getChildrenStore().get(CatalogAttribute.class);
+ }
+
+ /**
+ * Removes the {@link CatalogAttribute} identified by given name.
+ *
+ * @param name Name of the {@code CatalogAttribute} that has to be removed.
+ * @return Returns {@code true} if the {@code CatalogAttribute} with given name
+ * has been removed.
+ */
+ public boolean removeCatalogAttribute(String name) {
+ Optional<CatalogAttribute> catalogAttribute = getCatalogAttribute(name);
+ if (catalogAttribute.isPresent()) {
+ getCore().getChildrenStore().remove(catalogAttribute.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the {@link CatalogSensor} identified by given name.
+ *
+ * @param name The name of the {@code CatalogSensor}.
+ * @return The {@code Optional} is empty if a {@code CatalogSensor} with given
+ * name does not exist.
+ */
+ public Optional<CatalogSensor> getCatalogSensor(String name) {
+ return getCatalogSensors().stream().filter(cs -> cs.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link CatalogSensor}s related to this catalog
+ * component.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<CatalogSensor> getCatalogSensors() {
+ if (contextType.isTestEquipment()) {
+ return getCore().getChildrenStore().get(CatalogSensor.class);
+ }
+
+ return Collections.emptyList();
+ }
+
+ /**
+ * Removes the {@link CatalogSensor} identified by given name.
+ *
+ * @param name Name of the {@code CatalogSensor} that has to be removed.
+ * @return Returns {@code true} if the {@code CatalogSensor} with given name has
+ * been removed.
+ */
+ public boolean removeCatalogSensor(String name) {
+ Optional<CatalogSensor> catalogSensor = getCatalogSensor(name);
+ if (catalogSensor.isPresent()) {
+ getCore().getChildrenStore().remove(catalogSensor.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+ sb.append("ContextType = ").append(getContextType()).append(", ");
+ sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ List<CatalogAttribute> catalogAttributes = getCatalogAttributes();
+ if (!catalogAttributes.isEmpty()) {
+ sb.append(", CatalogAttributes = ").append(catalogAttributes);
+ }
+
+ List<CatalogSensor> catalogSensors = getCatalogSensors();
+ if (!catalogSensors.isEmpty()) {
+ sb.append(", CatalogSensors = ").append(catalogSensors);
+ }
+
+ return sb.append(')').toString();
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogSensor.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogSensor.java
new file mode 100644
index 0000000..d365abd
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/CatalogSensor.java
@@ -0,0 +1,126 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the catalog sensor entity type. A catalog sensor acts as a
+ * container to store sensor context data ("as measured", "as ordered"). It
+ * always belongs to a {@link CatalogComponent} of type
+ * {@link ContextType#TESTEQUIPMENT}. Each catalog sensor has a corresponding
+ * entity type whose name is equal to the name of the catalog sensor. Therefore
+ * the name of a catalog sensor has to be unique and is not allowed to be
+ * modified, once written. A catalog sensor consists of {@link CatalogAttribute}
+ * which describe the attributes of this container.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogComponent
+ * @see CatalogComponent
+ */
+public class CatalogSensor extends BaseEntity implements Datable, Deletable, Describable {
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ CatalogSensor(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the parent {@link CatalogComponent}.
+ *
+ * @return The parent {@code CatalogComponent} is returned.
+ */
+ public CatalogComponent getCatalogComponent() {
+ return getCore().getPermanentStore().get(CatalogComponent.class);
+ }
+
+ /**
+ * Returns the {@link CatalogAttribute} identified by given name.
+ *
+ * @param name The name of the {@code CatalogAttribute}.
+ * @return The {@code Optional} is empty if a {@code CatalogAttribute} with
+ * given name does not exist.
+ */
+ public Optional<CatalogAttribute> getCatalogAttribute(String name) {
+ return getCatalogAttributes().stream().filter(ca -> ca.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link CatalogAttribute}s related to this catalog
+ * sensor.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<CatalogAttribute> getCatalogAttributes() {
+ return getCore().getChildrenStore().get(CatalogAttribute.class);
+ }
+
+ /**
+ * Removes the {@link CatalogAttribute} identified by given name.
+ *
+ * @param name Name of the {@code CatalogAttribute} that has to be removed.
+ * @return Returns {@code true} if the {@code CatalogAttribute} with given name
+ * has been removed.
+ */
+ public boolean removeCatalogAttribute(String name) {
+ Optional<CatalogAttribute> catalogAttribute = getCatalogAttribute(name);
+ if (catalogAttribute.isPresent()) {
+ getCore().getChildrenStore().remove(catalogAttribute.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+ sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ List<CatalogAttribute> catalogAttributes = getCatalogAttributes();
+ if (!catalogAttributes.isEmpty()) {
+ sb.append(", CatalogAttributes = ").append(catalogAttributes);
+ }
+
+ return sb.append(')').toString();
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Classification.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Classification.java
new file mode 100644
index 0000000..6cb91ff
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Classification.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+
+public class Classification extends BaseEntity {
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ Classification(Core core) {
+ super(core);
+ }
+
+ /**
+ * Assigns this status to given {@link StatusAttachable}s.
+ *
+ * @param <T> The status attachable type.
+ * @param statusAttachables This status will be assigned to all of them.
+ */
+ public <T extends StatusAttachable> void assign(List<T> statusAttachables) {
+ statusAttachables.forEach(this::assign);
+ }
+
+ /**
+ * Assigns this status to given {@link StatusAttachable}.
+ *
+ * @param <T> The status attachable type.
+ * @param statusAttachable This status will be assigned to it.
+ */
+ public <T extends StatusAttachable> void assign(T statusAttachable) {
+ getCore(statusAttachable).getMutableStore().set(this);
+ }
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Domain.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Domain.java
new file mode 100644
index 0000000..f31fcdd
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Domain.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Describable;
+
+public class Domain extends BaseEntity implements Describable {
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ Domain(Core core) {
+ super(core);
+ }
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/EntityFactory.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/EntityFactory.java
new file mode 100644
index 0000000..d18d760
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/EntityFactory.java
@@ -0,0 +1,1244 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextSensor;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Quantity;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+import org.eclipse.mdm.api.base.model.VersionState;
+
+/**
+ * Creates new entities of the default application model.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public abstract class EntityFactory extends BaseEntityFactory {
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Creates a new {@link Role}.
+ *
+ * @param name Name of the created {@code Role}.
+ * @return The created {@code Role} is returned.
+ */
+ public Role createRole(String name) {
+ Role role = new Role(createCore(Role.class));
+
+ // properties
+ role.setName(name);
+
+ return role;
+ }
+
+ /**
+ * Always throws an UnsupportedOperationException since in a default model each
+ * {@link Test} has a parent {@link Pool}.
+ *
+ * @throws UnsupportedOperationException Is always thrown.
+ */
+ @Override
+ public Test createTest(String name) {
+ throw new UnsupportedOperationException("Test requires a parent Pool.");
+ }
+
+ /**
+ * Creates a new {@link Project}.
+ *
+ * @param name Name of the created {@code Project}.
+ * @return The created {@code Project} is returned.
+ */
+ public Project createProject(String name) {
+ Project project = new Project(createCore(Project.class));
+
+ // properties
+ project.setName(name);
+
+ return project;
+ }
+
+ /**
+ * Creates a new {@link Pool} for given {@link Project}.
+ *
+ * @param name Name of the created {@code Pool}.
+ * @param project The parent {@code Project}.
+ * @return The created {@code Pool} is returned.
+ */
+ public Pool createPool(String name, Project project) {
+ Pool pool = new Pool(createCore(Pool.class));
+
+ // relations
+ getCore(pool).getPermanentStore().set(project);
+ getCore(project).getChildrenStore().add(pool);
+
+ // properties
+ pool.setName(name);
+
+ return pool;
+ }
+
+ /**
+ * Creates a new {@link Test} for given {@link Pool}.
+ *
+ * @param name Name of the created {@code Test}.
+ * @param pool The parent {@code Pool}.
+ * @return The created {@code Test} is returned.
+ */
+ public Test createTest(String name, Pool pool) {
+ return createTest(name, pool, (Status) null);
+ }
+
+ /**
+ * Creates a new {@link Test} for given {@link Pool} using given
+ * {@link TemplateTest}.
+ *
+ * @param name Name of the created {@code Test}.
+ * @param pool The parent {@code Pool}.
+ * @param templateTest The template the returned {@code Test} will be derived
+ * from.
+ * @return The created {@code Test} is returned.
+ */
+ // TODO make a decision: status in or out!
+ public Test createTest(String name, Pool pool, TemplateTest templateTest) {
+ return createTest(name, pool, null, null, templateTest);
+ }
+
+ /**
+ * Creates a new {@link ContextRoot} for given {@link TestStep} using given
+ * {@link TemplateRoot}.
+ *
+ * @param testStep The parent {@code TestStep}.
+ * @param templateRoot The template the returned {@code ContextRoot} will be
+ * derived from.
+ * @return The created {@code ContextRoot} is returned.
+ */
+ public ContextRoot createContextRoot(TestStep testStep, TemplateRoot templateRoot) {
+ ContextRoot contextRoot = createContextRoot(templateRoot);
+
+ // relations
+ getCore(testStep).getMutableStore().set(contextRoot, templateRoot.getContextType());
+
+ return contextRoot;
+ }
+
+ /**
+ * Creates a new {@link ContextRoot} for given {@link Measurement} using given
+ * {@link TemplateRoot}.
+ *
+ * @param measurement The parent {@code Measurement}.
+ * @param templateRoot The template the returned {@code ContextRoot} will be
+ * derived from.
+ * @return The created {@code ContextRoot} is returned.
+ */
+ public ContextRoot createContextRoot(Measurement measurement, TemplateRoot templateRoot) {
+ return createContextRoot(Arrays.asList(measurement), templateRoot);
+ }
+
+ /**
+ * Creates a new {@link ContextRoot} for given {@link List} if
+ * {@link Measurement}s using given {@link TemplateRoot}. If List is null or
+ * empty context root is created with no relations.
+ *
+ * @param measurements The parent {@code Measurement}.
+ * @param templateRoot The template the returned {@code ContextRoot} will be
+ * derived from.
+ * @return The created {@code ContextRoot} is returned.
+ */
+ public ContextRoot createContextRoot(List<Measurement> measurements, TemplateRoot templateRoot) {
+ ContextRoot contextRoot = createContextRoot(templateRoot);
+
+ // relations
+ if (measurements != null && !measurements.isEmpty()) {
+ measurements.forEach(m -> getCore(m).getMutableStore().set(contextRoot, templateRoot.getContextType()));
+ }
+
+ return contextRoot;
+ }
+
+ /**
+ * Creates a new {@link ContextRoot} using given {@link TemplateRoot}.
+ *
+ * @param templateRoot The template the returned {@code ContextRoot} will be
+ * derived from.
+ * @return The created {@code ContextRoot} is returned.
+ */
+ public ContextRoot createContextRoot(TemplateRoot templateRoot) {
+ ContextRoot contextRoot = createContextRoot(templateRoot.getName(), templateRoot.getContextType());
+
+ // relations
+ getCore(contextRoot).getMutableStore().set(templateRoot);
+
+ // create default active and mandatory context components
+ templateRoot.getTemplateComponents().stream()
+ .filter(TemplateComponent.IS_DEFAULT_ACTIVE.or(TemplateComponent.IS_MANDATORY))
+ .forEach(templateComponent -> {
+ createContextComponent(templateComponent.getName(), contextRoot);
+ });
+
+ return contextRoot;
+ }
+
+ /**
+ * @throws IllegalArgumentException Thrown if given name is already in use or
+ * {@link TemplateComponent} with given name
+ * does not exist.
+ */
+ @Override
+ public ContextComponent createContextComponent(String name, ContextRoot contextRoot) {
+ if (contextRoot.getContextComponent(name).isPresent()) {
+ throw new IllegalArgumentException("Context component with name '" + name + "' already exists.");
+ }
+
+ TemplateRoot templateRoot = TemplateRoot.of(contextRoot)
+ .orElseThrow(() -> new IllegalArgumentException("Template root is not available."));
+
+ Optional<TemplateComponent> templateComponent = templateRoot.getTemplateComponent(name);
+ if (templateComponent.isPresent()) {
+ // recursively create missing parent context components
+ templateComponent.get().getParentTemplateComponent()
+ .filter(tc -> !contextRoot.getContextComponent(tc.getName()).isPresent())
+ .ifPresent(tc -> createContextComponent(tc.getName(), contextRoot));
+
+ // create context component if not already done
+ if (!contextRoot.getContextComponent(name).isPresent()) {
+ ContextComponent contextComponent = super.createContextComponent(
+ templateComponent.get().getCatalogComponent().getName(), contextRoot);
+
+ // relations
+ getCore(contextComponent).getMutableStore().set(templateComponent.get());
+
+ // properties
+ contextComponent.setName(name);
+ contextComponent
+ .setMimeType(contextComponent.getMimeType().addSubType(templateComponent.get().getName()));
+ hideValues(getCore(contextComponent), templateComponent.get().getTemplateAttributes());
+ templateComponent.get().getTemplateAttributes().forEach(ta -> {
+ contextComponent.getValue(ta.getName()).set(ta.getDefaultValue().extract());
+ });
+
+ // create default active and mandatory child context components
+ templateComponent.get().getTemplateComponents().stream().filter(TemplateComponent.IS_IMPLICIT_CREATE)
+ .forEach(childTemplateComponent -> {
+ createContextComponent(childTemplateComponent.getName(), contextRoot);
+ });
+
+ // create default active and mandatory context sensors
+ templateComponent.get().getTemplateSensors().stream().filter(TemplateSensor.IS_IMPLICIT_CREATE)
+ .forEach(templateSensor -> {
+ createContextSensor(templateSensor.getName(), contextComponent);
+ });
+
+ return contextComponent;
+ }
+ }
+
+ throw new IllegalArgumentException("Template component with name '" + name + "' does not exist.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ContextSensor createContextSensor(String name, ContextComponent contextComponent) {
+ if (contextComponent.getContextSensor(name).isPresent()) {
+ throw new IllegalArgumentException("Context sensor with name '" + name + "' already exists.");
+ }
+
+ TemplateComponent templateComponent = TemplateComponent.of(contextComponent)
+ .orElseThrow(() -> new IllegalArgumentException("Template component is not available."));
+
+ Optional<TemplateSensor> templateSensor = templateComponent.getTemplateSensor(name);
+ if (templateSensor.isPresent()) {
+ ContextSensor contextSensor = super.createContextSensor(templateSensor.get().getCatalogSensor().getName(),
+ contextComponent);
+
+ // relations
+ getCore(contextSensor).getMutableStore().set(templateSensor.get());
+
+ // properties
+ contextSensor.setName(name);
+ hideValues(getCore(contextSensor), templateSensor.get().getTemplateAttributes());
+ templateSensor.get().getTemplateAttributes().forEach(ta -> {
+ contextSensor.getValue(ta.getName()).set(ta.getDefaultValue().extract());
+ });
+
+ return contextSensor;
+ }
+
+ throw new IllegalArgumentException("Template sensor with name '" + name + "' does not exist.");
+ }
+
+ /**
+ * Creates a new {@link CatalogComponent} with given {@link ContextType} and
+ * name.
+ *
+ * @param contextType The {@code ContextType}.
+ * @param name Name of the created {@code CatalogComponent}.
+ * @return The created {@code CatalogComponent} is returned.
+ * @throws IllegalArgumentException Thrown if name is not allowed.
+ */
+ public CatalogComponent createCatalogComponent(ContextType contextType, String name) {
+ validateCatalogName(name, false);
+
+ CatalogComponent catalogComponent = new CatalogComponent(createCore(CatalogComponent.class, contextType));
+
+ // properties
+ catalogComponent.setName(name);
+ catalogComponent.setDateCreated(LocalDateTime.now());
+ catalogComponent.getValue("ValidFlag").set(VersionState.VALID);
+
+ return catalogComponent;
+ }
+
+ /**
+ * Creates a new {@link CatalogAttribute} for given {@link CatalogComponent}.
+ * The {@link ValueType} may be one of the following:
+ *
+ * <ul>
+ * <li>{@link ValueType#STRING}</li>
+ * <li>{@link ValueType#STRING_SEQUENCE}</li>
+ * <li>{@link ValueType#DATE}</li>
+ * <li>{@link ValueType#DATE_SEQUENCE}</li>
+ * <li>{@link ValueType#BOOLEAN}</li>
+ * <li>{@link ValueType#BOOLEAN_SEQUENCE}</li>
+ * <li>{@link ValueType#BYTE}</li>
+ * <li>{@link ValueType#BYTE_SEQUENCE}</li>
+ * <li>{@link ValueType#SHORT}</li>
+ * <li>{@link ValueType#SHORT_SEQUENCE}</li>
+ * <li>{@link ValueType#INTEGER}</li>
+ * <li>{@link ValueType#INTEGER_SEQUENCE}</li>
+ * <li>{@link ValueType#LONG}</li>
+ * <li>{@link ValueType#LONG_SEQUENCE}</li>
+ * <li>{@link ValueType#FLOAT}</li>
+ * <li>{@link ValueType#FLOAT_SEQUENCE}</li>
+ * <li>{@link ValueType#DOUBLE}</li>
+ * <li>{@link ValueType#DOUBLE_SEQUENCE}</li>
+ * <li>{@link ValueType#BYTE_STREAM}</li>
+ * <li>{@link ValueType#BYTE_STREAM_SEQUENCE}</li>
+ * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+ * <li>{@link ValueType#FLOAT_COMPLEX_SEQUENCE}</li>
+ * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+ * <li>{@link ValueType#DOUBLE_COMPLEX_SEQUENCE}</li>
+ * <li>{@link ValueType#FILE_LINK}</li>
+ * <li>{@link ValueType#FILE_LINK_SEQUENCE}</li>
+ * </ul>
+ *
+ *
+ * @param name Name of the created {@code CatalogAttribute}.
+ * @param valueType The {@code ValueType}.
+ * @param catalogComponent The parent {@code CatalogComponent}.
+ * @return The created {@code CatalogAttribute} is returned.
+ * @throws IllegalArgumentException Thrown if given name is already in use or
+ * not allowed or given {@code ValueType} is
+ * not supported.
+ */
+ public CatalogAttribute createCatalogAttribute(String name, ValueType<?> valueType,
+ CatalogComponent catalogComponent) {
+ validateCatalogName(name, true);
+
+ if (catalogComponent.getCatalogAttribute(name).isPresent()) {
+ throw new IllegalArgumentException("Catalog attribute with name '" + name + "' already exists.");
+ } else if (valueType.isEnumerationType() || valueType.isByteStreamType() || valueType.isUnknown()
+ || valueType.isBlob()) {
+ throw new IllegalArgumentException("Value type '" + valueType + "' is not allowed.");
+ }
+
+ CatalogAttribute catalogAttribute = new CatalogAttribute(
+ createCore(CatalogAttribute.class, catalogComponent.getContextType()));
+
+ // relations
+ getCore(catalogAttribute).getPermanentStore().set(catalogComponent);
+ getCore(catalogComponent).getChildrenStore().add(catalogAttribute);
+
+ // properties
+ catalogAttribute.setName(name);
+ catalogAttribute.setValueType(valueType);
+ catalogAttribute.setSortIndex(nextIndex(catalogComponent.getCatalogAttributes()));
+
+ return catalogAttribute;
+ }
+
+ /**
+ * Creates a new {@link CatalogAttribute} for given {@link CatalogComponent}.
+ *
+ * @param name Name of the created {@code CatalogAttribute}.
+ * @param enumerationObject The enumeration.
+ * @param catalogComponent The parent {@code CatalogComponent}.
+ * @return The created {@code CatalogAttribute} is returned.
+ * @throws IllegalArgumentException Thrown if given name is already in use or
+ * not allowed or given enumeration class is
+ * not supported.
+ */
+ public CatalogAttribute createCatalogAttribute(String name, Enumeration<?> enumerationObj,
+ CatalogComponent catalogComponent) {
+ validateCatalogName(name, true);
+ validateEnum(enumerationObj);
+ if (catalogComponent.getCatalogAttribute(name).isPresent()) {
+ throw new IllegalArgumentException("Catalog attribute with name '" + name + "' already exists.");
+ }
+
+ CatalogAttribute catalogAttribute = new CatalogAttribute(
+ createCore(CatalogAttribute.class, catalogComponent.getContextType()));
+
+ // relations
+ getCore(catalogAttribute).getPermanentStore().set(catalogComponent);
+ getCore(catalogComponent).getChildrenStore().add(catalogAttribute);
+
+ // properties
+ catalogAttribute.setName(name);
+ catalogAttribute.setEnumerationObj(enumerationObj);
+ catalogAttribute.setSortIndex(nextIndex(catalogComponent.getCatalogAttributes()));
+
+ return catalogAttribute;
+ }
+
+ /**
+ * Creates a new {@link CatalogAttribute} for given {@link CatalogSensor}. The
+ * {@link ValueType} may be one of the following like in
+ * {@link #createCatalogAttribute(String, ValueType, CatalogComponent)}:
+ *
+ * @param name Name of the created {@code CatalogAttribute}.
+ * @param valueType The {@code ValueType}.
+ * @param catalogSensor The parent {@code CatalogSensor}.
+ * @return The created {@code CatalogAttribute} is returned.
+ * @throws IllegalArgumentException Thrown if given name is already in use or
+ * not allowed or given {@code ValueType} is
+ * not supported.
+ */
+ public CatalogAttribute createCatalogSensorAttribute(String name, ValueType<?> valueType,
+ CatalogSensor catalogSensor) {
+ validateCatalogName(name, true);
+
+ if (catalogSensor.getCatalogAttribute(name).isPresent()) {
+ throw new IllegalArgumentException("CatalogSensor attribute with name '" + name + "' already exists.");
+ } else if (valueType.isEnumerationType() || valueType.isByteStreamType() || valueType.isUnknown()
+ || valueType.isBlob()) {
+ throw new IllegalArgumentException("Value type '" + valueType + "' is not allowed.");
+ }
+
+ CatalogAttribute catalogAttribute = new CatalogAttribute(createCore(CatalogAttribute.class));
+
+ // relations
+ getCore(catalogAttribute).getPermanentStore().set(catalogSensor);
+ getCore(catalogSensor).getChildrenStore().add(catalogAttribute);
+
+ // properties
+ catalogAttribute.setName(name);
+ catalogAttribute.setValueType(valueType);
+ catalogAttribute.setSortIndex(nextIndex(catalogSensor.getCatalogAttributes()));
+
+ return catalogAttribute;
+ }
+
+ /**
+ * Creates a new {@link CatalogSensor} for given {@link CatalogComponent}.
+ *
+ * @param name Name of the created {@code CatalogSensor}.
+ * @param enumerationObject The enumeration.
+ * @param catalogComponent The parent {@code CatalogComponent}.
+ * @return The created {@code CatalogSensor} is returned.
+ * @throws IllegalArgumentException Thrown if given name is already in use or
+ * not allowed
+ */
+ public CatalogSensor createCatalogSensor(String name, CatalogComponent catalogComponent) {
+ validateCatalogName(name, false);
+
+ if (!catalogComponent.getContextType().isTestEquipment()) {
+ throw new IllegalArgumentException("Catalog component is not of type 'TESTEQUIPMENT'");
+ } else if (catalogComponent.getCatalogSensor(name).isPresent()) {
+ throw new IllegalArgumentException("Catalog sensor with name '" + name + "' already exists.");
+ }
+
+ CatalogSensor catalogSensor = new CatalogSensor(createCore(CatalogSensor.class));
+
+ // relations
+ getPermanentStore(catalogSensor).set(catalogComponent);
+ getChildrenStore(catalogComponent).add(catalogSensor);
+
+ // properties
+ catalogSensor.setName(name);
+ catalogSensor.setDateCreated(LocalDateTime.now());
+
+ return catalogSensor;
+ }
+
+ /**
+ * Creates a new {@link TemplateRoot} with given {@link ContextType} and name.
+ *
+ * @param contextType The {@code ContextType}.
+ * @param name Name of the created {@code TemplateRoot}.
+ * @return The created {@code TemplateRoot} is returned.
+ */
+ public TemplateRoot createTemplateRoot(ContextType contextType, String name) {
+ TemplateRoot templateRoot = new TemplateRoot(createCore(TemplateRoot.class, contextType));
+
+ // properties
+ templateRoot.setName(name);
+ templateRoot.setDateCreated(LocalDateTime.now());
+ templateRoot.setVersionState(VersionState.EDITABLE);
+ templateRoot.setVersion(Integer.valueOf(1));
+
+ return templateRoot;
+ }
+
+ /**
+ * Creates a new {@link TemplateComponent} for given {@link TemplateRoot} using
+ * given {@link CatalogComponent}.
+ *
+ * @param name Name of the created {@code TemplateComponent}.
+ * @param templateRoot The parent {@code TemplateRoot}.
+ * @param catalogComponent The associated {@link CatalogComponent}.
+ * @return The created {@code TemplateComponent} is returned.
+ * @throws IllegalArgumentException Thrown if {@code ContextType} of {@code
+ * TemplateRoot} and {@code CatalogComponent} do not match or
+ * given name is already in use.
+ */
+ public TemplateComponent createTemplateComponent(String name, TemplateRoot templateRoot,
+ CatalogComponent catalogComponent) {
+ if (!templateRoot.getContextType().equals(catalogComponent.getContextType())) {
+ throw new IllegalArgumentException("Context type of template root and catalog component do not match.");
+ } else if (templateRoot.getTemplateComponent(name).isPresent()) {
+ throw new IllegalArgumentException("Template component with name '" + name + "' already exists.");
+ }
+
+ TemplateComponent templateComponent = new TemplateComponent(
+ createCore(TemplateComponent.class, templateRoot.getContextType()));
+
+ // relations
+ getCore(templateComponent).getPermanentStore().set(templateRoot);
+ getCore(templateComponent).getMutableStore().set(catalogComponent);
+ getCore(templateRoot).getChildrenStore().add(templateComponent);
+
+ // properties
+ templateComponent.setName(name);
+ templateComponent.setOptional(Boolean.TRUE);
+ templateComponent.setDefaultActive(Boolean.TRUE);
+ templateComponent.setSeriesConstant(Boolean.TRUE);
+ templateComponent.setSortIndex(nextIndex(templateRoot.getTemplateComponents()));
+
+ // create template attributes
+ catalogComponent.getCatalogAttributes().forEach(ca -> createTemplateAttribute(ca.getName(), templateComponent));
+
+ return templateComponent;
+ }
+
+ /**
+ * Creates a new {@link TemplateComponent} for given {@link TemplateComponent}
+ * using given {@link CatalogComponent}.
+ *
+ * @param name Name of the created
+ * {@code TemplateComponent}.
+ * @param partentComponentTemplate The parent {@code TemplateComponent}.
+ * @param catalogComponent The associated {@link CatalogComponent}.
+ * @return The created {@code TemplateComponent} is returned.
+ * @throws IllegalArgumentException Thrown if {@code ContextType} of {@code
+ * TemplateComponent} and {@code CatalogComponent} do not match or
+ * given name is already in use.
+ */
+ public TemplateComponent createTemplateComponent(String name, TemplateComponent partentComponentTemplate,
+ CatalogComponent catalogComponent) {
+ TemplateRoot templateRoot = partentComponentTemplate.getTemplateRoot();
+ if (!templateRoot.getContextType().equals(catalogComponent.getContextType())) {
+ throw new IllegalArgumentException("Context type of template root and catalog component do not match.");
+ } else if (templateRoot.getTemplateComponent(name).isPresent()) {
+ throw new IllegalArgumentException("Template component with name '" + name + "' already exists.");
+ }
+
+ TemplateComponent templateComponent = new TemplateComponent(
+ createCore(TemplateComponent.class, templateRoot.getContextType()));
+
+ // relations
+ getCore(templateComponent).getPermanentStore().set(partentComponentTemplate);
+ getCore(templateComponent).getMutableStore().set(catalogComponent);
+ getCore(partentComponentTemplate).getChildrenStore().add(templateComponent);
+
+ // properties
+ templateComponent.setName(name);
+ templateComponent.setOptional(Boolean.TRUE);
+ templateComponent.setDefaultActive(Boolean.TRUE);
+ templateComponent.setSeriesConstant(Boolean.TRUE);
+ templateComponent.setSortIndex(nextIndex(partentComponentTemplate.getTemplateComponents()));
+
+ // create template attributes
+ catalogComponent.getCatalogAttributes().forEach(ca -> createTemplateAttribute(ca.getName(), templateComponent));
+
+ return templateComponent;
+ }
+
+ /**
+ * Creates a new {@link TemplateAttribute} for given {@link TemplateComponent}.
+ *
+ * @param name Name of the created {@code TemplateAttribute}.
+ * @param templateComponent The parent {@code TemplateComponent}.
+ * @return The created {@code TemplateAttribute} is returned.
+ * @throws IllegalArgumentException Thrown if given name is already in use.
+ */
+ public TemplateAttribute createTemplateAttribute(String name, TemplateComponent templateComponent) {
+ if (templateComponent.getTemplateAttribute(name).isPresent()) {
+ throw new IllegalArgumentException("Template attribute with name '" + name + "' already exists.");
+ }
+
+ CatalogComponent catalogComponent = templateComponent.getCatalogComponent();
+ Optional<CatalogAttribute> catalogAttribute = catalogComponent.getCatalogAttribute(name);
+ if (catalogAttribute.isPresent()) {
+ TemplateAttribute templateAttribute = new TemplateAttribute(
+ createCore(TemplateAttribute.class, catalogComponent.getContextType()));
+
+ // relations
+ getCore(templateAttribute).getPermanentStore().set(templateComponent);
+ getCore(templateAttribute).getMutableStore().set(catalogAttribute.get());
+ getCore(templateComponent).getChildrenStore().add(templateAttribute);
+
+ // properties
+ templateAttribute.setName(name);
+ templateAttribute.setValueReadOnly(Boolean.FALSE);
+ templateAttribute.setOptional(Boolean.TRUE);
+
+ return templateAttribute;
+ }
+
+ throw new IllegalArgumentException("Catalog attribute with name '" + name + "' does not exists.");
+ }
+
+ /**
+ * Creates a new {@link TemplateSensor} for given {@link TemplateComponent}
+ * based on the given {@link CatalogSensor}.
+ *
+ * @param name Name of the created {@code TemplateAttribute}.
+ * @param templateComponent The parent {@code TemplateComponent}.
+ * @param catalogSensor reference CatalogSensor
+ * @param quantity Quantity to create {@link TemplateSensor} for
+ * @return The created {@code TemplateSensor} is returned.
+ * @throws IllegalArgumentException Thrown if given name is already in use.
+ */
+ public TemplateSensor createTemplateSensor(String name, TemplateComponent templateComponent,
+ CatalogSensor catalogSensor, Quantity quantity) {
+ if (templateComponent.getTemplateSensor(name).isPresent()) {
+ throw new IllegalArgumentException("Template sensor with name '" + name + "' already exists.");
+ }
+
+ if (catalogSensor != null) {
+ TemplateSensor templateSensor = new TemplateSensor(createCore(TemplateSensor.class));
+ // create all implicit TemplateAttributes
+ for (CatalogAttribute catAttr : catalogSensor.getCatalogAttributes()) {
+ TemplateAttribute tplAttr = new TemplateAttribute(createCore(TemplateAttribute.class));
+ tplAttr.setName(catAttr.getName());
+ tplAttr.setValueReadOnly(Boolean.FALSE);
+ tplAttr.setOptional(Boolean.TRUE);
+ getPermanentStore(tplAttr).set(templateSensor);
+ getMutableStore(tplAttr).set(catAttr);
+ getCore(templateSensor).getChildrenStore().add(tplAttr);
+ }
+
+ // relations
+ getPermanentStore(templateSensor).set(templateComponent);
+ getMutableStore(templateSensor).set(catalogSensor);
+ getMutableStore(templateSensor).set(quantity);
+ getChildrenStore(templateComponent).add(templateSensor);
+
+ // properties
+ templateSensor.setName(name);
+ templateSensor.setDefaultActive(true);
+ templateSensor.setOptional(Boolean.TRUE);
+
+ return templateSensor;
+ }
+
+ throw new IllegalArgumentException("Catalog attribute with name '" + name + "' does not exists.");
+ }
+
+ /**
+ * Creates a new {@link TemplateTestStep}.
+ *
+ * @param name Name of the created {@code TemplateTestStep}.
+ * @return The created {@code TemplateTestStep} is returned.
+ */
+ public TemplateTestStep createTemplateTestStep(String name) {
+ TemplateTestStep templateTestStep = new TemplateTestStep(createCore(TemplateTestStep.class));
+
+ // properties
+ templateTestStep.setName(name);
+ templateTestStep.setDateCreated(LocalDateTime.now());
+ templateTestStep.setVersionState(VersionState.EDITABLE);
+ templateTestStep.setVersion(Integer.valueOf(1));
+
+ return templateTestStep;
+ }
+
+ /**
+ * Creates a new {@link TemplateTest}.
+ *
+ * @param name Name of the created {@code TemplateTest}.
+ * @return The created {@code TemplateTest} is returned.
+ */
+ public TemplateTest createTemplateTest(String name) {
+ TemplateTest templateTest = new TemplateTest(createCore(TemplateTest.class));
+
+ // properties
+ templateTest.setName(name);
+ templateTest.setDateCreated(LocalDateTime.now());
+ templateTest.setVersion(Integer.valueOf(1));
+ templateTest.setVersionState(VersionState.EDITABLE);
+
+ return templateTest;
+ }
+
+ /**
+ * Creates a new {@link TemplateTestStepUsage} for given {@link TemplateTest}
+ * using given {@link TemplateTestStep}.
+ *
+ * @param name Name of the created {@code TemplateTestStepUsage}.
+ * @param templateTest The parent {@link TemplateTest}.
+ * @param templateTestStep The related {@link TemplateTestStep}.
+ * @return The created {@code TemplateTestStepUsage} is returned.
+ */
+ public TemplateTestStepUsage createTemplateTestStepUsage(String name, TemplateTest templateTest,
+ TemplateTestStep templateTestStep) {
+ if (templateTest.getTemplateTestStepUsage(name).isPresent()) {
+ throw new IllegalArgumentException("Template test step usage with name '" + name + "' already exists.");
+ }
+
+ TemplateTestStepUsage templateTestStepUsage = new TemplateTestStepUsage(
+ createCore(TemplateTestStepUsage.class));
+
+ // relations
+ getCore(templateTestStepUsage).getPermanentStore().set(templateTest);
+ getCore(templateTestStepUsage).getMutableStore().set(templateTestStep);
+ getCore(templateTest).getChildrenStore().add(templateTestStepUsage);
+
+ // properties
+ templateTestStepUsage.setName(name);
+ templateTestStepUsage.setOptional(Boolean.TRUE);
+ templateTestStepUsage.setDefaultActive(Boolean.TRUE);
+ templateTestStepUsage.setSortIndex(nextIndex(templateTest.getTemplateTestStepUsages()));
+
+ return templateTestStepUsage;
+ }
+
+ /**
+ * Creates a new {@link ValueList}.
+ *
+ * @param name Name of the created {@code ValueList}.
+ * @return The created {@code ValueList} is returned.
+ */
+ public ValueList createValueList(String name) {
+ ValueList valueList = new ValueList(createCore(ValueList.class));
+
+ // properties
+ valueList.setName(name);
+ valueList.setDateCreated(LocalDateTime.now());
+
+ return valueList;
+ }
+
+ /**
+ * Creates a new {@link ValueListValue} for given {@link ValueList}.
+ *
+ * @param name Name of the created {@code ValueListValue}.
+ * @param valueList The parent {@code ValueList}.
+ * @return The created {@code ValueListValue} is returned.
+ */
+ public ValueListValue createValueListValue(String name, ValueList valueList) {
+ if (valueList.getValueListValue(name).isPresent()) {
+ throw new IllegalArgumentException("Value list value with name '" + name + "' already exists.");
+ }
+
+ ValueListValue valueListValue = new ValueListValue(createCore(ValueListValue.class));
+
+ // relations
+ getCore(valueListValue).getPermanentStore().set(valueList);
+ getCore(valueList).getChildrenStore().add(valueListValue);
+
+ // properties
+ valueListValue.setName(name);
+ valueListValue.setSortIndex(nextIndex(valueList.getValueListValues()));
+
+ // this property is hidden by the public API and is not allowed to be
+ // modified!
+ valueListValue.getValue(ValueListValue.ATTR_SCALAR_TYPE).set(ScalarType.STRING);
+
+ return valueListValue;
+ }
+
+ /**
+ * Creates a new {@link Classification} for given {@link Domain},
+ * {@link ProjectDomain} and {@link Status}.
+ *
+ * @param domain The {@link Domain} for the {@link Classification}
+ * @param projectDomain The {@link ProjectDomain} for the {@link Classification}
+ * @param status The {@link Status} for the {@link Classification}
+ * @return The created {@link Classification} is returned.
+ */
+ public Classification createClassification(Domain domain, ProjectDomain projectDomain, Status status) {
+ String name = String.format("ProjDomainId_%s.DomainId_%s.StatusId_%s", projectDomain.getID(), domain.getID(),
+ status.getID());
+ return createClassification(name, status, projectDomain, domain);
+ }
+
+ /**
+ * Creates a new {@link Classification} for given {@link Domain},
+ * {@link ProjectDomain} and {@link Status}.
+ *
+ * @param name The name for the {@link Classification}
+ * @param status The {@link Status} for the {@link Classification}
+ * @param projectDomain The {@link ProjectDomain} for the {@link Classification}
+ * @param domain The {@link Domain} for the {@link Classification}
+ * @return The created {@link Classification} is returned.
+ */
+ public Classification createClassification(String name, Status status, ProjectDomain projectDomain, Domain domain) {
+ Classification classification = new Classification(createCore(Classification.class));
+
+ getMutableStore(classification).set(status);
+ getMutableStore(classification).set(projectDomain);
+ getMutableStore(classification).set(domain);
+
+ // properties
+ classification.setName(name);
+
+ return classification;
+ }
+
+ /**
+ * Creates a new {@link ProjectDomain} with given name.
+ *
+ * @param name Name of the {@link ProjectDomain}
+ * @return The created {@link ProjectDomain} is returned.
+ */
+ public ProjectDomain createProjectDomain(String name) {
+ ProjectDomain projectDomain = new ProjectDomain(createCore(ProjectDomain.class));
+ // properties
+ projectDomain.setName(name);
+ return projectDomain;
+ }
+
+ /**
+ * Creates a new {@link Domain} with given name.
+ *
+ * @param name Name of the {@link Domain}
+ * @return The created {@link Domain} is returned.
+ */
+ public Domain createDomain(String name) {
+ Domain domain = new Domain(createCore(Domain.class));
+
+ // properties
+ domain.setName(name);
+ return domain;
+ }
+
+ // ======================================================================
+ // Protected methods
+ // ======================================================================
+
+ /**
+ * Creates a new {@link Test} for given {@link Pool} using given
+ * {@link TemplateTest}.
+ *
+ * @param name Name of the created {@code Test}.
+ * @param pool The parent {@code Pool}.
+ * @param statusTest The related {@link Status} of the created {@code
+ * Test} .
+ * @param statusTestStep The related {@link Status} of the created {@code
+ * TestStep} .
+ * @param templateTest The template the returned {@code Test} will be derived
+ * from.
+ * @return The created {@code Test} is returned.
+ */
+ // TODO make a decision: status in or out!
+ protected Test createTest(String name, Pool pool, Status statusTest, Status statusTestStep,
+ TemplateTest templateTest) {
+ Test test = createTest(name, pool, statusTest);
+
+ // relations
+ getCore(test).getMutableStore().set(templateTest);
+
+ // create default active and mandatory test steps according to the
+ // template
+ templateTest.getTemplateTestStepUsages().stream().filter(TemplateTestStepUsage.IS_IMPLICIT_CREATE)
+ .map(TemplateTestStepUsage::getTemplateTestStep).forEach(templateTestStep -> {
+ createTestStep(test, statusTestStep, templateTestStep);
+ });
+
+ return test;
+ }
+
+ /**
+ * Creates a new {@link Test} for given {@link Pool} using given name,
+ * {@link TemplateTest} and {@link Classification}.
+ *
+ * @param name Name of the created {@code Test}.
+ * @param pool The parent {@code Pool}.
+ * @param templateTest The template the returned {@code Test} will be derived
+ * from.
+ * @param classification The {@link Classification} for the created
+ * {@link Test}.
+ * @param withTestSteps If true, {@link TestStep}s are automatically created
+ * based on configured {@link TemplateTestStepUsage}.
+ * @return The created {@code Test} is returned.
+ */
+ public Test createTest(String name, Pool pool, TemplateTest templateTest, Classification classification,
+ boolean withTestSteps) {
+ // TODO
+ Test test = createTest(name, pool);
+
+ // relations
+ if (templateTest != null) {
+ getCore(test).getMutableStore().set(templateTest);
+ }
+ getCore(test).getMutableStore().set(classification);
+
+ if (withTestSteps && templateTest != null) {
+ // create default active and mandatory test steps according to the
+ // template
+ templateTest.getTemplateTestStepUsages().stream().filter(TemplateTestStepUsage.IS_IMPLICIT_CREATE)
+ .map(TemplateTestStepUsage::getTemplateTestStep).forEach(templateTestStep -> {
+ createTestStep(test, templateTestStep, classification);
+ });
+ }
+
+ return test;
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given
+ * {@link TemplateTestStep} and {@link Classification}.
+ *
+ * @param test The parent {@code Test}.
+ * @param templateTestStep The template the returned {@code TestStep} will be
+ * derived from.
+ * @param classification The {@link Classification} for the created
+ * {@link TestStep}.
+ * @return The created {@code TestStep} is returned.
+ */
+ public TestStep createTestStep(Test test, TemplateTestStep templateTestStep, Classification classification) {
+ TestStep testStep = createTestStep(test, templateTestStep);
+ getCore(testStep).getMutableStore().set(classification);
+ return testStep;
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given
+ * {@link TemplateTestStep} and {@link Classification}.
+ *
+ * @param name Name of the created {@code TestStep}.
+ * @param test The parent {@code Test}.
+ * @param classification The {@link Classification} for the created
+ * {@link TestStep}.
+ * @return The created {@code TestStep} is returned.
+ */
+ public TestStep createTestStep(String name, Test test, Classification classification) {
+ TestStep testStep = createTestStep(name, test);
+ getCore(testStep).getMutableStore().set(classification);
+ return testStep;
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given name,
+ * {@link TemplateTestStep} and {@link Classification}.
+ *
+ * @param name Name of the created {@code TestStep}.
+ * @param test The parent {@code Test}.
+ * @param templateTestStep The template the returned {@code TestStep} will be
+ * derived from.
+ * @param classification The {@link Classification} for the created
+ * {@link TestStep}.
+ * @return The created {@code TestStep} is returned.
+ */
+ public TestStep createTestStep(String name, Test test, TemplateTestStep templateTestStep,
+ Classification classification) {
+ TestStep testStep = createTestStep(test, templateTestStep);
+ getCore(testStep).getMutableStore().set(classification);
+ testStep.setName(name);
+ return testStep;
+ }
+
+ /**
+ * Create a new {@link ExtSystem}
+ * @param name The name of the external system
+ * @return
+ */
+ public ExtSystem createExtSystem(String name) {
+ ExtSystem extSystem = new ExtSystem(createCore(ExtSystem.class));
+ extSystem.setName(name);
+ return extSystem;
+ }
+
+ /**
+ * Create a new {@link ExtSystemAttribute}
+ * @param name The name of the external system attribute
+ * @param extSystem The parent {@link ExtSystem}
+ * @return
+ */
+ public ExtSystemAttribute createExtSystemAttribute(String name, ExtSystem extSystem) {
+ ExtSystemAttribute extSystemAttribute = new ExtSystemAttribute(createCore(ExtSystemAttribute.class));
+ getCore(extSystemAttribute).getPermanentStore().set(extSystem);
+ getCore(extSystem).getChildrenStore().add(extSystemAttribute);
+ extSystemAttribute.setName(name);
+ return extSystemAttribute;
+ }
+
+ /**
+ * Create a new {@link MDMAttribute}
+ * @param name The name of the mdm attribute
+ * @param extSystemAttribute The parent {@link ExtSystemAttribute}
+ * @return
+ */
+ public MDMAttribute createMDMAttribute(String name, ExtSystemAttribute extSystemAttribute) {
+ MDMAttribute mdmAttribute = new MDMAttribute(createCore(MDMAttribute.class));
+ getCore(mdmAttribute).getPermanentStore().set(extSystemAttribute);
+ getCore(extSystemAttribute).getChildrenStore().add(mdmAttribute);
+ mdmAttribute.setName(name);
+ String[] values = name.split("\\.");
+ if(values.length == 3) {
+ mdmAttribute.setComponentType(values[0]);
+ mdmAttribute.setComponentName(values[1]);
+ mdmAttribute.setAttributeName(values[2]);
+ }
+ return mdmAttribute;
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given
+ * {@link TemplateTestStep} and {@link Classification}. Doesn't create context
+ * roots
+ *
+ * @param test The parent {@code Test}.
+ * @param templateTestStep The template the returned {@code TestStep} will be
+ * derived from.
+ * @param classification The {@link Classification} for the created
+ * {@link TestStep}.
+ * @return The created {@code TestStep} is returned.
+ */
+ public TestStep createTestStepWithOutContextRoots(Test test, TemplateTestStep templateTestStep,
+ Classification classification) {
+ TestStep testStep = createTestStepWithOutContextRoots(test, templateTestStep);
+ getCore(testStep).getMutableStore().set(classification);
+ return testStep;
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given
+ * {@link TemplateTestStep}. Doesn't create context roots
+ *
+ * @param test The parent {@code Test}.
+ * @param templateTestStep The template the returned {@code TestStep} will be
+ * derived from.
+ * @return The created {@code TestStep} is returned.
+ */
+ public TestStep createTestStepWithOutContextRoots(Test test, TemplateTestStep templateTestStep) {
+ return createTestStepWithOutContextRoots(test, null, templateTestStep);
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given
+ * {@link TemplateTestStep}.
+ *
+ * @param test The parent {@code Test}.
+ * @param status The related {@link Status}.
+ * @param templateTestStep The template the returned {@code TestStep} will be
+ * derived from.
+ * @return The created {@code TestStep} is returned.
+ */
+ // TODO make a decision: status in or out!
+ protected TestStep createTestStepWithOutContextRoots(Test test, Status status, TemplateTestStep templateTestStep) {
+ TemplateTest templateTest = TemplateTest.of(test)
+ .orElseThrow(() -> new IllegalArgumentException("Template test is not available."));
+ if (!templateTest.contains(templateTestStep)) {
+ throw new IllegalArgumentException("Template test step is not part of the test template.");
+ }
+
+ TestStep testStep = createTestStep(templateTestStep.getName(), test, status);
+
+ // relations
+ getCore(testStep).getMutableStore().set(templateTestStep);
+
+ return testStep;
+ }
+
+ /**
+ * Creates a new {@link Test} for given {@link Pool}.
+ *
+ * @param name Name of the created {@code Test}.
+ * @param pool The parent {@code Pool}.
+ * @param status The related {@link Status}.
+ * @return The created {@code Test} is returned.
+ */
+ // TODO make a decision: status in or out!
+ protected Test createTest(String name, Pool pool, Status status) {
+ Test test = super.createTest(name);
+
+ // relations
+ getCore(test).getPermanentStore().set(pool);
+ getCore(pool).getChildrenStore().add(test);
+
+ return test;
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given
+ * {@link TemplateTestStep}.
+ *
+ * @param test The parent {@code Test}.
+ * @param templateTestStep The template the returned {@code TestStep} will be
+ * derived from.
+ * @return The created {@code TestStep} is returned.
+ */
+ public TestStep createTestStep(Test test, TemplateTestStep templateTestStep) {
+ return createTestStep(test, null, templateTestStep);
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test} using given
+ * {@link TemplateTestStep}.
+ *
+ * @param test The parent {@code Test}.
+ * @param status The related {@link Status}.
+ * @param templateTestStep The template the returned {@code TestStep} will be
+ * derived from.
+ * @return The created {@code TestStep} is returned.
+ */
+ // TODO make a decision: status in or out!
+ protected TestStep createTestStep(Test test, Status status, TemplateTestStep templateTestStep) {
+
+ TestStep testStep = createTestStepWithOutContextRoots(test, status, templateTestStep);
+
+ // create initial context roots
+ templateTestStep.getTemplateRoots().forEach(templateRoot -> createContextRoot(testStep, templateRoot));
+
+ return testStep;
+ }
+
+ /**
+ * Creates a new {@link TestStep} for given {@link Test}.
+ *
+ * @param name Name of the created {@code Test}.
+ * @param test The parent {@code Test}.
+ * @param status The related {@link Status}.
+ * @return The created {@code TestStep} is returned.
+ */
+ // TODO make a decision: status in or out!
+ protected TestStep createTestStep(String name, Test test, Status status) {
+ TestStep testStep = super.createTestStep(name, test);
+
+ if (status != null) {
+ status.assign(testStep);
+ }
+
+ return testStep;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected <T extends BaseEntity> T createBaseEntity(Class<T> clazz, Core core) {
+ try {
+ Constructor<T> constructor = clazz.getDeclaredConstructor(Core.class);
+ try {
+ return constructor.newInstance(core);
+ } catch (IllegalAccessException exc) {
+ return super.createBaseEntity(clazz, core);
+ }
+ } catch (NoSuchMethodException | InvocationTargetException | InstantiationException exc) {
+ throw new IllegalStateException(exc.getMessage(), exc);
+ }
+ }
+
+ /**
+ * Checks whether given enumeration is defined in the application model or not.
+ *
+ * @param enumerationObj The checked enumeration class.
+ * @throws IllegalArgumentException Thrown if given enumeration class is not
+ * supported.
+ */
+ protected abstract void validateEnum(Enumeration<?> enumerationObj);
+
+ // ======================================================================
+ // Private methods
+ // ======================================================================
+
+ /**
+ * Checks whether given catalog name is allowed or not.
+ *
+ * @param name The checked name.
+ * @param isAttributeName Flag indicates whether given name is for a catalog
+ * attribute.
+ * @throws IllegalArgumentException Thrown if given name is not allowed.
+ */
+ private static void validateCatalogName(String name, boolean isAttributeName) {
+ if (!isValidCatalogName(name)) {
+ throw new IllegalArgumentException(
+ "A catalog name is not allowed to be empty and " + "must not exceed 30 characters.");
+ } else if (name.toLowerCase(Locale.ROOT).startsWith("ao")) {
+ throw new IllegalArgumentException("A catalog name is not allowed to " + "start with 'ao' (case ignored).");
+ } else if (!name.matches("^[\\w]+$")) {
+ throw new IllegalArgumentException(
+ "A calatog name may only constists of the " + "following characters: a-z, A-Z, 0-9 or _.");
+ } else if (isAttributeName && Arrays.asList("id", "name", "mimetype").contains(name.toLowerCase(Locale.ROOT))) {
+ throw new IllegalArgumentException(
+ "A catalog attribute name is not allowed to be " + "'id', 'name' or 'mimetype' (case ignored).");
+ }
+ }
+
+ /**
+ * Checks whether given catalog name is valid
+ *
+ * @param name The checked name.
+ * @return Returns {@code true} if name is a valid catalog name
+ */
+ private static boolean isValidCatalogName(String name) {
+ return name != null && !name.isEmpty() && name.length() <= 30;
+ }
+
+ /**
+ * Hides {@link Value} containers missing in the templates.
+ *
+ * @param contextCore The {@link ContextComponent} {@link Core}.
+ * @param templateAttributes The {@link TemplateAttribute}s of the template.
+ */
+ private static void hideValues(Core contextCore, List<TemplateAttribute> templateAttributes) {
+ Set<String> names = new HashSet<>(contextCore.getValues().keySet());
+ names.remove(Entity.ATTR_NAME);
+ names.remove(Entity.ATTR_MIMETYPE);
+ templateAttributes.stream().map(Entity::getName).forEach(names::remove);
+ contextCore.hideValues(names);
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystem.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystem.java
new file mode 100644
index 0000000..a6c45b2
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystem.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+
+/**
+ * Implementation of an external system entity type. An external system
+ * attribute contains several mdm attributes.
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class ExtSystem extends BaseEntity implements Describable, Deletable {
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ protected ExtSystem(Core core) {
+ super(core);
+ }
+
+ public List<ExtSystemAttribute> getAttributes() {
+ return getExtSystemAttributes();
+ }
+
+ /**
+ * Returns all available {@link ExtSystemAttribute}s related to this external
+ * system.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<ExtSystemAttribute> getExtSystemAttributes() {
+ return getCore().getChildrenStore().get(ExtSystemAttribute.class);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystemAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystemAttribute.java
new file mode 100644
index 0000000..806ba57
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ExtSystemAttribute.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+
+/**
+ * Implementation of an external system attribute entity type. An external
+ * system attribute contains several mdm attributes.
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class ExtSystemAttribute extends BaseEntity implements Describable, Deletable {
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ protected ExtSystemAttribute(Core core) {
+ super(core);
+ }
+
+ public List<MDMAttribute> getAttributes() {
+ return getMDMAttributes();
+ }
+
+ /**
+ * Returns all available {@link MDMAttribute}s related to this external system
+ * attribute.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<MDMAttribute> getMDMAttributes() {
+ return getCore().getChildrenStore().get(MDMAttribute.class);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/MDMAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/MDMAttribute.java
new file mode 100644
index 0000000..85b049d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/MDMAttribute.java
@@ -0,0 +1,98 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+
+/**
+ * Implementation of an external system entity type. An external system
+ * attribute contains several mdm attributes.
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class MDMAttribute extends BaseEntity implements Describable, Deletable {
+
+ public static final String ATTR_COMPONENT_TYPE = "CompType";
+ public static final String ATTR_COMPONENT_NAME = "CompName";
+ public static final String ATTR_ATTRIBUTE_NAME = "AttrName";
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ protected MDMAttribute(Core core) {
+ super(core);
+ }
+
+ /**
+ * Returns the component type for this attribute
+ *
+ * @return Returns the component type
+ */
+ public String getComponentType() {
+ return getValue(ATTR_COMPONENT_TYPE).extract();
+ }
+
+ /**
+ * Sets the component type for this attribute
+ *
+ * @param compType The component type
+ */
+ public void setComponentType(String compType) {
+ getValue(ATTR_COMPONENT_TYPE).set(compType);
+ }
+
+ /**
+ * Returns the component name for this attribute
+ *
+ * @return Returns the component name
+ */
+ public String getComponentName() {
+ return getValue(ATTR_COMPONENT_NAME).extract();
+ }
+
+ /**
+ * Sets the component name for this attribute
+ *
+ * @param compName The component name
+ */
+ public void setComponentName(String compName) {
+ getValue(ATTR_COMPONENT_NAME).set(compName);
+ }
+
+ /**
+ * Returns the attribute name for this attribute
+ *
+ * @return Returns the attribute name
+ */
+ public String getAttributeName() {
+ return getValue(ATTR_ATTRIBUTE_NAME).extract();
+ }
+
+ /**
+ * Sets the attribute name for this attribute
+ *
+ * @param attrName The attribute name
+ */
+ public void setAttributeName(String attrName) {
+ getValue(ATTR_ATTRIBUTE_NAME).set(attrName);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Pool.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Pool.java
new file mode 100644
index 0000000..bac6ce7
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Pool.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Test;
+
+/**
+ * Implementation of the pool entity type. The pool entity is used to establish
+ * a further navigation structure through the stored measurement data. Its name
+ * may be freely chosen but has to to be unique. A project contains {@link Test}
+ * entities as its children.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see Project
+ * @see Test
+ */
+public class Pool extends BaseEntity implements Deletable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The {@link Project} parent type.
+ */
+ public static final Class<Project> PARENT_TYPE_PROJECT = Project.class;
+
+ /**
+ * The {@link Test} child type.
+ */
+ public static final Class<Test> CHILD_TYPE_TEST = Test.class;
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ Pool(Core core) {
+ super(core);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Project.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Project.java
new file mode 100644
index 0000000..2c71b4d
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Project.java
@@ -0,0 +1,53 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+
+/**
+ * Implementation of the project entity type. The project is the top level of
+ * stored measurement data. Its name may be freely chosen but has to to be
+ * unique. A project contains {@link Pool} entities as its children.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see Pool
+ */
+public class Project extends BaseEntity implements Deletable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The {@link Pool} child type.
+ */
+ public static final Class<Pool> CHILD_TYPE_POOL = Pool.class;
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ Project(Core core) {
+ super(core);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ProjectDomain.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ProjectDomain.java
new file mode 100644
index 0000000..dae7b14
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ProjectDomain.java
@@ -0,0 +1,35 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Describable;
+
+public class ProjectDomain extends BaseEntity implements Describable {
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ ProjectDomain(Core core) {
+ super(core);
+ }
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Role.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Role.java
new file mode 100644
index 0000000..de12617
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Role.java
@@ -0,0 +1,55 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.User;
+
+/**
+ * Implementation of the role entity type. Each role can contain multiple
+ * {@link User} and each {@link User} can be assigned multiple {@link Role}s.
+ */
+public class Role extends BaseEntity implements Deletable, Describable {
+
+ public static final String ATTR_SUPERUSER_FLAG = "SuperuserFlag";
+ public static final String REL_GROUPS2USERS = "groups2users";
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ Role(Core core) {
+ super(core);
+ getValue(ATTR_SUPERUSER_FLAG).set((short) 0);
+ }
+
+ /**
+ * @param user User to add
+ */
+ public void addUser(User user) {
+ getCore().getNtoMStore().add(REL_GROUPS2USERS, user);
+ }
+
+ /**
+ * @param user {@link User} to remove
+ */
+ public void removeUser(User user) {
+ getCore().getNtoMStore().remove(REL_GROUPS2USERS, user);
+ }
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Status.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Status.java
new file mode 100644
index 0000000..702ad32
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Status.java
@@ -0,0 +1,94 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.StatusAttachable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Implementation of the status entity type. A status may be attached to
+ * {@link StatusAttachable} entities like {@link Test} or {@link TestStep} to
+ * indicate they have a state in a complete workflow.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class Status extends BaseEntity implements Describable {
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ Status(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Assigns this status to given {@link StatusAttachable}s.
+ *
+ * @param <T> The status attachable type.
+ * @param statusAttachables This status will be assigned to all of them.
+ */
+ public <T extends StatusAttachable> void assign(List<T> statusAttachables) {
+ statusAttachables.forEach(this::assign);
+ }
+
+ /**
+ * Assigns this status to given {@link StatusAttachable}.
+ *
+ * @param <T> The status attachable type.
+ * @param statusAttachable This status will be assigned to it.
+ */
+ public <T extends StatusAttachable> void assign(T statusAttachable) {
+ Classification classification = getCore(statusAttachable).getMutableStore().get(Classification.class);
+ if (classification == null) {
+ throw new DataAccessException("Mandatory element classification not found!");
+ }
+
+ getCore(classification).getMutableStore().set(this);
+ }
+
+ /**
+ * Returns the {@link Status} attached to given {@link StatusAttachable}.
+ *
+ * @param statusAttachable The {@code StatusAttachable}.
+ * @return Optional is empty if no {@code Status} is attached.
+ */
+ public static Optional<Status> of(StatusAttachable statusAttachable) {
+ Classification classification = getCore(statusAttachable).getMutableStore().get(Classification.class);
+ if (classification == null) {
+ return Optional.empty();
+ }
+ return Optional.ofNullable(getCore(classification).getMutableStore().get(Status.class));
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/SystemParameter.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/SystemParameter.java
new file mode 100644
index 0000000..310a654
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/SystemParameter.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+
+/**
+ * @author akn
+ *
+ */
+public class SystemParameter extends BaseEntity {
+
+ SystemParameter(Core core) {
+ super(core);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateAttribute.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateAttribute.java
new file mode 100644
index 0000000..998862b
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateAttribute.java
@@ -0,0 +1,408 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.DoubleComplex;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.FloatComplex;
+import org.eclipse.mdm.api.base.model.MimeType;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Implementation of the template attribute entity type. A template attribute
+ * adds meta data to a {@link CatalogAttribute} it is associated with. It always
+ * belongs to a {@link TemplateComponent} or a {@link TemplateSensor}. Its name
+ * is the same as the name of the associated {@code CatalogAttribute} and is not
+ * allowed to be modified at all.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateComponent
+ * @see TemplateSensor
+ */
+public class TemplateAttribute extends BaseEntity implements Deletable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * This {@code Comparator} compares {@link TemplateAttribute}s by the sort index
+ * of their corresponding {@link CatalogAttribute} in ascending order.
+ */
+ public static final Comparator<TemplateAttribute> COMPARATOR = Comparator
+ .comparing(ta -> ta.getCatalogAttribute().getSortIndex());
+
+ /**
+ * The 'DefaultValue' attribute name.
+ */
+ public static final String ATTR_DEFAULT_VALUE = "DefaultValue";
+
+ /**
+ * The 'ValueReadOnly' attribute name.
+ */
+ public static final String ATTR_VALUE_READONLY = "ValueReadonly";
+
+ /**
+ * The 'Optional' attribute name.
+ */
+ public static final String ATTR_OPTIONAL = "Obligatory";
+
+ private static final Map<ValueType<?>, Function<String, Object>> VALUETYPE_FUNCTION_MAP = new HashMap<>();
+
+ static {
+ VALUETYPE_FUNCTION_MAP.put(ValueType.STRING, v -> v);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.DATE, v -> LocalDateTime.parse(v, Value.LOCAL_DATE_TIME_FORMATTER));
+ VALUETYPE_FUNCTION_MAP.put(ValueType.BOOLEAN, Boolean::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.BYTE, Byte::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.SHORT, Short::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.INTEGER, Integer::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.LONG, Long::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.FLOAT, Float::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.DOUBLE, Double::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.FLOAT_COMPLEX, FloatComplex::valueOf);
+ VALUETYPE_FUNCTION_MAP.put(ValueType.DOUBLE_COMPLEX, DoubleComplex::valueOf);
+ }
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ TemplateAttribute(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the default {@link Value} of this template attribute.
+ *
+ * @return The default {@code Value} is returned.
+ */
+ @SuppressWarnings({ "rawtypes" })
+ public Value getDefaultValue() {
+ ValueType valueType = getCatalogAttribute().getValueType();
+ Value defaultValue = getValue(ATTR_DEFAULT_VALUE);
+ boolean isValid = defaultValue.isValid();
+ String value = defaultValue.extract();
+ if (valueType.isEnumerationType()) {
+ Enumeration enumObject = getCatalogAttribute().getEnumerationObject();
+ return valueType.create(getName(), "", isValid, isValid ? enumObject.valueOf(value) : null,
+ enumObject.getName());
+ } else {
+ return valueType.create(getName(), isValid ? parse(value, valueType) : null);
+ }
+ }
+
+ /**
+ * Sets a new default value for this template attribute. Given input will be
+ * stored in its {@link String} representation.
+ *
+ * @param input The new default value.
+ */
+ public void setDefaultValue(Object input) {
+ if (input == null) {
+ getValue(ATTR_DEFAULT_VALUE).set(null);
+ return;
+ }
+
+ ValueType<?> valueType = getCatalogAttribute().getValueType();
+ boolean sequence = valueType.isSequence();
+
+ // if this passes -> input is valid
+ Value value = valueType.create("notRelevant", input);
+
+ String stringValue;
+ if (valueType.isFileLinkType()) {
+ stringValue = getStringValueForFileLinkType(value, sequence);
+ } else if (valueType.isDateType()) {
+ LocalDateTime[] values = sequence ? value.extract() : new LocalDateTime[] { value.extract() };
+ stringValue = Stream.of(values).map(ldt -> ldt.format(Value.LOCAL_DATE_TIME_FORMATTER))
+ .collect(Collectors.joining(","));
+ } else {
+ if (input.getClass().isArray()) {
+ stringValue = IntStream.range(0, Array.getLength(input)).mapToObj(i -> Array.get(input, i).toString())
+ .collect(Collectors.joining(","));
+ } else {
+ stringValue = value.extract().toString();
+ }
+ }
+
+ getValue(ATTR_DEFAULT_VALUE).set(stringValue);
+ }
+
+ /**
+ * Returns the value read only flag of this template attribute.
+ *
+ * @return Returns {@code true} if it is not allowed to modify {@link Value}s
+ * derived from this template attribute.
+ */
+ public Boolean isValueReadOnly() {
+ return getValue(ATTR_VALUE_READONLY).extract();
+ }
+
+ /**
+ * Sets a new value read only flag for this template attribute.
+ *
+ * @param valueReadOnly The new value read only flag.
+ */
+ public void setValueReadOnly(Boolean valueReadOnly) {
+ getValue(ATTR_VALUE_READONLY).set(valueReadOnly);
+ }
+
+ /**
+ * Returns the optional flag of this template attribute.
+ *
+ * @return Returns {@code true} if it is allowed to omit a {@link Value} derived
+ * from this template attribute.
+ */
+ public Boolean isOptional() {
+ boolean mandatory = getValue(ATTR_OPTIONAL).extract();
+ return mandatory ? Boolean.FALSE : Boolean.TRUE;
+ }
+
+ /**
+ * Sets a new optional flag for this template attribute.
+ *
+ * @param optional The new optional flag.
+ */
+ public void setOptional(Boolean optional) {
+ getValue(ATTR_OPTIONAL).set(optional ? Boolean.FALSE : Boolean.TRUE);
+ }
+
+ /**
+ * Returns the {@link CatalogAttribute} this template attribute is associated
+ * with.
+ *
+ * @return The associated {@code CatalogAttribute} is returned.
+ */
+ public CatalogAttribute getCatalogAttribute() {
+ return getCore().getMutableStore().get(CatalogAttribute.class);
+ }
+
+ /**
+ * Returns the {@link TemplateRoot} this template attribute belongs to.
+ *
+ * @return The {@code TemplateRoot} is returned.
+ */
+ public TemplateRoot getTemplateRoot() {
+ Optional<TemplateComponent> templateComponent = getTemplateComponent();
+ Optional<TemplateSensor> templateSensor = getTemplateSensor();
+ if (templateComponent.isPresent()) {
+ return templateComponent.get().getTemplateRoot();
+ } else if (templateSensor.isPresent()) {
+ return templateSensor.get().getTemplateRoot();
+ } else {
+ throw new IllegalStateException("Parent entity is unknown.");
+ }
+ }
+
+ /**
+ * Returns the parent {@link TemplateComponent} of this template attribute.
+ *
+ * @return {@code Optional} is empty if a {@link TemplateSensor} is parent of
+ * this template attribute.
+ * @see #getTemplateSensor()
+ */
+ public Optional<TemplateComponent> getTemplateComponent() {
+ return Optional.ofNullable(getCore().getPermanentStore().get(TemplateComponent.class));
+ }
+
+ /**
+ * Returns the parent {@link TemplateSensor} of this template attribute.
+ *
+ * @return {@code Optional} is empty if a {@link TemplateComponent} is parent of
+ * this template attribute.
+ * @see #getTemplateComponent()
+ */
+ public Optional<TemplateSensor> getTemplateSensor() {
+ return Optional.ofNullable(getCore().getPermanentStore().get(TemplateSensor.class));
+ }
+
+ // ======================================================================
+ // Private methods
+ // ======================================================================
+
+ /**
+ * Parses given {@code String} to the corresponding type of given
+ * {@link ValueType}.
+ *
+ * @param value The {@code String} value.
+ * @param valueType Used to resolve the corresponding converter.
+ * @return The parsed object is returned.
+ */
+ private static Object parse(String value, ValueType<?> valueType) {
+ if (valueType.isFileLinkType()) {
+ Pattern pattern = Pattern.compile("([^,].*?)\\[(.*?),(.*?)\\]");
+ Matcher matcher = pattern.matcher(value);
+ List<FileLink> fileLinks = new ArrayList<>();
+ while (matcher.find()) {
+ fileLinks.add(FileLinkParser.parse(matcher.group()));
+ }
+
+ return valueType.isSequence() ? fileLinks.toArray(new FileLink[fileLinks.size()]) : fileLinks.get(0);
+ } else {
+ Function<String, Object> converter = getParser(valueType);
+ if (valueType.isSequence()) {
+ List<Object> values = Stream.of(value.split(",")).map(converter).collect(Collectors.toList());
+ Object array = Array.newInstance(valueType.getValueClass().getComponentType(), values.size());
+
+ if (valueType.getValueClass().getComponentType().isPrimitive()) {
+ IntStream.range(0, values.size()).forEach(i -> Array.set(array, i, values.get(i)));
+ } else {
+ values.toArray((Object[]) array);
+ }
+
+ return array;
+ } else {
+ return converter.apply(value);
+ }
+ }
+ }
+
+ /**
+ * Returns the {@code String} conversion function for given {@link ValueType}.
+ *
+ * @param valueType Used as identifier.
+ * @return The {@code String} conversion {@code Function} is returned.
+ * @throws IllegalArgumentException Thrown if a corresponding {@code String} is
+ * not supported.
+ */
+ private static Function<String, Object> getParser(ValueType<?> valueType) {
+ Function<String, Object> converter = VALUETYPE_FUNCTION_MAP.get(valueType);
+ if (converter == null) {
+ throw new IllegalArgumentException("String conversion for value type '" + valueType + "' not supported.");
+ }
+ return converter;
+ }
+
+ // ======================================================================
+ // Inner classes
+ // ======================================================================
+
+ /**
+ * Utility class restore a {@link FileLink} from given {@code String}.
+ */
+ private static final class FileLinkParser {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ // markers
+ private static final String NO_DESC_MARKER = "NO_DESC#";
+ private static final String LOCAL_MARKER = "LOCALPATH#";
+
+ // pattern group names
+ private static final String DESCRIPTION = "description";
+ private static final String MIMETYPE = "mimetype";
+ private static final String PATH = "path";
+
+ // pattern
+ private static final Pattern FILE_LINK_PATTERN = Pattern
+ .compile("(?<" + DESCRIPTION + ">.*?)\\[(?<" + MIMETYPE + ">.*?),(?<" + PATH + ">.*?)\\]");
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Parses given {@code String} and returns it as {@link FileLink}.
+ *
+ * @param value The {@code String} value which will be parsed.
+ * @return The corresponding {@code FileLink} is returned.
+ */
+ public static FileLink parse(String value) {
+ Matcher matcher = FILE_LINK_PATTERN.matcher(value);
+ if (!matcher.find()) {
+ throw new IllegalStateException("Unable to restore file link.");
+ }
+ String description = matcher.group(DESCRIPTION);
+ String path = matcher.group(PATH);
+ FileLink fileLink;
+ if (path.startsWith(LOCAL_MARKER)) {
+ try {
+ fileLink = FileLink.newLocal(Paths.get(path.replaceFirst(LOCAL_MARKER, "")));
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to restore local file link.", e);
+ }
+ } else {
+ fileLink = FileLink.newRemote(path, new MimeType(matcher.group(MIMETYPE)), description);
+ }
+
+ fileLink.setDescription(NO_DESC_MARKER.equals(description) ? null : description);
+ return fileLink;
+ }
+
+ }
+
+ /**
+ * Get string value for FileLinkType
+ *
+ * @param value The {@code Value} value.
+ * @param sequence The {@code boolean} sequence.
+ * @return Return {@code String} string value for FileLinkType
+ */
+ private String getStringValueForFileLinkType(Value value, boolean sequence) {
+ FileLink[] values = sequence ? value.extract() : new FileLink[] { value.extract() };
+ return Stream.of(values).map(fl -> {
+ StringBuilder sb = new StringBuilder();
+ if (fl.getDescription().isEmpty()) {
+ sb.append(FileLinkParser.NO_DESC_MARKER);
+ } else {
+ sb.append(fl.getDescription());
+ }
+ sb.append('[').append(fl.getMimeType()).append(',');
+ if (fl.isRemote()) {
+ sb.append(fl.getRemotePath());
+ } else if (fl.isLocal()) {
+ sb.append(FileLinkParser.LOCAL_MARKER).append(fl.getLocalStream());
+ } else {
+ throw new IllegalStateException("File link is neither in local nor remote state: " + fl);
+ }
+
+ return sb.append(']');
+ }).collect(Collectors.joining(","));
+ }
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateComponent.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateComponent.java
new file mode 100644
index 0000000..8caa7d2
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateComponent.java
@@ -0,0 +1,400 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template component entity type. A template attribute
+ * adds meta data to a {@link CatalogComponent} it is associated with. It always
+ * belongs to a template root or another template component. Its name has to be
+ * unique within all template components belonging to the same
+ * {@link TemplateRoot}. A template component may define {@link TemplateSensor}s
+ * where each extends a {@link CatalogSensor} provided by the associated {@code
+ * CatalogComponent}. It may define {@link TemplateAttribute}s where each
+ * uniquely extends a {@link CatalogAttribute} provided by the associated
+ * {@code CatalogComponent}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogComponent
+ * @see TemplateRoot
+ * @see TemplateAttribute
+ * @see TemplateSensor
+ */
+public class TemplateComponent extends BaseEntity implements Deletable, Sortable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The optional flag {@code Predicate}.
+ */
+ public static final Predicate<TemplateComponent> IS_OPTIONAL = TemplateComponent::isOptional;
+
+ /**
+ * The mandatory flag {@code Predicate}. This is the inversion of
+ * {@link #IS_OPTIONAL} {@code Predicate}.
+ */
+ public static final Predicate<TemplateComponent> IS_MANDATORY = IS_OPTIONAL.negate();
+
+ /**
+ * The default active flag {@code Predicate}.
+ */
+ public static final Predicate<TemplateComponent> IS_DEFAULT_ACTIVE = TemplateComponent::isDefaultActive;
+
+ /**
+ * The series constant flag {@code Predicate}.
+ */
+ public static final Predicate<TemplateComponent> IS_SERIES_CONSTANT = TemplateComponent::isSeriesConstant;
+
+ /**
+ * The series variable flag {@code Predicate}. This is the inversion of the
+ * {@link #IS_SERIES_CONSTANT} {@code Predicate}.
+ */
+ public static final Predicate<TemplateComponent> IS_SERIES_VARIABLE = IS_SERIES_CONSTANT.negate();
+
+ /**
+ * The implicit create flag {@code Predicate}. This is an OR combination of
+ * {@link #IS_DEFAULT_ACTIVE} and {@link #IS_MANDATORY} {@code Predicate}s.
+ */
+ public static final Predicate<TemplateComponent> IS_IMPLICIT_CREATE = IS_DEFAULT_ACTIVE.or(IS_MANDATORY);
+
+ /**
+ * The 'TestStepSeriesVariable' attribute name.
+ */
+ public static final String ATTR_SERIES_CONSTANT = "TestStepSeriesVariable";
+
+ /**
+ * The 'DefaultActive' attribute name.
+ */
+ public static final String ATTR_DEFAULT_ACTIVE = "DefaultActive";
+
+ /**
+ * The 'Optional' attribute name.
+ */
+ public static final String ATTR_OPTIONAL = "Optional";
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ TemplateComponent(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the optional flag of this template component.
+ *
+ * @return Returns {@code true} if it is allowed to omit a
+ * {@link ContextComponent} derived from this template component.
+ */
+ public Boolean isOptional() {
+ return getValue(ATTR_OPTIONAL).extract();
+ }
+
+ /**
+ * Sets a new optional flag for this template component.
+ *
+ * @param optional The new optional flag.
+ */
+ public void setOptional(Boolean optional) {
+ getValue(ATTR_OPTIONAL).set(optional);
+ }
+
+ /**
+ * Returns the default active flag of this template component.
+ *
+ * @return Returns {@code true} if a {@link ContextComponent} has to be created
+ * automatically each time a new {@link ContextRoot} is derived from the
+ * {@link TemplateRoot} this template component belongs to.
+ */
+ public Boolean isDefaultActive() {
+ return getValue(ATTR_DEFAULT_ACTIVE).extract();
+ }
+
+ /**
+ * Sets a new default active flag for this template component.
+ *
+ * @param defaultActive The new default active flag.
+ */
+ public void setDefaultActive(Boolean defaultActive) {
+ getValue(ATTR_DEFAULT_ACTIVE).set(defaultActive);
+ }
+
+ /**
+ * Returns the series constant flag of this template component.
+ *
+ * @return Returns {@code true} if the {@link ContextComponent}'s {@link Value}s
+ * across {@link TestStep} siblings contain the same values.
+ */
+ public Boolean isSeriesConstant() {
+ return getValue(ATTR_SERIES_CONSTANT).extract();
+ }
+
+ /**
+ * Sets a new series constant flag for this template component.
+ *
+ * @param seriesConstant The new series constant flag.
+ */
+ public void setSeriesConstant(Boolean seriesConstant) {
+ getValue(ATTR_SERIES_CONSTANT).set(seriesConstant);
+ }
+
+ /**
+ * Returns the {@link CatalogComponent} this template component is associated
+ * with.
+ *
+ * @return The associated {@code CatalogComponent} is returned.
+ */
+ public CatalogComponent getCatalogComponent() {
+ return getCore().getMutableStore().get(CatalogComponent.class);
+ }
+
+ /**
+ * Returns the {@link TemplateRoot} this template component belongs to.
+ *
+ * @return The {@code TemplateRoot} is returned.
+ */
+ public TemplateRoot getTemplateRoot() {
+ TemplateRoot templateRoot = getCore().getPermanentStore().get(TemplateRoot.class);
+ if (templateRoot == null) {
+ return getParentTemplateComponent()
+ .orElseThrow(() -> new IllegalStateException("Parent entity is unknown.")).getTemplateRoot();
+ }
+
+ return templateRoot;
+ }
+
+ /**
+ * Returns the parent {@link TemplateComponent} of this template component.
+ *
+ * @return {@code Optional} is empty if this template component is an immediate
+ * child of the {@link TemplateRoot}.
+ * @see #getTemplateRoot()
+ */
+ public Optional<TemplateComponent> getParentTemplateComponent() {
+ return Optional.ofNullable(getCore().getPermanentStore().get(TemplateComponent.class));
+ }
+
+ /**
+ * Returns the {@link TemplateAttribute} identified by given name.
+ *
+ * @param name The name of the {@code TemplateAttribute}.
+ * @return The {@code Optional} is empty if a {@code TemplateAttribute} with
+ * given name does not exist.
+ */
+ public Optional<TemplateAttribute> getTemplateAttribute(String name) {
+ return getTemplateAttributes().stream().filter(ta -> ta.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link TemplateAttribute}s related to this template
+ * component.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<TemplateAttribute> getTemplateAttributes() {
+ return getCore().getChildrenStore().get(TemplateAttribute.class);
+ }
+
+ /**
+ * Removes the {@link TemplateAttribute} identified by given name.
+ *
+ * @param name Name of the {@code TemplateAttribute} that has to be removed.
+ * @return Returns {@code true} if the {@code TemplateAttribute} with given name
+ * has been removed.
+ */
+ public boolean removeTemplateAttribute(String name) {
+ Optional<TemplateAttribute> templateAttribute = getTemplateAttribute(name);
+ if (templateAttribute.isPresent()) {
+ getCore().getChildrenStore().remove(templateAttribute.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the {@link TemplateComponent} identified by given name.
+ *
+ * <p>
+ * <b>NOTE:</b> The names of <u>all</u> template components belonging to the
+ * same {@link TemplateRoot} must have unique names (no matter they are
+ * immediate children or not). Therefore, if this template component does not
+ * have an immediate template component with the given name, this lookup request
+ * is recursively delegated to all of its child template components.
+ *
+ * @param name The name of the {@code TemplateComponent}.
+ * @return The {@code Optional} is empty if a {@code TemplateComponent} with
+ * given name does not exist (neither this template component nor one of
+ * its children has a template component with given name).
+ */
+ public Optional<TemplateComponent> getTemplateComponent(String name) {
+ List<TemplateComponent> templateComponents = getTemplateComponents();
+ Optional<TemplateComponent> templateComponent = templateComponents.stream().filter(tc -> tc.nameEquals(name))
+ .findAny();
+ if (templateComponent.isPresent()) {
+ return templateComponent;
+ }
+
+ return templateComponents.stream().map(ct -> ct.getTemplateComponent(name)).filter(Optional::isPresent)
+ .map(Optional::get).findAny();
+ }
+
+ /**
+ * Returns all immediate {@link TemplateComponent}s related to this template
+ * component.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<TemplateComponent> getTemplateComponents() {
+ return getCore().getChildrenStore().get(TemplateComponent.class);
+ }
+
+ /**
+ * Removes the {@link TemplateComponent} identified by given name.
+ *
+ * <p>
+ * <b>NOTE:</b> The names of <u>all</u> template components belonging to the
+ * same {@link TemplateRoot} must have unique names (no matter they are
+ * immediate children or not). Therefore, if this template component does not
+ * have an immediate template component with the given name, this remove request
+ * is recursively delegated to all of its child template components.
+ *
+ * @param name Name of the {@code TemplateComponent} that has to be removed.
+ * @return Returns {@code true} if the {@code TemplateComponent} with given name
+ * has been removed.
+ */
+ public boolean removeTemplateComponent(String name) {
+ Optional<TemplateComponent> templateComponent = getTemplateComponent(name);
+ if (templateComponent.isPresent()) {
+ Optional<TemplateComponent> parentTemplateComponent = templateComponent.get().getParentTemplateComponent();
+ if (parentTemplateComponent.isPresent()) {
+ parentTemplateComponent.get().removeTemplateComponent(name);
+ } else {
+ getCore().getChildrenStore().remove(templateComponent.get());
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the {@link TemplateSensor} identified by given name.
+ *
+ * @param name The name of the {@code TemplateSensor}.
+ * @return The {@code Optional} is empty if a {@code TemplateSensor} with given
+ * name does not exist.
+ */
+ public Optional<TemplateSensor> getTemplateSensor(String name) {
+ return getTemplateSensors().stream().filter(ts -> ts.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link TemplateSensor}s related to this template
+ * component.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<TemplateSensor> getTemplateSensors() {
+ if (getCatalogComponent().getContextType().isTestEquipment()) {
+ return getCore().getChildrenStore().get(TemplateSensor.class);
+ }
+
+ return Collections.emptyList();
+ }
+
+ /**
+ * Removes the {@link TemplateSensor} identified by given name.
+ *
+ * @param name Name of the {@code TemplateSensor} that has to be removed.
+ * @return Returns {@code true} if the {@code TemplateSensor} with given name
+ * has been removed.
+ */
+ public boolean removeTemplateSensor(String name) {
+ Optional<TemplateSensor> templateSensor = getTemplateSensor(name);
+ if (templateSensor.isPresent()) {
+ getCore().getChildrenStore().remove(templateSensor.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+ sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ List<TemplateAttribute> templateAttributes = getTemplateAttributes();
+ if (!templateAttributes.isEmpty()) {
+ sb.append(", TemplateAttributes = ").append(templateAttributes);
+ }
+
+ List<TemplateSensor> templateSensors = getTemplateSensors();
+ if (!templateSensors.isEmpty()) {
+ sb.append(", TemplateSensors = ").append(templateSensors);
+ }
+
+ List<TemplateComponent> templateComponents = getTemplateComponents();
+ if (!templateComponents.isEmpty()) {
+ sb.append(", TemplateComponents = ").append(templateComponents);
+ }
+
+ return sb.append(')').toString();
+ }
+
+ /**
+ * Returns the {@link TemplateComponent} the given {@link ContextComponent} is
+ * derived from.
+ *
+ * @param contextComponent The {@code ContextComponent} whose {@code
+ * TemplateComponent} is requested.
+ * @return {@code Optional} is empty if the given {@code ContextComponent} is
+ * not derived from a template, which is data source specific.
+ */
+ public static Optional<TemplateComponent> of(ContextComponent contextComponent) {
+ return Optional.ofNullable(getCore(contextComponent).getMutableStore().get(TemplateComponent.class));
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateRoot.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateRoot.java
new file mode 100644
index 0000000..21f04a1
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateRoot.java
@@ -0,0 +1,187 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template attribute entity type. A template root defines
+ * a tree of {@code TemplateComponent}s. Such a tree forms a hierarchical
+ * template structure which is used to describe the composition of a
+ * {@link ContextRoot}. A template root implements the {@link Versionable}
+ * interface and hence has a version and a state. As long as
+ * {@link #isEditable()} returns {@code true} any part of that template root is
+ * allowed to be modified. Once a template root is set to be valid
+ * ({@link #isValid()} == {@code true}) it may be used to compose a
+ * {@link TemplateTestStep} and then is no longer allowed to be modified in any
+ * way. If a valid template root needs to be modified, then a deep copy with a
+ * unique name and version combination has to be created (deep copy means new
+ * instances).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateComponent
+ * @see Versionable
+ */
+public class TemplateRoot extends BaseEntity implements Deletable, Versionable {
+
+ // ======================================================================
+ // Instance variables
+ // ======================================================================
+
+ private final ContextType contextType;
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ TemplateRoot(Core core) {
+ super(core);
+
+ String typeName = core.getTypeName().toUpperCase(Locale.ROOT);
+ for (ContextType contextTypeCandidate : ContextType.values()) {
+ if (typeName.contains(contextTypeCandidate.name())) {
+ contextType = contextTypeCandidate;
+ return;
+ }
+ }
+
+ throw new IllegalStateException("Core is incompatible.");
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the {@link ContextType} of this template root.
+ *
+ * @return The {@code ContextType} is returned.
+ */
+ public ContextType getContextType() {
+ return contextType;
+ }
+
+ /**
+ * Returns the {@link TemplateComponent} identified by given name.
+ *
+ * <p>
+ * <b>NOTE:</b> The names of <u>all</u> {@code TemplateComponent}s belonging to
+ * the same template root must have unique names (no matter they are immediate
+ * children or not). Therefore, if this template root does not have an immediate
+ * {@code TemplateComponent} with the given name, this lookup request is
+ * recursively delegated to all of its child {@code TemplateComponent}s.
+ *
+ * @param name The name of the {@code TemplateComponent}.
+ * @return The {@code Optional} is empty if a {@code TemplateComponent} with
+ * given name does not exist at all within this template root.
+ */
+ public Optional<TemplateComponent> getTemplateComponent(String name) {
+ List<TemplateComponent> templateComponents = getTemplateComponents();
+ Optional<TemplateComponent> templateComponent = templateComponents.stream().filter(tc -> tc.nameEquals(name))
+ .findAny();
+ if (templateComponent.isPresent()) {
+ return templateComponent;
+ }
+
+ return templateComponents.stream().map(tc -> tc.getTemplateComponent(name)).filter(Optional::isPresent)
+ .map(Optional::get).findAny();
+ }
+
+ /**
+ * Returns all immediate {@link TemplateComponent}s related to this template
+ * component.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<TemplateComponent> getTemplateComponents() {
+ return getCore().getChildrenStore().get(TemplateComponent.class);
+ }
+
+ /**
+ * Removes the {@link TemplateComponent} identified by given name.
+ *
+ * <p>
+ * <b>NOTE:</b> The names of <u>all</u> {@code TemplateComponent}s belonging to
+ * the same template roots must have unique names (no matter they are immediate
+ * children or not). Therefore, if this template root does not have an immediate
+ * {@code TemplateComponent} with the given name, this remove request is
+ * recursively delegated to all of its child {@code TemplateComponent}s.
+ *
+ * @param name Name of the {@code TemplateComponent} that has to be removed.
+ * @return Returns {@code true} if the {@code TemplateComponent} with given name
+ * has been removed.
+ */
+ public boolean removeTemplateComponent(String name) {
+ Optional<TemplateComponent> templateComponent = getTemplateComponent(name);
+ if (templateComponent.isPresent()) {
+ Optional<TemplateComponent> parentTemplateComponent = templateComponent.get().getParentTemplateComponent();
+ if (parentTemplateComponent.isPresent()) {
+ parentTemplateComponent.get().removeTemplateComponent(name);
+ } else {
+ getCore().getChildrenStore().remove(templateComponent.get());
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+ sb.append("ContextType = ").append(getContextType()).append(", ");
+ sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ List<TemplateComponent> templateComponents = getTemplateComponents();
+ if (!templateComponents.isEmpty()) {
+ sb.append(", TemplateComponents = ").append(templateComponents);
+ }
+
+ return sb.append(')').toString();
+ }
+
+ /**
+ * Returns the {@link TemplateRoot} the given {@link ContextRoot} is derived
+ * from.
+ *
+ * @param contextRoot The {@code ContextRoot} whose {@code TemplateRoot} is
+ * requested.
+ * @return {@code Optional} is empty if the given {@code ContextRoot} is not
+ * derived from a template, which is data source specific.
+ */
+ public static Optional<TemplateRoot> of(ContextRoot contextRoot) {
+ return Optional.ofNullable(getCore(contextRoot).getMutableStore().get(TemplateRoot.class));
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateSensor.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateSensor.java
new file mode 100644
index 0000000..6d38c4a
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateSensor.java
@@ -0,0 +1,337 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.ContextSensor;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Quantity;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template sensor entity type. A template sensor adds
+ * meta data to a {@link CatalogSensor} it is associated with. It always belongs
+ * to a template component or a template sensor. Its name has to be unique
+ * within all template sensors belonging to the same {@link TemplateComponent}.
+ * A template sensor define {@link TemplateAttribute}s where each uniquely
+ * extends a {@link CatalogAttribute} provided by the associated {@code
+ * CatalogSensor}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see CatalogSensor
+ * @see TemplateComponent
+ * @see TemplateAttribute
+ */
+public class TemplateSensor extends BaseEntity implements Deletable, Describable, Sortable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The optional flag {@code Predicate}.
+ */
+ public static final Predicate<TemplateSensor> IS_OPTIONAL = TemplateSensor::isOptional;
+
+ /**
+ * The mandatory flag {@code Predicate}. This is the inversion of
+ * {@link #IS_OPTIONAL} {@code Predicate}.
+ */
+ public static final Predicate<TemplateSensor> IS_MANDATORY = IS_OPTIONAL.negate();
+
+ /**
+ * The default active flag {@code Predicate}.
+ */
+ public static final Predicate<TemplateSensor> IS_DEFAULT_ACTIVE = TemplateSensor::isDefaultActive;
+
+ /**
+ * The implicit create flag {@code Predicate}. This is an OR combination of
+ * {@link #IS_DEFAULT_ACTIVE} and {@link #IS_MANDATORY} {@code Predicate}s.
+ */
+ public static final Predicate<TemplateSensor> IS_IMPLICIT_CREATE = IS_DEFAULT_ACTIVE.or(IS_MANDATORY);
+
+ /**
+ * The 'Optional' attribute name.
+ */
+ public static final String ATTR_OPTIONAL = "Optional";
+
+ /**
+ * The 'DefaultActive' attribute name.
+ */
+ public static final String ATTR_DEFAULT_ACTIVE = "DefaultActive";
+
+ /**
+ * The 'MeasuredValuesEditable' attribute name.
+ */
+ public static final String ATTR_MEASRED_VALUES_EDITABLE = "MeaQuantityValuesEditable";
+
+ /**
+ * The 'MeasuredValuesGeneratorName' attribute name.
+ */
+ public static final String ATTR_MEASRED_VALUES_GENERATOR_NAME = "MeaQuantityEditorPlugin";
+
+ /**
+ * The 'MeasuredValuesIndependent' attribute name.
+ */
+ public static final String ATTR_MEASRED_VALUES_INDEPENDENT = "MeaQuantityIndependent";
+
+ /**
+ * The 'MeasuredValuesAxisType' attribute name.
+ */
+ public static final String ATTR_MEASRED_VALUES_AXISTYPE = "MeaQuantityAxisType";
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ TemplateSensor(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the measured values editable flag of this template sensor.
+ *
+ * @return The measured values editable flag is returned.
+ */
+ public Boolean areMeasuredValuesEditable() {
+ return getValue(ATTR_MEASRED_VALUES_EDITABLE).extract();
+ }
+
+ /**
+ * Sets a new measured values editable flag for this template sensor.
+ *
+ * @param measuredValuesEditable The measured values editable flag.
+ */
+ public void setMeasuredValuesEditable(Boolean measuredValuesEditable) {
+ getValue(ATTR_MEASRED_VALUES_EDITABLE).set(measuredValuesEditable);
+ }
+
+ /**
+ * Returns the measured values generator name of this template sensor.
+ *
+ * @return The measured values generator name is returned.
+ */
+ public String getMeasuredValuesGeneratorName() {
+ return getValue(ATTR_MEASRED_VALUES_GENERATOR_NAME).extract();
+ }
+
+ /**
+ * Sets a new measured values generator name for this template sensor.
+ *
+ * @param measuredValuesGeneratorName The measured values generator name.
+ */
+ public void setMeasuredValuesGeneratorName(String measuredValuesGeneratorName) {
+ getValue(ATTR_MEASRED_VALUES_GENERATOR_NAME).set(measuredValuesGeneratorName);
+ }
+
+ /**
+ * Returns the measured values independent flag of this template sensor.
+ *
+ * @return The measured values independent flag is returned.
+ */
+ public Boolean areMeasuredValuesIndependent() {
+ return getValue(ATTR_MEASRED_VALUES_INDEPENDENT).extract();
+ }
+
+ /**
+ * Sets a new measured values independent flag for this template sensor.
+ *
+ * @param measuredValuesIndependent The measured values independent flag.
+ */
+ public void setMeasuredValuesIndependent(Boolean measuredValuesIndependent) {
+ getValue(ATTR_MEASRED_VALUES_INDEPENDENT).set(measuredValuesIndependent);
+ }
+
+ /**
+ * Returns the measured values {@link AxisType} of this template sensor.
+ *
+ * @return The measured values {@code AxisType} is returned.
+ */
+ public AxisType getMeasuredValuesAxisType() {
+ return getValue(ATTR_MEASRED_VALUES_AXISTYPE).extract();
+ }
+
+ /**
+ * Sets a new measured values {@link AxisType} for this template sensor.
+ *
+ * @param axisType The measured values {@code AxisType}.
+ */
+ public void setMeasuredValuesAxisType(AxisType axisType) {
+ getValue(ATTR_MEASRED_VALUES_AXISTYPE).set(axisType);
+ }
+
+ /**
+ * Returns the optional flag of this template sensor.
+ *
+ * @return Returns {@code true} if it is allowed to omit a {@link ContextSensor}
+ * derived from this template sensor.
+ */
+ public Boolean isOptional() {
+ return getValue(ATTR_OPTIONAL).extract();
+ }
+
+ /**
+ * Sets a new optional flag for this template sensor.
+ *
+ * @param optional The new optional flag.
+ */
+ public void setOptional(Boolean optional) {
+ getValue(ATTR_OPTIONAL).set(optional);
+ }
+
+ /**
+ * Returns the default active flag of this template sensor.
+ *
+ * @return Returns {@code true} if a {@link ContextSensor} has to be created
+ * automatically each time a new {@link ContextComponent} is derived
+ * from the {@link TemplateComponent} this template sensor belongs to.
+ */
+ public Boolean isDefaultActive() {
+ return getValue(ATTR_DEFAULT_ACTIVE).extract();
+ }
+
+ /**
+ * Sets a new default active flag for this template sensor.
+ *
+ * @param defaultActive The new default active flag.
+ */
+ public void setDefaultActive(Boolean defaultActive) {
+ getValue(ATTR_DEFAULT_ACTIVE).set(defaultActive);
+ }
+
+ /**
+ * Returns the {@link CatalogSensor} this template sensor is associated with.
+ *
+ * @return The associated {@code CatalogSensor} is returned.
+ */
+ public CatalogSensor getCatalogSensor() {
+ return getCore().getMutableStore().get(CatalogSensor.class);
+ }
+
+ /**
+ * Returns the {@link Quantity} measured data are associated with.
+ *
+ * @return The {@code Quantity} is returned.
+ */
+ public Quantity getQuantity() {
+ return getCore().getMutableStore().get(Quantity.class);
+ }
+
+ /**
+ * Returns the {@link TemplateRoot} this template sensor belongs to.
+ *
+ * @return The {@code TemplateRoot} is returned.
+ */
+ public TemplateRoot getTemplateRoot() {
+ return getTemplateComponent().getTemplateRoot();
+ }
+
+ /**
+ * Returns the parent {@link TemplateComponent} of this template sensor.
+ *
+ * @return The parent {@code TemplateComponent} is returned.
+ */
+ public TemplateComponent getTemplateComponent() {
+ return getCore().getPermanentStore().get(TemplateComponent.class);
+ }
+
+ /**
+ * Returns the {@link TemplateAttribute} identified by given name.
+ *
+ * @param name The name of the {@code TemplateAttribute}.
+ * @return The {@code Optional} is empty if a {@code TemplateAttribute} with
+ * given name does not exist.
+ */
+ public Optional<TemplateAttribute> getTemplateAttribute(String name) {
+ return getTemplateAttributes().stream().filter(ta -> ta.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link TemplateAttribute}s related to this template
+ * sensor.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<TemplateAttribute> getTemplateAttributes() {
+ return getCore().getChildrenStore().get(TemplateAttribute.class);
+ }
+
+ /**
+ * Removes the {@link TemplateAttribute} identified by given name.
+ *
+ * @param name Name of the {@code TemplateAttribute} that has to be removed.
+ * @return Returns {@code true} if the {@code TemplateAttribute} with given name
+ * has been removed.
+ */
+ public boolean removeTemplateAttribute(String name) {
+ Optional<TemplateAttribute> templateAttribute = getTemplateAttribute(name);
+ if (templateAttribute.isPresent()) {
+ getCore().getChildrenStore().remove(templateAttribute.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+ sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ List<TemplateAttribute> templateAttributes = getTemplateAttributes();
+ if (!templateAttributes.isEmpty()) {
+ sb.append(", TemplateAttributes = ").append(templateAttributes);
+ }
+
+ return sb.append(')').toString();
+ }
+
+ /**
+ * Returns the {@link TemplateSensor} the given {@link ContextSensor} is derived
+ * from.
+ *
+ * @param contextSensor The {@code ContextSensor} whose {@code
+ * TemplateSensor} is requested.
+ * @return {@code Optional} is empty if the given {@code ContextSensor} is not
+ * derived from a template, which is data source specific.
+ */
+ public static Optional<TemplateSensor> of(ContextSensor contextSensor) {
+ return Optional.ofNullable(getCore(contextSensor).getMutableStore().get(TemplateSensor.class));
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTest.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTest.java
new file mode 100644
index 0000000..2d39ad8
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTest.java
@@ -0,0 +1,224 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the template test entity type. A template test consists of
+ * {@link TemplateTestStepUsage}s with unique names. It describes a template for
+ * a test run and provides meta data to resolve hooks and data sources for
+ * naming, property validation, resolution and other purposes. A template test
+ * implements the {@link Versionable} interface and hence has a version and a
+ * state. As long as {@link #isEditable()} returns {@code true} any part of that
+ * template test is allowed to be modified. Once a template test is set to be
+ * valid ({@link #isValid()} == {@code true}) it may be used to define a test
+ * run therefore is no longer allowed to be modified in any way. If a valid
+ * template test needs to be modified, then a deep copy with a unique name and
+ * version combination has to be created (deep copy means new instances).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateTestStepUsage
+ * @see Versionable
+ */
+public class TemplateTest extends BaseEntity implements Deletable, Describable, Versionable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The 'NameHelperClassname' attribute name.
+ */
+ public static final String ATTR_NAMEHELPER_CLASSNAME = "NameHelperClassname";
+
+ /**
+ * The 'DataSourcePluginClassnames' attribute name.
+ */
+ public static final String ATTR_DATASOURCE_PLUGIN_CLASSNAMES = "DataSourcePluginClassnames";
+
+ /**
+ * The 'TestOrderActionClassnames' attribute name.
+ */
+ public static final String ATTR_TEST_ORDER_ACTION_CLASSNAMES = "TestOrderActionClassnames";
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ TemplateTest(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the name helper class name of this template test.
+ *
+ * @return The name helper class name is returned.
+ */
+ public String getNameHelperClassname() {
+ return getValue(ATTR_NAMEHELPER_CLASSNAME).extract();
+ }
+
+ /**
+ * Sets a new name helper class name for this template test.
+ *
+ * @param nameHelperClassname The new name helper class name.
+ */
+ public void setNameHelperClassname(String nameHelperClassname) {
+ getValue(ATTR_NAMEHELPER_CLASSNAME).set(nameHelperClassname);
+ }
+
+ /**
+ * Returns the data source plug-in class names of this template test.
+ *
+ * @return The data source plug-in class names are returned.
+ */
+ public String[] getDataSourcePluginClassnames() {
+ return getValue(ATTR_DATASOURCE_PLUGIN_CLASSNAMES).extract();
+ }
+
+ /**
+ * Sets new data source plug-in class names for this template test.
+ *
+ * @param dataSourcePluginClassnames The new data source plug-in class names.
+ */
+ public void setDataSourceClassnames(String[] dataSourcePluginClassnames) {
+ getValue(ATTR_DATASOURCE_PLUGIN_CLASSNAMES).set(dataSourcePluginClassnames);
+ }
+
+ /**
+ * Returns the test order action class names of this template test.
+ *
+ * @return The test order action class names are returned.
+ */
+ public String[] getTestOrderActionClassnames() {
+ return getValue(ATTR_TEST_ORDER_ACTION_CLASSNAMES).extract();
+ }
+
+ /**
+ * Sets new test order action class names for this template test.
+ *
+ * @param testOrderActionClassnames The new test order action class names.
+ */
+ public void setTestOrderActionClassnames(String[] testOrderActionClassnames) {
+ getValue(ATTR_TEST_ORDER_ACTION_CLASSNAMES).set(testOrderActionClassnames);
+ }
+
+ /**
+ * Returns the {@link TemplateTestStepUsage} identified by given name.
+ *
+ * @param name The name of the {@code TemplateTestStepUsage}.
+ * @return The {@code Optional} is empty if a {@code TemplateTestStepUsage} with
+ * given name does not exist.
+ */
+ public Optional<TemplateTestStepUsage> getTemplateTestStepUsage(String name) {
+ return getTemplateTestStepUsages().stream().filter(ttsu -> ttsu.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link TemplateTestStepUsage}s related to this template
+ * test.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<TemplateTestStepUsage> getTemplateTestStepUsages() {
+ return getCore().getChildrenStore().get(TemplateTestStepUsage.class);
+ }
+
+ /**
+ * Removes the {@link TemplateTestStepUsage} identified by given name.
+ *
+ * @param name Name of the {@code TemplateTestStepUsage} that has to be removed.
+ * @return Returns {@code true} if the {@code TemplateTestStepUsage} with given
+ * name has been removed.
+ */
+ public boolean removeTemplateTestStepUsage(String name) {
+ Optional<TemplateTestStepUsage> templateTestStepUsage = getTemplateTestStepUsage(name);
+ if (templateTestStepUsage.isPresent()) {
+ getCore().getChildrenStore().remove(templateTestStepUsage.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+ sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ List<TemplateTestStepUsage> templateTestStepUsages = getTemplateTestStepUsages();
+ if (!templateTestStepUsages.isEmpty()) {
+ sb.append(", TemplateTestStepUsages = ").append(templateTestStepUsages);
+ }
+
+ return sb.append(')').toString();
+ }
+
+ /**
+ * Returns the {@link TemplateComponent} the given {@link ContextComponent} is
+ * derived from.
+ *
+ * @param test The {@code ContextComponent} whose {@code TemplateComponent} is
+ * requested.
+ * @return {@code Optional} is empty if the given {@code ContextComponent} is
+ * not derived from a template, which is data source specific.
+ */
+ public static Optional<TemplateTest> of(Test test) {
+ return Optional.ofNullable(getCore(test).getMutableStore().get(TemplateTest.class));
+ }
+
+ // ======================================================================
+ // Package methods
+ // ======================================================================
+
+ /**
+ * Checks whether given {@link TemplateTestStepUsage} is contained in this
+ * template test.
+ *
+ * @param templateTestStep The {@code TemplateTestStepUsage}.
+ * @return Returns {@code true} if given {@code TemplateTestStepUsage} is
+ * contained in this template test.
+ */
+ boolean contains(TemplateTestStep templateTestStep) {
+ return getTemplateTestStepUsages().stream().map(TemplateTestStepUsage::getTemplateTestStep)
+ .filter(tts -> tts.getName().equals(templateTestStep.getName()))
+ .filter(tts -> tts.getVersion().equals(templateTestStep.getVersion())).findFirst().isPresent();
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStep.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStep.java
new file mode 100644
index 0000000..1690562
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStep.java
@@ -0,0 +1,127 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.TestStep;
+
+/**
+ * Implementation of the template test step entity type. A template test step
+ * describes the composition of {@link TemplateRoot}s which in finally is a
+ * template for a persisted context description ("as measured", "as ordered"). A
+ * template test step implements the {@link Versionable} interface and hence has
+ * a version and a state. As long as {@link #isEditable()} returns {@code
+ * true} any part of that template test step is allowed to be modified. Once a
+ * template test step is set to be valid ({@link #isValid()} == {@code true}) it
+ * may be used to compose a {@link TemplateTest} and then is no longer allowed
+ * to be modified in any way. If a valid template test step needs to be
+ * modified, then a deep copy with a unique name and version combination has to
+ * be created (deep copy means new instances).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateRoot
+ * @see Versionable
+ */
+public class TemplateTestStep extends BaseEntity implements Deletable, Describable, Versionable {
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ TemplateTestStep(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the related {@link TemplateRoot} with given {@link ContextType} of
+ * this template test step.
+ *
+ * @param contextType Used as identifier.
+ * @return {@code Optional} is empty if a {@code TemplateRoot} of given
+ * {@code ContextType} does not exist.
+ */
+ public Optional<TemplateRoot> getTemplateRoot(ContextType contextType) {
+ return Optional.ofNullable(getCore().getMutableStore().get(TemplateRoot.class, contextType));
+ }
+
+ /**
+ * Returns all available {@link TemplateRoot}s related to this template test
+ * step.
+ *
+ * @return Returns {@code List} contains up to 3 {@code TemplateRoot}s with
+ * distinct {@link ContextType}s.
+ */
+ public List<TemplateRoot> getTemplateRoots() {
+ List<TemplateRoot> templateRoots = new ArrayList<>();
+ getTemplateRoot(ContextType.UNITUNDERTEST).ifPresent(templateRoots::add);
+ getTemplateRoot(ContextType.TESTSEQUENCE).ifPresent(templateRoots::add);
+ getTemplateRoot(ContextType.TESTEQUIPMENT).ifPresent(templateRoots::add);
+ return templateRoots;
+ }
+
+ /**
+ * Replaces current {@link TemplateRoot} with the given one.
+ *
+ * @param templateRoot Is not allowed to be null.
+ * @see #removeTemplateRoot(ContextType)
+ */
+ public void setTemplateRoot(TemplateRoot templateRoot) {
+ getCore().getMutableStore().set(templateRoot, templateRoot.getContextType());
+ }
+
+ /**
+ * Removes current {@link TemplateRoot} with given {@link ContextType}.
+ *
+ * @param contextType Used as identifier.
+ * @return Returns {@code true} if the {@code TemplateRoot} has been removed.
+ */
+ public boolean removeTemplateRoot(ContextType contextType) {
+ boolean contained = getTemplateRoot(contextType).isPresent();
+ getCore().getMutableStore().remove(TemplateRoot.class, contextType);
+ return contained;
+ }
+
+ /**
+ * Returns the {@link TemplateTestStep} the given {@link TestStep} is derived
+ * from.
+ *
+ * @param testStep The {@code TestStep} whose {@code TemplateTestStep} is
+ * requested.
+ * @return {@code Optional} is empty if the given {@code TestStep} is not
+ * derived from a template.
+ */
+ public static Optional<TemplateTestStep> of(TestStep testStep) {
+ return Optional.ofNullable(getCore(testStep).getMutableStore().get(TemplateTestStep.class));
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStepUsage.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStepUsage.java
new file mode 100644
index 0000000..e7323c1
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/TemplateTestStepUsage.java
@@ -0,0 +1,148 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.function.Predicate;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
+
+/**
+ * Implementation of the template test step usage entity type. A template test
+ * relates a {@link TemplateTestStep} with a parent {@link TemplateTest} (n:m).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see TemplateTest
+ * @see TemplateTestStep
+ */
+public class TemplateTestStepUsage extends BaseEntity implements Deletable, Sortable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The optional flag {@code Predicate}.
+ */
+ public static final Predicate<TemplateTestStepUsage> IS_OPTIONAL = TemplateTestStepUsage::isOptional;
+
+ /**
+ * The mandatory flag {@code Predicate}. This is the inversion of
+ * {@link #IS_OPTIONAL} {@code Predicate}.
+ */
+ public static final Predicate<TemplateTestStepUsage> IS_MANDATORY = IS_OPTIONAL.negate();
+
+ /**
+ * The default active flag {@code Predicate}.
+ */
+ public static final Predicate<TemplateTestStepUsage> IS_DEFAULT_ACTIVE = TemplateTestStepUsage::isDefaultActive;
+
+ /**
+ * The implicit create flag {@code Predicate}. This is an OR combination of
+ * {@link #IS_DEFAULT_ACTIVE} and {@link #IS_MANDATORY} {@code Predicate}s.
+ */
+ public static final Predicate<TemplateTestStepUsage> IS_IMPLICIT_CREATE = IS_DEFAULT_ACTIVE.or(IS_MANDATORY);
+
+ /**
+ * The 'DefaultActive' attribute name.
+ */
+ public static final String ATTR_DEFAULT_ACTIVE = "DefaultActive";
+
+ /**
+ * The 'Optional' attribute name.
+ */
+ public static final String ATTR_OPTIONAL = "Optional";
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ TemplateTestStepUsage(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the default active flag of this template test step usage.
+ *
+ * @return Returns {@code true} if a {@link TestStep} has to be created
+ * automatically each time a new {@link Test} is derived from the
+ * {@link TemplateTest} this template test step usage belongs to.
+ */
+ public Boolean isDefaultActive() {
+ return getValue(ATTR_DEFAULT_ACTIVE).extract();
+ }
+
+ /**
+ * Sets a new default active flag for this template test step usage.
+ *
+ * @param defaultActive The new default active flag.
+ */
+ public void setDefaultActive(Boolean defaultActive) {
+ getValue(ATTR_DEFAULT_ACTIVE).set(defaultActive);
+ }
+
+ /**
+ * Returns the optional flag of this template test step.
+ *
+ * @return Returns {@code true} if it is allowed to omit a {@link TestStep}
+ * derived from this template test step usage.
+ */
+ public Boolean isOptional() {
+ return getValue(ATTR_OPTIONAL).extract();
+ }
+
+ /**
+ * Sets a new optional flag for this template test step usage.
+ *
+ * @param optional The new optional flag.
+ */
+ public void setOptional(Boolean optional) {
+ getValue(ATTR_OPTIONAL).set(optional);
+ }
+
+ /**
+ * Returns the parent {@link TemplateTest}.
+ *
+ * @return The parent {@code TemplateTest} is returned.
+ */
+ public TemplateTest getTemplateTest() {
+ return getCore().getPermanentStore().get(TemplateTest.class);
+ }
+
+ /**
+ * Returns the {@link TemplateTestStep} related to this template test step
+ * usage.
+ *
+ * @return The {@code TemplateTestStep} is returned.
+ */
+ public TemplateTestStep getTemplateTestStep() {
+ return getCore().getMutableStore().get(TemplateTestStep.class);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/UserParameter.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/UserParameter.java
new file mode 100644
index 0000000..7997ab7
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/UserParameter.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+
+/**
+ * @author akn
+ *
+ */
+public class UserParameter extends BaseEntity {
+
+ UserParameter(Core core) {
+ super(core);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueList.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueList.java
new file mode 100644
index 0000000..b6327b3
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueList.java
@@ -0,0 +1,110 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Implementation of the value list entity type. A value list provides a set of
+ * default values which may be used as options while defining default values in
+ * templates or modifying context data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see ValueListValue
+ * @see CatalogAttribute
+ */
+public class ValueList extends BaseEntity implements Datable, Describable, Deletable {
+
+ // ======================================================================
+ // Constructors
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ ValueList(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the {@link ValueListValue} identified by given name.
+ *
+ * @param name The name of the {@code ValueListValue}.
+ * @return The {@code Optional} is empty if a {@code ValueListValue} with given
+ * name does not exist.
+ */
+ public Optional<ValueListValue> getValueListValue(String name) {
+ return getValueListValues().stream().filter(vlv -> vlv.nameEquals(name)).findAny();
+ }
+
+ /**
+ * Returns all available {@link ValueListValue}s related to this value list.
+ *
+ * @return The returned {@code List} is unmodifiable.
+ */
+ public List<ValueListValue> getValueListValues() {
+ return getCore().getChildrenStore().get(ValueListValue.class);
+ }
+
+ /**
+ * Removes the {@link ValueListValue} identified by given name.
+ *
+ * @param name Name of the {@code ValueListValue} that has to be removed.
+ * @return Returns {@code true} if the {@code ValueListValues} with given name
+ * has been removed.
+ */
+ public boolean removeValueListValue(String name) {
+ Optional<ValueListValue> valueListValue = getValueListValue(name);
+ if (valueListValue.isPresent()) {
+ getCore().getChildrenStore().remove(valueListValue.get());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+ sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+ List<ValueListValue> valueListValues = getValueListValues();
+ if (!valueListValues.isEmpty()) {
+ sb.append(", ValueListValues = ").append(valueListValues);
+ }
+
+ return sb.append(')').toString();
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueListValue.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueListValue.java
new file mode 100644
index 0000000..936ad5f
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/ValueListValue.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Describable;
+import org.eclipse.mdm.api.base.model.Sortable;
+
+/**
+ * Implementation of the value list value entity type. A value list value is a
+ * unique value option within the parent {@link ValueList}. Therefore the names
+ * of the value list values within a {@code ValueList} have to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @see ValueList
+ */
+public class ValueListValue extends BaseEntity implements Deletable, Describable, Sortable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * The 'ScalarType' attribute name.
+ */
+ public static final String ATTR_SCALAR_TYPE = "DataType";
+
+ /**
+ * The 'Value' attribute name.
+ */
+ public static final String ATTR_VALUE = "Value";
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * Constructor.
+ *
+ * @param core The {@link Core}.
+ */
+ ValueListValue(Core core) {
+ super(core);
+ }
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setName(String name) {
+ getValue(ATTR_VALUE).set(name);
+ super.setName(name);
+ }
+
+ /**
+ * Returns the parent {@link ValueList}.
+ *
+ * @return The parent {@code ValueList} is returned.
+ */
+ public ValueList getValueList() {
+ return getCore().getPermanentStore().get(ValueList.class);
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Versionable.java b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Versionable.java
new file mode 100644
index 0000000..4ca00f4
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/main/java/org/eclipse/mdm/api/dflt/model/Versionable.java
@@ -0,0 +1,120 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import java.util.Comparator;
+
+import org.eclipse.mdm.api.base.model.Datable;
+import org.eclipse.mdm.api.base.model.VersionState;
+
+/**
+ * This interface extends the {@link Datable} interface and provides getter and
+ * setter methods for the 'Version' and 'VersionState' fields of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface Versionable extends Datable {
+
+ // ======================================================================
+ // Class variables
+ // ======================================================================
+
+ /**
+ * This {@code Comparator} compares {@link Versionable}s by their name (in
+ * ascending order) and version (in descending order).
+ */
+ Comparator<Versionable> COMPARATOR = Comparator.comparing(Versionable::getName)
+ .thenComparing(Comparator.comparing(Versionable::getVersion).reversed());
+
+ /**
+ * The 'Version' attribute name.
+ */
+ String ATTR_VERSION = "Version";
+
+ /**
+ * The 'VersionState' attribute name.
+ */
+ String ATTR_VERSION_STATE = "ValidFlag";
+
+ // ======================================================================
+ // Public methods
+ // ======================================================================
+
+ /**
+ * Returns the version of this entity.
+ *
+ * @return The version is returned.
+ */
+ default Integer getVersion() {
+ return Integer.valueOf(getValue(ATTR_VERSION).extract());
+ }
+
+ /**
+ * Sets new version for this entity.
+ *
+ * @param version The new version.
+ */
+ default void setVersion(Integer version) {
+ getValue(ATTR_VERSION).set(version.toString());
+ }
+
+ /**
+ * Returns the {@link VersionState} of this entity.
+ *
+ * @return The {@code VersionState} is returned.
+ */
+ default VersionState getVersionState() {
+ return getValue(ATTR_VERSION_STATE).extract();
+ }
+
+ /**
+ * Sets new {@link VersionState} for this entity.
+ *
+ * @param versionState The new {@code VersionState}.
+ */
+ default void setVersionState(VersionState versionState) {
+ getValue(ATTR_VERSION_STATE).set(versionState);
+ }
+
+ /**
+ * Checks whether parts of this versionable are allowed to be modified.
+ *
+ * @return Returns {@code true} if modifications are allowed.
+ */
+ default boolean isEditable() {
+ return getVersionState().isEditable();
+ }
+
+ /**
+ * Checks whether this versionable is valid and therefore is no longer allowed
+ * to be modified.
+ *
+ * @return Returns {@code true} if this versionable is valid.
+ */
+ default boolean isValid() {
+ return getVersionState().isValid();
+ }
+
+ /**
+ * Checks whether this versionable is archived.
+ *
+ * @return Returns {@code true} if this versionable is archived.
+ */
+ default boolean isArchived() {
+ return getVersionState().isArchived();
+ }
+
+}
diff --git a/org.eclipse.mdm.api.default/src/test/java/org/eclipse/mdm/api/dflt/model/EntityFactoryTest.java b/org.eclipse.mdm.api.default/src/test/java/org/eclipse/mdm/api/dflt/model/EntityFactoryTest.java
new file mode 100644
index 0000000..fe77bdb
--- /dev/null
+++ b/org.eclipse.mdm.api.default/src/test/java/org/eclipse/mdm/api/dflt/model/EntityFactoryTest.java
@@ -0,0 +1,43 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.dflt.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.junit.Test;
+
+public class EntityFactoryTest {
+
+ @Test
+ public void createBaseEntities() {
+ EntityFactory entityFactory = mock(EntityFactory.class);
+ when(entityFactory.createBaseEntity(any(), any())).thenCallRealMethod();
+
+ // The Entities below were chosen as representatives of their respective
+ // packages since their constructors don't do anything with the Core instances
+ // passed to them, so a null pointer is sufficient for this test.
+
+ // Channel class is in package org.eclipse.mdm.api.base.model
+ // (BaseEntityFactory's package):
+ assertThat(entityFactory.createBaseEntity(Channel.class, null)).isInstanceOf(Channel.class);
+ // CatalogSensor class is in package org.eclipse.mdm.api.dflt.model
+ // (EntityFactory's package):
+ assertThat(entityFactory.createBaseEntity(CatalogSensor.class, null)).isInstanceOf(CatalogSensor.class);
+ }
+}