diff --git a/README.md b/README.md index 9d6ad5f1..4f925e3f 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ The project contains several modules: - `dataformat-rdf` RDF de-/serializer - `dataformat-xml` XML de-/serializer - `dataformat-uanodeset` OPC UA I4AAS NodeSet de-/serializer +- `dataformat-aml` AutomationML serializer (deserializer is currently under development) @@ -45,21 +46,22 @@ We always look for contributions, bug reports, feature requests etc. Simply open # Contributors -| Name | Affiliation | Github Account | Parent | Core | AASX | JSON | XML | RDF | UA-Nodeset | Validator| ---- | --- | --- | :---: | :---: | :---: | :---: | :---: | :---: | :---:| :---: -| Mohammad Alreeni | Fraunhofer IWU | []() | | | | | x | | | -| Sebastian Bader | Fraunhofer IAIS | [sebbader](https://github.com/sebbader) | x | | | | | x | | x | -| Matthias Böckmann | Fraunhofer IAIS | [maboeckmann](https://github.com/maboeckmann) | x | | | | | x | | x | -| Maximilian Conradi | Fraunhofer IESE | []() | | | x | | x | | | | -| Helge Dickel | SAP SE | [heldic](https://github.com/heldic) | x | | | x | x | | | | -| Daniel Espen | Fraunhofer IESE | [daespen](https://github.com/daespen) | | x | x | x | x | | | | -| Michael Jacoby | Fraunhofer IOSB| [mjacoby](https://github.com/mjacoby) | x | x | | x | x | | | | -| Jens Müller | Fraunhofer IOSB | [JensMueller2709](https://github.com/JensMueller2709) | | | | x | | | | | -| Orthodoxos Kipouridis | SAP SE | [akiskips](https://github.com/akiskips) | x | | | x | x | | | | -| Bastian Rössl | Fraunhofer IOSB-INA | [br-iosb](https://github.com/br-iosb) | | | | x | | | x | | -| Frank Schnicke | Fraunhofer IESE | [frankschnicke](https://github.com/frankschnicke) | | | x | | x | | | | -| Manuel Sauer | SAP SE | [Manu3756](https://github.com/Manu3756) | x | | | | | | | | -| Arno Weiss | Fraunhofer IWU | [alw-iwu](https://github.com/alw-iwu) | | | | x | | | x | | +| Name | Affiliation | Github Account | Parent | Core | AASX | JSON | XML | RDF | UA-Nodeset | Validator| AutomationML +--- | --- | --- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: +| Mohammad Alreeni | Fraunhofer IWU | []() | | | | | x | | | | +| Sebastian Bader | Fraunhofer IAIS | [sebbader](https://github.com/sebbader) | x | | | | | x | | x | | +| Matthias Böckmann | Fraunhofer IAIS | [maboeckmann](https://github.com/maboeckmann) | x | | | | | x | | x | | +| Maximilian Conradi | Fraunhofer IESE | []() | | | x | | x | | | | | +| Helge Dickel | SAP SE | [heldic](https://github.com/heldic) | x | | | x | x | | | | | +| Daniel Espen | Fraunhofer IESE | [daespen](https://github.com/daespen) | | x | x | x | x | | | | | +| Michael Jacoby | Fraunhofer IOSB| [mjacoby](https://github.com/mjacoby) | x | x | | x | x | | | | x | +| Jens Müller | Fraunhofer IOSB | [JensMueller2709](https://github.com/JensMueller2709) | | | | x | | | | | x | +| Orthodoxos Kipouridis | SAP SE | [akiskips](https://github.com/akiskips) | x | | | x | x | | | | | +| Bastian Rössl | Fraunhofer IOSB-INA | [br-iosb](https://github.com/br-iosb) | | | | x | | | x | | | +| Frank Schnicke | Fraunhofer IESE | [frankschnicke](https://github.com/frankschnicke) | | | x | | x | | | | | +| Manuel Sauer | SAP SE | [Manu3756](https://github.com/Manu3756) | x | | | | | | | | | +| Arno Weiss | Fraunhofer IWU | [alw-iwu](https://github.com/alw-iwu) | | | | x | | | x | | | +| Jan Blume | Fraunhofer IOSB | []() | | | | | | | | | x | This project was initiated by SAP and Fraunhofer to provide a foundation for the AAS development and to foster its dissemination. diff --git a/dataformat-aml/.gitignore b/dataformat-aml/.gitignore new file mode 100644 index 00000000..298ee54d --- /dev/null +++ b/dataformat-aml/.gitignore @@ -0,0 +1,30 @@ +.idea/ +log/ +*.log +bin/ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +.classpath +.project + +testJsonSerialization.json diff --git a/dataformat-aml/LICENSE b/dataformat-aml/LICENSE new file mode 100644 index 00000000..e966af1a --- /dev/null +++ b/dataformat-aml/LICENSE @@ -0,0 +1,215 @@ +Copyright (C) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + +The AutomationML Serializer contained in this repository provide the functionalities to +serialize and deserialize instances of the Asset Administration Shell data model +from and to the AAS Java Model library. It is licensed under the Apache License +2.0 (Apache-2.0, see below). +The Model uses the concepts of the document "Details of the Asset +Administration Shell" published on www.plattform-i40.de which is licensed +under Creative Commons CC BY-ND 3.0 DE. + +------------------------------------------------------------------------------- + + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Fraunhofer IAIS + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/dataformat-aml/license-header.txt b/dataformat-aml/license-header.txt new file mode 100644 index 00000000..b531b74a --- /dev/null +++ b/dataformat-aml/license-header.txt @@ -0,0 +1,13 @@ +Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/dataformat-aml/pom.xml b/dataformat-aml/pom.xml new file mode 100644 index 00000000..f3efc7c5 --- /dev/null +++ b/dataformat-aml/pom.xml @@ -0,0 +1,132 @@ + + + 4.0.0 + + io.admin-shell.aas + dataformat-parent + ${revision} + + dataformat-aml + Asset Administration Shell AutomationML-Serializer + + + io.admin-shell.aas + model + ${revision} + compile + + + io.admin-shell.aas + dataformat-core + ${revision} + compile + + + org.slf4j + slf4j-api + ${slf4j.version} + + + javax.xml.bind + jaxb-api + ${jaxb.version} + + + org.eclipse.persistence + org.eclipse.persistence.moxy + ${moxy.version} + + + junit + junit + ${junit.version} + test + + + net.codesup.util + jaxb2-rich-contract-plugin + ${jaxb-rich-contract.version} + + + org.xmlunit + xmlunit-core + ${xmlunit.version} + test + + + org.xmlunit + xmlunit-matchers + ${xmlunit.version} + test + + + + + + org.codehaus.mojo + flatten-maven-plugin + ${plugin.flatten.version} + + true + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + org.apache.cxf + cxf-xjc-plugin + ${plugin.cxf.version} + + + net.codesup.util:jaxb2-rich-contract-plugin:${jaxb-rich-contract.version} + + + + + generate-caex-classes + generate-sources + + xsdtojava + + + ${basedir}/target/generated-sources/src + + + ${basedir}/src/main/resources/CAEX_ClassModel_V2.15.xsd + io.adminshell.aas.v3.dataformat.aml.model.caex + + -Xfluent-builder + -Ximmutable + + + + + + + + + + + + eis-public-repo + maven-public + https://maven.iais.fraunhofer.de/artifactory/eis-ids-public + + + diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDeserializationConfig.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDeserializationConfig.java new file mode 100644 index 00000000..a9d4ba0e --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDeserializationConfig.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml; + +import io.adminshell.aas.v3.dataformat.aml.deserialization.AasTypeFactory; + +public class AmlDeserializationConfig { + + public static Builder builder() { + return new Builder(); + } + + private final AasTypeFactory typeFactory; + + private AmlDeserializationConfig(AasTypeFactory typeFactory) { + this.typeFactory = typeFactory; + } + + public AasTypeFactory getTypeFactory() { + return typeFactory; + } + + public static class Builder { + + private AasTypeFactory typeFactory = new AasTypeFactory(); + + public AmlDeserializationConfig build() { + return new AmlDeserializationConfig(typeFactory); + } + + public Builder typeFactory(AasTypeFactory value) { + this.typeFactory = value; + return this; + } + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDeserializer.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDeserializer.java new file mode 100644 index 00000000..84d88f6b --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDeserializer.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml; + +import io.adminshell.aas.v3.dataformat.DeserializationException; +import io.adminshell.aas.v3.dataformat.Deserializer; +import io.adminshell.aas.v3.dataformat.aml.deserialization.Aml2AasMapper; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import java.io.StringReader; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import org.eclipse.persistence.jaxb.JAXBContextFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class for deserializing/parsing AAS AML documents. + */ +public class AmlDeserializer implements Deserializer { + + private static final Logger log = LoggerFactory.getLogger(AmlDeserializer.class); + + @Override + public AssetAdministrationShellEnvironment read(String value) throws DeserializationException { + try { + Unmarshaller unmarshaller = JAXBContextFactory.createContext(new Class[]{CAEXFile.class}, null).createUnmarshaller(); + StringReader reader = new StringReader(value); + CAEXFile aml = (CAEXFile) unmarshaller.unmarshal(reader); + Aml2AasMapper mapper = new Aml2AasMapper(new AmlDeserializationConfig.Builder().build()); + return mapper.map(aml); + } catch (JAXBException ex) { + throw new DeserializationException("error deserializing AssetAdministrationShellEnvironment", ex); + } catch (MappingException ex) { + throw new DeserializationException("error mapping AML document to AssetAdministrationShellEnvironment", ex); + } + } + + @Override + public void useImplementation(Class aasInterface, Class implementation) { + throw new UnsupportedOperationException("Not supported yet."); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDocumentInfo.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDocumentInfo.java new file mode 100644 index 00000000..98cafbc3 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlDocumentInfo.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml; + +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.ConceptDescription; +import java.util.Set; +import java.util.stream.Collectors; + +public class AmlDocumentInfo { + + public static final String DEFAULT_ASSET_ADMINISTRATION_SHELL_INSTANCE_HIERARCHY = "AssetAdministrationShellInstanceHierarchy"; + public static final String DEFAULT_ASSET_ADMINISTRATION_SHELL_SYSTEM_UNIT_CLASS_LIB = "AssetAdministrationShellSystemUnitClasses"; + public static final String DEFAULT_ASSET_ADMINISTRATION_SHELL_ROLE_CLASS_LIB = "AssetAdministrationShellRoleClassLib"; + public static final String DEFAULT_ASSET_ADMINISTRATION_SHELL_INTERFACE_CLASS_LIB = "AssetAdministrationShellInterfaceClassLib"; + public static final String DEFAULT_DATA_SPECIFICATION_TEMPLATES_UNIT_CLASS_LIB = "AssetAdministrationShellDataSpecificationTemplates"; + public static final String DEFAULT_CONCEPT_DESCRIPTION_INSTANCE_HIERARCHY = "ConceptDescriptionInstanceHierarchy"; + + private final String assetAdministrationShellSystemUnitClassLib; + private final String dataSpecificationTemplatesSystemUnitClassLib; + private final String assetAdministrationShellInstanceHierarchy; + private final String conceptDescriptionInstanceHierarchy; + private final String assetAdministrationShellRoleClassLib; + private final String assetAdministrationShellInterfaceClassLib; + + public AmlDocumentInfo() { + this.assetAdministrationShellSystemUnitClassLib = DEFAULT_ASSET_ADMINISTRATION_SHELL_SYSTEM_UNIT_CLASS_LIB; + this.dataSpecificationTemplatesSystemUnitClassLib = DEFAULT_DATA_SPECIFICATION_TEMPLATES_UNIT_CLASS_LIB; + this.assetAdministrationShellInstanceHierarchy = DEFAULT_ASSET_ADMINISTRATION_SHELL_INSTANCE_HIERARCHY; + this.conceptDescriptionInstanceHierarchy = DEFAULT_CONCEPT_DESCRIPTION_INSTANCE_HIERARCHY; + this.assetAdministrationShellRoleClassLib = DEFAULT_ASSET_ADMINISTRATION_SHELL_ROLE_CLASS_LIB; + this.assetAdministrationShellInterfaceClassLib = DEFAULT_ASSET_ADMINISTRATION_SHELL_INTERFACE_CLASS_LIB; + } + + public AmlDocumentInfo( + String assetAdministrationShellInstanceHierarchy, + String conceptDescriptionInstanceHierarchy, + String assetAdministrationShellSystemUnitClassLib) { + if (assetAdministrationShellInstanceHierarchy == null || assetAdministrationShellInstanceHierarchy.isBlank()) { + this.assetAdministrationShellInstanceHierarchy = DEFAULT_ASSET_ADMINISTRATION_SHELL_INSTANCE_HIERARCHY; + } else { + this.assetAdministrationShellInstanceHierarchy = assetAdministrationShellInstanceHierarchy; + } + if (assetAdministrationShellSystemUnitClassLib == null || assetAdministrationShellSystemUnitClassLib.isBlank()) { + this.assetAdministrationShellSystemUnitClassLib = DEFAULT_ASSET_ADMINISTRATION_SHELL_SYSTEM_UNIT_CLASS_LIB; + } else { + this.assetAdministrationShellSystemUnitClassLib = assetAdministrationShellSystemUnitClassLib; + } + if (conceptDescriptionInstanceHierarchy == null || conceptDescriptionInstanceHierarchy.isBlank()) { + this.conceptDescriptionInstanceHierarchy = DEFAULT_CONCEPT_DESCRIPTION_INSTANCE_HIERARCHY; + } else { + this.conceptDescriptionInstanceHierarchy = conceptDescriptionInstanceHierarchy; + } + this.dataSpecificationTemplatesSystemUnitClassLib = DEFAULT_DATA_SPECIFICATION_TEMPLATES_UNIT_CLASS_LIB; + this.assetAdministrationShellRoleClassLib = DEFAULT_ASSET_ADMINISTRATION_SHELL_ROLE_CLASS_LIB; + this.assetAdministrationShellInterfaceClassLib = DEFAULT_ASSET_ADMINISTRATION_SHELL_INTERFACE_CLASS_LIB; + } + + public String getAssetAdministrationShellSystemUnitClassLib() { + return assetAdministrationShellSystemUnitClassLib; + } + + public String getDataSpecificationTemplatesSystemUnitClassLib() { + return dataSpecificationTemplatesSystemUnitClassLib; + } + + public String getAssetAdministrationShellInstanceHierarchy() { + return assetAdministrationShellInstanceHierarchy; + } + + public String getConceptDescriptionInstanceHierarchy() { + return conceptDescriptionInstanceHierarchy; + } + + public String getAssetAdministrationShellRoleClassLib() { + return assetAdministrationShellRoleClassLib; + } + + public String getAssetAdministrationShellInterfaceClassLib() { + return assetAdministrationShellInterfaceClassLib; + } + + public static AmlDocumentInfo fromFile(CAEXFile file) { + String aasInstanceHierarchy = findInstanceHierarchy(file, AssetAdministrationShell.class); + String conceptDescriptionInstanceHierarchy = findInstanceHierarchy(file, ConceptDescription.class); + String aasSystemUnitClassLib = findSystemUnitClassLib(file, AssetAdministrationShell.class); + return new AmlDocumentInfo(aasInstanceHierarchy, conceptDescriptionInstanceHierarchy, aasSystemUnitClassLib); + } + + private static String findInstanceHierarchy(CAEXFile file, Class type) { + String typeName = type.getSimpleName(); + Set instanceHierarchies = file.getInstanceHierarchy().stream() + .filter(x -> x.getInternalElement().stream() + .anyMatch(y -> y.getRoleRequirements() + .equals(DEFAULT_ASSET_ADMINISTRATION_SHELL_ROLE_CLASS_LIB + "/" + typeName))) + .map(x -> x.getName()) + .collect(Collectors.toSet()); + if (instanceHierarchies.size() > 1) { + throw new IllegalArgumentException(String.format("found %d InstanceHierarchy containing %s definitions (%s), required exactly 1", + instanceHierarchies.size(), + typeName, + instanceHierarchies.stream().collect(Collectors.joining(",")))); + } + return instanceHierarchies.isEmpty() ? null : instanceHierarchies.iterator().next(); + } + + private static String findSystemUnitClassLib(CAEXFile file, Class type) { + String typeName = type.getSimpleName(); + Set systemUnitClassLibs = file.getSystemUnitClassLib().stream() + .filter(x -> x.getSystemUnitClass().stream() + .anyMatch(y -> y.getSupportedRoleClass() + .equals(DEFAULT_ASSET_ADMINISTRATION_SHELL_ROLE_CLASS_LIB + "/" + typeName))) + .map(x -> x.getName()) + .collect(Collectors.toSet()); + if (systemUnitClassLibs.size() > 1) { + throw new IllegalArgumentException(String.format("found %d SystemUnitClass containing %s definitions (%s), required exactly 1", + systemUnitClassLibs.size(), + typeName, + systemUnitClassLibs.stream().collect(Collectors.joining(",")))); + } + return systemUnitClassLibs.isEmpty() ? null : systemUnitClassLibs.iterator().next(); + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlSerializationConfig.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlSerializationConfig.java new file mode 100644 index 00000000..a33c550e --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlSerializationConfig.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml; + +import io.adminshell.aas.v3.dataformat.aml.header.WriterInfo; +import io.adminshell.aas.v3.dataformat.aml.serialization.id.UuidGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.id.IdGenerator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Configuration class for AML serialization. This class is immutable. + */ +public class AmlSerializationConfig { + + public static final String DEFAULT_SCHEMA_VERSION = "2.15"; + public static final String DEFAULT_AML_VERSION = "2.0"; + public static final String DEFAULT_FILENAME = "AssetAdministrationShellEnvironment.aml"; + public static final AmlSerializationConfig DEFAULT = new Builder().build(); + + public static Builder builder() { + return new Builder(); + } + + private final IdGenerator idGenerator; + private final String caexSchemaVersion; + private final String amlVersion; + private final String filename; + private final boolean includeLibraries; + private final WriterInfo writerInfo; + private final List additionalInformation; + + private AmlSerializationConfig( + IdGenerator idGenerator, + String schemaVersion, + String amlVersion, + String filename, + boolean includeLibraries, + WriterInfo writerInfo, + List additionalInformation) { + this.idGenerator = idGenerator; + this.caexSchemaVersion = schemaVersion; + this.amlVersion = amlVersion; + this.filename = filename; + this.includeLibraries = includeLibraries; + this.writerInfo = writerInfo; + this.additionalInformation = additionalInformation; + } + + /** + * Indicates if the predefined AAS libraries should be included in the + * result or not + * + * @return true is they should be included, otherwise false + */ + public boolean isIncludeLibraries() { + return includeLibraries; + } + + /** + * The IdGenerator used for AML creation. Default are UUID-based IDs but + * custom IdGenerator can be used. + * + * @return the IdGenerator to use + */ + public IdGenerator getIdGenerator() { + return idGenerator; + } + + /** + * Gets additional information that should be included in the file header + * + * @return list of additional information objects + */ + public List getAdditionalInformation() { + return additionalInformation; + } + + /** + * Gets the CAEX schema version + * + * @return the CAEX schema version + */ + public String getCaexSchemaVersion() { + return caexSchemaVersion; + } + + /** + * Gets the AML version + * + * @return the AML version + */ + public String getAmlVersion() { + return amlVersion; + } + + /** + * Gets the WriterInfo header to include in AML + * + * @return the WriterInfo + */ + public WriterInfo getWriterInfo() { + return writerInfo; + } + + public static class Builder { + + private IdGenerator idGenerator = new UuidGenerator(); + private String schemaVersion = DEFAULT_SCHEMA_VERSION; + private String amlVersion = DEFAULT_AML_VERSION; + private String filename = DEFAULT_FILENAME; + private boolean includeLibraries = true; + private WriterInfo writerInfo = null; + private final List additionalInformation = new ArrayList<>(); + + public AmlSerializationConfig build() { + return new AmlSerializationConfig( + idGenerator, + schemaVersion, + amlVersion, + filename, + includeLibraries, + writerInfo, + additionalInformation); + } + + public Builder includeLibraries() { + this.includeLibraries = true; + return this; + } + + public Builder excludeLibraries() { + this.includeLibraries = true; + return this; + } + + public Builder idGenerator(IdGenerator idGenerator) { + this.idGenerator = idGenerator; + return this; + } + + public Builder schemaVersion(String value) { + this.schemaVersion = value; + return this; + } + + public Builder amlVersion(String value) { + this.amlVersion = value; + return this; + } + + public Builder filename(String value) { + this.filename = value; + return this; + } + + public Builder writerInfo(WriterInfo value) { + this.writerInfo = value; + return this; + } + + public Builder additionalInformation(Object... values) { + this.additionalInformation.addAll(Arrays.asList(values)); + return this; + } + } + + public String getFilename() { + return filename; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlSerializer.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlSerializer.java new file mode 100644 index 00000000..9e16fb18 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/AmlSerializer.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml; + +import io.adminshell.aas.v3.dataformat.aml.serialization.AasToAmlMapper; +import io.adminshell.aas.v3.dataformat.SerializationException; +import io.adminshell.aas.v3.dataformat.Serializer; +import io.adminshell.aas.v3.dataformat.aml.header.AutomationMLVersion; +import io.adminshell.aas.v3.dataformat.aml.header.WriterInfo; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import java.io.IOException; +import java.io.StringWriter; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.bind.Unmarshaller; +import org.eclipse.persistence.jaxb.JAXBContextFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class for serializing an instance of AssetAdministrationShellEnvironment to + * AML. + */ +public class AmlSerializer implements Serializer { + + private static final String AAS_LIB_SOURCE = "/AssetAdministrationShellLib.aml"; + private static final Logger log = LoggerFactory.getLogger(AmlSerializer.class); + + @Override + public String write(AssetAdministrationShellEnvironment aasEnvironment) throws SerializationException { + return write(aasEnvironment, AmlSerializationConfig.DEFAULT); + } + + /** + * Serializes a given instance of AssetAdministrationShellEnvironment to + * string + * + * @param aasEnvironment the AssetAdministrationShellEnvironment to + * serialize + * @param config serialization configuration + * @return the string representation of the environment + * @throws SerializationException if serialization fails + */ + public String write(AssetAdministrationShellEnvironment aasEnvironment, AmlSerializationConfig config) throws SerializationException { + try { + CAEXFile aml = new AasToAmlMapper().map(aasEnvironment, config); + if (config.isIncludeLibraries()) { + aml = addAASLibrary(aml); + } + Marshaller marshaller = JAXBContextFactory.createContext(new Class[]{ + CAEXFile.class, + AutomationMLVersion.class, + WriterInfo.class, + WriterInfo.Wrapper.class + }, + null).createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + StringWriter writer = new StringWriter(); + marshaller.marshal(aml, writer); + return writer.toString(); + } catch (JAXBException ex) { + throw new SerializationException("error serializing AssetAdministrationShellEnvironment", ex); + } catch (MappingException ex) { + throw new SerializationException("error serializing AssetAdministrationShellEnvironment, mapping to AML failed", ex); + } catch (IOException ex) { + throw new SerializationException("error serializing AssetAdministrationShellEnvironment, AAS library could not be loaded", ex); + } + } + + private CAEXFile addAASLibrary(CAEXFile file) throws JAXBException, IOException { + CAEXFile aasLib = loadAASLibrary(); + return CAEXFile.copyOf(file) + .addInterfaceClassLib(aasLib.getInterfaceClassLib()) + .addRoleClassLib(aasLib.getRoleClassLib()) + .addSystemUnitClassLib(aasLib.getSystemUnitClassLib()) + .build(); + } + + private CAEXFile loadAASLibrary() throws JAXBException, IOException { + Unmarshaller unmarshaller = JAXBContextFactory.createContext(new Class[]{CAEXFile.class}, null).createUnmarshaller(); + return (CAEXFile) unmarshaller.unmarshal(getClass().getResource(AAS_LIB_SOURCE).openStream()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/AasTypeFactory.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/AasTypeFactory.java new file mode 100644 index 00000000..4027863b --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/AasTypeFactory.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialization; + +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Supports in creating instances of AAS interfaces + */ +public class AasTypeFactory { + + private Map, Class> typeMapping; + + public AasTypeFactory() { + typeMapping = ReflectionHelper.DEFAULT_IMPLEMENTATIONS.stream().collect(Collectors.toMap(x -> x.getInterfaceType(), x -> x.getImplementationType())); + } + + /** + * Defines which implementation class to use when creating instances of + * aasInterface. Subsequent class with the same aasInterface parameter will + * override the effects of all previous calls. + * + * @param the type of the interface to replace + * @param aasInterface the class of the interface to replace + * @param implementation the class implementing the interface that should be + * used for instantiation + */ + public void useImplementation(Class aasInterface, Class implementation) { + typeMapping.put(aasInterface, implementation); + } + + /** + * Creates a new instance for a given aasInterface. If the + * + * @param type to create + * @param aasInterface class to find instantiate + * @return an instance of aasInterface + * @throws NoSuchMethodException + * @throws InstantiationException + * @throws IllegalAccessException + * @throws IllegalArgumentException if aasInterface is null or no suitable + * concrete type to instantiate could be found + * @throws InvocationTargetException + */ + public T newInstance(Class aasInterface) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + if (aasInterface == null) { + throw new IllegalArgumentException("aasInterface must be non-null"); + } + Class classToInstantiate = aasInterface; + if (typeMapping.containsKey(aasInterface)) { + classToInstantiate = typeMapping.get(aasInterface); + } + if (classToInstantiate.isInterface()) { + throw new IllegalArgumentException("could not resolve type for interface " + classToInstantiate.getName()); + } + Constructor constructor = classToInstantiate.getConstructor(); + constructor.setAccessible(true); + return (T) constructor.newInstance(); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/Aml2AasMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/Aml2AasMapper.java new file mode 100644 index 00000000..ec730609 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/Aml2AasMapper.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialization; + +import io.adminshell.aas.v3.dataformat.aml.deserialization.mappers.AssetAdministrationShellEnvironmentMapper; +import io.adminshell.aas.v3.dataformat.aml.AmlDeserializationConfig; +import io.adminshell.aas.v3.dataformat.aml.AmlDocumentInfo; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.dataformat.mapping.MappingProvider; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import java.util.List; + +/** + * Maps an AML file to an AssetAdministrationShellEnvironment + */ +public class Aml2AasMapper { + + private final AmlDeserializationConfig config; + + public Aml2AasMapper(AmlDeserializationConfig config) { + this.config = config; + } + + /** + * Maps an AML file (represented by a CAEXFile) to an + * AssetAdministrationShellEnvironment + * + * @param aml the AML source file to map + * @return AssetAdministrationShellEnvironment representation + * @throws MappingException if the mapping fails + */ + public AssetAdministrationShellEnvironment map(CAEXFile aml) throws MappingException { + // unclear how to handle additional information + List additionalInformation = aml.getAdditionalInformation(); + AmlParser parser = new AmlParser(aml); + MappingProvider mappingProvider = new MappingProvider(Mapper.class, new DefaultMapper(), new DefaultMapper()); + mappingProvider.register(new AssetAdministrationShellEnvironmentMapper()); + MappingContext context = new MappingContext(mappingProvider, config.getTypeFactory()); + context.setDocumentInfo(AmlDocumentInfo.fromFile(aml)); + Object result = context.getMappingProvider().getMapper(AssetAdministrationShellEnvironment.class).map(parser, context); + return (AssetAdministrationShellEnvironment) result; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/AmlParser.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/AmlParser.java new file mode 100644 index 00000000..709d34b6 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/AmlParser.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialization; + +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXObject; + +/** + * Wraps an AML file and provides a pointer to the current position within that + * file + * + * @author jab + */ +public class AmlParser { + + private final CAEXFile content; + private CAEXObject current; + + public AmlParser(CAEXFile content) { + this.content = content; + } + + /** + * Gets the AML file the parser represents + * + * @return the AML file the parser represents + */ + public CAEXFile getContent() { + return content; + } + + /** + * Gets the CAEXObject that currently is being processed, i.e. a point to + * the current position within the AML file + * + * @return the current object + */ + public CAEXObject getCurrent() { + return current; + } + + /** + * Sets the CAEXObject that currently is being processed. + * + * @param current the object currently being processed + */ + public void setCurrent(CAEXObject current) { + this.current = current; + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/DefaultMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/DefaultMapper.java new file mode 100644 index 00000000..d12e5a1a --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/DefaultMapper.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialization; + +import com.google.common.reflect.TypeToken; +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * Default mapper for mapping AML to AAS. This mapper will be used when there no + * more specific one is available. + */ +public class DefaultMapper implements Mapper { + + @Override + public Object map(AmlParser parser, MappingContext context) throws MappingException { + if (parser.getCurrent() == null) { + return null; + } + if (InternalElementType.class.isAssignableFrom(parser.getCurrent().getClass())) { + return handleInternalElement(parser, context); + } else if (AttributeType.class.isAssignableFrom(parser.getCurrent().getClass())) { + return handleAttribute(parser, context); + } + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + /** + * This method is called whenever an InternalElement is encountered. + * + * @param parser the AML parser + * @param context the mapping context + * @return an AAS object representing the current object of the parser + */ + protected Object handleInternalElement(AmlParser parser, MappingContext context) { + Object result = null; + InternalElementType current = (InternalElementType) parser.getCurrent(); + String role = current.getRoleRequirements().getRefBaseRoleClassPath(); + if (role.startsWith(context.getDocumentInfo().getAssetAdministrationShellRoleClassLib())) { + String aasClassName = role.substring(context.getDocumentInfo().getAssetAdministrationShellRoleClassLib().length() + 1); + Optional implementationInfo = ReflectionHelper.DEFAULT_IMPLEMENTATIONS.stream() + .filter(x -> x.getInterfaceType().getSimpleName().equals(aasClassName)) + .findFirst(); + final Class aasClass; + // check if custom implementation should be used + if (implementationInfo.isPresent()) { + aasClass = implementationInfo.get().getImplementationType(); + } else { + aasClass = null; + } + if (aasClass != null) { + try { + result = context.getTypeFactory().newInstance(aasClass); + List properties = AasUtils.getAasProperties(aasClass); + List propertiesGivenAsAttribute = new ArrayList<>(); + for (AttributeType attribute : current.getAttribute()) { + Optional property = properties.stream() + .filter(x -> x.getName().equals(attribute.getName())) + .findFirst(); + if (property.isPresent()) { + parser.setCurrent(attribute); + Object attributeValue = context.getMappingProvider() + .getMapper(property.get().getReadMethod().getReturnType()) + .map(parser, context.with(property.get().getReadMethod().getReturnType())); + property.get().getWriteMethod().invoke(result, attributeValue); + propertiesGivenAsAttribute.add(property.get()); + } + } + + Map singleValueProperties = properties.stream() + .filter(x -> !Collection.class.isAssignableFrom(x.getReadMethod().getReturnType())) + .map(x -> new Object() { + PropertyDescriptor type = x; + String aasType = ReflectionHelper.getModelType(x.getReadMethod().getReturnType()); + }) + .filter(x -> x.aasType != null) + .collect(Collectors.toMap( + x -> x.type, + x -> x.aasType)); + + Map collectionValueProperties = properties.stream() + .filter(x -> Collection.class.isAssignableFrom(x.getReadMethod().getReturnType())) + .map(x -> new Object() { + PropertyDescriptor type = x; + String aasType = ReflectionHelper.getModelType(TypeToken.of(x.getReadMethod().getGenericReturnType()).resolveType(Collection.class.getTypeParameters()[0]).getRawType()); + }) + .filter(x -> x.aasType != null) + .collect(Collectors.toMap( + x -> x.type, + x -> x.aasType)); + + List propertyTypes = new ArrayList<>(); + propertyTypes.addAll(singleValueProperties.values()); + propertyTypes.addAll(collectionValueProperties.values()); + List duplicateTypes = propertyTypes.stream() + .filter(e -> Collections.frequency(propertyTypes, e) > 1) + .distinct() + .collect(Collectors.toList()); + if (!duplicateTypes.isEmpty()) { + throw new MappingException(duplicateTypes.stream().map(x + -> String.format("found multiple properties of type '%s' on type '%s'", x, aasClass)) + .collect(Collectors.joining(System.lineSeparator())) + ); + } + // single values + // find matching internal element, deserialize, assign + for (Map.Entry property : singleValueProperties.entrySet()) { + String propertyRole = context.getDocumentInfo().getAssetAdministrationShellRoleClassLib() + "/" + property.getValue(); + List valueElements = current.getInternalElement().stream() + .filter(y -> y.getRoleRequirements().getRefBaseRoleClassPath().equals(propertyRole)) + .collect(Collectors.toList()); + if (!valueElements.isEmpty()) { + if (valueElements.size() > 1) { + throw new MappingException(String.format( + "found multiple InternalElement with role '%s' but only 1 allowed (ids: %s)", + propertyRole, + valueElements.stream() + .map(x -> x.getID()) + .collect(Collectors.joining(", ")))); + } + parser.setCurrent(valueElements.get(0)); + Object propertyValue = context.getMappingProvider() + .getMapper(property.getKey().getReadMethod().getReturnType()) + .map(parser, context); + property.getKey().getWriteMethod().invoke(result, propertyValue); + } + } + + // collection values + // 1. find all internal elements + // 2. deserialize + // 3. build collection (based on actual type, might be collection, list, set,...) + // 4. add to collection + // 5. assign to property + for (Map.Entry property : collectionValueProperties.entrySet()) { + String propertyRole = context.getDocumentInfo().getAssetAdministrationShellRoleClassLib() + "/" + property.getValue(); + List valueElements = current.getInternalElement().stream() + .filter(y -> y.getRoleRequirements().getRefBaseRoleClassPath().equals(propertyRole)) + .collect(Collectors.toList()); + if (!valueElements.isEmpty()) { + Collection propertyValue = (Collection) property.getKey().getReadMethod().getReturnType().getConstructor().newInstance(); + for (InternalElementType element : valueElements) { + parser.setCurrent(element); + Object elementValue = context.getMappingProvider() + .getMapper(property.getKey().getReadMethod().getReturnType()) + .map(parser, context); + propertyValue.add(elementValue); + } + property.getKey().getWriteMethod().invoke(result, propertyValue); + } + } + } catch (Exception ex) { + Logger.getLogger(DefaultMapper.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + return result; + } + + /** + * This method is called whenever an AttributeType is encountered. + * + * @param parser the AML parser + * @param context the mapping context + * @return an object representing the current object of the parser + */ + protected Object handleAttribute(AmlParser parser, MappingContext context) throws MappingException { + AttributeType current = (AttributeType) parser.getCurrent(); + if (context.getType() == null) { + throw new MappingException(String.format("error processing Attribute '%s', missing type information in context", current.getName())); + } + Object result = null; + Class aasType = ReflectionHelper.getAasInterface(context.getType()); + if (aasType != null) { + try { + result = context.getTypeFactory().newInstance(aasType); + List properties = AasUtils.getAasProperties(aasType); + for (AttributeType attribute : current.getAttribute()) { + Optional property = properties.stream() + .filter(x -> x.getName().equals(attribute.getName())) + .findFirst(); + if (property.isPresent()) { + parser.setCurrent(attribute); + Object attributeValue = context.getMappingProvider() + .getMapper(property.get().getReadMethod().getReturnType()) + .map(parser, context.with(property.get().getReadMethod().getReturnType())); + property.get().getWriteMethod().invoke(result, attributeValue); + } + } + } catch (Exception ex) { + Logger.getLogger(DefaultMapper.class.getName()).log(Level.SEVERE, null, ex); + } + } else { + result = current.getValue(); + } + return result; + } + +// private void T instanceFromRoleRequirements(Inter) +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/Mapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/Mapper.java new file mode 100644 index 00000000..3b8f964f --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/Mapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialization; + +import io.adminshell.aas.v3.dataformat.mapping.TargetBasedMapper; + +/** + * Utility interface for all AML to AAS mappers + * + * @param type to be deserialized + */ +public interface Mapper extends TargetBasedMapper { +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/MappingContext.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/MappingContext.java new file mode 100644 index 00000000..9312f4c6 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/MappingContext.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialization; + +import io.adminshell.aas.v3.dataformat.aml.AmlDocumentInfo; +import io.adminshell.aas.v3.dataformat.mapping.MappingProvider; +import io.adminshell.aas.v3.dataformat.mapping.TargetBasedMappingContext; + +/** + * Mapping Context for mapping AML to AAS + */ +public class MappingContext extends TargetBasedMappingContext { + + private AmlDocumentInfo documentInfo; + private AasTypeFactory typeFactory; + private Class type; + + public MappingContext(MappingProvider mappingProvider, AasTypeFactory typeFactory) { + super(mappingProvider); + this.typeFactory = typeFactory; + this.type = null; + } + + private MappingContext(MappingProvider mappingProvider, AasTypeFactory typeFactory, Class type) { + super(mappingProvider); + this.typeFactory = typeFactory; + this.type = type; + } + + public MappingContext with(Class type) { + return new MappingContext(mappingProvider, typeFactory, type); + } + + public AmlDocumentInfo getDocumentInfo() { + return documentInfo; + } + + public void setDocumentInfo(AmlDocumentInfo documentInfo) { + this.documentInfo = documentInfo; + } + + public Class getType() { + return type; + } + + public AasTypeFactory getTypeFactory() { + return typeFactory; + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/mappers/AssetAdministrationShellEnvironmentMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/mappers/AssetAdministrationShellEnvironmentMapper.java new file mode 100644 index 00000000..a75da886 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/deserialization/mappers/AssetAdministrationShellEnvironmentMapper.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.AmlDocumentInfo; +import io.adminshell.aas.v3.dataformat.aml.deserialization.AmlParser; +import io.adminshell.aas.v3.dataformat.aml.deserialization.Mapper; +import io.adminshell.aas.v3.dataformat.aml.deserialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.impl.DefaultAssetAdministrationShellEnvironment; +import java.util.List; +import java.util.function.Predicate; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +public class AssetAdministrationShellEnvironmentMapper implements Mapper { + + @Override + public AssetAdministrationShellEnvironment map(AmlParser parser, MappingContext context) throws MappingException { + AssetAdministrationShellEnvironment result = new DefaultAssetAdministrationShellEnvironment.Builder().build(); + List shells = parser.getContent().getInstanceHierarchy().stream() + .flatMap(x -> x.getInternalElement().stream().filter(filterByRole(AssetAdministrationShell.class))) + .collect(Collectors.toList()); + shells.forEach(x -> { + parser.setCurrent(x); + try { + AssetAdministrationShell aas = (AssetAdministrationShell) context.getMappingProvider().getMapper(AssetAdministrationShell.class).map(parser, context); + result.getAssetAdministrationShells().add(aas); + } catch (MappingException ex) { + Logger.getLogger(AssetAdministrationShellEnvironmentMapper.class.getName()).log(Level.SEVERE, null, ex); + } + }); + return result; + } + + private Predicate filterByRole(Class type) { + return x -> x.getRoleRequirements() != null + && x.getRoleRequirements().getRefBaseRoleClassPath().equals( + AmlDocumentInfo.DEFAULT_ASSET_ADMINISTRATION_SHELL_ROLE_CLASS_LIB + "/" + type.getSimpleName()); + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/header/AutomationMLVersion.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/header/AutomationMLVersion.java new file mode 100644 index 00000000..fb8d44db --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/header/AutomationMLVersion.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.header; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlType; + +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(namespace = "http://www.w3.org/2001/XMLSchema", name = "string") +/** + * Utility class to represent AutomationML version in an AML document + */ +public class AutomationMLVersion { + + @XmlAttribute(name = "AutomationMLVersion") + private final String value; + + public AutomationMLVersion() { + this.value = ""; + } + + public AutomationMLVersion(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/header/WriterInfo.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/header/WriterInfo.java new file mode 100644 index 00000000..bb92069a --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/header/WriterInfo.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.header; + +import java.text.SimpleDateFormat; +import java.util.Date; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + +/** + * Utility class to represent the WriterInfo section in an AML document + */ +public class WriterInfo { + + @XmlElement(name = "WriterName") + private String name; + @XmlElement(name = "WriterID") + private String id; + @XmlElement(name = "WriterVendor") + private String vendor; + @XmlElement(name = "WriterVendorURL") + private String vendorUrl; + @XmlElement(name = "WriterVersion") + private String version; + @XmlElement(name = "WriterRelease") + private String release; + @XmlElement(name = "LastWritingDateTime") + private String writingDate; + @XmlElement(name = "WriterProjectTitle") + private String projectTitle; + @XmlElement(name = "WriterProjectID") + private String projectID; + + public WriterInfo() { + SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); + writingDate = formatter.format(new Date()); + } + + public String getName() { + return name; + } + + @XmlType(name = "xs:anyType") + public static class Wrapper { + + @XmlElement(name = "WriterHeader") + private WriterInfo writerHeader; + + public Wrapper() { + } + + public WriterInfo getWriterHeader() { + return writerHeader; + } + + public void setWriterHeader(WriterInfo writerHeader) { + this.writerHeader = writerHeader; + } + } + + public Object wrap() { + Wrapper result = new Wrapper(); + result.setWriterHeader(this); + return result; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getVendor() { + return vendor; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public String getVendorUrl() { + return vendorUrl; + } + + public void setVendorUrl(String vendorUrl) { + this.vendorUrl = vendorUrl; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getRelease() { + return release; + } + + public void setRelease(String release) { + this.release = release; + } + + public String getWritingDate() { + return writingDate; + } + + public void setWritingDate(String writingDate) { + this.writingDate = writingDate; + } + + public String getProjectTitle() { + return projectTitle; + } + + public void setProjectTitle(String projectTitle) { + this.projectTitle = projectTitle; + } + + public String getProjectID() { + return projectID; + } + + public void setProjectID(String projectID) { + this.projectID = projectID; + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/AasToAmlMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/AasToAmlMapper.java new file mode 100644 index 00000000..0491c97f --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/AasToAmlMapper.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization; + +import io.adminshell.aas.v3.dataformat.aml.AmlSerializationConfig; +import io.adminshell.aas.v3.dataformat.aml.serialization.naming.PropertyNamingStrategy; +import io.adminshell.aas.v3.dataformat.aml.serialization.naming.AbstractClassNamingStrategy; +import io.adminshell.aas.v3.dataformat.aml.serialization.naming.NumberingClassNamingStrategy; +import io.adminshell.aas.v3.dataformat.aml.header.AutomationMLVersion; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.AssetAdministrationShellEnvironmentMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.AssetAdministrationShellMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.ConstraintCollectionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.DataSpecificationContentMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.DataSpecificationIEC61360Mapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.EmbeddedDataSpecificationCollectionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.FileMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.LangStringCollectionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.OperationVariableCollectionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.OperationVariableMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.QualifierMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.ReferenceCollectionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.ReferenceElementMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.RelationshipElementMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.SubmodelMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.ViewMapper; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.ConceptDescriptionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.PropertyMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.RangeMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.mappers.ReferenceMapper; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.dataformat.mapping.MappingProvider; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.LangString; +import io.adminshell.aas.v3.model.Qualifier; +import io.adminshell.aas.v3.model.Referable; +import org.slf4j.LoggerFactory; +import io.adminshell.aas.v3.dataformat.mapping.SourceBasedMapper; +import io.adminshell.aas.v3.model.MultiLanguageProperty; +import io.adminshell.aas.v3.model.Reference; + +/** + * Maps an AssetAdministrationShellEnvironment to an AML file + */ +public class AasToAmlMapper { + + private static final org.slf4j.Logger log = LoggerFactory.getLogger(AasToAmlMapper.class); + + /** + * Maps an AssetAdministrationShellEnvironment to an AML file (represented + * by a CAEXFile) + * + * @param env the AssetAdministrationShellEnvironment to map + * @param config the serialization conig + * @return an AML representation of the AssetAdministrationShellEnvironment + * @throws MappingException if the mapping fails + */ + public CAEXFile map(AssetAdministrationShellEnvironment env, AmlSerializationConfig config) throws MappingException { + AbstractClassNamingStrategy classNamingStrategy = new NumberingClassNamingStrategy(); + classNamingStrategy.registerCustomNaming(LangString.class, x -> "aml-lang=" + x.getLanguage()); + PropertyNamingStrategy propertyNamingStrategy = new PropertyNamingStrategy(); + propertyNamingStrategy.registerCustomNaming(Referable.class, "descriptions", "description", true); + propertyNamingStrategy.registerCustomNaming(MultiLanguageProperty.class, "values", "value", true); + propertyNamingStrategy.registerCustomNaming(Qualifier.class, x -> "qualifier:" + x.getType() + "=" + x.getValue(), false); + MappingProvider mappingProvider = new MappingProvider<>( + SourceBasedMapper.class, + new DefaultMapper(), + new DefaultCollectionMapper()); + + mappingProvider.register(new AssetAdministrationShellEnvironmentMapper()); + mappingProvider.register(new LangStringCollectionMapper()); + mappingProvider.register(new ReferenceMapper()); + mappingProvider.register(new AssetAdministrationShellMapper()); + mappingProvider.register(new OperationVariableMapper()); + mappingProvider.register(new OperationVariableCollectionMapper()); + mappingProvider.register(new ReferenceCollectionMapper()); + mappingProvider.register(new ConstraintCollectionMapper()); + mappingProvider.register(new QualifierMapper()); + mappingProvider.register(new FileMapper()); + mappingProvider.register(new SubmodelMapper()); + mappingProvider.register(new EmbeddedDataSpecificationCollectionMapper()); + mappingProvider.register(new DataSpecificationContentMapper()); + mappingProvider.register(new ReferenceElementMapper()); + mappingProvider.register(new RelationshipElementMapper()); + mappingProvider.register(new DataSpecificationIEC61360Mapper()); + mappingProvider.register(new ViewMapper()); + mappingProvider.register(new PropertyMapper()); + mappingProvider.register(new RangeMapper()); + mappingProvider.register(new ConceptDescriptionMapper()); + MappingContext context = new MappingContext( + mappingProvider, + classNamingStrategy, + propertyNamingStrategy, + env); + CAEXFile.Builder builder = CAEXFile.builder() + .withSchemaVersion(config.getCaexSchemaVersion()) + .withFileName(config.getFilename()) + .addAdditionalInformation(new AutomationMLVersion(config.getAmlVersion())); + if (config.getWriterInfo() != null) { + builder = builder.addAdditionalInformation(config.getWriterInfo().wrap()); + } + if (!config.getAdditionalInformation().isEmpty()) { + builder = builder.addAdditionalInformation(config.getAdditionalInformation()); + } + context.map(env, AmlGenerator.builder() + .file(builder) + .idGenerator(config.getIdGenerator()) + .build()); + return builder.build(); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/AmlGenerator.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/AmlGenerator.java new file mode 100644 index 00000000..cc4fb335 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/AmlGenerator.java @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization; + +import io.adminshell.aas.v3.dataformat.aml.AmlDocumentInfo; +import io.adminshell.aas.v3.dataformat.aml.serialization.id.IdGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.id.UuidGenerator; +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXObject; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.RoleClassType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.SystemUnitClassType; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.impl.DefaultReference; +import java.beans.PropertyDescriptor; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Immutable class supporting creation of AML file by encalsulating different + * common tasks and functionality, e.g. id generation and caching. To create new + * instances with modified properties use provided with...(...) functions. + */ +public class AmlGenerator { + + private static final Logger log = LoggerFactory.getLogger(AmlGenerator.class); + public static final String REFERABLE_REFERENCE_INTERFACE_CLASS = "ReferableReference"; + private static final String DEFAULT_REF_SEMANTIC_PREFIX = "AAS"; + + public static Builder builder() { + return new Builder(); + } + private final String refSemanticPrefix; + private final CAEXObject.Builder current; + private final AmlDocumentInfo documentInfo; + private final Reference reference; + private final IdGenerator idGenerator; + private final Map idCache; + private CAEXFile.Builder fileBuilder; + + private AmlGenerator( + AmlDocumentInfo documentInfo, + IdGenerator idGenerator, + Map idCache, + String refSemanticPrefix, + CAEXFile.Builder fileBuilder, + CAEXObject.Builder current, + Reference reference) { + this.documentInfo = documentInfo; + this.idGenerator = idGenerator; + this.idCache = idCache; + this.refSemanticPrefix = refSemanticPrefix; + this.fileBuilder = fileBuilder; + this.current = current; + this.reference = reference; + } + + /** + * Creates a new instance with new current CAEXObject.Builder + * + * @param current new current CAEXObject.Builder + * @return new immutable instance with CAEXObject.Builder + */ + public AmlGenerator with(CAEXObject.Builder current) { + return new AmlGenerator(documentInfo, + idGenerator, + idCache, + refSemanticPrefix, + fileBuilder, + current, + reference); + } + + /** + * Creates a new instance with reference to new parent object in AAS + * + * @param parent reference to new parent element + * @return new immutable instance with new parent + */ + public AmlGenerator with(Referable parent) { + return new AmlGenerator( + documentInfo, + idGenerator, + idCache, + refSemanticPrefix, + fileBuilder, + current, + AasUtils.toReference(reference, parent)); + } + + /** + * Creates a new instance with given prefix for refSemantic tags + * + * @param value new prefix for refSemantic tags + * @return new immutable instance given refSemantic prefix + */ + public AmlGenerator withRefSemanticPrefix(String value) { + return new AmlGenerator( + documentInfo, + idGenerator, + idCache, + value, + fileBuilder, + current, + reference); + } + + /** + * Adds additional information to the AML file + * + * @param additionalInformation additional information to add + */ + public void addAdditionalInformation(List additionalInformation) { + fileBuilder.addAdditionalInformation(additionalInformation); + } + + /** + * Generates a new ID without caching it. + * + * @return a new ID + */ + public String newId() { + return idGenerator.next(); + } + + /** + * Gets the ID for given object. If obj is an instance of Referable it is + * first converted to reference pointing to that element. In that case, or + * if the obj is already an instance of Reference, an already existing ID + * will be returned if available, otherwise a new one is created and cached. + * If obj is neither an instance of Reference nor Referable, a new ID is + * generated and not cached. + * + * @param obj object to generate an ID for + * @return an ID that might or might not be cached (depending of type of + * obj) + */ + public String getId(Object obj) { + if (obj == null) { + return idGenerator.next(); + } + Reference key; + if (Reference.class.isAssignableFrom(obj.getClass())) { + key = (Reference) obj; + } else if (Referable.class.isAssignableFrom(obj.getClass())) { + key = AasUtils.toReference(reference, (Referable) obj); + } else { + return idGenerator.next(); + } + Optional cacheKey = idCache.keySet().stream() + .filter(x -> AasUtils.sameAs(x, key)) + .findFirst(); + if (cacheKey.isPresent()) { + return idCache.get(cacheKey.get()); + } + String result = idGenerator.next(); + idCache.put(key, result); + return result; + } + + /** + * Adds an object to the current element of the AML document + * + * @param caexObject the object to add + */ + public void add(CAEXObject caexObject) { + if (caexObject == null) { + return; + } + if (AttributeType.class.isAssignableFrom(caexObject.getClass())) { + addAttribute((AttributeType) caexObject); + } else if (InternalElementType.class.isAssignableFrom(caexObject.getClass())) { + addInternalElement((InternalElementType) caexObject); + } else { + log.warn("adding caex object failed because unsupported type '{}'", caexObject.getClass()); + } + } + + /** + * Adds an attribute to the current element of the AML document + * + * @param attribute the attribute to add + */ + public void addAttribute(AttributeType attribute) { + if (attribute == null) { + return; + } + if (AttributeType.Builder.class.isAssignableFrom(current.getClass())) { + AttributeType.Builder builder = (AttributeType.Builder) current; + builder.addAttribute(attribute); + } else if (InternalElementType.Builder.class.isAssignableFrom(current.getClass())) { + InternalElementType.Builder builder = (InternalElementType.Builder) current; + builder.addAttribute(attribute); + } else { + log.warn("adding attribute failed because no parent builder defined"); + } + } + + private void addExternalInterface(RoleClassType.ExternalInterface externalInterface, boolean allowDuplicate) { + if (externalInterface == null) { + return; + } + if (InternalElementType.Builder.class.isAssignableFrom(current.getClass())) { + InternalElementType.Builder builder = (InternalElementType.Builder) current; + if (!builder.build().getExternalInterface().stream() + .anyMatch(x -> x.getName().equals(externalInterface.getName()) + && x.getRefBaseClassPath().equals(externalInterface.getRefBaseClassPath()))) { + builder.addExternalInterface(externalInterface); + } + } else { + log.warn("adding external interface failed because no parent builder defined"); + } + } + + /** + * Adds an external interface with name and roleCall ReferableReference to + * the current element of the AML document + */ + public void addExternalInterfaceForReference() { + addExternalInterface(RoleClassType.ExternalInterface.builder() + .withID(newId()) + .withName(REFERABLE_REFERENCE_INTERFACE_CLASS) + .withRefBaseClassPath(documentInfo.getAssetAdministrationShellInterfaceClassLib() + "/" + REFERABLE_REFERENCE_INTERFACE_CLASS) + .build(), false); + } + + /** + * Adds an internal link with given namen pointing from source to target to + * the current element of the AML document + * + * @param name name if the link + * @param source source element of the link + * @param target reference pointing to the target element + */ + public void addInternalLink(String name, Referable source, Reference target) { + if (InternalElementType.Builder.class.isAssignableFrom(current.getClass())) { + InternalElementType.Builder builder = (InternalElementType.Builder) current; + builder.addInternalLink((SystemUnitClassType.InternalLink.builder() + .withName(name) + .withID(newId()) + .withRefPartnerSideA(getId(source) + ":" + REFERABLE_REFERENCE_INTERFACE_CLASS) + .withRefPartnerSideB(getId(target) + ":" + REFERABLE_REFERENCE_INTERFACE_CLASS) + .build())); + } else { + log.warn("adding internal link failed because no parent builder defined"); + } + } + + /** + * Adds an external interface of type ReferableReference with given name + * with unresolvabled reference as value to the current element of the AML + * document + * + * @param name name of the interface + * @param reference unresolvable target reference + */ + public void addExternalInterfaceForUnresolvableReference(String name, Reference reference) { + addExternalInterface(RoleClassType.ExternalInterface.builder() + .withID(idGenerator.next()) + .withName(name) + .withRefBaseClassPath(documentInfo.getAssetAdministrationShellInterfaceClassLib() + "/" + REFERABLE_REFERENCE_INTERFACE_CLASS) + .addAttribute(AttributeType.builder() + .withName("value") + .withID(newId()) + .withAttributeDataType("xs:string") + .withValue(AasUtils.asString(reference)) + .build()) + .build(), + false); + } + + /** + * Clears the ID cache. This should be used with caution as it may cause + * reference resolution mechanism to fail. Typically it will only be called + * after processing the InstanceHierarchy elements and before creating + * custom SystemUnitClasses + */ + public void clearIdCache() { + idCache.clear(); + } + + public void addSystemUnitClassLib(CAEXFile.SystemUnitClassLib systemUnitClassLib) { + if (systemUnitClassLib == null) { + return; + } + if (fileBuilder != null) { + fileBuilder = fileBuilder.addSystemUnitClassLib(systemUnitClassLib); + } + } + + public void addInstanceHierarchy(CAEXFile.InstanceHierarchy instanceHierarchy) { + if (instanceHierarchy == null) { + return; + } + if (fileBuilder != null) { + fileBuilder = fileBuilder.addInstanceHierarchy(instanceHierarchy); + } + } + + public void addInternalElement(InternalElementType internalElement, Object source) { + addInternalElement(InternalElementType + .copyOf(internalElement) + .withID(getId(source)) + .build()); + } + + public void addInternalElement(InternalElementType element) { + if (element == null) { + return; + } + InternalElementType value = element; + if (value.getID() == null || value.getID().isBlank()) { + value = InternalElementType + .copyOf(element) + .withID(idGenerator.next()) + .build(); + } + if (InternalElementType.Builder.class.isAssignableFrom(current.getClass())) { + InternalElementType.Builder builder = (InternalElementType.Builder) current; + builder.addInternalElement(value); + } else if (CAEXFile.InstanceHierarchy.Builder.class.isAssignableFrom(current.getClass())) { + CAEXFile.InstanceHierarchy.Builder builder = (CAEXFile.InstanceHierarchy.Builder) current; + builder.addInternalElement(value); + } else { + log.warn("adding internalElement failed because no parent builder defined"); + } + } + + public void appendReferenceTargetInterfaceIfRequired(Object obj, MappingContext context) { + RoleClassType.ExternalInterface referenceTargetInterface = getReferenceTargetInterface(obj, context); + if (referenceTargetInterface != null) { + addExternalInterface(referenceTargetInterface, false); + } + } + + public RoleClassType.ExternalInterface getReferenceTargetInterface(Object obj, MappingContext context) { + RoleClassType.ExternalInterface result = null; + if (obj != null && Referable.class.isAssignableFrom(obj.getClass())) { + Referable referable = (Referable) obj; + Reference targetRef = AasUtils.toReference(reference, referable); + if (context.isTargetOfInternalLink(targetRef)) { + result = RoleClassType.ExternalInterface.builder() + .withID(newId()) + .withName("ReferableReference") + .withRefBaseClassPath(documentInfo.getAssetAdministrationShellInterfaceClassLib() + "/ReferableReference") + .build(); + } + } + return result; + } + + public InternalElementType.RoleRequirements roleRequirement(String value) { + return InternalElementType.RoleRequirements.builder() + .withRefBaseRoleClassPath(documentInfo.getAssetAdministrationShellRoleClassLib() + "/" + value) + .build(); + } + + public AttributeType.RefSemantic refSemantic(Class type, String propertyName) { + return AttributeType.RefSemantic.builder() + .withCorrespondingAttributePath(refSemanticPrefix + (refSemanticPrefix.isBlank() ? "" : ":") + type.getSimpleName() + "/" + propertyName) + .build(); + } + + /** + * Creates a refSemantic object for a given property and property name. + * + * @param property the property + * @param propertyName the property name to use in the refSemantic. + * @return the generated refSemantic object + */ + public AttributeType.RefSemantic refSemantic(PropertyDescriptor property, String propertyName) { + return refSemantic(property.getReadMethod().getDeclaringClass(), propertyName); + } + + /** + * Gets to AML document info + * + * @return the AML document info + */ + public AmlDocumentInfo getDocumentInfo() { + return documentInfo; + } + + public static class Builder { + + private String refSemanticPrefix = DEFAULT_REF_SEMANTIC_PREFIX; + private CAEXObject.Builder current; + private CAEXFile.Builder fileBuilder = CAEXFile.builder(); + private AmlDocumentInfo documentInfo = new AmlDocumentInfo(); + private IdGenerator idGenerator = new UuidGenerator(); + + public AmlGenerator build() { + return new AmlGenerator(documentInfo, + idGenerator, + new HashMap<>(), + refSemanticPrefix, + fileBuilder, + current, + new DefaultReference.Builder().build()); + } + + public Builder refSemanticPrefix(String value) { + this.refSemanticPrefix = value; + return this; + } + + public Builder current(CAEXObject.Builder value) { + this.current = value; + return this; + } + + public Builder idGenerator(IdGenerator value) { + this.idGenerator = value; + return this; + } + + public Builder file(CAEXFile.Builder value) { + this.fileBuilder = value; + return this; + } + + public Builder documentInfo(AmlDocumentInfo value) { + this.documentInfo = value; + return this; + } + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/DefaultCollectionMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/DefaultCollectionMapper.java new file mode 100644 index 00000000..5fbba9dc --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/DefaultCollectionMapper.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization; + +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import java.lang.reflect.ParameterizedType; +import java.util.Collection; + +public class DefaultCollectionMapper extends DefaultMapper> { + + @Override + protected Class getType(Collection collection, MappingContext context) { + if (context.getProperty() != null) { + return (Class) ((ParameterizedType) context.getProperty().getReadMethod().getGenericReturnType()).getActualTypeArguments()[0]; + } + if (collection != null && !collection.isEmpty()) { + return (Class) ReflectionHelper.getAasInterface(collection.iterator().next().getClass()); + } + return null; + } + + @Override + protected void asInternalElement(Collection collection, AmlGenerator generator, MappingContext context) throws MappingException { + for (T element : collection) { + context.withoutProperty().map(element, generator); + } + } + + @Override + protected void mapProperties(Collection collection, AmlGenerator generator, MappingContext context) throws MappingException { + } + + @Override + protected void asAttribute(Collection collection, AmlGenerator generator, MappingContext context) throws MappingException { + if (collection != null && !collection.isEmpty()) { + AttributeType.Builder builder = super.toAttribute(collection, generator, context); + for (T element : collection) { + context.map(element, generator.with(builder)); + } + generator.add(builder.build()); + } + } + + @Override + protected String getAttributeName(Collection value, MappingContext context) { + return context.getAttributeNamingStrategy().getName( + context.getProperty().getReadMethod().getDeclaringClass(), + value, + context.getProperty().getName()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/DefaultMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/DefaultMapper.java new file mode 100644 index 00000000..f65b4d61 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/DefaultMapper.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization; + +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Referable; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class DefaultMapper implements Mapper { + + private final Set ignoredProperties = new HashSet<>(); + + public DefaultMapper() { + } + + public DefaultMapper(String... ignoredProperties) { + this.ignoredProperties.addAll(Arrays.asList(ignoredProperties)); + } + + protected Class getType(T value, MappingContext context) { + return value.getClass(); + } + + @Override + public void map(T value, AmlGenerator generator, MappingContext context) throws MappingException { + if (value == null || context == null) { + return; + } + Class aasType = getType(value, context); + if (aasType == null) { + return; + } + Class aasTypeInfo = ReflectionHelper.getMostSpecificTypeWithModelType(aasType); + if (aasTypeInfo != null) { + asInternalElement(value, generator, context); + } else { + asAttribute(value, generator, context); + } + } + + protected void asInternalElement(T value, AmlGenerator generator, MappingContext context) throws MappingException { + InternalElementType.Builder builder = toInternalElement(value, generator, context); + if (builder != null) { + generator.with(builder).appendReferenceTargetInterfaceIfRequired(value, context); + generator.addInternalElement(builder.build(), value); + } + } + + protected void asAttribute(T value, AmlGenerator generator, MappingContext context) throws MappingException { + AttributeType.Builder builder = toAttribute(value, generator, context); + if (builder != null) { + generator.add(builder.build()); + } + } + + protected InternalElementType.Builder toInternalElement(T value, AmlGenerator generator, MappingContext context) throws MappingException { + InternalElementType.Builder builder = InternalElementType.builder(); + builder = builder + .withName(getInternalElementName(value, context)) + .withRoleRequirements(getRoleRequirementClass(value, generator, context)); + AmlGenerator subGenerator = generator; + if (Referable.class.isAssignableFrom(value.getClass())) { + subGenerator = generator.with((Referable) value); + } + mapProperties(value, subGenerator.with(builder), context); + return builder; + } + + protected InternalElementType.RoleRequirements getRoleRequirementClass(T value, AmlGenerator generator, MappingContext context) { + return generator.roleRequirement(ReflectionHelper.getModelType(value.getClass())); + } + + protected AttributeType.RefSemantic getRefSemantic(T value, AmlGenerator generator, MappingContext context) { + return generator.refSemantic( + context.getProperty(), + context.getAttributeNamingStrategy().getNameForRefSemantic( + context.getProperty().getReadMethod().getGenericReturnType(), + value, + context.getProperty().getName())); + } + + protected String getInternalElementName(Object value, MappingContext context) { + return context.getInternalElementNamingStrategy().getName( + value.getClass(), + value, + null); + } + + protected String getAttributeName(T value, MappingContext context) { + return context.getAttributeNamingStrategy().getName( + context.getProperty().getReadMethod().getGenericReturnType(), + value, + context.getProperty().getName()); + } + + protected AttributeType.Builder toAttribute(T value, AmlGenerator generator, MappingContext context) throws MappingException { + Class aasType = ReflectionHelper.getAasInterface(value.getClass()); + AttributeType.Builder builder = AttributeType.builder(); + if (context.getProperty() != null) { + builder = builder + .withName(getAttributeName(value, context)) + .withRefSemantic(getRefSemantic(value, generator, context)); + } + if (aasType != null) { + mapProperties(value, generator.with(builder), context); + } else { + + builder = builder.withValue(value); + } + return builder; + } + + protected boolean skipProperty(PropertyDescriptor property) { + return ignoredProperties.contains(property.getName()); + } + + protected void mapProperties(T value, AmlGenerator generator, MappingContext context) throws MappingException { + List collect = AasUtils.getAasProperties(value.getClass()).stream().map(x -> x.getName()).collect(Collectors.toList()); + for (PropertyDescriptor property : AasUtils.getAasProperties(value.getClass())) { + if (!skipProperty(property)) { + context.with(property) + .map(property.getReadMethod().getGenericReturnType(), + getPropertyValue(value, property, context), + generator); + } + } + } + + protected Object getPropertyValue(T value, PropertyDescriptor property, MappingContext context) throws MappingException { + try { + return property.getReadMethod().invoke(value); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new MappingException("failed to get property value for property " + property.getName(), ex); + } + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/IdentityProvider.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/IdentityProvider.java new file mode 100644 index 00000000..cab9952a --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/IdentityProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization; + +import io.adminshell.aas.v3.dataformat.aml.serialization.id.IdGenerator; +import java.util.HashMap; +import java.util.Map; + +public class IdentityProvider { + + private final Map cache; + private final IdGenerator idGenerator; + + public IdentityProvider(IdGenerator idGenerator) { + this.cache = new HashMap<>(); + this.idGenerator = idGenerator; + } + + public String getCachedId(Object obj) { + if (cache.containsKey(obj)) { + return cache.get(obj); + } + String result = generateId(); + cache.put(obj, result); + return result; + } + + public String generateId() { + String result = null; + do { + result = idGenerator.next(); + } while (cache.values().contains(result)); + return result; + } + + public IdGenerator getIdGenerator() { + return idGenerator; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/Mapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/Mapper.java new file mode 100644 index 00000000..abbfc4bb --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/Mapper.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization; + +import io.adminshell.aas.v3.dataformat.mapping.SourceBasedMapper; + +public interface Mapper extends SourceBasedMapper { + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/MappingContext.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/MappingContext.java new file mode 100644 index 00000000..a67652eb --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/MappingContext.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization; + +import io.adminshell.aas.v3.dataformat.aml.serialization.naming.NamingStrategy; +import io.adminshell.aas.v3.dataformat.aml.util.ReferencedReferableCollector; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.dataformat.mapping.MappingProvider; +import io.adminshell.aas.v3.dataformat.mapping.SourceBasedMappingContext; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Type; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import io.adminshell.aas.v3.model.Reference; +import java.util.Set; + +public class MappingContext extends SourceBasedMappingContext { + + private static final Logger log = LoggerFactory.getLogger(MappingContext.class); + private final AssetAdministrationShellEnvironment environment; + private final NamingStrategy internalElementNamingStrategy; + private final NamingStrategy attributeNamingStrategy; + + private final PropertyDescriptor property; + private final Set referencedReferables; + + public MappingContext(MappingProvider mappingProvider, + NamingStrategy internalElementNamingStrategy, + NamingStrategy attributeNamingStrategy, + AssetAdministrationShellEnvironment environment) { + this(mappingProvider, + internalElementNamingStrategy, + attributeNamingStrategy, + environment, + null, + null); + } + + public NamingStrategy getInternalElementNamingStrategy() { + return internalElementNamingStrategy; + } + + public NamingStrategy getAttributeNamingStrategy() { + return attributeNamingStrategy; + } + + private MappingContext(MappingProvider mappingProvider, + NamingStrategy internalElementNamingStrategy, + NamingStrategy attributeNamingStrategy, + AssetAdministrationShellEnvironment environment, + Set referencedReferables, + PropertyDescriptor property) { + super(mappingProvider); + this.internalElementNamingStrategy = internalElementNamingStrategy; + this.attributeNamingStrategy = attributeNamingStrategy; + this.environment = environment; + this.property = property; + if (referencedReferables == null) { + this.referencedReferables = new ReferencedReferableCollector(environment).collect(); + } else { + this.referencedReferables = referencedReferables; + } + } + + public boolean isTargetOfInternalLink(Reference targetRef) { + return referencedReferables.stream().anyMatch(x -> AasUtils.sameAs(x, targetRef)); + } + + public void map(T value, AmlGenerator generator) throws MappingException { + mappingProvider.getMapper(value).map(value, generator, this); + } + + public void map(Type type, T value, AmlGenerator generator) throws MappingException { + mappingProvider.getMapper(type).map(value, generator, this); + } + + public MappingContext with(PropertyDescriptor property) { + return new MappingContext( + getMappingProvider(), + internalElementNamingStrategy, + attributeNamingStrategy, + environment, + referencedReferables, + property); + } + + public MappingContext withoutProperty() { + return new MappingContext( + getMappingProvider(), + internalElementNamingStrategy, + attributeNamingStrategy, + environment, + referencedReferables, + null); + } + + public PropertyDescriptor getProperty() { + return property; + } + + public AssetAdministrationShellEnvironment getEnvironment() { + return environment; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/IdGenerator.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/IdGenerator.java new file mode 100644 index 00000000..a9074e14 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/IdGenerator.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.id; + +public interface IdGenerator { + + public String next(); +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/IntegerIdGenerator.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/IntegerIdGenerator.java new file mode 100644 index 00000000..05472323 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/IntegerIdGenerator.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.id; + +public class IntegerIdGenerator implements IdGenerator { + + private int id = 1; + + @Override + public String next() { + return Integer.toString(id++); + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/UuidGenerator.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/UuidGenerator.java new file mode 100644 index 00000000..ef218427 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/id/UuidGenerator.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.id; + +import java.util.UUID; + +public class UuidGenerator implements IdGenerator { + + @Override + public String next() { + return UUID.randomUUID().toString(); + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AbstractElementMapperWithValueType.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AbstractElementMapperWithValueType.java new file mode 100644 index 00000000..bdd5cd38 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AbstractElementMapperWithValueType.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Abstract base class for AAS types that have the properties 'value' and + * 'valueType' that ensures valueType is serialized as attribute of value + * + */ +public abstract class AbstractElementMapperWithValueType extends DefaultMapper { + + protected static final String PROPERTY_VALUE_NAME = "value"; + protected static final String PROPERTY_VALUE_TYPE_NAME = "valueType"; + protected static final String PROPERTY_VALUE_TYPE_NAMESPACE_PREFIX = "xs:"; + private List typedProperties = List.of(PROPERTY_VALUE_NAME); + + protected AbstractElementMapperWithValueType(String... typedProperties) { + super(PROPERTY_VALUE_TYPE_NAME); + this.typedProperties = Arrays.asList(typedProperties); + } + + protected AbstractElementMapperWithValueType() { + super(PROPERTY_VALUE_TYPE_NAME); + } + + @Override + protected InternalElementType.Builder toInternalElement(T value, AmlGenerator generator, MappingContext context) throws MappingException { + InternalElementType original = super.toInternalElement(value, generator, context).build(); + Optional valueTypeProperty = AasUtils.getAasProperties(value.getClass()).stream() + .filter(x -> PROPERTY_VALUE_TYPE_NAME.equals(x.getName())) + .findFirst(); + List untouchedAttributes = original.getAttribute().stream() + .filter(x -> !typedProperties.contains(x.getName())) + .collect(Collectors.toList()); + InternalElementType.Builder builder = InternalElementType + .copyOf(original) + .withAttribute(untouchedAttributes); + for (String property : typedProperties) { + Optional attributeToType = original.getAttribute().stream() + .filter(x -> property.equals(x.getName())) + .findFirst(); + if (attributeToType.isPresent()) { + AttributeType.Builder typedAttributeBuilder = AttributeType.copyOf(attributeToType.get()); + if (valueTypeProperty.isPresent()) { + try { + typedAttributeBuilder = typedAttributeBuilder.withAttributeDataType( + PROPERTY_VALUE_TYPE_NAMESPACE_PREFIX + valueTypeProperty.get().getReadMethod().invoke(value)); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new MappingException(String.format("error reading property %s", PROPERTY_VALUE_TYPE_NAME)); + } + } + builder = builder.addAttribute(typedAttributeBuilder.build()); + } + } + return builder; + } + + @Override + protected AttributeType.Builder toAttribute(T value, AmlGenerator generator, MappingContext context) throws MappingException { + AttributeType original = super.toAttribute(value, generator, context).build(); + Optional valueTypeProperty = AasUtils.getAasProperties(value.getClass()).stream() + .filter(x -> PROPERTY_VALUE_TYPE_NAME.equals(x.getName())) + .findFirst(); + List untouchedAttributes = original.getAttribute().stream() + .filter(x -> !typedProperties.contains(x.getName())) + .collect(Collectors.toList()); + AttributeType.Builder builder = AttributeType + .copyOf(original) + .withAttribute(untouchedAttributes); + for (String property : typedProperties) { + Optional attributeToType = original.getAttribute().stream() + .filter(x -> property.equals(x.getName())) + .findFirst(); + if (attributeToType.isPresent()) { + AttributeType.Builder typedAttributeBuilder = AttributeType.copyOf(attributeToType.get()); + if (valueTypeProperty.isPresent()) { + try { + typedAttributeBuilder = typedAttributeBuilder.withAttributeDataType( + PROPERTY_VALUE_TYPE_NAMESPACE_PREFIX + valueTypeProperty.get().getReadMethod().invoke(value)); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + throw new MappingException(String.format("error reading property %s", PROPERTY_VALUE_TYPE_NAME)); + } + } + builder = builder.addAttribute(typedAttributeBuilder.build()); + } + } + return builder; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AssetAdministrationShellEnvironmentMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AssetAdministrationShellEnvironmentMapper.java new file mode 100644 index 00000000..dad931b5 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AssetAdministrationShellEnvironmentMapper.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import com.google.inject.util.Types; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile; +import io.adminshell.aas.v3.dataformat.aml.model.caex.CAEXFile.SystemUnitClassLib; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.SystemUnitClassType.SupportedRoleClass; +import io.adminshell.aas.v3.dataformat.aml.model.caex.SystemUnitFamilyType; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.ConceptDescription; +import io.adminshell.aas.v3.model.ModelingKind; +import io.adminshell.aas.v3.model.Submodel; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class AssetAdministrationShellEnvironmentMapper extends DefaultMapper { + + @Override + public void map(AssetAdministrationShellEnvironment value, AmlGenerator generator, MappingContext context) throws MappingException { + List assetAdministrationShells = value.getAssetAdministrationShells().stream() + .filter(x -> x.getSubmodels().stream() + .anyMatch(sm -> { + Submodel submodel = AasUtils.resolve(sm, value, Submodel.class); + return submodel != null && submodel.getKind() != ModelingKind.TEMPLATE; + })) + .collect(Collectors.toList()); + toHierarchy(generator.getDocumentInfo().getAssetAdministrationShellInstanceHierarchy(), + AssetAdministrationShell.class, + assetAdministrationShells, + generator, + context); + toHierarchy( + generator.getDocumentInfo().getConceptDescriptionInstanceHierarchy(), + ConceptDescription.class, + value.getConceptDescriptions(), + generator, + context); + mapTemplates(value, generator, context); + } + + protected void toHierarchy( + String hierarchyName, + Class type, + Collection value, + AmlGenerator generator, + MappingContext context) throws MappingException { + CAEXFile.InstanceHierarchy.Builder builder = CAEXFile.InstanceHierarchy.builder() + .withName(hierarchyName); + context.map(Types.newParameterizedType(Collection.class, type), value, generator.with(builder)); + generator.addInstanceHierarchy(builder.build()); + } + + protected void mapTemplates(AssetAdministrationShellEnvironment env, AmlGenerator generator, MappingContext context) throws MappingException { + boolean empty = true; + SystemUnitClassLib.Builder builder = SystemUnitClassLib.builder() + .withName(generator.getDocumentInfo().getAssetAdministrationShellSystemUnitClassLib()); + + // generate SystemUnitClass for each AAS with at least 1 Submodel with kind == TEMPLATE + // generate SystemUnitClass for each Submodel with king == TEMPLATE + for (AssetAdministrationShell aas : env.getAssetAdministrationShells()) { + List submodelTemplates = AasUtils.getSubmodelTemplates(aas, env); + if (!submodelTemplates.isEmpty()) { + empty = false; + generator.clearIdCache(); + InternalElementType.Builder temp = InternalElementType.builder(); + context.withoutProperty().map(aas, generator.with(temp)); + builder.addSystemUnitClass(internalElementToSystemUnitClass(temp.build().getInternalElement().get(0))); + } + generator.clearIdCache(); + for (Submodel submodel : submodelTemplates) { + InternalElementType.Builder temp = InternalElementType.builder(); + context.withoutProperty().map(submodel, generator.with(temp)); + builder.addSystemUnitClass(internalElementToSystemUnitClass(temp.build().getInternalElement().get(0))); + } + } + if (!empty) { + generator.addSystemUnitClassLib(builder.build()); + } + } + + protected SystemUnitFamilyType internalElementToSystemUnitClass(InternalElementType internalElement) { + return SystemUnitFamilyType.builder() + .withName(internalElement.getName()) + .withID(internalElement.getID()) + .addAttribute(internalElement.getAttribute()) + .addInternalElement(internalElement.getInternalElement()) + .withSupportedRoleClass(SupportedRoleClass.builder() + .withRefRoleClassPath(internalElement.getRoleRequirements().getRefBaseRoleClassPath()) + .build()) + .build(); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AssetAdministrationShellMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AssetAdministrationShellMapper.java new file mode 100644 index 00000000..a824feee --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/AssetAdministrationShellMapper.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.ModelingKind; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.Submodel; +import java.beans.PropertyDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AssetAdministrationShellMapper extends DefaultMapper { + + private static final Logger log = LoggerFactory.getLogger(AssetAdministrationShellMapper.class); + + @Override + protected boolean skipProperty(PropertyDescriptor property) { + return "submodels".equals(property.getName()); + } + + @Override + public void map(AssetAdministrationShell aas, AmlGenerator generator, MappingContext context) throws MappingException { + if (aas == null) { + return; + } + InternalElementType.Builder builder = toInternalElement(aas, generator, context); + boolean hasTemplateSubmodel = false; + for (Reference reference : aas.getSubmodels()) { + Submodel resolvedSubmodel = AasUtils.resolve(reference, context.getEnvironment(), Submodel.class); + if (resolvedSubmodel != null) { + context.map(resolvedSubmodel, generator.with(builder)); + if (resolvedSubmodel.getKind() == ModelingKind.TEMPLATE) { + hasTemplateSubmodel = true; + } + } else { + log.warn("unresolvable submodel reference '{}' found in AssetAdministrationShell '{}'", + AasUtils.asString(reference), + aas.getIdentification().getIdentifier()); + context.map(AasUtils.asString(reference), generator); + } + } + if (hasTemplateSubmodel) { + builder = builder.withRefBaseSystemUnitPath(generator.getDocumentInfo().getAssetAdministrationShellSystemUnitClassLib() + + "/" + context.getInternalElementNamingStrategy().getName(aas.getClass(), aas, null)); + } + generator.with(builder).appendReferenceTargetInterfaceIfRequired(aas, context); + generator.add(builder.build()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ConceptDescriptionMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ConceptDescriptionMapper.java new file mode 100644 index 00000000..d38d9189 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ConceptDescriptionMapper.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType.RefSemantic; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.ConceptDescription; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class ConceptDescriptionMapper extends DefaultMapper { + + protected static final String PROPERTY_IS_CASE_OF_NAME = "isCaseOf"; + protected static final String PROPERTY_IS_CASE_OFS_NAME = PROPERTY_IS_CASE_OF_NAME + "s"; + + @Override + protected InternalElementType.Builder toInternalElement(ConceptDescription value, AmlGenerator generator, MappingContext context) throws MappingException { + InternalElementType original = super.toInternalElement(value, generator, context).build(); + List untouchedAttributes = original.getAttribute().stream() + .filter(x -> !PROPERTY_IS_CASE_OFS_NAME.equals(x.getName())) + .collect(Collectors.toList()); + InternalElementType.Builder builder = InternalElementType + .copyOf(original) + .withAttribute(untouchedAttributes); + Optional isCaseOfAttribute = original.getAttribute().stream() + .filter(x -> PROPERTY_IS_CASE_OFS_NAME.equals(x.getName())) + .findFirst(); + if (isCaseOfAttribute.isPresent()) { + String path = isCaseOfAttribute.get().getRefSemantic().get(0).getCorrespondingAttributePath(); + String newPath = path.substring(0, path.lastIndexOf("/") + 1) + PROPERTY_IS_CASE_OF_NAME; + builder = builder.addAttribute(AttributeType + .copyOf(isCaseOfAttribute.get()) + .withName(PROPERTY_IS_CASE_OF_NAME) + .withRefSemantic(RefSemantic.copyOf(isCaseOfAttribute.get().getRefSemantic().get(0)) + .withCorrespondingAttributePath(newPath) + .build()) + .build()); + } + return builder; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ConstraintCollectionMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ConstraintCollectionMapper.java new file mode 100644 index 00000000..97a8d183 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ConstraintCollectionMapper.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.Mapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Constraint; +import java.util.Collection; + +public class ConstraintCollectionMapper implements Mapper> { + + @Override + public void map(Collection value, AmlGenerator generator, MappingContext context) throws MappingException { + if (value == null || value.isEmpty()) { + return; + } + for (Constraint element : value) { + context.map(element, generator); + } + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationContentMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationContentMapper.java new file mode 100644 index 00000000..2ddbe430 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationContentMapper.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.DataSpecificationContent; + +public class DataSpecificationContentMapper extends DefaultMapper { + + public DataSpecificationContentMapper() { + } + + @Override + public void map(DataSpecificationContent content, AmlGenerator generator, MappingContext context) throws MappingException { + toInternalElement(content, generator, context); + } + + @Override + protected InternalElementType.RoleRequirements getRoleRequirementClass(DataSpecificationContent value, AmlGenerator generator, MappingContext context) { + return generator.roleRequirement(DataSpecificationContent.class.getSimpleName()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationIEC61360Mapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationIEC61360Mapper.java new file mode 100644 index 00000000..acacdbcc --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationIEC61360Mapper.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.DataSpecificationContent; +import io.adminshell.aas.v3.model.DataSpecificationIEC61360; +import java.beans.PropertyDescriptor; + +public class DataSpecificationIEC61360Mapper extends DefaultMapper { + + @Override + public void map(DataSpecificationIEC61360 content, AmlGenerator generator, MappingContext context) throws MappingException { + asInternalElement(content, generator, context); + } + +// @Override +// protected String getId(DataSpecificationIEC61360 value, AmlGenerator generator, Aas2AmlMappingContext context) { +// return context.generateId(); +// } + @Override + protected InternalElementType.RoleRequirements getRoleRequirementClass(DataSpecificationIEC61360 value, AmlGenerator generator, MappingContext context) { + return generator.roleRequirement(DataSpecificationContent.class.getSimpleName()); + } + + @Override + protected boolean skipProperty(PropertyDescriptor property) { + return property.getName().equals("levelTypes") || property.getName().equals("valueList"); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationMapper.java new file mode 100644 index 00000000..60a04f58 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/DataSpecificationMapper.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.DataSpecificationContent; +import io.adminshell.aas.v3.model.EmbeddedDataSpecification; + +public class DataSpecificationMapper extends DefaultMapper { + + public DataSpecificationMapper() { + } + + @Override + public void map(EmbeddedDataSpecification value, AmlGenerator generator, MappingContext context) throws MappingException { + if (value.getDataSpecificationContent() != null) { + //embedded + DataSpecificationContent content = value.getDataSpecificationContent(); + String refSystemUnitPath = generator.getDocumentInfo().getDataSpecificationTemplatesSystemUnitClassLib() + + "/" + content.getClass().getSimpleName() + "Template/" + + content.getClass().getSimpleName(); + InternalElementType.Builder builder = InternalElementType.builder() + .withRefBaseSystemUnitPath(refSystemUnitPath) + .withName("EmbeddedDataSpecification"); + // serialize properties, but with different attribute path ("IEC:DataSpecificationIEC63360/[propertyName]) + } else { + // linked + // should this even be serialized for AML? + } + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/EmbeddedDataSpecificationCollectionMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/EmbeddedDataSpecificationCollectionMapper.java new file mode 100644 index 00000000..30bd860e --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/EmbeddedDataSpecificationCollectionMapper.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.core.DataSpecificationInfo; +import io.adminshell.aas.v3.dataformat.core.DataSpecificationManager; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.ConceptDescription; +import io.adminshell.aas.v3.model.DataSpecificationContent; +import io.adminshell.aas.v3.model.EmbeddedDataSpecification; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class EmbeddedDataSpecificationCollectionMapper extends DefaultMapper> { + + @Override + public void map(Collection value, AmlGenerator generator, MappingContext context) throws MappingException { + if (value == null || context == null || value.isEmpty()) { + return; + } + long countAttributes = value.stream().filter(x -> x.getDataSpecificationContent() == null).count(); + long countInternalElement = value.size() - countAttributes; + List attributes = new ArrayList<>(); + List internalElements = new ArrayList<>(); + for (EmbeddedDataSpecification element : value) { + if (element.getDataSpecificationContent() == null) { + AttributeType.Builder builder = AttributeType.builder() + .withName("hasDataSpecification" + (countAttributes > 1 ? "_" + (attributes.size() + 1) : "")) + .withValue(AasUtils.asString(element.getDataSpecification())) + .withRefSemantic(generator.refSemantic(ConceptDescription.class, "dataSpecification")); + attributes.add(builder.build()); + } else { + DataSpecificationInfo dataSpecification = DataSpecificationManager.getDataSpecification(element.getDataSpecificationContent().getClass()); + if (dataSpecification == null) { + throw new MappingException("unkown data specification " + element.getDataSpecificationContent().getClass()); + } + InternalElementType.Builder temp = InternalElementType.builder(); + AmlGenerator subGenerator = generator.with(temp).withRefSemanticPrefix(dataSpecification.getPrefix()); + context.map(element.getDataSpecificationContent(), subGenerator); + InternalElementType.Builder builder = InternalElementType.copyOf(temp.build().getInternalElement().get(0)) + .withName("EmbeddedDataSpecification" + (countInternalElement > 1 ? "_" + (internalElements.size() + 1) : "")) + .withID(generator.getId(value)) + .withRefBaseSystemUnitPath(generator.getDocumentInfo().getDataSpecificationTemplatesSystemUnitClassLib() + + "/" + getDataSpecificationContentType(element.getDataSpecificationContent().getClass()) + "Template/" + + getDataSpecificationContentType(element.getDataSpecificationContent().getClass())); + internalElements.add(builder.build()); + } + } + attributes.forEach(x -> generator.addAttribute(x)); + if (internalElements.size() > 1) { + InternalElementType wrapper = InternalElementType.builder() + .withName("EmbeddedDataSpecifications") + .addInternalElement(internalElements) + .build(); + generator.addInternalElement(wrapper); + } else { + internalElements.forEach(x -> generator.addInternalElement(x)); + } + } + + private String getDataSpecificationContentType(Class type) { + // TODO should be resolved using DataSpecificationManager but this requires fundamental changes to + // DataSpecificationManager as it currently is based on Reference instead of name + // workaround: go up superclasses/interfaces and find most-specific interface that extends DataSpecificationContent + if (type == null) { + return null; + } + Class[] interfaces = type.getInterfaces(); + for (Class temp : interfaces) { + if (DataSpecificationContent.class.isAssignableFrom(temp)) { + return temp.getSimpleName(); + } + } + return getDataSpecificationContentType(type.getSuperclass()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/FileMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/FileMapper.java new file mode 100644 index 00000000..afa6bded --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/FileMapper.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.aml.model.caex.RoleClassType; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.File; + +public class FileMapper extends DefaultMapper { + + private static final String FILE_INTERFACE_NAME = "FileDataReference"; + private static final String ATTRIBUTE_MIMETYPE_NAME = "MIMEType"; + private static final String ATTRIBUTE_MIMETYPE_DATATYPE = "xs:string"; + private static final String ATTRIBUTE_REFURI_NAME = "refURI"; + private static final String ATTRIBUTE_REFURI_DATATYPE = "xs:anyURI"; + + public FileMapper() { + } + + @Override + protected InternalElementType.Builder toInternalElement(File value, AmlGenerator generator, MappingContext context) throws MappingException { + InternalElementType.Builder builder = super.toInternalElement(value, generator, context); + if (builder != null) { + builder.withExternalInterface(RoleClassType.ExternalInterface.builder() + .withID(generator.newId()) + .withName(FILE_INTERFACE_NAME) + .withRefBaseClassPath(generator.getDocumentInfo().getAssetAdministrationShellInterfaceClassLib() + "/" + FILE_INTERFACE_NAME) + .addAttribute(AttributeType.builder() + .withName(ATTRIBUTE_MIMETYPE_NAME) + .withAttributeDataType(ATTRIBUTE_MIMETYPE_DATATYPE) + .withValue(value.getMimeType()) + .build()) + .addAttribute(AttributeType.builder() + .withName(ATTRIBUTE_REFURI_NAME) + .withValue(value.getValue()) + .withAttributeDataType(ATTRIBUTE_REFURI_DATATYPE) + .build()) + .build()); + } + return builder; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/LangStringCollectionMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/LangStringCollectionMapper.java new file mode 100644 index 00000000..58fbbf30 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/LangStringCollectionMapper.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultCollectionMapper; +import io.adminshell.aas.v3.model.LangString; +import java.lang.reflect.ParameterizedType; +import java.util.Collection; +import java.util.stream.Collectors; + +public class LangStringCollectionMapper extends DefaultCollectionMapper { + + private static final String NAME_PREFIX = "aml-lang="; + + @Override + public void map(Collection value, AmlGenerator generator, MappingContext context) { + if (context == null || context.getProperty() == null) { + throw new IllegalArgumentException("context.property must be non-null"); + } + if (value == null || value.isEmpty()) { + return; + } + Object t = (Class) ((ParameterizedType) context.getProperty().getReadMethod().getGenericReturnType()).getActualTypeArguments()[0]; + + generator.addAttribute(AttributeType.builder() + .withName(context.getAttributeNamingStrategy().getName( + context.getProperty().getReadMethod().getDeclaringClass(), + value, + context.getProperty().getName())) + .withRefSemantic(generator.refSemantic( + context.getProperty(), + context.getAttributeNamingStrategy().getNameForRefSemantic( + context.getProperty().getReadMethod().getDeclaringClass(), + value, + context.getProperty().getName()))) + .addAttribute(value.stream() + .map(x -> AttributeType.builder() + .withName(NAME_PREFIX + x.getLanguage()) + .withValue(x.getValue()) + .build()) + .collect(Collectors.toList())) + .build()); + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/OperationVariableCollectionMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/OperationVariableCollectionMapper.java new file mode 100644 index 00000000..2954cce1 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/OperationVariableCollectionMapper.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultCollectionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.OperationVariable; +import java.util.Collection; + +public class OperationVariableCollectionMapper extends DefaultCollectionMapper { + + @Override + public void map(Collection value, AmlGenerator generator, MappingContext context) throws MappingException { + if (value == null || value.isEmpty()) { + return; + } + String name = context.getAttributeNamingStrategy().getName( + value.getClass(), + value, + context.getProperty().getName()); + name = name.substring(0, 1).toUpperCase() + name.substring(1); + InternalElementType.Builder builder = InternalElementType.builder() + .withName(name) + .withID(generator.getId(value)) + .withRoleRequirements(generator.roleRequirement("Operation" + name)); + for (OperationVariable element : value) { + context.withoutProperty() + .map(element, generator.with(builder)); + } + generator.addInternalElement(builder.build()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/OperationVariableMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/OperationVariableMapper.java new file mode 100644 index 00000000..50522e2a --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/OperationVariableMapper.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.OperationVariable; + +public class OperationVariableMapper extends DefaultMapper { + + public OperationVariableMapper() { + } + + @Override + public void map(OperationVariable operationVariable, AmlGenerator generator, MappingContext context) throws MappingException { + if (operationVariable != null && operationVariable.getValue() != null) { + context.withoutProperty().map(operationVariable.getValue(), generator); + } + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/PropertyMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/PropertyMapper.java new file mode 100644 index 00000000..fd369150 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/PropertyMapper.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.model.Property; + +public class PropertyMapper extends AbstractElementMapperWithValueType { + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/QualifierMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/QualifierMapper.java new file mode 100644 index 00000000..3495405f --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/QualifierMapper.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Qualifier; + +public class QualifierMapper extends AbstractElementMapperWithValueType { + + @Override + public void map(Qualifier value, AmlGenerator generator, MappingContext context) throws MappingException { + asAttribute(value, generator, context); + } + + @Override + protected String getAttributeName(Qualifier value, MappingContext context) { + return context.getAttributeNamingStrategy().getName( + Qualifier.class, + value, + context.getProperty().getName()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/RangeMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/RangeMapper.java new file mode 100644 index 00000000..8aea3809 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/RangeMapper.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.model.Range; + +public class RangeMapper extends AbstractElementMapperWithValueType { + + protected static final String PROPERTY_MIN_NAME = "min"; + protected static final String PROPERTY_MAX_NAME = "max"; + + public RangeMapper() { + super(PROPERTY_MIN_NAME, PROPERTY_MAX_NAME); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceCollectionMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceCollectionMapper.java new file mode 100644 index 00000000..84d7f376 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceCollectionMapper.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultCollectionMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Reference; +import java.util.Collection; + +public class ReferenceCollectionMapper extends DefaultCollectionMapper { + + @Override + public void map(Collection value, AmlGenerator generator, MappingContext context) throws MappingException { + if (value == null || value.isEmpty()) { + return; + } + for (Reference element : value) { + context.map(element, generator); + } + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceElementMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceElementMapper.java new file mode 100644 index 00000000..c9db554e --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceElementMapper.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.ReferenceElement; + +public class ReferenceElementMapper extends DefaultMapper { + + private static final String PROPERTY_VALUE_NAME = "value"; + private static final String PROPERTY_VALUE_TYPE = "xs:string"; + + public ReferenceElementMapper() { + super(PROPERTY_VALUE_NAME); + } + + @Override + public void map(ReferenceElement element, AmlGenerator generator, MappingContext context) throws MappingException { + if (element == null) { + return; + } + InternalElementType.Builder builder = InternalElementType.builder() + .withName(context.getInternalElementNamingStrategy().getName( + element.getClass(), + element, + null)) + .withRoleRequirements(generator.roleRequirement(ReflectionHelper.getModelType(element.getClass()))); + AmlGenerator subGenerator = generator.with(builder); + mapProperties(element, subGenerator, context); + Referable resolvedReference = AasUtils.resolve(element.getValue(), context.getEnvironment()); + if (resolvedReference != null) { + subGenerator.addExternalInterfaceForReference(); + subGenerator.addInternalLink(PROPERTY_VALUE_NAME, element, element.getValue()); + } else { + if (element.getValue() != null) { + subGenerator.addExternalInterfaceForUnresolvableReference(PROPERTY_VALUE_NAME, element.getValue()); + } + } + subGenerator.appendReferenceTargetInterfaceIfRequired(element, context); + generator.addInternalElement(builder.build(), element); + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceMapper.java new file mode 100644 index 00000000..4b00027e --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ReferenceMapper.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.model.caex.AttributeType; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Qualifier; +import io.adminshell.aas.v3.model.Reference; + +public class ReferenceMapper extends DefaultMapper { + + @Override + protected AttributeType.Builder toAttribute(Reference value, AmlGenerator generator, MappingContext context) throws MappingException { + AttributeType.Builder builder = AttributeType.builder() + .withValue(AasUtils.asString(value)); + if (context.getProperty() != null) { + builder = builder + .withName(getAttributeName(value, context)) + .withRefSemantic(getRefSemantic(value, generator, context)); + } + return builder; + } + + @Override + protected String getAttributeName(Reference value, MappingContext context) { + return context.getAttributeNamingStrategy().getName( + Reference.class, + value, + context.getProperty().getName()); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/RelationshipElementMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/RelationshipElementMapper.java new file mode 100644 index 00000000..ded6b30b --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/RelationshipElementMapper.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.RelationshipElement; + +public class RelationshipElementMapper extends DefaultMapper { + + private static final String PROPERTY_FIRST_NAME = "first"; + private static final String PROPERTY_SECOND_NAME = "second"; + + public RelationshipElementMapper() { + super(PROPERTY_FIRST_NAME, PROPERTY_SECOND_NAME); + } + + @Override + public void map(RelationshipElement element, AmlGenerator generator, MappingContext context) throws MappingException { + if (element == null) { + return; + } + InternalElementType.Builder builder = InternalElementType.builder() + .withName(context.getInternalElementNamingStrategy().getName( + element.getClass(), + element, + null)) + .withRoleRequirements(generator.roleRequirement(ReflectionHelper.getModelType(element.getClass()))); + AmlGenerator subGenerator = generator.with(builder); + mapProperties(element, subGenerator, context); + mapProperty(element, element.getFirst(), PROPERTY_FIRST_NAME, subGenerator, context); + mapProperty(element, element.getSecond(), PROPERTY_SECOND_NAME, subGenerator, context); + generator.with(builder).appendReferenceTargetInterfaceIfRequired(element, context); + generator.addInternalElement(builder.build(), element); + } + + private void mapProperty(RelationshipElement element, Reference reference, String name, AmlGenerator generator, MappingContext context) { + Referable resolvedReference = AasUtils.resolve(reference, context.getEnvironment()); + if (resolvedReference != null) { + generator.addExternalInterfaceForReference(); + generator.addInternalLink(name, element, reference); + } else { + generator.addExternalInterfaceForUnresolvableReference(name, reference); + } + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/SubmodelMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/SubmodelMapper.java new file mode 100644 index 00000000..cbd16296 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/SubmodelMapper.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.ModelingKind; +import io.adminshell.aas.v3.model.Submodel; + +public class SubmodelMapper extends DefaultMapper { + + public SubmodelMapper() { + } + + @Override + protected InternalElementType.Builder toInternalElement(Submodel value, AmlGenerator generator, MappingContext context) throws MappingException { + InternalElementType.Builder builder = super.toInternalElement(value, generator, context); + if (value.getKind() == ModelingKind.TEMPLATE) { + builder = builder.withRefBaseSystemUnitPath(generator.getDocumentInfo().getAssetAdministrationShellSystemUnitClassLib() + + "/" + context.getInternalElementNamingStrategy().getName(value.getClass(), value, null)); + } + return builder; + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ViewMapper.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ViewMapper.java new file mode 100644 index 00000000..87e474d9 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/mappers/ViewMapper.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.mappers; + +import io.adminshell.aas.v3.dataformat.aml.serialization.DefaultMapper; +import io.adminshell.aas.v3.dataformat.aml.serialization.AmlGenerator; +import io.adminshell.aas.v3.dataformat.aml.serialization.MappingContext; +import io.adminshell.aas.v3.dataformat.aml.model.caex.InternalElementType; +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.mapping.MappingException; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.View; + +public class ViewMapper extends DefaultMapper { + + private static final String PROPERTY_CONTAINED_ELEMENTS_NAME = "containedElements"; + + public ViewMapper() { + super(PROPERTY_CONTAINED_ELEMENTS_NAME); + } + + @Override + public void map(View view, AmlGenerator generator, MappingContext context) throws MappingException { + if (view == null) { + return; + } + InternalElementType.Builder builder = InternalElementType.builder(); + builder = builder.withName(context.getInternalElementNamingStrategy().getName( + view.getClass(), + view, + null)) + .withRoleRequirements(generator.roleRequirement(ReflectionHelper.getModelType(view.getClass()))); + generator.with(builder).appendReferenceTargetInterfaceIfRequired(view, context); + for (Reference reference : view.getContainedElements()) { + Referable referable = AasUtils.resolve(reference, context.getEnvironment()); + builder.addInternalElement(InternalElementType.builder() + .withName(getInternalElementName(referable, context)) + .withID(generator.newId()) + .withRefBaseSystemUnitPath(generator.getId(reference)) + .build()); + + } + generator.addInternalElement(builder.build(), view); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/AbstractClassNamingStrategy.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/AbstractClassNamingStrategy.java new file mode 100644 index 00000000..4fe99457 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/AbstractClassNamingStrategy.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.naming; + +import com.google.common.reflect.TypeToken; +import io.adminshell.aas.v3.dataformat.core.util.MostSpecificTypeTokenComparator; +import io.adminshell.aas.v3.model.Referable; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; + +public abstract class AbstractClassNamingStrategy implements NamingStrategy { + + protected final boolean preferIdShort; + protected Map cache = new HashMap<>(); + protected List customNamings = new ArrayList<>(); + + private class TypeSafeFunction { + + public TypeSafeFunction(Class inputType, BiFunction provider) { + this.inputType = TypeToken.of(inputType); + this.provider = provider; + } + TypeToken inputType; + BiFunction provider; + } + + public void registerCustomNaming(Class type, Function provider) { + customNamings.add(new TypeSafeFunction(type, (x, y) -> provider.apply((T) x))); + } + + public void registerCustomNaming(Class type, BiFunction provider) { + customNamings.add(new TypeSafeFunction(type, provider)); + } + + private Optional getCustomNaming(Type type) { + return customNamings.stream() + .filter(x -> x.inputType.isSupertypeOf(type)) + .sorted((x, y) -> Objects.compare(x.inputType, y.inputType, new MostSpecificTypeTokenComparator())) + .findFirst(); + } + + protected AbstractClassNamingStrategy() { + this(true); + } + + protected AbstractClassNamingStrategy(boolean preferIdShort) { + this.preferIdShort = preferIdShort; + } + + @Override + public String getName(Type type, Object obj, String property) { + if (cache.containsKey(obj)) { + return cache.get(obj); + } + String result = null; + if (preferIdShort && Referable.class.isAssignableFrom(obj.getClass())) { + Referable referable = (Referable) obj; + if (referable.getIdShort() != null && !referable.getIdShort().isEmpty()) { + result = referable.getIdShort(); + } + } + if (result == null) { + Optional customNaming = getCustomNaming(type); + if (customNaming.isPresent()) { + result = customNaming.get().provider.apply(obj, property).toString(); + } + } + if (result == null) { + result = generateName(obj); + } + cache.put(obj, result); + return result; + } + + @Override + public String getNameForRefSemantic(Type type, Object obj, String property) { + return getName(type, obj, property); + } + + protected abstract String generateName(Object obj); +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/IdClassNamingStrategy.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/IdClassNamingStrategy.java new file mode 100644 index 00000000..66a01acc --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/IdClassNamingStrategy.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.naming; + +import java.util.UUID; + +public class IdClassNamingStrategy extends AbstractClassNamingStrategy { + + public IdClassNamingStrategy() { + super(); + } + + public IdClassNamingStrategy(boolean preferIdShort) { + super(preferIdShort); + } + + @Override + protected String generateName(Object obj) { + return UUID.randomUUID().toString(); + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/NamingStrategy.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/NamingStrategy.java new file mode 100644 index 00000000..93dfdecc --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/NamingStrategy.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.naming; + +import java.lang.reflect.Type; + +public interface NamingStrategy { + + public String getName(Type type, Object obj, String property); + + public String getNameForRefSemantic(Type type, Object obj, String property); +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/NumberingClassNamingStrategy.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/NumberingClassNamingStrategy.java new file mode 100644 index 00000000..b7909658 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/NumberingClassNamingStrategy.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.naming; + +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import java.util.HashMap; +import java.util.Map; + +public class NumberingClassNamingStrategy extends AbstractClassNamingStrategy { + + private final Map, Integer> counter = new HashMap<>(); + + public NumberingClassNamingStrategy() { + super(); + } + + public NumberingClassNamingStrategy(boolean preferIdShort) { + super(preferIdShort); + } + + @Override + protected String generateName(Object obj) { + if (obj == null) { + return null; + } + Class type = ReflectionHelper.getAasInterface(obj.getClass()); + if (!counter.containsKey(type)) { + counter.put(type, 0); + } + counter.put(type, counter.get(type) + 1); + return type.getSimpleName() + "_" + counter.get(type); + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/PropertyNamingStrategy.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/PropertyNamingStrategy.java new file mode 100644 index 00000000..48050167 --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/serialization/naming/PropertyNamingStrategy.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialization.naming; + +import com.google.common.reflect.TypeToken; +import io.adminshell.aas.v3.dataformat.core.util.MostSpecificTypeTokenComparator; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class PropertyNamingStrategy implements NamingStrategy { + + protected List customNamings = new ArrayList<>(); + + protected class TypeSafeFunction { + + public TypeSafeFunction(Class inputType, BiFunction provider, boolean applyToRefSemantic) { + this.inputType = TypeToken.of(inputType); + this.provider = provider; + this.applyToRefSemantic = applyToRefSemantic; + } + TypeToken inputType; + BiFunction provider; + boolean applyToRefSemantic; + } + + public void registerCustomNaming(Class type, BiFunction provider, boolean applyToRefSemantic) { + customNamings.add(new TypeSafeFunction(type, provider, applyToRefSemantic)); + } + + public void registerCustomNaming(Class type, String oldName, String newName, boolean applyToRefSemantic) { + customNamings.add(new TypeSafeFunction(type, (obj, property) -> Objects.equals(oldName, property) ? newName : null, applyToRefSemantic)); + } + + public void registerCustomNaming(Class type, Function provider, boolean applyToRefSemantic) { + customNamings.add(new TypeSafeFunction(type, (x, y) -> provider.apply((T) x), applyToRefSemantic)); + } + + private List getCustomNaming(Type type, String property, boolean applyToRefSemantic) { + return customNamings.stream() + .filter(x -> x.inputType.isSupertypeOf(type)) + .filter(x -> !applyToRefSemantic || x.applyToRefSemantic) + .sorted((x, y) -> Objects.compare(x.inputType, y.inputType, new MostSpecificTypeTokenComparator())) + .collect(Collectors.toList()); + } + + @Override + public String getName(Type type, Object obj, String property) { + for (TypeSafeFunction customNaming : getCustomNaming(type, property, false)) { + String result = (String) customNaming.provider.apply(obj, property); + if (result != null) { + return result; + } + } + return property; + } + + @Override + public String getNameForRefSemantic(Type type, Object obj, String property) { + for (TypeSafeFunction customNaming : getCustomNaming(type, property, true)) { + String result = (String) customNaming.provider.apply(obj, property); + if (result != null) { + return result; + } + } + return property; + } + +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/util/ReferencedByViewCollector.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/util/ReferencedByViewCollector.java new file mode 100644 index 00000000..b228fe0b --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/util/ReferencedByViewCollector.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.util; + +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.core.visitor.AssetAdministrationShellElementWalkerVisitor; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.View; +import java.util.HashSet; +import java.util.Set; + +public class ReferencedByViewCollector { + + private AssetAdministrationShellEnvironment env; + + public ReferencedByViewCollector(AssetAdministrationShellEnvironment env) { + this.env = env; + } + + public Set collect() { + Visitor visitor = new Visitor(); + visitor.visit(env); + return visitor.referencedElements; + } + + private class Visitor implements AssetAdministrationShellElementWalkerVisitor { + + Set referencedElements = new HashSet<>(); + + @Override + public void visit(View view) { + view.getContainedElements().forEach(x -> handleReference(x)); + AssetAdministrationShellElementWalkerVisitor.super.visit(view); + } + + private void handleReference(Reference reference) { + Referable target = AasUtils.resolve(reference, env); + if (target != null) { + referencedElements.add(target); + } + } + + } +} diff --git a/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/util/ReferencedReferableCollector.java b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/util/ReferencedReferableCollector.java new file mode 100644 index 00000000..277a3a5c --- /dev/null +++ b/dataformat-aml/src/main/java/io/adminshell/aas/v3/dataformat/aml/util/ReferencedReferableCollector.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.util; + +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; +import io.adminshell.aas.v3.dataformat.core.visitor.AssetAdministrationShellElementWalkerVisitor; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.ReferenceElement; +import io.adminshell.aas.v3.model.RelationshipElement; +import java.util.HashSet; +import java.util.Set; + +public class ReferencedReferableCollector { + + private AssetAdministrationShellEnvironment env; + + public ReferencedReferableCollector(AssetAdministrationShellEnvironment env) { + this.env = env; + } + + public Set collect() { + Visitor visitor = new Visitor(); + visitor.visit(env); + return visitor.referencedElements; + } + + private class Visitor implements AssetAdministrationShellElementWalkerVisitor { + + Set referencedElements = new HashSet<>(); + + @Override + public void visit(ReferenceElement referenceElement) { + handleReference(referenceElement.getValue()); + AssetAdministrationShellElementWalkerVisitor.super.visit(referenceElement); + } + + private void handleReference(Reference reference) { + Referable target = AasUtils.resolve(reference, env); + if (target != null) { + referencedElements.add(reference); + } + } + + @Override + public void visit(RelationshipElement relationshipElement) { + handleReference(relationshipElement.getFirst()); + handleReference(relationshipElement.getSecond()); + AssetAdministrationShellElementWalkerVisitor.super.visit(relationshipElement); + } + } +} diff --git a/dataformat-aml/src/main/resources/AssetAdministrationShellLib.aml b/dataformat-aml/src/main/resources/AssetAdministrationShellLib.aml new file mode 100644 index 00000000..06506457 --- /dev/null +++ b/dataformat-aml/src/main/resources/AssetAdministrationShellLib.aml @@ -0,0 +1,1422 @@ + + + + + + + + + + + + AutomationML Editor + 916578CA-FE0D-474E-A4FC-9E1719892369 + AutomationML e.V. + www.AutomationML.org + 5.2.7.0 + 5.2.7.0 + 2019-11-20T12:12:12.6586496 + Application Recommendation Asset Administration Shell + AR AAS + + + + Interface Class Library according to Details of the Asset Administration Shell V2.0. + 1.0.0 + + A FileDataReference represents the address to a File. FileDataReference is derived from the AutomationML Interface Class ExternalDataReference that is defined in AutomationML BPR_005E_ExternalDataReference_v1.0.0_2:The interface class “ExternalDataReference” shall be used in order to reference external documents out of the scope of AutomationML. + + + Reference to any other referable element of the same of any other AAS or a reference to an external object or entity. For local references inside the same Asset Administration Shell an InternalLink between two objects with this interface "ReferableReference" shall be set. In this case the attribute value has to be empty. For references between different Asset Administration Shells or external objects or entities the attribute value shall be used and no InternalLink shall be set. + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable element of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + + Standard Automation Markup Language Interface Class Library - Part 1 Content extended with Part 3 and Part 4 Content + 2.2.2 + + + + + + + + + + The attribute refURI is an IRI that can represent an absolute or relative path to an L document. An added fragment (with #) references inside the document + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + 1.0.0 + + + Mime type of the content of the File. + + + + + Role Class Library according to Details of the Asset Administration Shell V2.0. + 1.0.0 + + An Asset Administration Shell. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + + The derivedFrom attribute is used to establish a relationship between two Asset Administration Shells that are derived from each other. + + + + + + An Asset describes meta data of an asset that is represented by an AAS. The asset may either represent an asset type or an asset instance. The asset has a globally unique identifier plus – if needed – additional domain specific (proprietary) identifiers. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the asset: either type or instance. + Instance + Instance + + + + Instance + Type + + + + + + A Submodel defines a specific aspect of the asset represented by the AAS. A submodel is used to structure the virtual representation and technical functionality of an Administration Shell into distinguishable parts. Each submodel refers to a well-defined domain or subject matter. Submodels can become standardized and thus become submodels types. Submodels can have different life-cycles. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + A submodel element collection is a set or list of submodel elements. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + If allowDuplicates=true, then it is allowed that the collection contains the same element several times. + false + + + + If ordered=false, then the elements in the property collection are not ordered. If ordered=true then the elements in the collection are ordered. Default = false. Note: An ordered submodel element collection is typically implemented as an indexed array. + false + + + + Submodel element contained in the collection. + + + + + A BLOB is a data element that represents a file that is contained with its source code in the value attribute. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + Mime type of the content of the BLOB. The mime type states which file extension the file has. Valid values are e.g. “application/json”, “application/xls”, ”image/jpg”. The allowed values are defined as in RFC2046. + + + + + The value of the BLOB instance of a blob data element. Note: In contrast to the file property the file content is stored directly as value in the Blob data element. + + + + + + A capability is the implementation-independent description of the potential of an asset to achieve a certain effect in the physical or virtual world. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + A role class for a File that a data element that represents an address to a file. It is derived from the AutomationML role class ExternalData that is an role type for a document type and the base class for all document type roles. It describes different document types. ExternalData is defined in AutomationML BPR_005E_ExternalDataReference_v1.0.0_2. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + The attribute refURI is an IRI that can represent an absolute or relative path to an L document. An added fragment (with #) references inside the document + + + Mime type of the content of the File. + + + + + A property is a data element that has a single value. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + The value of the property instance. + + + + Reference to the global unique id if a coded value. + + + + + A reference element is a data element that defines a logical reference to another element within the same or another AAS or a reference to an external object or entity. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable elment of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + + A relationship element is used to define a relationship between two referable elements. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable elment of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable elment of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + An annotated relationship element is an relationship element that can be annotated with additional data elements. + + Annotations that hold for the relationships between the two elements. + + + + + An operation is a submodel element with input and output variables. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + The list of AAS OperationVariableIn entities. In AML, the corresponding InternalElement with this role is a child of the InternalElement with the Operation role. + + + The list of AAS OperationVariableOut entities. In AML, the corresponding InternalElement with this role is a child of the InternalElement with the Operation role. + + + The list of AAS OperationVariableOut entities. In AML, the corresponding InternalElement with this role is a child of the InternalElement with the Operation role. + + + A view is a collection of referable elements w.r.t. to a specific viewpoint of one or more stakeholders. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + + A dictionary contains elements that can be reused. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + + Explanation: The semantics of a property or other elements that may have a semantic description is defined by a concept description. The description of the concept should follow a standardized schema (realized as data specification template). + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + Global reference to an external definition the concept is compatible to or was derived from. + + + + + + Description Role class of an element that has a data specification template. A template defines the additional attributes an element may or shall have. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + + Content of the data specification template. + + + An entity is a submodel element that is used to model entities. Constraint AASd-056: If the semanticId of a Entity submodel element references a ConceptDescription then the ConceptDescription/category shall be one of following values: ENTITY. The ConceptDescription describes the elements assigned to the entity via Entity/statement. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + Describes statements applicable to the entity by a set of submodel elements, typically with a qualified value. + + + + Describes whether the entity is a co-managed entity or a self-managed entity. + SelfManagedEntity + SelfManagedEntity + + + + CoManagedEntity + SelfManagedEntity + + + + + Reference to an identifier key value pair representing a specific identifier of the asset represented by the asset administration shell. See Constraint AASd-014 + + + + Reference to the asset the entity is representing. Constraint AASd-014: Either the attribute globalAssetId or specificAssetId of an Entity must be set if Entity/entityType is set to "SelfManagedEntity". They are not existing otherwise. + + + + + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + + + + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + Reference to the global unique id if a coded value. + + + + + + + + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + The value of the property instance. + + + + Reference to the global unique id if a coded value. + + + + + + Automation Markup Language Base Role Class Library - Part 1 Content extended with Part 3 and Part 4 Content + 2.2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.0.0 + + + + 0 + + An AAS Data Specification template for IEC61369. A template consists of the DataSpecificationContent containing the additional attributes to be added to the element instance that references the data specification template and meta information about the template itself (this is why DataSpecification inherits from Identifiable). In UML these are two separated classes. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360 + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + IRI + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + + The content of an AAS Data Specification template for IEC61360. + + Identifies the attribute hierarchy for preferredName in above attribute hierachy. Subordinate attributes are designated by the country code information (see aml-lang literal). + + + + Identifies the attribute for shortName in above attribute hierarchy. + + + + Identifies the attribute for unit in above attribute hierarchy. + + + + Identifies the attribute for unitId in above attribute hierarchy in its string serialization. + + + + Identifies the attribute for sourceOfDefinition in above attribute hierachy. Subordinate attributes are designated by the country code information (see aml-lang literal). + + + + Identifies the attribute for symbol in above attribute hierarchy. + + + + Identifies the attribute for dataType in above attribute hierarchy. + + + + Identifies the attribute for definition in above attribute hierachy. Subordinate attributes are designated by the country code information (see aml-lang literal). + + + + Identifies the attribute for valueFormat in above attribute hierarchy. + + + + Identifies the attribute for valueList in above attribute hierarchy. + + + + The attribute value. + + + + The id for the value. + + + + + + + diff --git a/dataformat-aml/src/main/resources/CAEX_ClassModel_V2.15.xsd b/dataformat-aml/src/main/resources/CAEX_ClassModel_V2.15.xsd new file mode 100644 index 00000000..31acecb4 --- /dev/null +++ b/dataformat-aml/src/main/resources/CAEX_ClassModel_V2.15.xsd @@ -0,0 +1,592 @@ + + + + + + + Optionally describes the change state of a CAEX object. If used, the ChangeMode shall have the following value range: state, create, delete and change. This information should be used for further change management applications. + + + + + + + + + + + Defines a group of organizational information, like description, version, revision, copyright, etc. + + + + + Textual description for CAEX objects. + + + + + + + + + + + + Organizational information about the state of the version. + + + + + + + + + + + + Organizational information about the state of the revision. + + + + + + + + + + + + + + + + + + Organizational information about copyright. + + + + + + + + + + + + Optional auxiliary field that may contain any additional information about a CAEX object. + + + + + + + CAEX basis object that comprises a basic set of attributes and header information which exist for all CAEX elements. + + + + + Optionally describes the change state of a CAEX object. If used, the ChangeMode shall have the following value range: state, create, delete and change. This information should be used for further change management applications. + + + + + + + CAEX basis object derived from CAEXBasicObject, augmented by + Name (required) and ID (optional). + + + + + + + Optional attribute that describes a unique identifier of the CAEX object. + + + + + Describes the name of the CAEX object. + + + + + + + + Shall be used for InterfaceClass definition, provides base structures for an interface class definition. + + + + + + + Characterizes properties of the InterfaceClass. + + + + + + Stores the reference of a class to its base class. References contain the full path to the referred class object. + + + + + + + + Defines base structures for a hierarchical InterfaceClass tree. The hierarchical structure of an interface library has organizational character only. + + + + + + + Element that allows definition of child InterfaceClasses within the class hierarchy. The parent child relation between two InterfaceClasses has no semantic. + + + + + + + + + Shall be used for RoleClass definition, provides base structures for a role class definition. + + + + + + + Characterizes properties of the RoleClass. + + + + + Description of an external interface. + + + + + + + + + + + Stores the reference of a class to its base class. References contain the full path to the referred class object. + + + + + + + + Defines base structures for a hierarchical RoleClass tree. The hierarchical structure of a role library has organizational character only. + + + + + + + Element that allows definition of child RoleClasses within the class hierarchy. The parent child relation between two RoleClasses has no semantic. + + + + + + + + + Defines base structures for a SystemUnit class definition. + + + + + + + Characterizes properties of the SystemUnitClass. + + + + + Description of an external interface. + + + + + Shall be used in order to define nested objects inside of a SystemUnitClass or another InternalElement. Allows description of the internal structure of a CAEX object. + + + + + Allows the association to a RoleClass which this SystemUnitClass can play. A SystemUnitClass may reference multiple roles. + + + + + + + + + + + + + + + Shall be used in order to define the relationships between internal interfaces of InternalElements. + + + + + + + + + + + + + + + + + Defines base structures for a hierarchical SystemUnitClass tree. The hierarchical structure of a SystemUnit library has organizational character only. + + + + + + + Element that allows definition of child SystemUnitClasses within the class hierarchy. The parent child relation between two SystemUnitClasses has no semantic. + + + + + + Stores the reference of a class to its base class. References contain the full path to the referred class object. + + + + + + + + Type for definition of nested objects inside of a SystemUnitClass. + + + + + + + Describes role requirements of an InternalElement. It allows the definition of a reference to a RoleClass and the specification of role requirements like required attributes and required interfaces. + + + + + + + + Characterizes properties of the RoleRequirements. + + + + + + + + + + + + Host element for AttributeNameMapping and InterfaceNameMapping. + + + + + + Stores the reference of an InternalElement to a class or instance definition. References contain the full path information. + + + + + + + + Defines base structures for attribute definitions. + + + + + + + A predefined default value for an attribute. + + + + + Element describing the value of an attribute. + + + + + A reference to a definition of a defined attribute, e. g. to an attribute in a standardized library, this allows the semantic definition of the attribute. + + + + + + + + + + + + Element to restrict the range of validity of a defined attribute. + + + + + Element that allows the description of nested attributes. + + + + + + Describes the unit of the attribute. + + + + + Describes the data type of the attribute using XML notation. + + + + + + + + + + + Defines base structures for definition of value requirements of an attribute. + + + + + + + Element of to define constraints of ordinal scaled attribute values. + + + + + + Element to define a maximum value of an attribute. + + + + + Element to define a required value of an attribute. + + + + + Element to define a minimum value of an attribute. + + + + + + + + Element of to define constraints of nominal scaled attribute values. + + + + + + Element to define a required value of an attribute. It may be defined multiple times in order to define a discrete value range of the attribute. + + + + + + + + Element to define constraints for attribute values of an unknown scale type. + + + + + + Defines informative requirements as a constraint for an attribute value. + + + + + + + + + Describes the name of the constraint. + + + + + + + + Base element for AttributeNameMapping and InterfaceNameMapping. + + + + + + + Allows the definition of the mapping between attribute names of corresponding RoleClasses and SystemUnitClasses. + + + + + + + + + + + + + Mapping of interface names of corresponding RoleClasses and SystemUnitClasses. + + + + + + + + + + + + + + + + + Root-element of the CAEX schema. + + + + + + + + Container element for the alias definition of external CAEX files. + + + + + + + Describes the path of the external CAEX file. Absolute and relative paths are allowed. + + + + + Describes the alias name of an external CAEX file to enable referencing elements of the external CAEX file. + + + + + + + + + Root element for a system hierarchy of object instances. + + + + + + + + Shall be used in order to define nested objects inside of a SystemUnitClass or another InternalElement. Allows description of the internal structure of a CAEX object. + + + + + + + + + + Container element for a hierarchy of InterfaceClass definitions. It shall contain any interface class definitions. CAEX supports multiple interface libraries.. + + + + + + + + Class definition for interfaces. + + + + + + + + + + Container element for a hierarchy of RoleClass definitions. It shall contain any RoleClass definitions. CAEX supports multiple role libraries. + + + + + + + + Definition of a class of a role type. + + + + + + + + + + Container element for a hierarchy of SystemUnitClass definitions. It shall contain any SystemunitClass definitions. CAEX supports multiple SystemUnitClass libraries. + + + + + + + + Shall be used for SystemUnitClass definition, provides definition of a class of a SystemUnitClass type. + + + + + + + + + + + Describes the name of the CAEX file. + + + + + Describes the version of the schema. Each CAEX document must specify which CAEX version it requires. The version number of a CAEX document must fit to the version number specified in the CAEX schema file. + + + + + + + \ No newline at end of file diff --git a/dataformat-aml/src/main/resources/application.properties b/dataformat-aml/src/main/resources/application.properties new file mode 100644 index 00000000..91a2f342 --- /dev/null +++ b/dataformat-aml/src/main/resources/application.properties @@ -0,0 +1 @@ +logging.level.serialize=DEBUG diff --git a/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/deserialize/AmlDeserializerTest.java b/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/deserialize/AmlDeserializerTest.java new file mode 100644 index 00000000..f0a4cb64 --- /dev/null +++ b/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/deserialize/AmlDeserializerTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.deserialize; + +import io.adminshell.aas.v3.dataformat.DeserializationException; +import io.adminshell.aas.v3.dataformat.aml.AmlDeserializer; +import io.adminshell.aas.v3.dataformat.aml.fixtures.FullExample; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import java.io.FileNotFoundException; +import static org.junit.Assert.assertEquals; + +import org.junit.Ignore; +import org.junit.Test; + +public class AmlDeserializerTest { + + private final AmlDeserializer deserializer = new AmlDeserializer(); + + @Test + @Ignore + public void testSAPFullExample() throws DeserializationException, FileNotFoundException { + AssetAdministrationShellEnvironment actual = deserializer.read(FullExample.FILE); + assertEquals(FullExample.ENVIRONMENT, actual); + } +} diff --git a/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/fixtures/FullExample.java b/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/fixtures/FullExample.java new file mode 100644 index 00000000..b36b551e --- /dev/null +++ b/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/fixtures/FullExample.java @@ -0,0 +1,1767 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.fixtures; + +import io.adminshell.aas.v3.model.*; +import io.adminshell.aas.v3.model.impl.*; + +import java.util.Arrays; +import java.util.Base64; + +public class FullExample { + + public static final java.io.File FILE = new java.io.File("src/test/resources/test_demo_full_example.aml"); + + public static final AssetAdministrationShell AAS_1 = new DefaultAssetAdministrationShell.Builder() + .idShort("TestAssetAdministrationShell") + .description(new LangString("An Example Asset Administration Shell for the test application", "en-us")) + .description(new LangString("Ein Beispiel-Verwaltungsschale für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_AssetAdministrationShell") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .derivedFrom(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.ASSET_ADMINISTRATION_SHELL) + .idType(KeyType.IRI) + .value("https://acplt.org/TestAssetAdministrationShell2") + .build()) + .build()) + .assetInformation(new DefaultAssetInformation.Builder() + .assetKind(AssetKind.INSTANCE) + .globalAssetId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.ASSET) + .idType(KeyType.IRI) + .value("https://acplt.org/Test_Asset") + .build()) + .build()) + .billOfMaterial((new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .idType(KeyType.IRI) + .value("http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial") + .build())) + .build()) + .build()) + .submodel(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel") + .idType(KeyType.IRI) + .build()) + .build()) + .submodel(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial") + .idType(KeyType.IRI) + .build()) + .build()) + .submodel(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("http://acplt.org/Submodels/Assets/TestAsset/Identification") + .idType(KeyType.IRI) + .build()) + .build()) + .build(); + + public static final AssetAdministrationShell AAS_2 = new DefaultAssetAdministrationShell.Builder() + .idShort("") + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_AssetAdministrationShell_Mandatory") + .build()) + .assetInformation(new DefaultAssetInformation.Builder() + .assetKind(AssetKind.INSTANCE) + .globalAssetId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.ASSET) + .idType(KeyType.IRI) + .value("https://acplt.org/Test_Asset_Mandatory") + .build()) + .build()) + .build()) + .submodel(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Mandatory") + .idType(KeyType.IRI) + .build()) + .build()) + .submodel(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel2_Mandatory") + .idType(KeyType.IRI) + .build()) + .build()) + .build(); + + public static final AssetAdministrationShell AAS_3 = new DefaultAssetAdministrationShell.Builder() + .idShort("") + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_AssetAdministrationShell2_Mandatory") + .build()) + .assetInformation(new DefaultAssetInformation.Builder() + .assetKind(AssetKind.INSTANCE) + .globalAssetId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.ASSET) + .idType(KeyType.IRI) + .value("https://acplt.org/Test_Asset_Mandatory") + .build()) + .build()) + .build()) + .build(); + + public static final AssetAdministrationShell AAS_4 = new DefaultAssetAdministrationShell.Builder() + .idShort("TestAssetAdministrationShell") + .description(new LangString("An Example Asset Administration Shell for the test application", "en-us")) + .description(new LangString("Ein Beispiel-Verwaltungsschale für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_AssetAdministrationShell_Missing") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .assetInformation(new DefaultAssetInformation.Builder() + .assetKind(AssetKind.INSTANCE) + .globalAssetId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.ASSET) + .idType(KeyType.IRI) + .value("https://acplt.org/Test_Asset_Missing") + .build()) + .build()) + .build()) + .submodel(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build()) + .build()) + .view(new DefaultView.Builder() + .idShort("ExampleView") + .containedElement((new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build())) + .build()) + .build()) + .view(new DefaultView.Builder() + .idShort("ExampleView2") + .build()) + .build(); + + public static final Submodel SUBMODEL_1 = new DefaultSubmodel.Builder() + .idShort("Identification") + .description(new LangString("An example asset identification submodel for the test application", "en-us")) + .description(new LangString("Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("http://acplt.org/Submodels/Assets/TestAsset/Identification") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .kind(ModelingKind.INSTANCE) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .idType(KeyType.IRI) + .value("http://acplt.org/SubmodelTemplates/AssetIdentification") + .build()) + .build()) + .submodelElement(new DefaultProperty.Builder() + .idShort("ManufacturerName") + .description(new LangString("Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation.", "en-us")) + .description(new LangString("Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("0173-1#02-AAO677#002") + .idType(KeyType.IRI) + .build()) + .build()) + .qualifier(new DefaultQualifier.Builder() + .value("100") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("int") + .type("http://acplt.org/Qualifier/ExampleQualifier") + .build()) + .qualifier(new DefaultQualifier.Builder() + .value("50") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("int") + .type("http://acplt.org/Qualifier/ExampleQualifier2") + .build()) + .value("ACPLT") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .submodelElement(new DefaultProperty.Builder() + .idShort("InstanceId") + .description(new LangString("Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation.", "en-us")) + .description(new LangString("Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber") + .idType(KeyType.IRI) + .build()) + .build()) + .value("978-8234-234-342") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .build(); + + public static final Submodel SUBMODEL_2 = new DefaultSubmodel.Builder() + .idShort("BillOfMaterial") + .description(new LangString("An example bill of material submodel for the test application", "en-us")) + .description(new LangString("Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .build()) + .kind(ModelingKind.INSTANCE) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .idType(KeyType.IRI) + .value("http://acplt.org/SubmodelTemplates/BillOfMaterial") + .build()) + .build()) + .submodelElement(new DefaultEntity.Builder() + .idShort("ExampleEntity") + .description(new LangString("Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation.", "en-us")) + .description(new LangString("Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber") + .idType(KeyType.IRI) + .build()) + .build()) + .statement(new DefaultProperty.Builder() + .idShort("ExampleProperty2") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value("exampleValue2") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .statement(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value("exampleValue") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .entityType(EntityType.CO_MANAGED_ENTITY) + .build()) + .submodelElement(new DefaultEntity.Builder() + .idShort("ExampleEntity2") + .description(new LangString("Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation.", "en-us")) + .description(new LangString("Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber") + .idType(KeyType.IRI) + .build()) + .build()) + .entityType(EntityType.SELF_MANAGED_ENTITY) + .globalAssetId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.ASSET) + .idType(KeyType.IRI) + .value("https://acplt.org/Test_Asset2") + .build()) + .build()) + .build()) + .build(); + + public static final Submodel SUBMODEL_3 = new DefaultSubmodel.Builder() + .idShort("TestSubmodel") + .description(new LangString("An example submodel for the test application", "en-us")) + .description(new LangString("Ein Beispiel-Teilmodell für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_Submodel") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .kind(ModelingKind.INSTANCE) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/SubmodelTemplates/ExampleSubmodel") + .build()) + .build()) + .submodelElement(new DefaultRelationshipElement.Builder() + .idShort("ExampleRelationshipElement") + .category("Parameter") + .description(new LangString("Example RelationshipElement object", "en-us")) + .description(new LangString("Beispiel RelationshipElement Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/RelationshipElements/ExampleRelationshipElement") + .idType(KeyType.IRI) + .build()) + .build()) + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.ENTITY) + .value("ExampleEntity") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty2") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .build()) + .submodelElement(new DefaultAnnotatedRelationshipElement.Builder() + .idShort("ExampleAnnotatedRelationshipElement") + .category("Parameter") + .description(new LangString("Example AnnotatedRelationshipElement object", "en-us")) + .description(new LangString("Beispiel AnnotatedRelationshipElement Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement") + .idType(KeyType.IRI) + .build()) + .build()) + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.ENTITY) + .value("ExampleEntity") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty2") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .annotation(new DefaultProperty.Builder() + .kind(ModelingKind.INSTANCE) + .idShort("ExampleProperty3") + .category("Parameter") + .value("some example annotation") + .valueType("string") + .build()) + .build()) + .submodelElement(new DefaultOperation.Builder() + .idShort("ExampleOperation") + .category("Parameter") + .description(new LangString("Example Operation object", "en-us")) + .description(new LangString("Beispiel Operation Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Operations/ExampleOperation") + .idType(KeyType.IRI) + .build()) + .build()) + .inputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty1") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value("exampleValue") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .build()) + .outputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty2") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value("exampleValue") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .build()) + .inoutputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty3") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value("exampleValue") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .build()) + .build()) + .submodelElement(new DefaultCapability.Builder() + .idShort("ExampleCapability") + .category("Parameter") + .description(new LangString("Example Capability object", "en-us")) + .description(new LangString("Beispiel Capability Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Capabilities/ExampleCapability") + .idType(KeyType.IRI) + .build()) + .build()) + .build()) + .submodelElement(new DefaultBasicEvent.Builder() + .idShort("ExampleBasicEvent") + .category("Parameter") + .description(new LangString("Example BasicEvent object", "en-us")) + .description(new LangString("Beispiel BasicEvent Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Events/ExampleBasicEvent") + .idType(KeyType.IRI) + .build()) + .build()) + .observed(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .idType(KeyType.ID_SHORT) + .value("ExampleProperty") + .build()) + .build()) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionOrdered") + .category("Parameter") + .description(new LangString("Example SubmodelElementCollectionOrdered object", "en-us")) + .description(new LangString("Beispiel SubmodelElementCollectionOrdered Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value("exampleValue") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + .valueType("string") + .build()) + .value(new DefaultMultiLanguageProperty.Builder() + .idShort("ExampleMultiLanguageProperty") + .category("Constant") + .description(new LangString("Example MultiLanguageProperty object", "en-us")) + .description(new LangString("Beispiel MulitLanguageProperty Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new LangString("Example value of a MultiLanguageProperty element", "en-us")) + .value(new LangString("Beispielswert für ein MulitLanguageProperty-Element", "de")) + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleMultiLanguageValueId") + .build()) + .build()) + .build()) + .value(new DefaultRange.Builder() + .idShort("ExampleRange") + .category("Parameter") + .description(new LangString("Example Range object", "en-us")) + .description(new LangString("Beispiel Range Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Ranges/ExampleRange") + .idType(KeyType.IRI) + .build()) + .build()) + .valueType("int") + .min("0") + .max("100") + .build()) + .ordered(true) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionUnordered") + .category("Parameter") + .description(new LangString("Example SubmodelElementCollectionUnordered object", "en-us")) + .description(new LangString("Beispiel SubmodelElementCollectionUnordered Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new DefaultBlob.Builder() + .idShort("ExampleBlob") + .category("Parameter") + .description(new LangString("Example Blob object", "en-us")) + .description(new LangString("Beispiel Blob Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder().type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Blobs/ExampleBlob") + .idType(KeyType.IRI) + .build()) + .build()) + .mimeType("application/pdf") + .value(Base64.getDecoder().decode("AQIDBAU=")) + .build()) + .value(new DefaultFile.Builder() + .idShort("ExampleFile") + .category("Parameter") + .description(new LangString("Example File object", "en-us")) + .description(new LangString("Beispiel File Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Files/ExampleFile") + .idType(KeyType.IRI) + .build()) + .build()) + .value("/TestFile.pdf") + .mimeType("application/pdf") + .build()) + .value(new DefaultReferenceElement.Builder() + .idShort("ExampleReferenceElement") + .category("Parameter") + .description(new LangString("Example Reference Element object", "en-us")) + .description(new LangString("Beispiel Reference Element Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE).value( + "http://acplt.org/ReferenceElements/ExampleReferenceElement") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .idType(KeyType.ID_SHORT) + .value("ExampleProperty") + .build()) + .build()) + .build()) + .ordered(false) + .build()) + .build(); + + public static final Submodel SUBMODEL_4 = new DefaultSubmodel.Builder() + .idShort("") + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_Submodel_Mandatory") + .build()) + .kind(ModelingKind.TEMPLATE) + .submodelElement(new DefaultRelationshipElement.Builder() + .idShort("ExampleRelationshipElement") + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Mandatory") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Mandatory") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.MULTI_LANGUAGE_PROPERTY) + .value("ExampleMultiLanguageProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .build()) + .submodelElement(new DefaultAnnotatedRelationshipElement.Builder() + .idShort("ExampleAnnotatedRelationshipElement") + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Mandatory") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Mandatory") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.MULTI_LANGUAGE_PROPERTY) + .value("ExampleMultiLanguageProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .build()) + .submodelElement(new DefaultOperation.Builder() + .idShort("ExampleOperation") + .build()) + .submodelElement(new DefaultCapability.Builder() + .idShort("ExampleCapability") + .build()) + .submodelElement(new DefaultBasicEvent.Builder() + .idShort("ExampleBasicEvent") + .observed(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Mandatory") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .idType(KeyType.ID_SHORT) + .value("ExampleProperty") + .build()) + .build()) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionOrdered") + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .value(null) + .valueType("string") + .build()) + .value(new DefaultMultiLanguageProperty.Builder() + .idShort("ExampleMultiLanguageProperty") + .build()) + .value(new DefaultRange.Builder() + .idShort("ExampleRange") + .valueType("int") + .min(null) + .max(null) + .build()) + .ordered(true) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionUnordered") + .value(new DefaultBlob.Builder() + .idShort("ExampleBlob") + .mimeType("application/pdf") + .build()) + .value(new DefaultFile.Builder() + .idShort("ExampleFile") + .value(null) + .mimeType("application/pdf") + .build()) + .value(new DefaultReferenceElement.Builder() + .idShort("ExampleReferenceElement") + .build()) + .ordered(false) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionUnordered2") + .ordered(false) + .build()) + .build(); + + public static final Submodel SUBMODEL_5 = new DefaultSubmodel.Builder() + .idShort("") + .kind(ModelingKind.INSTANCE) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_Submodel2_Mandatory") + .build()) + .build(); + + public static final Submodel SUBMODEL_6 = new DefaultSubmodel.Builder() + .idShort("TestSubmodel") + .description(new LangString("An example submodel for the test application", "en-us")) + .description(new LangString("Ein Beispiel-Teilmodell für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_Submodel_Missing") + .build()) + .kind(ModelingKind.INSTANCE) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0").build()) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/SubmodelTemplates/ExampleSubmodel") + .build()) + .build()) + .submodelElement(new DefaultRelationshipElement.Builder() + .idShort("ExampleRelationshipElement") + .category("Parameter") + .description(new LangString("Example RelationshipElement object", "en-us")) + .description(new LangString("Beispiel RelationshipElement Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/RelationshipElements/ExampleRelationshipElement") + .idType(KeyType.IRI) + .build()) + .build()) + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.MULTI_LANGUAGE_PROPERTY) + .value("ExampleMultiLanguageProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .build()) + .submodelElement(new DefaultAnnotatedRelationshipElement.Builder() + .idShort("ExampleAnnotatedRelationshipElement") + .category("Parameter") + .description(new LangString("Example AnnotatedRelationshipElement object", "en-us")) + .description(new LangString("Beispiel AnnotatedRelationshipElement Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement") + .idType(KeyType.IRI) + .build()) + .build()) + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.MULTI_LANGUAGE_PROPERTY) + .value("ExampleMultiLanguageProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .annotation(new DefaultProperty.Builder() + .kind(ModelingKind.INSTANCE) + .idShort("ExampleProperty") + .category("Parameter") + .value("some example annotation") + .valueType("string") + .build()) + .build()) + .submodelElement(new DefaultOperation.Builder() + .idShort("ExampleOperation") + .category("Parameter") + .description(new LangString("Example Operation object", "en-us")) + .description(new LangString("Beispiel Operation Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Operations/ExampleOperation") + .idType(KeyType.IRI) + .build()) + .build()) + .inputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty1") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .qualifier(new DefaultQualifier.Builder() + .valueType("string") + .type("http://acplt.org/Qualifier/ExampleQualifier") + .build()) + .value("exampleValue") + .valueType("string") + .build()) + .build()) + .outputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty2") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .qualifier(new DefaultQualifier.Builder() + .valueType("string") + .type("http://acplt.org/Qualifier/ExampleQualifier") + .build()) + .value("exampleValue") + .valueType("string") + .build()) + .build()) + .inoutputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty3") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .qualifier(new DefaultQualifier.Builder() + .valueType("string") + .type("http://acplt.org/Qualifier/ExampleQualifier") + .build()) + .value("exampleValue") + .valueType("string") + .build()) + .build()) + .build()) + .submodelElement(new DefaultCapability.Builder() + .idShort("ExampleCapability") + .category("Parameter") + .description(new LangString("Example Capability object", "en-us")) + .description(new LangString("Beispiel Capability Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Capabilities/ExampleCapability") + .idType(KeyType.IRI) + .build()) + .build()) + .build()) + .submodelElement(new DefaultBasicEvent.Builder() + .idShort("ExampleBasicEvent") + .category("Parameter") + .description(new LangString("Example BasicEvent object", "en-us")) + .description(new LangString("Beispiel BasicEvent Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Events/ExampleBasicEvent") + .idType(KeyType.IRI) + .build()) + .build()) + .observed(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .idType(KeyType.ID_SHORT) + .value("ExampleProperty") + .build()) + .build()) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionOrdered") + .category("Parameter") + .description(new LangString("Example SubmodelElementCollectionOrdered object", "en-us")) + .description(new LangString("Beispiel SubmodelElementCollectionOrdered Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .qualifier(new DefaultQualifier.Builder() + .valueType("string") + .type("http://acplt.org/Qualifier/ExampleQualifier") + .build()) + .value("exampleValue") + .valueType("string") + .build()) + .value(new DefaultMultiLanguageProperty.Builder() + .idShort("ExampleMultiLanguageProperty") + .category("Constant") + .description(new LangString("Example MultiLanguageProperty object", "en-us")) + .description(new LangString("Beispiel MulitLanguageProperty Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new LangString("Example value of a MultiLanguageProperty element", "en-us")) + .value(new LangString("Beispielswert für ein MulitLanguageProperty-Element", "de")) + .build()) + .value(new DefaultRange.Builder() + .idShort("ExampleRange") + .category("Parameter") + .description(new LangString("Example Range object", "en-us")) + .description(new LangString("Beispiel Range Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Ranges/ExampleRange") + .idType(KeyType.IRI) + .build()) + .build()) + .valueType("int") + .min("0") + .max("100") + .build()) + .ordered(true) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionUnordered") + .category("Parameter") + .description(new LangString("Example SubmodelElementCollectionUnordered object", "en-us")) + .description(new LangString("Beispiel SubmodelElementCollectionUnordered Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new DefaultBlob.Builder() + .idShort("ExampleBlob") + .category("Parameter") + .description(new LangString("Example Blob object", "en-us")) + .description(new LangString("Beispiel Blob Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Blobs/ExampleBlob") + .idType(KeyType.IRI) + .build()) + .build()) + .mimeType("application/pdf") + .value(Base64.getDecoder().decode("AQIDBAU=")) + .build()) + .value(new DefaultFile.Builder() + .idShort("ExampleFile") + .category("Parameter") + .description(new LangString("Example File object", "en-us")) + .description(new LangString("Beispiel File Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Files/ExampleFile") + .idType(KeyType.IRI) + .build()) + .build()) + .value("/TestFile.pdf") + .mimeType("application/pdf") + .build()) + .value(new DefaultReferenceElement.Builder() + .idShort("ExampleReferenceElement") + .category("Parameter") + .description(new LangString("Example Reference Element object", "en-us")) + .description(new LangString("Beispiel Reference Element Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/ReferenceElements/ExampleReferenceElement") + .idType(KeyType.IRI) + .build()) + .build()) + .value(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL) + .value("https://acplt.org/Test_Submodel_Missing") + .idType(KeyType.IRI) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.SUBMODEL_ELEMENT_COLLECTION) + .value("ExampleSubmodelCollectionOrdered") + .idType(KeyType.ID_SHORT) + .build()) + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .idType(KeyType.ID_SHORT) + .value("ExampleProperty") + .build()) + .build()) + .build()) + .ordered(false) + .build()) + .build(); + + public static final Submodel SUBMODEL_7 = new DefaultSubmodel.Builder() + .idShort("TestSubmodel") + .description(new LangString("An example submodel for the test application", "en-us")) + .description(new LangString("Ein Beispiel-Teilmodell für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_Submodel_Template") + .build()) + .kind(ModelingKind.INSTANCE) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/SubmodelTemplates/ExampleSubmodel") + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .submodelElement(new DefaultRelationshipElement.Builder() + .idShort("ExampleRelationshipElement") + .category("Parameter") + .description(new LangString("Example RelationshipElement object", "en-us")) + .description(new LangString("Beispiel RelationshipElement Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/RelationshipElements/ExampleRelationshipElement") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .build()) + .submodelElement(new DefaultAnnotatedRelationshipElement.Builder().idShort("ExampleAnnotatedRelationshipElement") + .category("Parameter") + .description(new LangString("Example AnnotatedRelationshipElement object", "en-us")) + .description(new LangString("Beispiel AnnotatedRelationshipElement Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .first(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .second(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .value("ExampleProperty") + .idType(KeyType.ID_SHORT) + .build()) + .build()) + .build()) + .submodelElement(new DefaultOperation.Builder() + .idShort("ExampleOperation") + .category("Parameter") + .description(new LangString("Example Operation object", "en-us")) + .description(new LangString("Beispiel Operation Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Operations/ExampleOperation") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .inputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .value(null) + .valueType("string") + .build()) + .build()) + .outputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .value(null) + .valueType("string") + .build()) + .build()) + .inoutputVariable(new DefaultOperationVariable.Builder() + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .value(null) + .valueType("string") + .build()) + .build()) + .build()) + .submodelElement(new DefaultCapability.Builder() + .idShort("ExampleCapability") + .category("Parameter") + .description(new LangString("Example Capability object", "en-us")) + .description(new LangString("Beispiel Capability Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Capabilities/ExampleCapability") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .build()) + .submodelElement(new DefaultBasicEvent.Builder() + .idShort("ExampleBasicEvent") + .category("Parameter") + .description(new LangString("Example BasicEvent object", "en-us")) + .description(new LangString("Beispiel BasicEvent Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Events/ExampleBasicEvent") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .observed(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.PROPERTY) + .idType(KeyType.ID_SHORT) + .value("ExampleProperty") + .build()) + .build()) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionOrdered") + .category("Parameter") + .description(new LangString("Example SubmodelElementCollectionOrdered object", "en-us")) + .description(new LangString("Beispiel SubmodelElementCollectionOrdered Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .value(new DefaultProperty.Builder() + .idShort("ExampleProperty") + .category("Constant") + .description(new LangString("Example Property object", "en-us")) + .description(new LangString("Beispiel Property Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Properties/ExampleProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .value(null) + .valueType("string") + .build()) + .value(new DefaultMultiLanguageProperty.Builder() + .idShort("ExampleMultiLanguageProperty") + .category("Constant") + .description(new LangString("Example MultiLanguageProperty object", "en-us")) + .description(new LangString("Beispiel MulitLanguageProperty Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE).value( + "http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .build()) + .value(new DefaultRange.Builder() + .idShort("ExampleRange") + .category("Parameter") + .description(new LangString("Example Range object", "en-us")) + .description(new LangString("Beispiel Range Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Ranges/ExampleRange") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .valueType("int") + .min(null) + .max("100") + .build()) + .value(new DefaultRange.Builder() + .idShort("ExampleRange2") + .category("Parameter") + .description(new LangString("Example Range object", "en-us")) + .description(new LangString("Beispiel Range Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Ranges/ExampleRange") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .valueType("int") + .min("0") + .max(null) + .build()) + .ordered(true) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionUnordered") + .category("Parameter") + .description(new LangString("Example SubmodelElementCollectionUnordered object", "en-us")) + .description(new LangString("Beispiel SubmodelElementCollectionUnordered Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .value(new DefaultBlob.Builder() + .idShort("ExampleBlob") + .category("Parameter") + .description(new LangString("Example Blob object", "en-us")) + .description(new LangString("Beispiel Blob Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Blobs/ExampleBlob") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .mimeType("application/pdf") + .build()) + .value(new DefaultFile.Builder() + .idShort("ExampleFile") + .category("Parameter") + .description(new LangString("Example File object", "en-us")) + .description(new LangString("Beispiel File Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/Files/ExampleFile") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .value(null) + .mimeType("application/pdf") + .build()) + .value(new DefaultReferenceElement.Builder() + .idShort("ExampleReferenceElement") + .category("Parameter") + .description(new LangString("Example Reference Element object", "en-us")) + .description(new LangString("Beispiel Reference Element Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/ReferenceElements/ExampleReferenceElement") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .build()) + .ordered(false) + .build()) + .submodelElement(new DefaultSubmodelElementCollection.Builder() + .idShort("ExampleSubmodelCollectionUnordered2") + .category("Parameter") + .description(new LangString("Example SubmodelElementCollectionUnordered object", "en-us")) + .description(new LangString("Beispiel SubmodelElementCollectionUnordered Element", "de")) + .semanticId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .value("http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered") + .idType(KeyType.IRI) + .build()) + .build()) + .kind(ModelingKind.TEMPLATE) + .ordered(false) + .build()) + .build(); + + public final static ConceptDescription CONCEPT_DESCRIPTION_1 = new DefaultConceptDescription.Builder() + .idShort("TestConceptDescription") + .description(new LangString("An example concept description for the test application", "en-us")) + .description(new LangString("Ein Beispiel-ConceptDescription für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_ConceptDescription") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .isCaseOf(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription") + .build()) + .build()) + .build(); + + public final static ConceptDescription CONCEPT_DESCRIPTION_2 = new DefaultConceptDescription.Builder() + .idShort("") + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_ConceptDescription_Mandatory") + .build()) + .build(); + + public final static ConceptDescription CONCEPT_DESCRIPTION_3 = new DefaultConceptDescription.Builder() + .idShort("TestConceptDescription1") + .description(new LangString("An example concept description for the test application", "en-us")) + .description(new LangString("Ein Beispiel-ConceptDescription für eine Test-Anwendung", "de")) + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("https://acplt.org/Test_ConceptDescription_Missing") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .build(); + + public final static ConceptDescription CONCEPT_DESCRIPTION_4 = new DefaultConceptDescription.Builder() + .idShort("TestSpec_01") + .identification(new DefaultIdentifier.Builder() + .idType(IdentifierType.IRI) + .identifier("http://acplt.org/DataSpecifciations/Example/Identification") + .build()) + .administration(new DefaultAdministrativeInformation.Builder() + .version("0.9") + .revision("0") + .build()) + .isCaseOf(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ReferenceElements/ConceptDescriptionX") + .build()) + .build()) + .embeddedDataSpecification(new DefaultEmbeddedDataSpecification.Builder() + .dataSpecificationContent(new DefaultDataSpecificationIEC61360.Builder() + .preferredName(new LangString("Test Specification", "de")) + .preferredName(new LangString("TestSpecification", "en-us")) + .dataType(DataTypeIEC61360.REAL_MEASURE) + .definition(new LangString("Dies ist eine Data Specification für Testzwecke", "de")) + .definition(new LangString("This is a DataSpecification for testing purposes", "en-us")) + .shortName(new LangString("Test Spec", "de")) + .shortName(new LangString("TestSpec", "en-us")) + .unit("SpaceUnit") + .unitId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/Units/SpaceUnit") + .build()) + .build()) + .sourceOfDefinition("http://acplt.org/DataSpec/ExampleDef") + .symbol("SU") + .valueFormat("string") + .value("TEST") + .levelType(LevelType.MIN) + .levelType(LevelType.MAX) + .valueList(new DefaultValueList.Builder() + .valueReferencePairTypes(new DefaultValueReferencePair.Builder() + .value("exampleValue") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId") + .build()) + .build()) + // TODO valueType + .build()) + .valueReferencePairTypes(new DefaultValueReferencePair.Builder() + .value("exampleValue2") + .valueId(new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(KeyElements.GLOBAL_REFERENCE) + .idType(KeyType.IRI) + .value("http://acplt.org/ValueId/ExampleValueId2") + .build()) + .build()) + // TODO valueType + .build()) + .build()) + .build()) + .build() + ) + .build(); + + public static final AssetAdministrationShellEnvironment ENVIRONMENT = new DefaultAssetAdministrationShellEnvironment.Builder() + .assetAdministrationShells(Arrays.asList( + AAS_1, + AAS_2, + AAS_3, + AAS_4)) + .submodels(Arrays.asList( + SUBMODEL_1, + SUBMODEL_2, + SUBMODEL_3, + SUBMODEL_4, + SUBMODEL_5, + SUBMODEL_6, + SUBMODEL_7)) + .conceptDescriptions(Arrays.asList( + CONCEPT_DESCRIPTION_1, + CONCEPT_DESCRIPTION_2, + CONCEPT_DESCRIPTION_3, + CONCEPT_DESCRIPTION_4)) + .build(); +} diff --git a/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/serialize/AmlSerializerTest.java b/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/serialize/AmlSerializerTest.java new file mode 100644 index 00000000..ad286ac7 --- /dev/null +++ b/dataformat-aml/src/test/java/io/adminshell/aas/v3/dataformat/aml/serialize/AmlSerializerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.aml.serialize; + +import io.adminshell.aas.v3.dataformat.aml.fixtures.FullExample; +import io.adminshell.aas.v3.dataformat.SerializationException; +import io.adminshell.aas.v3.dataformat.aml.AmlSerializationConfig; +import io.adminshell.aas.v3.dataformat.aml.AmlSerializer; +import io.adminshell.aas.v3.dataformat.aml.serialization.id.IntegerIdGenerator; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Iterator; +import org.junit.Test; +import org.xml.sax.SAXException; +import org.xmlunit.builder.DiffBuilder; +import org.xmlunit.diff.DefaultNodeMatcher; +import org.xmlunit.diff.Diff; +import org.xmlunit.diff.Difference; +import org.xmlunit.diff.ElementSelectors; + +public class AmlSerializerTest { + + @Test + public void testSAPFullExample() throws SerializationException, SAXException, IOException { + validateAmlSerializer(FullExample.FILE, FullExample.ENVIRONMENT); + } + + private void validateAmlSerializer(File expectedFile, AssetAdministrationShellEnvironment environment) + throws SerializationException, SAXException, IOException { + String expected = Files.readString(expectedFile.toPath()); + String actual = new AmlSerializer().write(environment, AmlSerializationConfig.builder() + .idGenerator(new IntegerIdGenerator()) + .build()); + System.out.println(actual); + Diff diff = DiffBuilder + .compare(expected) + .withTest(actual) + .normalizeWhitespace() + .withNodeMatcher(new DefaultNodeMatcher( + ElementSelectors.conditionalBuilder() + .whenElementIsNamed("Attribute") + .thenUse(ElementSelectors.byNameAndAttributes("Name")) + .whenElementIsNamed("InternalElement") + .thenUse(ElementSelectors.byNameAndAttributes("Name", "ID")) + .whenElementIsNamed("ExternalInterface") + .thenUse(ElementSelectors.byNameAndAttributes("Name")) + .elseUse(ElementSelectors.byNameAndText) + .build())) + .ignoreComments() + .ignoreWhitespace() + .withNodeFilter(node -> !node.getNodeName().equals("AdditionalInformation")) + .build(); + Iterator iter = diff.getDifferences().iterator(); + int size = 0; + while (iter.hasNext()) { + System.out.println(iter.next()); + size++; + } + System.err.println(String.format("found %d validation error(s)", size)); + assert (size == 0); + } + +} diff --git a/dataformat-aml/src/test/resources/test_demo_full_example.aml b/dataformat-aml/src/test/resources/test_demo_full_example.aml new file mode 100644 index 00000000..e29583fa --- /dev/null +++ b/dataformat-aml/src/test/resources/test_demo_full_example.aml @@ -0,0 +1,3751 @@ + + + + + + + + + 0 + + + + 0.9 + + + + + + + INSTANCE + + + + (Submodel)[IRI]http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + + + + (Asset)[IRI]https://acplt.org/Test_Asset + + + + + (AssetAdministrationShell)[IRI]https://acplt.org/TestAssetAdministrationShell2 + + + + + + An Example Asset Administration Shell for the test application + + + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + + + TestAssetAdministrationShell + + + + + + IRI + + + + https://acplt.org/Test_AssetAdministrationShell + + + + + + + + 0 + + + + 0.9 + + + + + + + An example submodel for the test application + + + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + TestSubmodel + + + + + + IRI + + + + https://acplt.org/Test_Submodel + + + + + INSTANCE + + + + (GlobalReference)[IRI]http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + Parameter + + + + + + Example RelationshipElement object + + + Beispiel RelationshipElement Element + + + + ExampleRelationshipElement + + + + (GlobalReference)[IRI]http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + + + + + + Parameter + + + + + + Example AnnotatedRelationshipElement object + + + Beispiel AnnotatedRelationshipElement Element + + + + ExampleAnnotatedRelationshipElement + + + + (GlobalReference)[IRI]http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + + Parameter + + + + ExampleProperty3 + + + + INSTANCE + + + + some example annotation + + + + + + + + + + + Parameter + + + + + + Example Operation object + + + Beispiel Operation Element + + + + ExampleOperation + + + + (GlobalReference)[IRI]http://acplt.org/Operations/ExampleOperation + + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty3 + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + exampleValue + + + + + + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty1 + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + exampleValue + + + + + + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty2 + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + exampleValue + + + + + + + + + + + Parameter + + + + + + Example Capability object + + + Beispiel Capability Element + + + + ExampleCapability + + + + (GlobalReference)[IRI]http://acplt.org/Capabilities/ExampleCapability + + + + + + + Parameter + + + + + + Example BasicEvent object + + + Beispiel BasicEvent Element + + + + ExampleBasicEvent + + + + (Submodel)[IRI]https://acplt.org/Test_Submodel,(SubmodelElementCollection)[ID_SHORT]ExampleSubmodelCollectionOrdered,(Property)[ID_SHORT]ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/Events/ExampleBasicEvent + + + + + + + false + + + + Parameter + + + + + + Example SubmodelElementCollectionOrdered object + + + Beispiel SubmodelElementCollectionOrdered Element + + + + ExampleSubmodelCollectionOrdered + + + + true + + + + (GlobalReference)[IRI]http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + exampleValue + + + + + + + + Constant + + + + + + Example MultiLanguageProperty object + + + Beispiel MulitLanguageProperty Element + + + + ExampleMultiLanguageProperty + + + + (GlobalReference)[IRI]http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleMultiLanguageValueId + + + + + + Example value of a MultiLanguageProperty element + + + Beispielswert für ein MulitLanguageProperty-Element + + + + + + + Parameter + + + + + + Example Range object + + + Beispiel Range Element + + + + ExampleRange + + + + (GlobalReference)[IRI]http://acplt.org/Ranges/ExampleRange + + + + 0 + + + + 100 + + + + + + + + + false + + + + Parameter + + + + + + Example SubmodelElementCollectionUnordered object + + + Beispiel SubmodelElementCollectionUnordered Element + + + + ExampleSubmodelCollectionUnordered + + + + false + + + + (GlobalReference)[IRI]http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered + + + + + Parameter + + + + + + Example Blob object + + + Beispiel Blob Element + + + + ExampleBlob + + + + application/pdf + + + + (GlobalReference)[IRI]http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + + + + + + + Parameter + + + + + + Example File object + + + Beispiel File Element + + + + ExampleFile + + + + application/pdf + + + + (GlobalReference)[IRI]http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + + + + + application/pdf + + + /TestFile.pdf + + + + + + + Parameter + + + + + + Example Reference Element object + + + Beispiel Reference Element Element + + + + ExampleReferenceElement + + + + (GlobalReference)[IRI]http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + + + + + + + + + + + 0.9 + + + + + + + An example bill of material submodel for the test application + + + Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + + + + BillOfMaterial + + + + + + IRI + + + + http://acplt.org/Submodels/Assets/TestAsset/BillOfMaterial + + + + + INSTANCE + + + + (Submodel)[IRI]http://acplt.org/SubmodelTemplates/BillOfMaterial + + + + + + + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + CO_MANAGED_ENTITY + + + + ExampleEntity + + + + (GlobalReference)[IRI]http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty2 + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + exampleValue2 + + + + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + exampleValue + + + + + + + + + + + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + SELF_MANAGED_ENTITY + + + + (Asset)[IRI]https://acplt.org/Test_Asset2 + + + + ExampleEntity2 + + + + (GlobalReference)[IRI]http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + + + + + + + + 0 + + + + 0.9 + + + + + + + An example asset identification submodel for the test application + + + Ein Beispiel-Identifikations-Submodel für eine Test-Anwendung + + + + Identification + + + + + + IRI + + + + http://acplt.org/Submodels/Assets/TestAsset/Identification + + + + + INSTANCE + + + + (Submodel)[IRI]http://acplt.org/SubmodelTemplates/AssetIdentification + + + + + + + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + ManufacturerName + + + + + + http://acplt.org/Qualifier/ExampleQualifier + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + 100 + + + + + + + http://acplt.org/Qualifier/ExampleQualifier2 + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + 50 + + + + + (GlobalReference)[IRI]0173-1#02-AAO677#002 + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + ACPLT + + + + + + + + + Legally valid designation of the natural or judicial person which is directly responsible for the design, production, packaging and labeling of a product in respect to its being brought into circulation. + + + Bezeichnung für eine natürliche oder juristische Person, die für die Auslegung, Herstellung und Verpackung sowie die Etikettierung eines Produkts im Hinblick auf das 'Inverkehrbringen' im eigenen Namen verantwortlich ist + + + + InstanceId + + + + (GlobalReference)[IRI]http://opcfoundation.org/UA/DI/1.1/DeviceType/Serialnumber + + + + (GlobalReference)[IRI]http://acplt.org/ValueId/ExampleValueId + + + + 978-8234-234-342 + + + + + + + + + + + + + INSTANCE + + + + (Asset)[IRI]https://acplt.org/Test_Asset_Mandatory + + + + + + + + + + + IRI + + + + https://acplt.org/Test_AssetAdministrationShell_Mandatory + + + + + + + + + + + + IRI + + + + https://acplt.org/Test_Submodel_Mandatory + + + + + TEMPLATE + + + + + ExampleRelationshipElement + + + + + + + + + + ExampleAnnotatedRelationshipElement + + + + + + + + + + ExampleOperation + + + + + + + ExampleCapability + + + + + + + ExampleBasicEvent + + + + (Submodel)[IRI]https://acplt.org/Test_Submodel_Mandatory,(SubmodelElementCollection)[ID_SHORT]ExampleSubmodelCollectionOrdered,(Property)[ID_SHORT]ExampleProperty + + + + + + + false + + + + ExampleSubmodelCollectionOrdered + + + + true + + + + + ExampleProperty + + + + + + + + ExampleMultiLanguageProperty + + + + + + + + ExampleRange + + + + + + + + + false + + + + ExampleSubmodelCollectionUnordered + + + + false + + + + + ExampleBlob + + + + application/pdf + + + + + + + ExampleFile + + + + application/pdf + + + + + application/pdf + + + + + + + + ExampleReferenceElement + + + + + + + + + false + + + + ExampleSubmodelCollectionUnordered2 + + + + false + + + + + + + + + + + + + + + IRI + + + + https://acplt.org/Test_Submodel2_Mandatory + + + + + INSTANCE + + + + + + + + + + + 0 + + + + 0.9 + + + + + + + INSTANCE + + + + (Asset)[IRI]https://acplt.org/Test_Asset_Missing + + + + + + + An Example Asset Administration Shell for the test application + + + Ein Beispiel-Verwaltungsschale für eine Test-Anwendung + + + + TestAssetAdministrationShell + + + + + + IRI + + + + https://acplt.org/Test_AssetAdministrationShell_Missing + + + + + + + + + + + + + + + 0 + + + + 0.9 + + + + + + + An example submodel for the test application + + + Ein Beispiel-Teilmodell für eine Test-Anwendung + + + + TestSubmodel + + + + + + IRI + + + + https://acplt.org/Test_Submodel_Missing + + + + + INSTANCE + + + + (GlobalReference)[IRI]http://acplt.org/SubmodelTemplates/ExampleSubmodel + + + + + Parameter + + + + + + Example RelationshipElement object + + + Beispiel RelationshipElement Element + + + + ExampleRelationshipElement + + + + (GlobalReference)[IRI]http://acplt.org/RelationshipElements/ExampleRelationshipElement + + + + + + + + + + Parameter + + + + + + Example AnnotatedRelationshipElement object + + + Beispiel AnnotatedRelationshipElement Element + + + + ExampleAnnotatedRelationshipElement + + + + (GlobalReference)[IRI]http://acplt.org/RelationshipElements/ExampleAnnotatedRelationshipElement + + + + + + Parameter + + + + ExampleProperty + + + + INSTANCE + + + + some example annotation + + + + + + + + + + + Parameter + + + + + + Example Operation object + + + Beispiel Operation Element + + + + ExampleOperation + + + + (GlobalReference)[IRI]http://acplt.org/Operations/ExampleOperation + + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty3 + + + + + + http://acplt.org/Qualifier/ExampleQualifier + + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + exampleValue + + + + + + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty1 + + + + + + http://acplt.org/Qualifier/ExampleQualifier + + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + exampleValue + + + + + + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty2 + + + + + + http://acplt.org/Qualifier/ExampleQualifier + + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + exampleValue + + + + + + + + + + + Parameter + + + + + + Example Capability object + + + Beispiel Capability Element + + + + ExampleCapability + + + + (GlobalReference)[IRI]http://acplt.org/Capabilities/ExampleCapability + + + + + + + Parameter + + + + + + Example BasicEvent object + + + Beispiel BasicEvent Element + + + + ExampleBasicEvent + + + + (Submodel)[IRI]https://acplt.org/Test_Submodel_Missing,(SubmodelElementCollection)[ID_SHORT]ExampleSubmodelCollectionOrdered,(Property)[ID_SHORT]ExampleProperty + + + + (GlobalReference)[IRI]http://acplt.org/Events/ExampleBasicEvent + + + + + + + false + + + + Parameter + + + + + + Example SubmodelElementCollectionOrdered object + + + Beispiel SubmodelElementCollectionOrdered Element + + + + ExampleSubmodelCollectionOrdered + + + + true + + + + (GlobalReference)[IRI]http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionOrdered + + + + + Constant + + + + + + Example Property object + + + Beispiel Property Element + + + + ExampleProperty + + + + + + http://acplt.org/Qualifier/ExampleQualifier + + + + + (GlobalReference)[IRI]http://acplt.org/Properties/ExampleProperty + + + + exampleValue + + + + + + + + Constant + + + + + + Example MultiLanguageProperty object + + + Beispiel MulitLanguageProperty Element + + + + ExampleMultiLanguageProperty + + + + (GlobalReference)[IRI]http://acplt.org/MultiLanguageProperties/ExampleMultiLanguageProperty + + + + + + Example value of a MultiLanguageProperty element + + + Beispielswert für ein MulitLanguageProperty-Element + + + + + + + + Parameter + + + + + + Example Range object + + + Beispiel Range Element + + + + ExampleRange + + + + (GlobalReference)[IRI]http://acplt.org/Ranges/ExampleRange + + + + 0 + + + + 100 + + + + + + + + + false + + + + Parameter + + + + + + Example SubmodelElementCollectionUnordered object + + + Beispiel SubmodelElementCollectionUnordered Element + + + + ExampleSubmodelCollectionUnordered + + + + false + + + + (GlobalReference)[IRI]http://acplt.org/SubmodelElementCollections/ExampleSubmodelElementCollectionUnordered + + + + + Parameter + + + + + + Example Blob object + + + Beispiel Blob Element + + + + ExampleBlob + + + + application/pdf + + + + (GlobalReference)[IRI]http://acplt.org/Blobs/ExampleBlob + + + + AQIDBAU= + + + + + + + Parameter + + + + + + Example File object + + + Beispiel File Element + + + + ExampleFile + + + + application/pdf + + + + (GlobalReference)[IRI]http://acplt.org/Files/ExampleFile + + + + /TestFile.pdf + + + + + application/pdf + + + /TestFile.pdf + + + + + + + Parameter + + + + + + Example Reference Element object + + + Beispiel Reference Element Element + + + + ExampleReferenceElement + + + + (GlobalReference)[IRI]http://acplt.org/ReferenceElements/ExampleReferenceElement + + + + + + + + + + + + + + + + + + + 0 + + + + 0.9 + + + + + + + An example concept description for the test application + + + Ein Beispiel-ConceptDescription für eine Test-Anwendung + + + + TestConceptDescription + + + + + + IRI + + + + https://acplt.org/Test_ConceptDescription + + + + + (GlobalReference)[IRI]http://acplt.org/DataSpecifications/ConceptDescriptions/TestConceptDescription + + + + + + + + + + + + + IRI + + + + https://acplt.org/Test_ConceptDescription_Mandatory + + + + + + + + + + 0 + + + + 0.9 + + + + + + + An example concept description for the test application + + + Ein Beispiel-ConceptDescription für eine Test-Anwendung + + + + TestConceptDescription1 + + + + + + IRI + + + + https://acplt.org/Test_ConceptDescription_Missing + + + + + + + + + + 0 + + + + 0.9 + + + + + TestSpec_01 + + + + + + IRI + + + + http://acplt.org/DataSpecifciations/Example/Identification + + + + + (GlobalReference)[IRI]http://acplt.org/ReferenceElements/ConceptDescriptionX + + + + + REAL_MEASURE + + + + + + Dies ist eine Data Specification für Testzwecke + + + This is a DataSpecification for testing purposes + + + + + + Test Specification + + + TestSpecification + + + + + + Test Spec + + + TestSpec + + + + http://acplt.org/DataSpec/ExampleDef + + + + SU + + + + SpaceUnit + + + + (GlobalReference)[IRI]http://acplt.org/Units/SpaceUnit + + + + TEST + + + + string + + + + + + + + + Interface Class Library according to Details of the Asset Administration Shell V2.0. + 1.0.0 + + A FileDataReference represents the address to a File. FileDataReference is derived from the AutomationML Interface Class ExternalDataReference that is defined in AutomationML BPR_005E_ExternalDataReference_v1.0.0_2:The interface class “ExternalDataReference” shall be used in order to reference external documents out of the scope of AutomationML. + + + Reference to any other referable element of the same of any other AAS or a reference to an external object or entity. For local references inside the same Asset Administration Shell an InternalLink between two objects with this interface "ReferableReference" shall be set. In this case the attribute value has to be empty. For references between different Asset Administration Shells or external objects or entities the attribute value shall be used and no InternalLink shall be set. + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable element of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + + Standard Automation Markup Language Interface Class Library - Part 1 Content extended with Part 3 and Part 4 Content + 2.2.2 + + + + + + + + + + The attribute refURI is an IRI that can represent an absolute or relative path to an L document. An added fragment (with #) references inside the document + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + 1.0.0 + + + Mime type of the content of the File. + + + + + Role Class Library according to Details of the Asset Administration Shell V2.0. + 1.0.0 + + An Asset Administration Shell. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + + The derivedFrom attribute is used to establish a relationship between two Asset Administration Shells that are derived from each other. + + + + + + An Asset describes meta data of an asset that is represented by an AAS. The asset may either represent an asset type or an asset instance. The asset has a globally unique identifier plus – if needed – additional domain specific (proprietary) identifiers. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the asset: either type or instance. + Instance + Instance + + + + Instance + Type + + + + + + A Submodel defines a specific aspect of the asset represented by the AAS. A submodel is used to structure the virtual representation and technical functionality of an Administration Shell into distinguishable parts. Each submodel refers to a well-defined domain or subject matter. Submodels can become standardized and thus become submodels types. Submodels can have different life-cycles. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + A submodel element collection is a set or list of submodel elements. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + If allowDuplicates=true, then it is allowed that the collection contains the same element several times. + false + + + + If ordered=false, then the elements in the property collection are not ordered. If ordered=true then the elements in the collection are ordered. Default = false. Note: An ordered submodel element collection is typically implemented as an indexed array. + false + + + + Submodel element contained in the collection. + + + + + A BLOB is a data element that represents a file that is contained with its source code in the value attribute. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + Mime type of the content of the BLOB. The mime type states which file extension the file has. Valid values are e.g. “application/json”, “application/xls”, ”image/jpg”. The allowed values are defined as in RFC2046. + + + + + The value of the BLOB instance of a blob data element. Note: In contrast to the file property the file content is stored directly as value in the Blob data element. + + + + + + A capability is the implementation-independent description of the potential of an asset to achieve a certain effect in the physical or virtual world. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + A role class for a File that a data element that represents an address to a file. It is derived from the AutomationML role class ExternalData that is an role type for a document type and the base class for all document type roles. It describes different document types. ExternalData is defined in AutomationML BPR_005E_ExternalDataReference_v1.0.0_2. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + The attribute refURI is an IRI that can represent an absolute or relative path to an L document. An added fragment (with #) references inside the document + + + Mime type of the content of the File. + + + + + A property is a data element that has a single value. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + The value of the property instance. + + + + Reference to the global unique id if a coded value. + + + + + A reference element is a data element that defines a logical reference to another element within the same or another AAS or a reference to an external object or entity. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable elment of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + + A relationship element is used to define a relationship between two referable elements. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable elment of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + Reference to any other referable element of any other AAS or a reference to an external object or entity. Note: For references to any other referable elment of the same AAS InternalLinks are used and this attribute value shall be empty. + + + + + An annotated relationship element is an relationship element that can be annotated with additional data elements. + + Annotations that hold for the relationships between the two elements. + + + + + An operation is a submodel element with input and output variables. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + The list of AAS OperationVariableIn entities. In AML, the corresponding InternalElement with this role is a child of the InternalElement with the Operation role. + + + The list of AAS OperationVariableOut entities. In AML, the corresponding InternalElement with this role is a child of the InternalElement with the Operation role. + + + The list of AAS OperationVariableOut entities. In AML, the corresponding InternalElement with this role is a child of the InternalElement with the Operation role. + + + A view is a collection of referable elements w.r.t. to a specific viewpoint of one or more stakeholders. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + + A dictionary contains elements that can be reused. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + + Explanation: The semantics of a property or other elements that may have a semantic description is defined by a concept description. The description of the concept should follow a standardized schema (realized as data specification template). + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + Global reference to the data specification template used by the element. + + + + Global reference to an external definition the concept is compatible to or was derived from. + + + + + + Description Role class of an element that has a data specification template. A template defines the additional attributes an element may or shall have. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + + Content of the data specification template. + + + An entity is a submodel element that is used to model entities. Constraint AASd-056: If the semanticId of a Entity submodel element references a ConceptDescription then the ConceptDescription/category shall be one of following values: ENTITY. The ConceptDescription describes the elements assigned to the entity via Entity/statement. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + Describes statements applicable to the entity by a set of submodel elements, typically with a qualified value. + + + + Describes whether the entity is a co-managed entity or a self-managed entity. + SelfManagedEntity + SelfManagedEntity + + + + CoManagedEntity + SelfManagedEntity + + + + + Reference to an identifier key value pair representing a specific identifier of the asset represented by the asset administration shell. See Constraint AASd-014 + + + + Reference to the asset the entity is representing. Constraint AASd-014: Either the attribute globalAssetId or specificAssetId of an Entity must be set if Entity/entityType is set to "SelfManagedEntity". They are not existing otherwise. + + + + + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + + + + + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + Reference to the global unique id if a coded value. + + + + + + + + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + Global reference to the data specification template used by the element. + + + + + Kind of the element: either template or instance. + Instance + Instance + + + + Instance + Type + + + + + Description or comments on the element. The description can be provided in several languages. This attribute has the name of the label and has a value with the label written in the default language. The individual languages are modelled as child attributes. The names of the child attributes are the prefix “aml-lang=” with the expression of the language in compliance with RFC5646. At it, the values of the child attributes are the labels within the respective language. + + + + + A qualifier is a type-value-pair that makes additional statements w.r.t. the value of the element. [TYPE] is the value of the attribute type and [VALUE] is the value of the attribute value. + + + The type describes the type of the qualifier that is applied to the element. + + + + + The qualifier value is the value of the qualifier. Constraint AASd-006: if both, the value and the valueId are present then the value needs to be identical to the value of the referenced coded value in valueId. + + + + + Reference to the global unqiue id of a coded value. + + + + + + The value of the property instance. + + + + Reference to the global unique id if a coded value. + + + + + + Automation Markup Language Base Role Class Library - Part 1 Content extended with Part 3 and Part 4 Content + 2.2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.0.0 + + + + + + + + INSTANCE + + + + (Asset)[IRI]https://acplt.org/Test_Asset_Mandatory + + + + + + + + + + + IRI + + + + https://acplt.org/Test_AssetAdministrationShell_Mandatory + + + + + + + + + + + + IRI + + + + https://acplt.org/Test_Submodel_Mandatory + + + + + TEMPLATE + + + + + ExampleRelationshipElement + + + + + + + + + + ExampleAnnotatedRelationshipElement + + + + + + + + + + ExampleOperation + + + + + + + ExampleCapability + + + + + + + ExampleBasicEvent + + + + (Submodel)[IRI]https://acplt.org/Test_Submodel_Mandatory,(SubmodelElementCollection)[ID_SHORT]ExampleSubmodelCollectionOrdered,(Property)[ID_SHORT]ExampleProperty + + + + + + + false + + + + ExampleSubmodelCollectionOrdered + + + + true + + + + + ExampleProperty + + + + + + + + ExampleMultiLanguageProperty + + + + + + + + ExampleRange + + + + + + + + + false + + + + ExampleSubmodelCollectionUnordered + + + + false + + + + + ExampleBlob + + + + application/pdf + + + + + + + ExampleFile + + + + application/pdf + + + + + application/pdf + + + + + + + + ExampleReferenceElement + + + + + + + + + false + + + + ExampleSubmodelCollectionUnordered2 + + + + false + + + + + + + + + + + + + + + IRI + + + + https://acplt.org/Test_Submodel2_Mandatory + + + + + INSTANCE + + + + + + + + + + + + + + + IRI + + + + https://acplt.org/Test_Submodel_Mandatory + + + + + TEMPLATE + + + + + ExampleRelationshipElement + + + + + + + + + + ExampleAnnotatedRelationshipElement + + + + + + + + + + ExampleOperation + + + + + + + ExampleCapability + + + + + + + ExampleBasicEvent + + + + (Submodel)[IRI]https://acplt.org/Test_Submodel_Mandatory,(SubmodelElementCollection)[ID_SHORT]ExampleSubmodelCollectionOrdered,(Property)[ID_SHORT]ExampleProperty + + + + + + + false + + + + ExampleSubmodelCollectionOrdered + + + + true + + + + + ExampleProperty + + + + + + + + ExampleMultiLanguageProperty + + + + + + + + ExampleRange + + + + + + + + + false + + + + ExampleSubmodelCollectionUnordered + + + + false + + + + + ExampleBlob + + + + application/pdf + + + + + + + ExampleFile + + + + application/pdf + + + + + application/pdf + + + + + + + + ExampleReferenceElement + + + + + + + + + false + + + + ExampleSubmodelCollectionUnordered2 + + + + false + + + + + + + + + 0 + + An AAS Data Specification template for IEC61369. A template consists of the DataSpecificationContent containing the additional attributes to be added to the element instance that references the data specification template and meta information about the template itself (this is why DataSpecification inherits from Identifiable). In UML these are two separated classes. + + Identifying string of the element within its name space. Constraint AASd-001: In case of a referable element not being an identifiable element this id is mandatory and used for referring to the element in its name space. Constraint AASd-002: idShort shall only feature letters, digits, underscore ("_"); starting mandatory with a letter. Constraint AASd-003: idShort shall be matched case-insensitive. Note: In case of an identifiable element idShort is optional but recommended to be defined. It can be used for unique reference in its name space and thus allows better usability and a more performant implementation. In this case it is similar to the “BrowserPath” in OPC UA. + + + + The category is a value that gives further meta information w.r.t. to the class of the element. It affects the expected existence of attributes and the applicability of constraints. + + + + + Description or comments on the element. The description can be provided in several languages. + + + + + + + + + + + Abstract attribute class for identification. Has the subattributes id and idType. + + + Identifier of the element. Its type is defined in idType. Id is a subproperty of identification. + http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360 + + + + Type of the Identifier, e.g. IRI, IRDI etc. The supported Identifier types are defined in the enumeration “IdentifierType”. IdType is a subproperty of identification. + IRI + + + + + Abstract attribute for administration. Has the subattributes revision and version. + + + Revision of the element. Constraint AASd-005: A revision requires a version. This means, if there is no version there is no revision neither. Revision is a subproperty of administration. + + + + + Version of the element. Version is a subproperty of administration. + + + + + + + The content of an AAS Data Specification template for IEC61360. + + Identifies the attribute hierarchy for preferredName in above attribute hierachy. Subordinate attributes are designated by the country code information (see aml-lang literal). + + + + Identifies the attribute for shortName in above attribute hierarchy. + + + + Identifies the attribute for unit in above attribute hierarchy. + + + + Identifies the attribute for unitId in above attribute hierarchy in its string serialization. + + + + Identifies the attribute for sourceOfDefinition in above attribute hierachy. Subordinate attributes are designated by the country code information (see aml-lang literal). + + + + Identifies the attribute for symbol in above attribute hierarchy. + + + + Identifies the attribute for dataType in above attribute hierarchy. + + + + Identifies the attribute for definition in above attribute hierachy. Subordinate attributes are designated by the country code information (see aml-lang literal). + + + + Identifies the attribute for valueFormat in above attribute hierarchy. + + + + Identifies the attribute for valueList in above attribute hierarchy. + + + + The attribute value. + + + + The id for the value. + + + + + + + diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/Deserializer.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/Deserializer.java index 62a955ba..a79c4ab5 100644 --- a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/Deserializer.java +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/Deserializer.java @@ -27,18 +27,17 @@ import io.adminshell.aas.v3.model.*; /** - * * Generic deserializer interface to deserialize a given string, Outputstream - * or java.io.File into an instance of AssetAdministrationShellEnvironment + * Generic deserializer interface to deserialize a given string, Outputstream or + * java.io.File into an instance of AssetAdministrationShellEnvironment */ public interface Deserializer { /** - * * Default charset that will be used when no charset is specified + * Default charset that will be used when no charset is specified */ Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; /** - * * * Deserializes a given string into an instance of * AssetAdministrationShellEnvironment * @@ -50,7 +49,6 @@ public interface Deserializer { AssetAdministrationShellEnvironment read(String value) throws DeserializationException; /** - * * * Deserializes a given InputStream into an instance of * AssetAdministrationShellEnvironment using DEFAULT_CHARSET * @@ -64,7 +62,6 @@ default AssetAdministrationShellEnvironment read(InputStream src) throws Deseria } /** - * * * Deserializes a given InputStream into an instance of * AssetAdministrationShellEnvironment using a given charset * @@ -81,9 +78,7 @@ default AssetAdministrationShellEnvironment read(InputStream src, Charset charse .collect(Collectors.joining(System.lineSeparator()))); } - // Note that the AAS also defines a file class /** - * * * Deserializes a given File into an instance of * AssetAdministrationShellEnvironment using DEFAULT_CHARSET * @@ -100,7 +95,6 @@ default AssetAdministrationShellEnvironment read(java.io.File file, Charset char } /** - * * * Deserializes a given File into an instance of * AssetAdministrationShellEnvironment using a given charset * @@ -115,7 +109,6 @@ default AssetAdministrationShellEnvironment read(java.io.File file) throws FileN } /** - * * * Enables usage of custom implementation to be used for deserialization * instead of default implementation, e.g. defining a custom implementation * of the Submodel interface {@code class diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/DataSpecificationInfo.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/DataSpecificationInfo.java new file mode 100644 index 00000000..a8731eb1 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/DataSpecificationInfo.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.core; + +import io.adminshell.aas.v3.model.DataSpecificationContent; +import io.adminshell.aas.v3.model.Reference; + +/** + * Class representing all information required for a (custom) data specification + */ +public class DataSpecificationInfo { + + private final Class type; + private final Reference reference; + private final String prefix; + + public DataSpecificationInfo(Class type, Reference reference, String prefix) { + this.type = type; + this.reference = reference; + this.prefix = prefix; + } + + public Class getType() { + return type; + } + + public Reference getReference() { + return reference; + } + + public String getPrefix() { + return prefix; + } +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/DataSpecificationManager.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/DataSpecificationManager.java index be9bf22a..73feb594 100644 --- a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/DataSpecificationManager.java +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/DataSpecificationManager.java @@ -15,8 +15,8 @@ */ package io.adminshell.aas.v3.dataformat.core; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; import java.util.Arrays; -import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -27,43 +27,35 @@ import io.adminshell.aas.v3.model.Reference; import io.adminshell.aas.v3.model.impl.DefaultKey; import io.adminshell.aas.v3.model.impl.DefaultReference; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; /** * This class is used to manage supported data specification templates. Each - * template is identified through a reference and provides a corresponding Java - * class. + * template is identified through a reference and a prefix and provides a + * corresponding Java class. */ public class DataSpecificationManager { public static final String PROP_DATA_SPECIFICATION = "dataSpecification"; public static final String PROP_DATA_SPECIFICATION_CONTENT = "dataSpecificationContent"; + public static final String DATA_SPECIFICATION_IEC61360_IRI = "http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0"; + public static final String DATA_SPECIFICATION_IEC61360_PREFIX = "IEC"; - private static final Map> KNOWN_IMPLEMENTATIONS = Map.of( - createGlobalIri("http://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/2/0"), - DataSpecificationIEC61360.class); + private static final Set KNOWN_IMPLEMENTATIONS = new HashSet<>(Arrays.asList( + new DataSpecificationInfo(DataSpecificationIEC61360.class, + createGlobalIri(DATA_SPECIFICATION_IEC61360_IRI), + DATA_SPECIFICATION_IEC61360_PREFIX))); /** - * Allows to register an additional data specification template based on any - * kind of Reference. + * Allows to register an additional data specification template * - * @param reference The reference used to identify the data specification - * template - * @param implementation The Java class implementing that template + * @param dataSpecification Details of the data specification template to + * register */ - public static void register(Reference reference, Class implementation) { - KNOWN_IMPLEMENTATIONS.put(reference, implementation); - } - - /** - * Allows to register an additional data specification template based on a - * global IRI. - * - * @param iri The IRI of the global reference used to identify the data - * specification template - * @param implementation The Java class implementing that template - */ - public static void registerGlobalIri(String iri, Class implementation) { - KNOWN_IMPLEMENTATIONS.put(createGlobalIri(iri), implementation); + public static void register(DataSpecificationInfo dataSpecification) { + KNOWN_IMPLEMENTATIONS.add(dataSpecification); } private static Reference createGlobalIri(String iri) { @@ -73,62 +65,44 @@ private static Reference createGlobalIri(String iri) { } /** - * Returns a Reference describing the data specification template - * implemented by the given class. If the class is unknown, an - * IllegalArgumentException is thrown + * Returns a DataSpecificationInfo describing the data specification + * template implemented by the given class. If the class is unknown, null is + * returned. * * @param implementation type of the implementation class - * @return a reference describing the data specification template - * implemented by the given class - * @throws IllegalArgumentException when implementation class is not known + * @return a DataSpecificationInfo describing the data specification + * template represented by the given class, or null if the implementation + * class does not represent any data specification */ - public static Reference getReference(Class implementation) { - Reference result = getReferenceSafe(implementation); + public static DataSpecificationInfo getDataSpecification(Class implementation) { + DataSpecificationInfo result = getDataSpecification(x -> Objects.equals(x.getType(), implementation)); if (result == null) { - throw new IllegalArgumentException( - String.format("unknown data specification implementation '%s'", implementation.getName())); + result = getDataSpecification(x -> x.getType().isAssignableFrom(implementation)); } return result; } /** - * Returns a Reference describing the data specification template - * implemented by the given class. If the class is unknown, null is + * Returns a DataSpecificationInfo describing the data specification + * template implemented by the given class. If the class is unknown, null is * returned. * - * @param implementation type of the implementation class - * @return a reference describing the data specification template - * implemented by the given class, or null if the implementation class is - * unknown + * @param reference Reference associated with the wanted data specficiation + * @return a DataSpecificationInfo describing the data specification + * template represented by the reference, or null if the reference does not + * represent any data specification */ - public static Reference getReferenceSafe(Class implementation) { - Optional exactMatch = KNOWN_IMPLEMENTATIONS.entrySet().stream() - .filter(x -> Objects.equals(x.getValue(), implementation)).map(x -> x.getKey()).findFirst(); + public static DataSpecificationInfo getDataSpecification(Reference reference) { + return getDataSpecification(x -> AasUtils.sameAs(x.getReference(), reference)); + } + + private static DataSpecificationInfo getDataSpecification(Predicate filter) { + Optional exactMatch = KNOWN_IMPLEMENTATIONS.stream() + .filter(filter) + .findFirst(); if (exactMatch.isPresent()) { return exactMatch.get(); } - Optional inheritanceMatch = KNOWN_IMPLEMENTATIONS.entrySet().stream() - .filter(x -> x.getValue().isAssignableFrom(implementation)).map(x -> x.getKey()).findFirst(); - if (inheritanceMatch.isPresent()) { - return inheritanceMatch.get(); - } return null; } - - /** - * Returns the Java class implementing the data specification template - * identified by the given reference. If the reference is unkown - * - * @param reference A reference used to identify the used data specification - * template. - * @return Java class implementing the given data specification template - * @throws IllegalArgumentException if there is no known implementation for - * the given reference identifier - */ - public static Class getImplementation(Reference reference) { - if (KNOWN_IMPLEMENTATIONS.containsKey(reference)) { - return KNOWN_IMPLEMENTATIONS.get(reference); - } - throw new IllegalArgumentException(String.format("unknown data specification reference '%s'", reference)); - } } diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/ReflectionHelper.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/ReflectionHelper.java index 8d01f56a..5a421416 100644 --- a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/ReflectionHelper.java +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/ReflectionHelper.java @@ -15,14 +15,17 @@ */ package io.adminshell.aas.v3.dataformat.core; +import com.google.common.reflect.TypeToken; +import io.adminshell.aas.v3.dataformat.core.util.MostSpecificTypeTokenComparator; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; - +import org.apache.commons.lang3.ClassUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,8 +87,13 @@ public class ReflectionHelper { */ public static final Map, Set>> SUBTYPES; /** - * Expanded list of all mixin classes defined in the JSON_MIXINS_PACKAGE_NAME - * package together with the corresponding class they should be applied to. + * List of all interfaces classes defined by the AAS. + */ + public static final Set INTERFACES; + /** + * Expanded list of all mixin classes defined in the + * JSON_MIXINS_PACKAGE_NAME package together with the corresponding class + * they should be applied to. */ public static final Map, Class> JSON_MIXINS; /** @@ -104,7 +112,7 @@ public class ReflectionHelper { * not have any default implementation and therefore are excluded * explicitely. */ - public static final Set> INTERFACES_WITHOUT_DEFAULT_IMPLEMENTATION; // = List.of(DataSpecificationContent.class); + public static final Set> INTERFACES_WITHOUT_DEFAULT_IMPLEMENTATION; /** * List of enums from the MODEL_PACKAGE_NAME package. */ @@ -135,7 +143,7 @@ public Class getImplementationType() { * * @param type the class to check * @return whether the given class is an interface and from within the - * MODEL_PACKAGE_NAME package + * MODEL_PACKAGE_NAME package */ public static boolean isModelInterface(Class type) { return type.isInterface() && MODEL_PACKAGE_NAME.equals(type.getPackageName()); @@ -167,19 +175,45 @@ public static boolean hasDefaultImplementation(Class interfaceType) { * * @param type the class to check * @return whether the given class is an interface from within the - * MODEL_PACKAGE_NAME package as well as a default implementation or not + * MODEL_PACKAGE_NAME package as well as a default implementation or not */ public static boolean isModelInterfaceOrDefaultImplementation(Class type) { return isModelInterface(type) || isDefaultImplementation(type); } + public static Class getAasInterface(Class type) { + Set> implementedAasInterfaces = getAasInterfaces(type); + if (implementedAasInterfaces.isEmpty()) { + return null; + } + if (implementedAasInterfaces.size() == 1) { + return implementedAasInterfaces.iterator().next(); + } + logger.warn("class '{}' implements more than one AAS interface, but only most specific one is returned", type.getName()); + return implementedAasInterfaces.stream().map(x -> TypeToken.of(x)) + .sorted(new MostSpecificTypeTokenComparator()) + .findFirst().get() + .getRawType(); + } + + public static Set> getAasInterfaces(Class type) { + Set> result = new HashSet<>(); + if (type != null) { + if (INTERFACES.contains(type)) { + result.add(type); + } + result.addAll(ClassUtils.getAllInterfaces(type).stream().filter(x -> INTERFACES.contains(x)).collect(Collectors.toSet())); + } + return result; + } + /** * Returns the AAS type information used for de-/serialization for a given * class or null if type information should not be included * * @param clazz the class to find the type information for * @return the type information for the given class or null if there is no - * type information or type information should not be included + * type information or type information should not be included */ public static String getModelType(Class clazz) { Class type = getMostSpecificTypeWithModelType(clazz); @@ -205,9 +239,12 @@ public static String getModelType(Class clazz) { * * @param clazz the class to find the type for * @return the most specific supertype of given class that contains some AAS - * type information or null if there is none + * type information or null if there is none */ public static Class getMostSpecificTypeWithModelType(Class clazz) { + if (clazz == null) { + return null; + } return TYPES_WITH_MODEL_TYPE.stream() .filter(x -> clazz.isInterface() ? x.equals(clazz) : x.isAssignableFrom(clazz)) .sorted((Class o1, Class o2) -> { @@ -239,6 +276,7 @@ public static Class getMostSpecificTypeWithModelType(Class clazz) { JSON_MIXINS = scanMixins(modelScan, JSON_MIXINS_PACKAGE_NAME); XML_MIXINS = scanMixins(modelScan, XML_MIXINS_PACKAGE_NAME); DEFAULT_IMPLEMENTATIONS = scanDefaultImplementations(modelScan); + INTERFACES = scanAasInterfaces(); ENUMS = modelScan.getAllEnums().loadClasses(Enum.class); INTERFACES_WITHOUT_DEFAULT_IMPLEMENTATION = getInterfacesWithoutDefaultImplementation(modelScan); } @@ -249,6 +287,19 @@ private static Set> getInterfacesWithoutDefaultImplementation(ScanResul .collect(Collectors.toSet()); } + public static Set> getSuperTypes(Class clazz, boolean recursive) { + Set> result = SUBTYPES.entrySet().stream() + .filter(x -> x.getValue().contains(clazz)) + .map(x -> x.getKey()) + .collect(Collectors.toSet()); + if (recursive) { + result.addAll(result.stream() + .flatMap(x -> getSuperTypes(x, true).stream()) + .collect(Collectors.toSet())); + } + return result; + } + private static List scanDefaultImplementations(ScanResult modelScan) { ScanResult defaulImplementationScan = new ClassGraph() .enableClassInfo() @@ -276,6 +327,10 @@ private static List scanDefaultImplementations(ScanResult mo return defaultImplementations; } + private static Set scanAasInterfaces() { + return DEFAULT_IMPLEMENTATIONS.stream().map(x -> x.interfaceType).collect(Collectors.toSet()); + } + private static Map, Class> scanMixins(ScanResult modelScan, String packageName) { ScanResult mixinScan = new ClassGraph() .enableClassInfo() diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EmbeddedDataSpecificationDeserializer.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EmbeddedDataSpecificationDeserializer.java index 8d3b4125..2c031437 100644 --- a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EmbeddedDataSpecificationDeserializer.java +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EmbeddedDataSpecificationDeserializer.java @@ -60,7 +60,7 @@ public EmbeddedDataSpecification deserialize(JsonParser parser, DeserializationC Reference reference = parserReference.readValueAs(Reference.class); JsonNode nodeContent = node.get(PROP_DATA_SPECIFICATION_CONTENT); if (nodeContent != null) { - Class targetClass = DataSpecificationManager.getImplementation(reference); + Class targetClass = DataSpecificationManager.getDataSpecification(reference).getType(); JsonParser parserContent = parser.getCodec().getFactory().getCodec().treeAsTokens(nodeContent); parserContent.nextToken(); DataSpecificationContent content = parserContent.readValueAs(targetClass); diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EnumDeserializer.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EnumDeserializer.java index a1769054..ec1ed975 100644 --- a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EnumDeserializer.java +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/deserialization/EnumDeserializer.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; /** * Deserializes enum values converting element names from UpperCamelCase to @@ -30,7 +31,6 @@ */ public class EnumDeserializer extends JsonDeserializer { - protected static final char UNDERSCORE = '_'; protected final Class type; public EnumDeserializer(Class type) { @@ -39,27 +39,7 @@ public EnumDeserializer(Class type) { @Override public T deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException { - return (T) Enum.valueOf(type, translate(parser.getText())); + return (T) Enum.valueOf(type, AasUtils.deserializeEnumName(parser.getText())); } - /** - * Translates an enum value from CamelCase to SCREAMING_SNAKE_CASE - * @param input input name in CamelCase - * @return name in SCREAMING_SNAKE_CASE - */ - public static String translate(String input) { - String result = ""; - if (input == null || input.isEmpty()) { - return result; - } - result += input.charAt(0); - for (int i = 1; i < input.length(); i++) { - char currentChar = input.charAt(i); - if (Character.isUpperCase(currentChar)) { - result += UNDERSCORE; - } - result += Character.toUpperCase(currentChar); - } - return result; - } } diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EmbeddedDataSpecificationSerializer.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EmbeddedDataSpecificationSerializer.java index 0be44532..a7b8f2e2 100644 --- a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EmbeddedDataSpecificationSerializer.java +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EmbeddedDataSpecificationSerializer.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import io.adminshell.aas.v3.dataformat.core.DataSpecificationInfo; import io.adminshell.aas.v3.dataformat.core.DataSpecificationManager; import io.adminshell.aas.v3.model.DataSpecificationContent; @@ -52,7 +53,8 @@ public void serialize(EmbeddedDataSpecification data, JsonGenerator generator, S Reference reference = null; DataSpecificationContent content = data.getDataSpecificationContent(); if (content != null) { - Reference implicitType = DataSpecificationManager.getReferenceSafe(content.getClass()); + DataSpecificationInfo implicitDataSpecification = DataSpecificationManager.getDataSpecification(content.getClass()); + Reference implicitType = implicitDataSpecification != null ? implicitDataSpecification.getReference() : null; Reference explicitType = data.getDataSpecification(); if (implicitType == null) { logger.warn( diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EnumSerializer.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EnumSerializer.java index e9e6004d..cea7e38f 100644 --- a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EnumSerializer.java +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/serialization/EnumSerializer.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; /** * Serializes enum values. If enum is part of the AAS Java model, the name will @@ -34,32 +35,10 @@ public class EnumSerializer extends JsonSerializer { @Override public void serialize(Enum value, JsonGenerator gen, SerializerProvider provider) throws IOException { if (ReflectionHelper.ENUMS.contains(value.getClass())) { - gen.writeString(translate(value.name())); + gen.writeString(AasUtils.serializeEnumName(value.name())); } else { provider.findValueSerializer(Enum.class).serialize(value, gen, provider); } } - /** - * Translates an enum value from SCREAMING_SNAKE_CASE to CamelCase - * - * @param input input name in SCREAMING_SNAKE_CASE - * @return name in CamelCase - */ - public static String translate(String input) { - String result = ""; - boolean capitalize = true; - for (int i = 0; i < input.length(); i++) { - char currentChar = input.charAt(i); - if (UNDERSCORE == currentChar) { - capitalize = true; - } else { - result += capitalize - ? currentChar - : Character.toLowerCase(currentChar); - capitalize = false; - } - } - return result; - } } diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/AasUtils.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/AasUtils.java new file mode 100644 index 00000000..ebc40a9d --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/AasUtils.java @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.core.util; + +import com.google.common.base.Objects; +import com.google.common.reflect.TypeToken; +import io.adminshell.aas.v3.dataformat.core.ReflectionHelper; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.Identifiable; +import io.adminshell.aas.v3.model.Key; +import io.adminshell.aas.v3.model.KeyElements; +import io.adminshell.aas.v3.model.KeyType; +import io.adminshell.aas.v3.model.ModelingKind; +import io.adminshell.aas.v3.model.Operation; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.Submodel; +import io.adminshell.aas.v3.model.impl.DefaultKey; +import io.adminshell.aas.v3.model.impl.DefaultReference; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides utility functions related to AAS + */ +public class AasUtils { + + private static final Logger log = LoggerFactory.getLogger(AasUtils.class); + + private static final char UNDERSCORE = '_'; + + private AasUtils() { + } + + /** + * Formats a Reference as string + * + * @param reference Reference to serialize + * @return string representation of the reference for serialization, null if + * reference is null + */ + public static String asString(Reference reference) { + if (reference == null) { + return null; + } + return reference.getKeys().stream() + .map(x -> String.format("(%s)[%s]%s", serializeEnumName(x.getType().name()), x.getIdType(), x.getValue())) + .collect(Collectors.joining(",")); + } + + /** + * Checks if a reference is a local reference or not. This functionality may + * not be 100% correct as since v3.0RC01 of the AAS specification there no + * longer is an isLocal property to check this and no alternative way to + * determine whether a reference is local or not is introduced. This method + * only checks for the presence of any Key with type GLOBAL_REFERENCE. + * Another approach would be to actually try resolving the reference + * locally. + * + * @param reference The reference to check + * @param environment The environment context the reference resides. In + * current implementation this is not used + * @return true if the reference is a local reference to the given + * environment, false otherwise + */ + public static boolean isLocal(Reference reference, AssetAdministrationShellEnvironment environment) { + return !reference.getKeys().stream().anyMatch(x -> x.getType() == KeyElements.GLOBAL_REFERENCE); + } + + public static List getSubmodelTemplates(AssetAdministrationShell aas, AssetAdministrationShellEnvironment environment) { + return aas.getSubmodels().stream() + .map(ref -> resolve(ref, environment, Submodel.class)) + .filter(sm -> sm != null) + .filter(sm -> sm.getKind() != ModelingKind.INSTANCE) + .collect(Collectors.toList()); + } + + public static boolean hasTemplate(AssetAdministrationShell aas, AssetAdministrationShellEnvironment environment) { + return !getSubmodelTemplates(aas, environment).isEmpty(); + } + + /** + * Creates a reference for an Identifiable instance + * + * @param identifiable the identifiable to create the reference for + * @return a reference representing the identifiable + */ + public static Reference toReference(Identifiable identifiable) { + return new DefaultReference.Builder() + .key(new DefaultKey.Builder() + .type(referableToKeyType(identifiable)) + .idType(KeyType.valueOf(identifiable.getIdentification().getIdType().toString())) + .value(identifiable.getIdentification().getIdentifier()) + .build()) + .build(); + } + + /** + * Gets the KeyElements type matching the provided Referable + * + * @param referable The referable to convert to KeyElements type + * @return the most specific KeyElements type representing the Referable, + * i.e. abstract types like SUBMODEL_ELEMENT or DATA_ELEMENT are never + * returned; null if there is no corresponding KeyElements type + */ + public static KeyElements referableToKeyType(Referable referable) { + Class aasInterface = ReflectionHelper.getAasInterface(referable.getClass()); + if (aasInterface != null) { + return KeyElements.valueOf(deserializeEnumName(aasInterface.getSimpleName())); + } + return null; + } + + /** + * Translates an enum value from SCREAMING_SNAKE_CASE to CamelCase + * + * @param input input name in SCREAMING_SNAKE_CASE + * @return name in CamelCase + */ + public static String serializeEnumName(String input) { + String result = ""; + boolean capitalize = true; + for (int i = 0; i < input.length(); i++) { + char currentChar = input.charAt(i); + if (UNDERSCORE == currentChar) { + capitalize = true; + } else { + result += capitalize + ? currentChar + : Character.toLowerCase(currentChar); + capitalize = false; + } + } + return result; + } + + /** + * Translates an enum value from CamelCase to SCREAMING_SNAKE_CASE + * + * @param input input name in CamelCase + * @return name in SCREAMING_SNAKE_CASE + */ + public static String deserializeEnumName(String input) { + String result = ""; + if (input == null || input.isEmpty()) { + return result; + } + result += input.charAt(0); + for (int i = 1; i < input.length(); i++) { + char currentChar = input.charAt(i); + if (Character.isUpperCase(currentChar)) { + result += UNDERSCORE; + } + result += Character.toUpperCase(currentChar); + } + return result; + } + + /** + * Gets a Java interface representing the type provided by key. + * + * @param key The KeyElements type + * @return a Java interface representing the provided KeyElements type or + * null if no matching Class/interface could be found. It also returns + * abstract types like SUBMODEL_ELEMENT or DATA_ELEMENT + */ + public static Class keyTypeToClass(KeyElements key) { + return Stream.concat(ReflectionHelper.INTERFACES.stream(), ReflectionHelper.INTERFACES_WITHOUT_DEFAULT_IMPLEMENTATION.stream()) + .filter(x -> x.getSimpleName().equals(serializeEnumName(key.name()))) + .findAny() + .orElse(null); + } + + /** + * Creates a reference for an element given a potential parent + * + * @param parent Reference to the parent. Can only be null when element is + * instance of Identifiable, otherwise result will always be null + * @param element the element to create a reference for + * @return A reference representing the element or null if either element is + * null or parent is null and element not an instance of Identifiable. In + * case element is an instance of Identifiable, the returned reference will + * only contain one key pointing directly to the element. + */ + public static Reference toReference(Reference parent, Referable element) { + if (element == null) { + return null; + } else if (Identifiable.class.isAssignableFrom(element.getClass())) { + return toReference((Identifiable) element); + } else { + Reference result = clone(parent); + if (result != null) { + result.getKeys().add(new DefaultKey.Builder() + .type(AasUtils.referableToKeyType(element)) + .idType(KeyType.ID_SHORT) + .value(element.getIdShort()) + .build()); + } + return result; + } + } + + /** + * Checks if two references are refering to the same element + * + * @param ref1 reference 1 + * @param ref2 reference 2 + * @return returns true if both references are refering to the same element, + * otherwise false + */ + public static boolean sameAs(Reference ref1, Reference ref2) { + boolean ref1Empty = ref1 == null || ref1.getKeys() == null || ref1.getKeys().isEmpty(); + boolean ref2Empty = ref2 == null || ref2.getKeys() == null || ref2.getKeys().isEmpty(); + if (ref1Empty && ref2Empty) { + return true; + } + if (ref1Empty != ref2Empty) { + return false; + } + int keyLength = Math.min(ref1.getKeys().size(), ref2.getKeys().size()); + for (int i = 0; i < keyLength; i++) { + Key ref1Key = ref1.getKeys().get(ref1.getKeys().size() - (i + 1)); + Key ref2Key = ref2.getKeys().get(ref2.getKeys().size() - (i + 1)); + Class ref1Type = keyTypeToClass(ref1Key.getType()); + Class ref2Type = keyTypeToClass(ref2Key.getType()); + if ((ref1Type == null && ref2Type != null) + || (ref1Type != null && ref2Type == null)) { + return false; + } + if (ref1Type != ref2Type) { + if (!(ref1Type.isAssignableFrom(ref2Type) + || ref2Type.isAssignableFrom(ref1Type))) { + return false; + } + } + if (!(Objects.equal(ref1Key.getIdType(), ref2Key.getIdType()) + && Objects.equal(ref1Key.getValue(), ref2Key.getValue()))) { + return false; + } + if ((ref1Key.getIdType() == KeyType.IRI) + || (ref1Key.getIdType() == KeyType.IRDI) + || (ref1Key.getIdType() == KeyType.CUSTOM)) { + return true; + } + } + return true; + } + + /** + * Creates a deep-copy clone of a reference + * + * @param reference the reference to clone + * @return the cloned reference + */ + public static Reference clone(Reference reference) { + if (reference == null || reference.getKeys() == null || reference.getKeys().isEmpty()) { + return null; + } + return new DefaultReference.Builder() + .keys(reference.getKeys().stream().map(x -> new DefaultKey.Builder() + .idType(x.getIdType()) + .type(x.getType()) + .value(x.getValue()) + .build()) + .collect(Collectors.toList())) + .build(); + } + + /** + * Resolves a Reference within an AssetAdministrationShellEnvironment and + * returns the targeted object if available, null otherwise + * + * + * @param reference The reference to resolve + * @param env The AssetAdministrationShellEnvironment to resolve the + * reference against + * @return returns an instance of T if the reference could successfully be + * resolved, otherwise null + * @throws IllegalArgumentException if something goes wrong while resolving + */ + public static Referable resolve(Reference reference, AssetAdministrationShellEnvironment env) { + return resolve(reference, env, Referable.class); + } + + /** + * Resolves a Reference within an AssetAdministrationShellEnvironment and + * returns the targeted object if available, null otherwise + * + * @param sub-type of Referable of the targeted type. If unknown use + * Referable.class + * @param reference The reference to resolve + * @param env The AssetAdministrationShellEnvironment to resolve the + * reference against + * @param type desired return type, use Referable.class is unknwon/not + * needed + * @return returns an instance of T if the reference could successfully be + * resolved, otherwise null + * @throws IllegalArgumentException if something goes wrong while resolving + */ + public static T resolve(Reference reference, AssetAdministrationShellEnvironment env, Class type) { + if (reference == null || reference.getKeys() == null || reference.getKeys().isEmpty()) { + return null; + } + Set identifiables = new IdentifiableCollector(env).collect(); + Object current = null; + int i = reference.getKeys().size() - 1; + if (type != null) { + Class actualType = keyTypeToClass(reference.getKeys().get(i).getType()); + if (!type.isAssignableFrom(actualType)) { + log.warn("reference {} could not be resolved as target type is not assignable from actual type (target: {}, actual: {})", + asString(reference), type.getName(), actualType.getName()); + return null; + } + } + for (; i >= 0; i--) { + Key key = reference.getKeys().get(i); + Class referencedType = keyTypeToClass(key.getType()); + if (referencedType != null) { + List matchingIdentifiables = identifiables.stream() + .filter(x -> referencedType.isAssignableFrom(x.getClass())) + .filter(x -> key.getIdType().name().equals(x.getIdentification().getIdType().name())) + .filter(x -> x.getIdentification().getIdentifier().equals(key.getValue())) + .collect(Collectors.toList()); + if (matchingIdentifiables.size() > 1) { + throw new IllegalArgumentException("found multiple matching Identifiables for id '" + key.getValue() + "'"); + } + if (matchingIdentifiables.size() == 1) { + current = matchingIdentifiables.get(0); + break; + } + } + } + if (current == null) { + return null; + } + i++; + if (i == reference.getKeys().size()) { + return (T) current; + } + // follow idShort path until target + for (; i < reference.getKeys().size(); i++) { + Key key = reference.getKeys().get(i); + Class keyType = keyTypeToClass(key.getType()); + if (keyType != null) { + Collection collection; + // operation needs special handling because of nested values + if (Operation.class.isAssignableFrom(current.getClass())) { + Operation operation = (Operation) current; + + collection = Stream.of(operation.getInputVariables().stream(), + operation.getOutputVariables().stream(), + operation.getInoutputVariables().stream()) + .flatMap(x -> x.map(y -> y.getValue())) + .collect(Collectors.toSet()); + } else { + List matchingProperties = getAasProperties(current.getClass()).stream() + .filter(x -> Collection.class.isAssignableFrom(x.getReadMethod().getReturnType())) + .filter(x -> TypeToken.of(x.getReadMethod().getGenericReturnType()) + .resolveType(Collection.class.getTypeParameters()[0]) + .isSupertypeOf(keyType)) + .collect(Collectors.toList()); + if (matchingProperties.isEmpty()) { + throw new IllegalArgumentException(String.format("error resolving reference - could not find matching property for type %s in class %s", + keyType.getSimpleName(), + current.getClass().getSimpleName())); + } + if (matchingProperties.size() > 1) { + throw new IllegalArgumentException(String.format("error resolving reference - found %d possible property paths for class %s (%s)", + matchingProperties.size(), + current.getClass().getSimpleName(), + matchingProperties.stream() + .map(x -> x.getName()) + .collect(Collectors.joining(", ")))); + } + try { + collection = (Collection) matchingProperties.get(0).getReadMethod().invoke(current); + } catch (Exception ex) { + throw new IllegalArgumentException("error resolving reference", ex); + } + Optional next = collection.stream() + .filter(x -> ((Referable) x).getIdShort().equals(key.getValue())) + .findFirst(); + if (next.isEmpty()) { + throw new IllegalArgumentException("error resolving reference - could not find idShort " + key.getValue()); + } + current = next.get(); + } + } + } + return (T) current; + } + + /** + * Gets a list of all properties defined for a class implementing at least + * one AAS interface. + * + * @param type A class implementing at least one AAS interface. If it is + * does not implement any AAS interface the result will be an empty list + * @return a list of all properties defined in any of AAS interface + * implemented by type. If type does not implement any AAS interface an + * empty list is returned. + */ + public static List getAasProperties(Class type) { + Class aasType = ReflectionHelper.getAasInterface(type); + Set> types = new HashSet<>(); + if (aasType != null) { + types.add(aasType); + types.addAll(ReflectionHelper.getSuperTypes(aasType, true)); + } + return types.stream() + .flatMap(x -> { + try { + return Stream.of(Introspector.getBeanInfo(x).getPropertyDescriptors()); + } catch (IntrospectionException ex) { + log.warn("error finding properties of class '{}'", type, ex); + } + return Stream.empty(); + }) + .sorted(Comparator.comparing(x -> x.getName())) + .collect(Collectors.toList()); + } +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/IdentifiableCollector.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/IdentifiableCollector.java new file mode 100644 index 00000000..c66b680e --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/IdentifiableCollector.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.core.util; + +import io.adminshell.aas.v3.dataformat.core.visitor.AssetAdministrationShellElementWalkerVisitor; +import io.adminshell.aas.v3.model.Asset; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.ConceptDescription; +import io.adminshell.aas.v3.model.Identifiable; +import io.adminshell.aas.v3.model.Submodel; +import java.util.HashSet; +import java.util.Set; + +/** + * Collects all Identifiable elements within an + * AssetAdministrationShellEnvironment + */ +public class IdentifiableCollector { + + private AssetAdministrationShellEnvironment env; + + public IdentifiableCollector(AssetAdministrationShellEnvironment env) { + this.env = env; + } + + public Set collect() { + Visitor visitor = new Visitor(); + visitor.visit(env); + return visitor.identifiables; + } + + private class Visitor implements AssetAdministrationShellElementWalkerVisitor { + + Set identifiables = new HashSet<>(); + + @Override + public void visit(AssetAdministrationShell value) { + identifiables.add(value); + AssetAdministrationShellElementWalkerVisitor.super.visit(value); + } + + @Override + public void visit(Asset value) { + identifiables.add(value); + AssetAdministrationShellElementWalkerVisitor.super.visit(value); + } + + @Override + public void visit(Submodel value) { + identifiables.add(value); + AssetAdministrationShellElementWalkerVisitor.super.visit(value); + } + + @Override + public void visit(ConceptDescription value) { + identifiables.add(value); + AssetAdministrationShellElementWalkerVisitor.super.visit(value); + } + } +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/MostSpecificTypeTokenComparator.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/MostSpecificTypeTokenComparator.java new file mode 100644 index 00000000..6257c6e3 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/util/MostSpecificTypeTokenComparator.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.core.util; + +import com.google.common.reflect.TypeToken; +import java.util.Comparator; + +/** + * Comparator comparing two TypeToken regarding which type is more specific. + */ +public class MostSpecificTypeTokenComparator implements Comparator { + + @Override + public int compare(TypeToken x, TypeToken y) { + if (x.isSubtypeOf(y)) { + if (y.isSubtypeOf(x)) { + return 0; + } + return -1; + } + return 1; + } +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/visitor/AssetAdministrationShellElementVisitor.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/visitor/AssetAdministrationShellElementVisitor.java new file mode 100644 index 00000000..deeafa2d --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/visitor/AssetAdministrationShellElementVisitor.java @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.core.visitor; + +import io.adminshell.aas.v3.model.AccessControl; +import io.adminshell.aas.v3.model.AccessControlPolicyPoints; +import io.adminshell.aas.v3.model.AccessPermissionRule; +import io.adminshell.aas.v3.model.AdministrativeInformation; +import io.adminshell.aas.v3.model.AnnotatedRelationshipElement; +import io.adminshell.aas.v3.model.Asset; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.AssetInformation; +import io.adminshell.aas.v3.model.BasicEvent; +import io.adminshell.aas.v3.model.Blob; +import io.adminshell.aas.v3.model.BlobCertificate; +import io.adminshell.aas.v3.model.Capability; +import io.adminshell.aas.v3.model.Certificate; +import io.adminshell.aas.v3.model.ConceptDescription; +import io.adminshell.aas.v3.model.Constraint; +import io.adminshell.aas.v3.model.DataElement; +import io.adminshell.aas.v3.model.DataSpecificationContent; +import io.adminshell.aas.v3.model.DataSpecificationIEC61360; +import io.adminshell.aas.v3.model.DataSpecificationPhysicalUnit; +import io.adminshell.aas.v3.model.EmbeddedDataSpecification; +import io.adminshell.aas.v3.model.Entity; +import io.adminshell.aas.v3.model.Event; +import io.adminshell.aas.v3.model.EventElement; +import io.adminshell.aas.v3.model.EventMessage; +import io.adminshell.aas.v3.model.Extension; +import io.adminshell.aas.v3.model.File; +import io.adminshell.aas.v3.model.Formula; +import io.adminshell.aas.v3.model.HasDataSpecification; +import io.adminshell.aas.v3.model.HasExtensions; +import io.adminshell.aas.v3.model.HasKind; +import io.adminshell.aas.v3.model.HasSemantics; +import io.adminshell.aas.v3.model.Identifiable; +import io.adminshell.aas.v3.model.Identifier; +import io.adminshell.aas.v3.model.IdentifierKeyValuePair; +import io.adminshell.aas.v3.model.Key; +import io.adminshell.aas.v3.model.LangString; +import io.adminshell.aas.v3.model.MultiLanguageProperty; +import io.adminshell.aas.v3.model.ObjectAttributes; +import io.adminshell.aas.v3.model.Operation; +import io.adminshell.aas.v3.model.OperationVariable; +import io.adminshell.aas.v3.model.Permission; +import io.adminshell.aas.v3.model.PermissionsPerObject; +import io.adminshell.aas.v3.model.PolicyAdministrationPoint; +import io.adminshell.aas.v3.model.PolicyDecisionPoint; +import io.adminshell.aas.v3.model.PolicyEnforcementPoints; +import io.adminshell.aas.v3.model.PolicyInformationPoints; +import io.adminshell.aas.v3.model.Property; +import io.adminshell.aas.v3.model.Qualifiable; +import io.adminshell.aas.v3.model.Qualifier; +import io.adminshell.aas.v3.model.Range; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.ReferenceElement; +import io.adminshell.aas.v3.model.RelationshipElement; +import io.adminshell.aas.v3.model.Security; +import io.adminshell.aas.v3.model.SubjectAttributes; +import io.adminshell.aas.v3.model.Submodel; +import io.adminshell.aas.v3.model.SubmodelElement; +import io.adminshell.aas.v3.model.SubmodelElementCollection; +import io.adminshell.aas.v3.model.ValueList; +import io.adminshell.aas.v3.model.ValueReferencePair; +import io.adminshell.aas.v3.model.View; + +public interface AssetAdministrationShellElementVisitor { + + public default void visit(Certificate certificate) { + if (certificate == null) { + return; + } + Class type = certificate.getClass(); + if (BlobCertificate.class.isAssignableFrom(type)) { + visit((BlobCertificate) certificate); + } + } + + public default void visit(Constraint constraint) { + if (constraint == null) { + return; + } + Class type = constraint.getClass(); + if (Qualifier.class.isAssignableFrom(type)) { + visit((Qualifier) constraint); + } else if (Formula.class.isAssignableFrom(type)) { + visit((Formula) constraint); + } + } + + public default void visit(DataElement dataElement) { + if (dataElement == null) { + return; + } + Class type = dataElement.getClass(); + if (Property.class.isAssignableFrom(type)) { + visit((Property) dataElement); + } else if (MultiLanguageProperty.class.isAssignableFrom(type)) { + visit((MultiLanguageProperty) dataElement); + } else if (Range.class.isAssignableFrom(type)) { + visit((Range) dataElement); + } else if (ReferenceElement.class.isAssignableFrom(type)) { + visit((ReferenceElement) dataElement); + } else if (File.class.isAssignableFrom(type)) { + visit((File) dataElement); + } else if (Blob.class.isAssignableFrom(type)) { + visit((Blob) dataElement); + } + } + + public default void visit(DataSpecificationContent dataSpecificationContent) { + if (dataSpecificationContent == null) { + return; + } + Class type = dataSpecificationContent.getClass(); + if (DataSpecificationIEC61360.class.isAssignableFrom(type)) { + visit((DataSpecificationIEC61360) dataSpecificationContent); + } + } + + public default void visit(Event event) { + if (event == null) { + return; + } + Class type = event.getClass(); + if (BasicEvent.class.isAssignableFrom(type)) { + visit((BasicEvent) event); + } + } + + public default void visit(HasDataSpecification hasDataSpecification) { + if (hasDataSpecification == null) { + return; + } + Class type = hasDataSpecification.getClass(); + if (AssetAdministrationShell.class.isAssignableFrom(type)) { + visit((AssetAdministrationShell) hasDataSpecification); + } else if (Submodel.class.isAssignableFrom(type)) { + visit((Submodel) hasDataSpecification); + } else if (View.class.isAssignableFrom(type)) { + visit((View) hasDataSpecification); + } else if (Asset.class.isAssignableFrom(type)) { + visit((Asset) hasDataSpecification); + } else if (SubmodelElement.class.isAssignableFrom(type)) { + visit((SubmodelElement) hasDataSpecification); + } + + } + + public default void visit(HasExtensions hasExtensions) { + if (hasExtensions == null) { + return; + } + Class type = hasExtensions.getClass(); + if (Referable.class.isAssignableFrom(type)) { + visit((Referable) hasExtensions); + } + } + + public default void visit(HasKind hasKind) { + if (hasKind == null) { + return; + } + Class type = hasKind.getClass(); + if (Submodel.class.isAssignableFrom(type)) { + visit((Submodel) hasKind); + } else if (SubmodelElement.class.isAssignableFrom(type)) { + visit((SubmodelElement) hasKind); + } + } + + public default void visit(HasSemantics hasSemantics) { + if (hasSemantics == null) { + return; + } + Class type = hasSemantics.getClass(); + if (Extension.class.isAssignableFrom(type)) { + visit((Extension) hasSemantics); + } else if (IdentifierKeyValuePair.class.isAssignableFrom(type)) { + visit((IdentifierKeyValuePair) hasSemantics); + } else if (Submodel.class.isAssignableFrom(type)) { + visit((Submodel) hasSemantics); + } else if (SubmodelElement.class.isAssignableFrom(type)) { + visit((SubmodelElement) hasSemantics); + } else if (View.class.isAssignableFrom(type)) { + visit((View) hasSemantics); + } else if (Qualifier.class.isAssignableFrom(type)) { + visit((Qualifier) hasSemantics); + } + } + + public default void visit(Identifiable identifiable) { + if (identifiable == null) { + return; + } + Class type = identifiable.getClass(); + if (AssetAdministrationShell.class.isAssignableFrom(type)) { + visit((AssetAdministrationShell) identifiable); + } else if (Asset.class.isAssignableFrom(type)) { + visit((Asset) identifiable); + } else if (Submodel.class.isAssignableFrom(type)) { + visit((Submodel) identifiable); + } else if (ConceptDescription.class.isAssignableFrom(type)) { + visit((ConceptDescription) identifiable); + } + } + + public default void visit(SubmodelElement submodelElement) { + if (submodelElement == null) { + return; + } + Class type = submodelElement.getClass(); + if (RelationshipElement.class.isAssignableFrom(type)) { + visit((RelationshipElement) submodelElement); + } else if (DataElement.class.isAssignableFrom(type)) { + visit((DataElement) submodelElement); + } else if (Capability.class.isAssignableFrom(type)) { + visit((Capability) submodelElement); + } else if (SubmodelElementCollection.class.isAssignableFrom(type)) { + visit((SubmodelElementCollection) submodelElement); + } else if (Operation.class.isAssignableFrom(type)) { + visit((Operation) submodelElement); + } else if (Event.class.isAssignableFrom(type)) { + visit((Event) submodelElement); + } else if (Entity.class.isAssignableFrom(type)) { + visit((Entity) submodelElement); + } + } + + public default void visit(Qualifiable qualifiable) { + if (qualifiable == null) { + return; + } + Class type = qualifiable.getClass(); + if (Submodel.class.isAssignableFrom(type)) { + visit((Submodel) qualifiable); + } else if (SubmodelElement.class.isAssignableFrom(type)) { + visit((SubmodelElement) qualifiable); + } else if (AccessPermissionRule.class.isAssignableFrom(type)) { + visit((AccessPermissionRule) qualifiable); + } + } + + public default void visit(Referable referable) { + if (referable == null) { + return; + } + Class type = referable.getClass(); + if (Identifiable.class.isAssignableFrom(type)) { + visit((Identifiable) referable); + } else if (SubmodelElement.class.isAssignableFrom(type)) { + visit((SubmodelElement) referable); + } else if (View.class.isAssignableFrom(type)) { + visit((View) referable); + } else if (AccessPermissionRule.class.isAssignableFrom(type)) { + visit((AccessPermissionRule) referable); + } + } + + public default void visit(AssetAdministrationShellEnvironment assetAdministrationShellEnvironment) { + } + + public default void visit(AccessControl accessControl) { + } + + public default void visit(AccessControlPolicyPoints accessControlPolicyPoints) { + } + + public default void visit(AccessPermissionRule accessPermissionRule) { + } + + public default void visit(AdministrativeInformation administrativeInformation) { + } + + public default void visit(AnnotatedRelationshipElement annotatedRelationshipElement) { + } + + public default void visit(Asset asset) { + } + + public default void visit(AssetAdministrationShell assetAdministrationShell) { + } + + public default void visit(AssetInformation assetInformation) { + } + + public default void visit(BasicEvent basicEvent) { + } + + public default void visit(Blob blob) { + } + + public default void visit(BlobCertificate blobCertificate) { + } + + public default void visit(Capability capability) { + } + + public default void visit(ConceptDescription conceptDescription) { + } + + public default void visit(DataSpecificationIEC61360 dataSpecificationIEC61360) { + } + + public default void visit(DataSpecificationPhysicalUnit dataSpecificationPhysicalUnit) { + } + + public default void visit(EmbeddedDataSpecification embeddedDataSpecification) { + } + + public default void visit(Entity entity) { + } + + public default void visit(EventElement eventElement) { + } + + public default void visit(EventMessage eventMessage) { + } + + public default void visit(Extension extension) { + } + + public default void visit(File file) { + } + + public default void visit(Formula formula) { + } + + public default void visit(Identifier identifier) { + } + + public default void visit(IdentifierKeyValuePair identifierKeyValuePair) { + } + + public default void visit(Key key) { + } + + public default void visit(LangString langString) { + } + + public default void visit(MultiLanguageProperty multiLanguageProperty) { + } + + public default void visit(ObjectAttributes objectAttributes) { + } + + public default void visit(Operation operation) { + } + + public default void visit(OperationVariable operationVariable) { + } + + public default void visit(Permission permission) { + } + + public default void visit(PermissionsPerObject permissionsPerObject) { + } + + public default void visit(PolicyAdministrationPoint policyAdministrationPoint) { + } + + public default void visit(PolicyDecisionPoint policyDecisionPoint) { + } + + public default void visit(PolicyEnforcementPoints policyEnforcementPoints) { + } + + public default void visit(PolicyInformationPoints policyInformationPoints) { + } + + public default void visit(Property property) { + } + + public default void visit(Qualifier qualifier) { + } + + public default void visit(Range range) { + } + + public default void visit(Reference reference) { + } + + public default void visit(ReferenceElement referenceElement) { + } + + public default void visit(RelationshipElement relationshipElement) { + } + + public default void visit(Security security) { + } + + public default void visit(SubjectAttributes subjectAttributes) { + } + + public default void visit(Submodel submodel) { + } + + public default void visit(SubmodelElementCollection submodelElementCollection) { + } + + public default void visit(ValueList valueList) { + } + + public default void visit(ValueReferencePair valueReferencePair) { + } + + public default void visit(View view) { + } +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/visitor/AssetAdministrationShellElementWalkerVisitor.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/visitor/AssetAdministrationShellElementWalkerVisitor.java new file mode 100644 index 00000000..b98b9520 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/core/visitor/AssetAdministrationShellElementWalkerVisitor.java @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.core.visitor; + +import io.adminshell.aas.v3.model.AccessControl; +import io.adminshell.aas.v3.model.AccessControlPolicyPoints; +import io.adminshell.aas.v3.model.AccessPermissionRule; +import io.adminshell.aas.v3.model.AnnotatedRelationshipElement; +import io.adminshell.aas.v3.model.AssetAdministrationShell; +import io.adminshell.aas.v3.model.AssetAdministrationShellEnvironment; +import io.adminshell.aas.v3.model.AssetInformation; +import io.adminshell.aas.v3.model.BasicEvent; +import io.adminshell.aas.v3.model.BlobCertificate; +import io.adminshell.aas.v3.model.Certificate; +import io.adminshell.aas.v3.model.ConceptDescription; +import io.adminshell.aas.v3.model.Entity; +import io.adminshell.aas.v3.model.Extension; +import io.adminshell.aas.v3.model.Formula; +import io.adminshell.aas.v3.model.HasDataSpecification; +import io.adminshell.aas.v3.model.HasExtensions; +import io.adminshell.aas.v3.model.HasSemantics; +import io.adminshell.aas.v3.model.Identifiable; +import io.adminshell.aas.v3.model.IdentifierKeyValuePair; +import io.adminshell.aas.v3.model.MultiLanguageProperty; +import io.adminshell.aas.v3.model.ObjectAttributes; +import io.adminshell.aas.v3.model.Operation; +import io.adminshell.aas.v3.model.OperationVariable; +import io.adminshell.aas.v3.model.Permission; +import io.adminshell.aas.v3.model.PermissionsPerObject; +import io.adminshell.aas.v3.model.PolicyAdministrationPoint; +import io.adminshell.aas.v3.model.PolicyInformationPoints; +import io.adminshell.aas.v3.model.Property; +import io.adminshell.aas.v3.model.Qualifiable; +import io.adminshell.aas.v3.model.Qualifier; +import io.adminshell.aas.v3.model.Referable; +import io.adminshell.aas.v3.model.Reference; +import io.adminshell.aas.v3.model.ReferenceElement; +import io.adminshell.aas.v3.model.RelationshipElement; +import io.adminshell.aas.v3.model.Security; +import io.adminshell.aas.v3.model.SubjectAttributes; +import io.adminshell.aas.v3.model.Submodel; +import io.adminshell.aas.v3.model.SubmodelElementCollection; +import io.adminshell.aas.v3.model.ValueList; +import io.adminshell.aas.v3.model.ValueReferencePair; +import io.adminshell.aas.v3.model.View; + +public interface AssetAdministrationShellElementWalkerVisitor extends AssetAdministrationShellElementVisitor { + + @Override + public default void visit(AccessControl accessControl) { + if (accessControl == null) { + return; + } + visit(accessControl.getDefaultEnvironmentAttributes()); + visit(accessControl.getDefaultPermissions()); + visit(accessControl.getDefaultSubjectAttributes()); + visit(accessControl.getSelectableEnvironmentAttributes()); + visit(accessControl.getSelectablePermissions()); + visit(accessControl.getSelectableSubjectAttributes()); + accessControl.getAccessPermissionRules().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(accessControl); + } + + @Override + public default void visit(AccessControlPolicyPoints accessControlPolicyPoints) { + if (accessControlPolicyPoints == null) { + return; + } + visit(accessControlPolicyPoints.getPolicyAdministrationPoint()); + visit(accessControlPolicyPoints.getPolicyDecisionPoint()); + visit(accessControlPolicyPoints.getPolicyEnforcementPoint()); + visit(accessControlPolicyPoints.getPolicyInformationPoints()); + AssetAdministrationShellElementVisitor.super.visit(accessControlPolicyPoints); + } + + @Override + public default void visit(AccessPermissionRule accessPermissionRule) { + if (accessPermissionRule == null) { + return; + } + visit(accessPermissionRule.getTargetSubjectAttributes()); + accessPermissionRule.getPermissionsPerObjects().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(accessPermissionRule); + } + + @Override + public default void visit(AnnotatedRelationshipElement annotatedRelationshipElement) { + if (annotatedRelationshipElement == null) { + return; + } + annotatedRelationshipElement.getAnnotations().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(annotatedRelationshipElement); + } + + @Override + public default void visit(AssetAdministrationShell assetAdministrationShell) { + if (assetAdministrationShell == null) { + return; + } + visit(assetAdministrationShell.getDerivedFrom()); + visit(assetAdministrationShell.getSecurity()); + visit(assetAdministrationShell.getAssetInformation()); + assetAdministrationShell.getSubmodels().forEach(x -> visit(x)); + assetAdministrationShell.getViews().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(assetAdministrationShell); + } + + @Override + public default void visit(AssetInformation assetInformation) { + if (assetInformation == null) { + return; + } + visit(assetInformation.getGlobalAssetId()); + visit(assetInformation.getDefaultThumbnail()); + assetInformation.getSpecificAssetIds().forEach(x -> visit(x)); + assetInformation.getBillOfMaterials().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(assetInformation); + } + + @Override + public default void visit(BasicEvent basicEvent) { + if (basicEvent == null) { + return; + } + visit(basicEvent.getObserved()); + AssetAdministrationShellElementVisitor.super.visit(basicEvent); + } + + @Override + public default void visit(Certificate certificate) { + if (certificate == null) { + return; + } + visit(certificate.getPolicyAdministrationPoint()); + AssetAdministrationShellElementVisitor.super.visit(certificate); + } + + @Override + public default void visit(ConceptDescription conceptDescription) { + if (conceptDescription == null) { + return; + } + conceptDescription.getIsCaseOfs().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(conceptDescription); + } + + @Override + public default void visit(HasDataSpecification hasDataSpecification) { + if (hasDataSpecification == null) { + return; + } + hasDataSpecification.getEmbeddedDataSpecifications().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(hasDataSpecification); + } + + @Override + public default void visit(HasExtensions hasExtensions) { + if (hasExtensions == null) { + return; + } + hasExtensions.getExtensions().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(hasExtensions); + } + + @Override + public default void visit(HasSemantics hasSemantics) { + if (hasSemantics == null) { + return; + } + visit(hasSemantics.getSemanticId()); + AssetAdministrationShellElementVisitor.super.visit(hasSemantics); + } + + @Override + public default void visit(Identifiable identifiable) { + if (identifiable == null) { + return; + } + visit(identifiable.getAdministration()); + visit(identifiable.getIdentification()); + AssetAdministrationShellElementVisitor.super.visit(identifiable); + } + + @Override + public default void visit(IdentifierKeyValuePair identifierKeyValuePair) { + if (identifierKeyValuePair == null) { + return; + } + visit(identifierKeyValuePair.getExternalSubjectId()); + AssetAdministrationShellElementVisitor.super.visit(identifierKeyValuePair); + } + + @Override + public default void visit(MultiLanguageProperty multiLanguageProperty) { + if (multiLanguageProperty == null) { + return; + } + multiLanguageProperty.getValues().forEach(x -> visit(x)); + visit(multiLanguageProperty.getValueId()); + AssetAdministrationShellElementVisitor.super.visit(multiLanguageProperty); + } + + @Override + public default void visit(ObjectAttributes objectAttributes) { + if (objectAttributes == null) { + return; + } + objectAttributes.getObjectAttributes().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(objectAttributes); + } + + @Override + public default void visit(OperationVariable operationVariable) { + if (operationVariable == null) { + return; + } + visit(operationVariable.getValue()); + AssetAdministrationShellElementVisitor.super.visit(operationVariable); + } + + @Override + public default void visit(PolicyInformationPoints policyInformationPoints) { + if (policyInformationPoints == null) { + return; + } + policyInformationPoints.getInternalInformationPoints().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(policyInformationPoints); + } + + @Override + public default void visit(Property property) { + if (property == null) { + return; + } + visit(property.getValueId()); + AssetAdministrationShellElementVisitor.super.visit(property); + } + + @Override + public default void visit(Qualifiable qualifiable) { + if (qualifiable == null) { + return; + } + qualifiable.getQualifiers().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(qualifiable); + } + + @Override + public default void visit(Qualifier qualifier) { + if (qualifier == null) { + return; + } + visit(qualifier.getValueId()); + AssetAdministrationShellElementVisitor.super.visit(qualifier); + } + + @Override + public default void visit(Referable referable) { + if (referable == null) { + return; + } + referable.getDescriptions().forEach(x -> visit(x)); + referable.getDisplayNames().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(referable); + } + + @Override + public default void visit(Reference reference) { + if (reference == null) { + return; + } + reference.getKeys().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(reference); + } + + @Override + public default void visit(ReferenceElement referenceElement) { + if (referenceElement == null) { + return; + } + visit(referenceElement.getValue()); + AssetAdministrationShellElementVisitor.super.visit(referenceElement); + } + + @Override + public default void visit(RelationshipElement relationshipElement) { + if (relationshipElement == null) { + return; + } + visit(relationshipElement.getFirst()); + visit(relationshipElement.getSecond()); + AssetAdministrationShellElementVisitor.super.visit(relationshipElement); + } + + @Override + public default void visit(Security security) { + if (security == null) { + return; + } + visit(security.getAccessControlPolicyPoints()); + security.getCertificates().forEach(x -> visit(x)); + security.getRequiredCertificateExtensions().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(security); + } + + @Override + public default void visit(SubjectAttributes subjectAttributes) { + if (subjectAttributes == null) { + return; + } + subjectAttributes.getSubjectAttributes().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(subjectAttributes); + } + + @Override + public default void visit(Permission permission) { + if (permission == null) { + return; + } + visit(permission.getPermission()); + AssetAdministrationShellElementVisitor.super.visit(permission); + } + + @Override + public default void visit(PermissionsPerObject permissionsPerObject) { + if (permissionsPerObject == null) { + return; + } + visit(permissionsPerObject.getObject()); + visit(permissionsPerObject.getTargetObjectAttributes()); + permissionsPerObject.getPermissions().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(permissionsPerObject); + } + + @Override + public default void visit(PolicyAdministrationPoint policyAdministrationPoint) { + if (policyAdministrationPoint == null) { + return; + } + visit(policyAdministrationPoint.getLocalAccessControl()); + AssetAdministrationShellElementVisitor.super.visit(policyAdministrationPoint); + } + + @Override + public default void visit(Entity entity) { + if (entity == null) { + return; + } + visit(entity.getGlobalAssetId()); + visit(entity.getSpecificAssetId()); + entity.getStatements().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(entity); + } + + @Override + public default void visit(Formula formula) { + if (formula == null) { + return; + } + formula.getDependsOns().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(formula); + } + + @Override + public default void visit(Extension extension) { + if (extension == null) { + return; + } + visit(extension.getRefersTo()); + AssetAdministrationShellElementVisitor.super.visit(extension); + } + + @Override + public default void visit(AssetAdministrationShellEnvironment assetAdministrationShellEnvironment) { + if (assetAdministrationShellEnvironment == null) { + return; + } + assetAdministrationShellEnvironment.getAssetAdministrationShells().forEach(x -> visit(x)); + assetAdministrationShellEnvironment.getConceptDescriptions().forEach(x -> visit(x)); + assetAdministrationShellEnvironment.getSubmodels().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(assetAdministrationShellEnvironment); + } + + @Override + public default void visit(Submodel submodel) { + if (submodel == null) { + return; + } + submodel.getSubmodelElements().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(submodel); + } + + @Override + public default void visit(SubmodelElementCollection submodelElementCollection) { + if (submodelElementCollection == null) { + return; + } + submodelElementCollection.getValues().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(submodelElementCollection); + } + + @Override + public default void visit(Operation operation) { + if (operation == null) { + return; + } + operation.getInputVariables().forEach(x -> visit(x.getValue())); + operation.getInoutputVariables().forEach(x -> visit(x.getValue())); + operation.getOutputVariables().forEach(x -> visit(x.getValue())); + AssetAdministrationShellElementVisitor.super.visit(operation); + } + + @Override + public default void visit(BlobCertificate blobCertificate) { + if (blobCertificate == null) { + return; + } + visit(blobCertificate.getBlobCertificate()); + visit(blobCertificate.getPolicyAdministrationPoint()); + blobCertificate.getContainedExtensions().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(blobCertificate); + } + + @Override + public default void visit(ValueList valueList) { + if (valueList == null) { + return; + } + valueList.getValueReferencePairTypes().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(valueList); + } + + @Override + public default void visit(ValueReferencePair valueReferencePair) { + if (valueReferencePair == null) { + return; + } + visit(valueReferencePair.getValueId()); + AssetAdministrationShellElementVisitor.super.visit(valueReferencePair); + } + + @Override + public default void visit(View view) { + if (view == null) { + return; + } + view.getContainedElements().forEach(x -> visit(x)); + AssetAdministrationShellElementVisitor.super.visit(view); + } + +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/Mapper.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/Mapper.java new file mode 100644 index 00000000..1cf80c00 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/Mapper.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +/** + * Generic interface used by MappingProvider to infere generic arguments. This + * is used to automatically determine best-matching mapper + * + * @param The type that this Mapper can process + */ +public interface Mapper { + +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingContext.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingContext.java new file mode 100644 index 00000000..259b76b3 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingContext.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Abstract super-class for a MappingContext that already provides a + * MappingProvider + * + * @param Type of mapper the the MappingProvider can operate on + */ +public abstract class MappingContext { + + protected static final Logger log = LoggerFactory.getLogger(MappingContext.class); + protected final MappingProvider mappingProvider; + + public MappingContext(MappingProvider mappingProvider) { + this.mappingProvider = mappingProvider; + } + + public MappingProvider getMappingProvider() { + return mappingProvider; + } +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingException.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingException.java new file mode 100644 index 00000000..507b7295 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingException.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +/** + * Exception throw upon any error on mapping + */ +public class MappingException extends Exception { + + public MappingException(String msg) { + super(msg); + } + + public MappingException(String msg, Throwable err) { + super(msg, err); + } + +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingProvider.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingProvider.java new file mode 100644 index 00000000..d96ac465 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/MappingProvider.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +import com.google.common.reflect.TypeToken; +import io.adminshell.aas.v3.dataformat.core.util.MostSpecificTypeTokenComparator; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Manages a set of mappers and allows finding them by type. This is the + * cornerstone functionality of the mapping framework. + * + * @param Type of mappers that are supported + */ +public class MappingProvider { + + private static final Logger log = LoggerFactory.getLogger(MappingProvider.class); + + private final T defaultMapper; + private final T defaultCollectionMapper; + private final Map, List> mappings = new HashMap<>(); + + public MappingProvider(Class type, + Mapper defaultMapper, + Mapper> defaultCollectionMapper) { + if (type == null) { + throw new IllegalArgumentException("type must be non-null"); + } + if (defaultMapper == null) { + throw new IllegalArgumentException("defaultMapper must be non-null"); + } + if (defaultCollectionMapper == null) { + throw new IllegalArgumentException("defaultCollectionMapper must be non-null"); + } + if (!type.isAssignableFrom(defaultMapper.getClass())) { + throw new IllegalArgumentException("defaultMapper must be of type " + type); + } + if (!type.isAssignableFrom(defaultCollectionMapper.getClass())) { + throw new IllegalArgumentException("defaultCollectionMapper must be of type " + type); + } + this.defaultMapper = (T) defaultMapper; + this.defaultCollectionMapper = (T) defaultCollectionMapper; + } + + public void register(T mapper) { + TypeToken key = getMappedType(mapper.getClass()); + if (!mappings.containsKey(key)) { + mappings.put(key, new ArrayList<>()); + } + mappings.get(key).add(mapper); + } + + private TypeToken getMappedType(Class type) { + return TypeToken.of(type) + .getTypes().stream() + .filter(y -> Mapper.class.equals(y.getRawType())) + .findFirst() + .get() + .resolveType(Mapper.class.getTypeParameters()[0]); + } + + /** + * Find the most specific mapper for a given object. + * + * @param obj The object to find a suitable mapper for. If this is an + * instance of Type (e.g. a Class) type information for that is returned. + * @return The most specific mapper for the given object + */ + public T getMapper(Object obj) { + if (obj == null) { + return getMapper(Object.class); + } + if (Type.class.isAssignableFrom(obj.getClass())) { + return getMapper((Type) obj); + } + return getMapper(obj.getClass()); + } + + /** + * Find the most specific mapper for a given type. + * + * @param type The type to find a suitable mapper for. + * @return The most specific mapper for the given type + */ + public T getMapper(Type type) { + Optional> customMapper = mappings.entrySet().stream() + .filter(x -> x.getKey().isSupertypeOf(type)) + .sorted((x, y) -> Objects.compare(x.getKey(), y.getKey(), new MostSpecificTypeTokenComparator())) + .map(x -> x.getValue()) + .findFirst(); + if (!customMapper.isPresent() || customMapper.get().isEmpty()) { + if (TypeToken.of(Collection.class).isSupertypeOf(type) && defaultCollectionMapper != null) { + return defaultCollectionMapper; + } + return defaultMapper; + } + if (customMapper.get().size() > 1) { + log.warn("found {} equally suitable mappers for type '{}'", customMapper.get().size(), type); + } + return customMapper.get().get(0); + } + +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/SourceBasedMapper.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/SourceBasedMapper.java new file mode 100644 index 00000000..c98f323e --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/SourceBasedMapper.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +/** + * A mapper that when mapping from A to B allows to write mappers based on the + * classes of A (the source of the mapping) + * + * @param type that the mapper accepts, here: any class of A + * @param the generator type, here: to generate instances of B + * @param the type of mapping context + */ +public interface SourceBasedMapper extends Mapper { + + /** + * Maps the given value to target format via the generator. + * + * @param value the value to map + * @param generator the generator to write the mapping result to + * @param context the context of the mapping + * @throws MappingException + */ + public void map(T value, G generator, C context) throws MappingException; +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/SourceBasedMappingContext.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/SourceBasedMappingContext.java new file mode 100644 index 00000000..54b1e432 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/SourceBasedMappingContext.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +public abstract class SourceBasedMappingContext extends MappingContext { + + public SourceBasedMappingContext(MappingProvider mappingProvider) { + super(mappingProvider); + } + +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/TargetBasedMapper.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/TargetBasedMapper.java new file mode 100644 index 00000000..960afa81 --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/TargetBasedMapper.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +/** + * A mapper that when mapping from A to B allows to write mappers based on the + * classes of B (the target of the mapping) + * + * @param type that the mapper accepts, here: any class of B + * @param

the parser type, here: to parse data of A + * @param the type of mapping context + */ +public interface TargetBasedMapper extends Mapper { + + /** + * Reads from the parser and returns the mapping result. + * + * @param parser the parser to read the actual input + * @param context the context + * @return a new instance of T created by mapping data given by the parser + * @throws MappingException + */ + public T map(P parser, C context) throws MappingException; +} diff --git a/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/TargetBasedMappingContext.java b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/TargetBasedMappingContext.java new file mode 100644 index 00000000..d87531bf --- /dev/null +++ b/dataformat-core/src/main/java/io/adminshell/aas/v3/dataformat/mapping/TargetBasedMappingContext.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.mapping; + +public abstract class TargetBasedMappingContext extends MappingContext { + + public TargetBasedMappingContext(MappingProvider mappingProvider) { + super(mappingProvider); + } + +} diff --git a/dataformat-rdf/license-header.txt b/dataformat-rdf/license-header.txt new file mode 100644 index 00000000..b531b74a --- /dev/null +++ b/dataformat-rdf/license-header.txt @@ -0,0 +1,13 @@ +Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/EmbeddedDataSpecificationSerializer.java b/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/EmbeddedDataSpecificationSerializer.java index 1320f7f1..711cda56 100644 --- a/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/EmbeddedDataSpecificationSerializer.java +++ b/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/EmbeddedDataSpecificationSerializer.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import io.adminshell.aas.v3.dataformat.core.DataSpecificationInfo; import static io.adminshell.aas.v3.dataformat.core.DataSpecificationManager.PROP_DATA_SPECIFICATION; import static io.adminshell.aas.v3.dataformat.core.DataSpecificationManager.PROP_DATA_SPECIFICATION_CONTENT; @@ -52,7 +53,8 @@ public void serialize(EmbeddedDataSpecification data, JsonGenerator generator, S Reference reference = null; DataSpecificationContent content = data.getDataSpecificationContent(); if (content != null) { - Reference implicitType = DataSpecificationManager.getReferenceSafe(content.getClass()); + DataSpecificationInfo implicitDataSpecification = DataSpecificationManager.getDataSpecification(content.getClass()); + Reference implicitType = implicitDataSpecification != null ? implicitDataSpecification.getReference() : null; Reference explicitType = data.getDataSpecification(); if (implicitType == null) { logger.warn("Trying to serialize unknown implementation of DataSpecificationContent ({}). " diff --git a/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/KeySerializer.java b/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/KeySerializer.java index b3fe9d9d..3ca87ac0 100644 --- a/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/KeySerializer.java +++ b/dataformat-xml/src/main/java/io/adminshell/aas/v3/dataformat/xml/serialization/KeySerializer.java @@ -1,52 +1,52 @@ -/* - * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.adminshell.aas.v3.dataformat.xml.serialization; - -import java.io.IOException; - -import javax.xml.stream.XMLStreamException; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; - -import io.adminshell.aas.v3.dataformat.core.serialization.EnumSerializer; -import io.adminshell.aas.v3.model.Key; - -public class KeySerializer extends JsonSerializer { - - @Override - public void serialize(Key key, JsonGenerator gen, SerializerProvider serializers) throws IOException { - ToXmlGenerator xgen = (ToXmlGenerator) gen; - xgen.writeObjectFieldStart("key"); - - try { - String idTypeValue = EnumSerializer.translate(key.getIdType().toString()); - xgen.getStaxWriter().writeAttribute("idType", idTypeValue); - String keyTypeValue = EnumSerializer.translate(key.getType().toString()); - xgen.getStaxWriter().writeAttribute("type", keyTypeValue); - } catch (XMLStreamException e) { - e.printStackTrace(); - } - xgen.setNextIsAttribute(false); - xgen.setNextIsUnwrapped(true); - xgen.writeFieldName("value"); - xgen.writeString(key.getValue()); - - xgen.writeEndObject(); - } -} +/* + * Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.adminshell.aas.v3.dataformat.xml.serialization; + +import java.io.IOException; + +import javax.xml.stream.XMLStreamException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; +import io.adminshell.aas.v3.dataformat.core.util.AasUtils; + +import io.adminshell.aas.v3.model.Key; + +public class KeySerializer extends JsonSerializer { + + @Override + public void serialize(Key key, JsonGenerator gen, SerializerProvider serializers) throws IOException { + ToXmlGenerator xgen = (ToXmlGenerator) gen; + xgen.writeObjectFieldStart("key"); + + try { + String idTypeValue = AasUtils.serializeEnumName(key.getIdType().toString()); + xgen.getStaxWriter().writeAttribute("idType", idTypeValue); + String keyTypeValue = AasUtils.serializeEnumName(key.getType().toString()); + xgen.getStaxWriter().writeAttribute("type", keyTypeValue); + } catch (XMLStreamException e) { + e.printStackTrace(); + } + xgen.setNextIsAttribute(false); + xgen.setNextIsUnwrapped(true); + xgen.writeFieldName("value"); + xgen.writeString(key.getValue()); + + xgen.writeEndObject(); + } +} diff --git a/pom.xml b/pom.xml index aefc8fef..394a18d3 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ pom dataformat-aasx + dataformat-aml dataformat-core dataformat-json dataformat-xml @@ -45,6 +46,7 @@ 11 UTF-8 UTF-8 + 3.3.1 1.2.2 3.2.0 4.1 @@ -53,11 +55,14 @@ 2.6 2.12.3 2.0.1.Final + 2.3.1 + 2.1.0 4.1.0 1.5.0 1.0.56 4.13 1.1.1 + 2.7.8 4.1.2 1.7.31 2.8.2 diff --git a/validator/license-header.txt b/validator/license-header.txt new file mode 100644 index 00000000..b531b74a --- /dev/null +++ b/validator/license-header.txt @@ -0,0 +1,13 @@ +Copyright (c) 2021 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e. V. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file