diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/Readme.md b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/Readme.md
new file mode 100644
index 000000000..c133b7417
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/Readme.md
@@ -0,0 +1,19 @@
+# AssetAdministrationShell Repository - Registry Integration
+This feature automatically integrates the Descriptor with the Registry while creation of the Shell at Repository.
+It also automatically removes the Descriptor from the Registry when the Shell is removed from the Repository.
+
+To enable this feature, the following two properties should be configured:
+
+```
+basyx.aasrepository.feature.registryintegration = {AAS-Registry-Base-Url}
+basyx.externalurl = {AAS-Repo-Base-Url}
+```
+
+This feature gets enabled automatically when both of the above defined properties are configured, i.e., no external enabled/disabled property is required.
+
+An example valid configuration:
+
+```
+basyx.aasrepository.feature.registryintegration = http://localhost:8050/api/v3.0
+basyx.externalurl = http://localhost:8081
+```
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/pom.xml b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/pom.xml
new file mode 100644
index 000000000..b331ff60f
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/pom.xml
@@ -0,0 +1,45 @@
+
+ 4.0.0
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasrepository
+ ${revision}
+
+
+ basyx.aasrepository-feature-registry-integration
+
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasregistry-client-native
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasrepository-core
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.http
+ test
+ tests
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.http
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasrepository-http
+ tests
+ test
+
+
+ org.apache.httpcomponents.client5
+ httpclient5
+ test
+
+
+
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasDescriptorFactory.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasDescriptorFactory.java
new file mode 100644
index 000000000..92bf90d47
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasDescriptorFactory.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
+import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.Extension;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringNameType;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringTextType;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetAdministrationShellDescriptor;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.Endpoint;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.ProtocolInformation;
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier;
+
+/**
+ * Factory for creating the {@link AssetAdministrationShellDescriptor}
+ *
+ * @author danish
+ */
+public class AasDescriptorFactory {
+
+ private static final String AAS_INTERFACE = "AAS-3.0";
+ private static final String AAS_REPOSITORY_PATH = "/shells";
+
+ private AssetAdministrationShell shell;
+ private String aasRepositoryURL;
+
+ private AttributeMapper attributeMapper;
+
+ public AasDescriptorFactory(AssetAdministrationShell shell, String aasRepositoryBaseURL, AttributeMapper attributeMapper) {
+ super();
+ this.shell = shell;
+ this.aasRepositoryURL = createAasRepositoryUrl(aasRepositoryBaseURL);
+ this.attributeMapper = attributeMapper;
+ }
+
+ /**
+ * Creates {@link AssetAdministrationShellDescriptor}
+ *
+ * @return the created AssetAdministrationShellDescriptor
+ */
+ public AssetAdministrationShellDescriptor create() {
+
+ AssetAdministrationShellDescriptor descriptor = new AssetAdministrationShellDescriptor();
+
+ setId(shell.getId(), descriptor);
+
+ setIdShort(shell.getIdShort(), descriptor);
+
+ setEndpointItem(shell.getId(), descriptor);
+
+ setDescription(shell.getDescription(), descriptor);
+
+ setDisplayName(shell.getDisplayName(), descriptor);
+
+ setExtensions(shell.getExtensions(), descriptor);
+
+ setAdministration(shell.getAdministration(), descriptor);
+
+ setAssetKind(shell.getAssetInformation(), descriptor);
+
+ setAssetType(shell.getAssetInformation(), descriptor);
+
+ setGlobalAssetId(shell.getAssetInformation(), descriptor);
+
+ return descriptor;
+ }
+
+ private void setDescription(List descriptions, AssetAdministrationShellDescriptor descriptor) {
+
+ if (descriptions == null || descriptions.isEmpty())
+ return;
+
+ descriptor.setDescription(attributeMapper.mapDescription(descriptions));
+ }
+
+ private void setDisplayName(List displayNames, AssetAdministrationShellDescriptor descriptor) {
+
+ if (displayNames == null || displayNames.isEmpty())
+ return;
+
+ descriptor.setDisplayName(attributeMapper.mapDisplayName(displayNames));
+ }
+
+ private void setExtensions(List extensions, AssetAdministrationShellDescriptor descriptor) {
+
+ if (extensions == null || extensions.isEmpty())
+ return;
+
+ descriptor.setExtensions(attributeMapper.mapExtensions(extensions));
+ }
+
+ private void setAdministration(AdministrativeInformation administration, AssetAdministrationShellDescriptor descriptor) {
+
+ if (administration == null)
+ return;
+
+ descriptor.setAdministration(attributeMapper.mapAdministration(administration));
+ }
+
+ private void setAssetKind(AssetInformation assetInformation, AssetAdministrationShellDescriptor descriptor) {
+
+ if (assetInformation == null || assetInformation.getAssetKind() == null)
+ return;
+
+ descriptor.setAssetKind(attributeMapper.mapAssetKind(assetInformation.getAssetKind()));
+ }
+
+ private void setAssetType(AssetInformation assetInformation, AssetAdministrationShellDescriptor descriptor) {
+
+ if (assetInformation == null || assetInformation.getAssetType() == null)
+ return;
+
+ descriptor.setAssetType(assetInformation.getAssetType());
+ }
+
+ private void setGlobalAssetId(AssetInformation assetInformation, AssetAdministrationShellDescriptor descriptor) {
+
+ if (assetInformation == null || assetInformation.getGlobalAssetId() == null)
+ return;
+
+ descriptor.setGlobalAssetId(assetInformation.getGlobalAssetId());
+ }
+
+ private void setEndpointItem(String shellId, AssetAdministrationShellDescriptor descriptor) {
+
+ Endpoint endpoint = new Endpoint();
+ endpoint.setInterface(AAS_INTERFACE);
+ ProtocolInformation protocolInformation = createProtocolInformation(shellId);
+ endpoint.setProtocolInformation(protocolInformation);
+
+ descriptor.addEndpointsItem(endpoint);
+ }
+
+ private ProtocolInformation createProtocolInformation(String shellId) {
+ String href = String.format("%s/%s", aasRepositoryURL, Base64UrlEncodedIdentifier.encodeIdentifier(shellId));
+
+ ProtocolInformation protocolInformation = new ProtocolInformation();
+ protocolInformation.endpointProtocol(getProtocol(href));
+ protocolInformation.setHref(href);
+
+ return protocolInformation;
+ }
+
+ private void setIdShort(String idShort, AssetAdministrationShellDescriptor descriptor) {
+ descriptor.setIdShort(idShort);
+ }
+
+ private void setId(String shellId, AssetAdministrationShellDescriptor descriptor) {
+ descriptor.setId(shellId);
+ }
+
+ private String getProtocol(String endpoint) {
+ try {
+ return new URL(endpoint).getProtocol();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ private String createAasRepositoryUrl(String aasRepositoryBaseURL) {
+
+ try {
+ return new URL(new URL(aasRepositoryBaseURL), AAS_REPOSITORY_PATH).toString();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("The AAS Repository Base url is malformed.\n" + e.getMessage());
+ }
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLink.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLink.java
new file mode 100644
index 000000000..9210e24cd
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLink.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
+import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
+
+/**
+ * Represents information for linking {@link AasRepository} with AasRegistry
+ *
+ * @author danish
+ */
+public class AasRepositoryRegistryLink {
+
+ private RegistryAndDiscoveryInterfaceApi registryApi;
+ private String aasRepositoryBaseURL;
+
+ public AasRepositoryRegistryLink(RegistryAndDiscoveryInterfaceApi registryApi, String aasRepositoryBaseURL) {
+ super();
+ this.registryApi = registryApi;
+ this.aasRepositoryBaseURL = aasRepositoryBaseURL;
+ }
+
+ public RegistryAndDiscoveryInterfaceApi getRegistryApi() {
+ return registryApi;
+ }
+
+ public String getAasRepositoryBaseURL() {
+ return aasRepositoryBaseURL;
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepository.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepository.java
new file mode 100644
index 000000000..18c73a895
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepository.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (C) 2021 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
+import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.ApiException;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetAdministrationShellDescriptor;
+import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.RepositoryRegistryLinkException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.RepositoryRegistryUnlinkException;
+import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult;
+import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Decorator for linking {@link AasRepository} with AasRegistry
+ *
+ * @author danish
+ *
+ */
+public class RegistryIntegrationAasRepository implements AasRepository {
+ private static Logger logger = LoggerFactory.getLogger(RegistryIntegrationAasRepository.class);
+
+ private AasRepository decorated;
+
+ private AasRepositoryRegistryLink aasRepositoryRegistryLink;
+ private AttributeMapper attributeMapper;
+
+ public RegistryIntegrationAasRepository(AasRepository decorated, AasRepositoryRegistryLink aasRepositoryRegistryLink, AttributeMapper attributeMapper) {
+ this.decorated = decorated;
+ this.aasRepositoryRegistryLink = aasRepositoryRegistryLink;
+ this.attributeMapper = attributeMapper;
+ }
+
+ @Override
+ public CursorResult> getAllAas(PaginationInfo pInfo) {
+ return decorated.getAllAas(pInfo);
+ }
+
+ @Override
+ public AssetAdministrationShell getAas(String shellId) throws ElementDoesNotExistException {
+ return decorated.getAas(shellId);
+ }
+
+ @Override
+ public void createAas(AssetAdministrationShell shell) throws CollidingIdentifierException {
+ decorated.createAas(shell);
+
+ integrateAasWithRegistry(shell, aasRepositoryRegistryLink.getAasRepositoryBaseURL());
+ }
+
+ @Override
+ public void updateAas(String shellId, AssetAdministrationShell shell) {
+ decorated.updateAas(shellId, shell);
+ }
+
+ @Override
+ public void deleteAas(String shellId) {
+ deleteFromRegistry(shellId);
+
+ decorated.deleteAas(shellId);
+ }
+
+ @Override
+ public String getName() {
+ return decorated.getName();
+ }
+
+ @Override
+ public CursorResult> getSubmodelReferences(String shellId, PaginationInfo paginationInfo) {
+ return decorated.getSubmodelReferences(shellId, paginationInfo);
+ }
+
+ @Override
+ public void addSubmodelReference(String shellId, Reference submodelReference) {
+ decorated.addSubmodelReference(shellId, submodelReference);
+ }
+
+ @Override
+ public void removeSubmodelReference(String shellId, String submodelId) {
+ decorated.removeSubmodelReference(shellId, submodelId);
+ }
+
+ @Override
+ public void setAssetInformation(String shellId, AssetInformation shellInfo) throws ElementDoesNotExistException {
+ decorated.setAssetInformation(shellId, shellInfo);
+ }
+
+ @Override
+ public AssetInformation getAssetInformation(String shellId) throws ElementDoesNotExistException {
+ return decorated.getAssetInformation(shellId);
+ }
+
+ private void integrateAasWithRegistry(AssetAdministrationShell shell, String aasRepositoryURL) {
+ AssetAdministrationShellDescriptor descriptor = new AasDescriptorFactory(shell, aasRepositoryURL, attributeMapper).create();
+
+ RegistryAndDiscoveryInterfaceApi registryApi = aasRepositoryRegistryLink.getRegistryApi();
+
+ try {
+ registryApi.postAssetAdministrationShellDescriptor(descriptor);
+
+ logger.info("Shell '{}' has been automatically linked with the Registry", shell.getId());
+ } catch (ApiException e) {
+ e.printStackTrace();
+
+ throw new RepositoryRegistryLinkException(shell.getId());
+ }
+ }
+
+ private void deleteFromRegistry(String shellId) {
+ RegistryAndDiscoveryInterfaceApi registryApi = aasRepositoryRegistryLink.getRegistryApi();
+
+ if (!shellExistsOnRegistry(shellId, registryApi)) {
+ logger.error("Unable to un-link the AAS descriptor '{}' from the Registry because it does not exist on the Registry.", shellId);
+
+ return;
+ }
+
+ try {
+ registryApi.deleteAssetAdministrationShellDescriptorById(shellId);
+
+ logger.info("Shell '{}' has been automatically un-linked from the Registry.", shellId);
+ } catch (ApiException e) {
+ e.printStackTrace();
+
+ throw new RepositoryRegistryUnlinkException(shellId);
+ }
+ }
+
+ private boolean shellExistsOnRegistry(String shellId, RegistryAndDiscoveryInterfaceApi registryApi) {
+ try {
+ registryApi.getAssetAdministrationShellDescriptorById(shellId);
+
+ return true;
+ } catch (ApiException e) {
+ return false;
+ }
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryConfiguration.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryConfiguration.java
new file mode 100644
index 000000000..c4700498b
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryConfiguration.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
+import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Configuration for integrating {@link AasRepository} with AasRegistry
+ *
+ * @author danish
+ */
+@Configuration
+@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${basyx.aasrepository.feature.registryintegration:}') && !T(org.springframework.util.StringUtils).isEmpty('${basyx.externalurl:}')")
+public class RegistryIntegrationAasRepositoryConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AasRepositoryRegistryLink getAasRepositoryRegistryLink(@Value("${basyx.aasrepository.feature.registryintegration}") String registryBasePath, @Value("${basyx.externalurl}") String aasRepositoryBaseURL) {
+
+ return new AasRepositoryRegistryLink(new RegistryAndDiscoveryInterfaceApi(registryBasePath), aasRepositoryBaseURL);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AttributeMapper getAasAttributeMapper(ObjectMapper objectMapper) {
+
+ return new AttributeMapper(objectMapper);
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryFactory.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryFactory.java
new file mode 100644
index 000000000..4ef1d37dd
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryFactory.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
+import org.eclipse.digitaltwin.basyx.aasrepository.AasRepositoryFactory;
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper;
+
+/**
+ * Factory for creating {@link RegistryIntegrationAasRepository}
+ *
+ * @author danish
+ */
+public class RegistryIntegrationAasRepositoryFactory implements AasRepositoryFactory {
+
+ private AasRepositoryFactory decorated;
+ private AasRepositoryRegistryLink aasRepositoryRegistryLink;
+ private AttributeMapper attributeMapper;
+
+ public RegistryIntegrationAasRepositoryFactory(AasRepositoryFactory decorated, AasRepositoryRegistryLink aasRepositoryRegistryLink, AttributeMapper attributeMapper) {
+ this.decorated = decorated;
+ this.aasRepositoryRegistryLink = aasRepositoryRegistryLink;
+ this.attributeMapper = attributeMapper;
+ }
+
+ @Override
+ public AasRepository create() {
+ return new RegistryIntegrationAasRepository(decorated.create(), aasRepositoryRegistryLink, attributeMapper);
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryFeature.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryFeature.java
new file mode 100644
index 000000000..0023d0b59
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationAasRepositoryFeature.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
+import org.eclipse.digitaltwin.basyx.aasrepository.AasRepositoryFactory;
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.AasRepositoryFeature;
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.stereotype.Component;
+
+/**
+ * Feature for integrating Registry with {@link AasRepository}
+ *
+ * @author danish
+ */
+@Component
+@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${basyx.aasrepository.feature.registryintegration:}') && !T(org.springframework.util.StringUtils).isEmpty('${basyx.externalurl:}')")
+public class RegistryIntegrationAasRepositoryFeature implements AasRepositoryFeature {
+ public final static String FEATURENAME = "basyx.aasrepository.feature.registryintegration";
+
+ private AasRepositoryRegistryLink aasRepositoryRegistryLink;
+
+ @Value("${" + FEATURENAME + ":}")
+ private String registryBaseURL;
+
+ @Value("${basyx.externalurl:}")
+ private String aasRepositoryExternalBaseURL;
+
+ private AttributeMapper attributeMapper;
+
+ @Autowired
+ public RegistryIntegrationAasRepositoryFeature(AasRepositoryRegistryLink aasRepositoryRegistryLink, AttributeMapper attributeMapper) {
+ this.aasRepositoryRegistryLink = aasRepositoryRegistryLink;
+ this.attributeMapper = attributeMapper;
+ }
+
+ @Override
+ public AasRepositoryFactory decorate(AasRepositoryFactory aasRepositoryFactory) {
+ return new RegistryIntegrationAasRepositoryFactory(aasRepositoryFactory, aasRepositoryRegistryLink, attributeMapper);
+ }
+
+ @Override
+ public void initialize() {
+ }
+
+ @Override
+ public void cleanUp() {
+
+ }
+
+ @Override
+ public String getName() {
+ return "AasRepository Registry Integration";
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return !registryBaseURL.isBlank() && !aasRepositoryExternalBaseURL.isBlank();
+ }
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/mapper/AttributeMapper.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/mapper/AttributeMapper.java
new file mode 100644
index 000000000..f2352601a
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/mapper/AttributeMapper.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper;
+
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
+import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetKind;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.Extension;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringNameType;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringTextType;
+import org.eclipse.digitaltwin.basyx.http.CustomTypeCloneFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Maps the models defined in AAS4J to the AasRegistry client models
+ *
+ * @author danish
+ */
+public class AttributeMapper {
+
+ private Logger logger = LoggerFactory.getLogger(AttributeMapper.class);
+
+ private ObjectMapper mapper;
+
+ public AttributeMapper(ObjectMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ /**
+ * Maps {@link AssetAdministrationShell#getDescription()} from AAS4J to
+ * AasRegistry client
+ *
+ * @param descriptions
+ * @return the mapped descriptions
+ */
+ public List mapDescription(List descriptions) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(LangStringTextType.class, mapper);
+
+ List mappedDescriptions = cloneFactory.create(descriptions);
+
+ if (mappedDescriptions == null)
+ logger.error("Descriptions could not be mapped due to a failure.");
+
+ return mappedDescriptions;
+ }
+
+ /**
+ * Maps {@link AssetAdministrationShell#getDisplayName()} from AAS4J to
+ * AasRegistry client
+ *
+ * @param displayNames
+ * @return the mapped displayNames
+ */
+ public List mapDisplayName(List displayNames) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(LangStringNameType.class, mapper);
+
+ List mappedDisplayNames = cloneFactory.create(displayNames);
+
+ if (mappedDisplayNames == null)
+ logger.error("DisplayNames could not be mapped due to a failure.");
+
+ return mappedDisplayNames;
+ }
+
+ /**
+ * Maps {@link AssetAdministrationShell#getExtensions()} from AAS4J to
+ * AasRegistry client
+ *
+ * @param extensions
+ * @return the mapped extensions
+ */
+ public List mapExtensions(List extensions) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(Extension.class, mapper);
+
+ List mappedExtensions = cloneFactory.create(extensions);
+
+ if (mappedExtensions == null)
+ logger.error("Extensions could not be mapped due to a failure.");
+
+ return cloneFactory.create(extensions);
+ }
+
+ /**
+ * Maps {@link AssetAdministrationShell#getAdministration()} from AAS4J to
+ * AasRegistry client
+ *
+ * @param administrativeInformation
+ * @return the mapped administrativeInformation
+ */
+ public AdministrativeInformation mapAdministration(org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation administrativeInformation) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(AdministrativeInformation.class, mapper);
+
+ AdministrativeInformation mappedAdministrativeInformation = cloneFactory.create(administrativeInformation);
+
+ if (mappedAdministrativeInformation == null)
+ logger.error("AdministrativeInformation could not be mapped due to a failure.");
+
+ return mappedAdministrativeInformation;
+ }
+
+ /**
+ * Maps {@link AssetInformation#getAssetKind()} from AAS4J to AasRegistry client
+ *
+ * @param assetKind
+ * @return the mapped assetKind
+ */
+ public AssetKind mapAssetKind(org.eclipse.digitaltwin.aas4j.v3.model.AssetKind assetKind) {
+
+ return AssetKind.valueOf(AssetKind.class, assetKind.name());
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryTestLink.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryTestLink.java
new file mode 100644
index 000000000..521cec341
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryTestLink.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.ApiException;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetAdministrationShellDescriptor;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetKind;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.Endpoint;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.GetAssetAdministrationShellDescriptorsResult;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.ProtocolInformation;
+import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier;
+import org.eclipse.digitaltwin.basyx.http.serialization.BaSyxHttpTestUtils;
+import org.junit.Test;
+import org.springframework.http.HttpStatus;
+
+/**
+ * Integration test for {@link RegistryIntegrationAasRepository} feature
+ *
+ * @author danish
+ */
+public class AasRepositoryRegistryTestLink {
+
+ private static final String AAS_REPOSITORY_PATH = "/shells";
+ private static final String DUMMY_GLOBAL_ASSETID = "globalAssetId";
+ private static final String DUMMY_IDSHORT = "ExampleMotor";
+ private static final String DUMMY_AAS_ID = "customIdentifier";
+
+ public static String aasRepoBaseUrl = "http://localhost:8081";
+ public static String aasRegistryUrl = "http://localhost:8050/api/v3.0";
+
+ private static final AssetAdministrationShellDescriptor DUMMY_DESCRIPTOR = createExpectedDescriptor();
+
+ @Test
+ public void createAas() throws FileNotFoundException, IOException, ApiException {
+ String aasJsonContent = getAas1JSONString();
+
+ CloseableHttpResponse creationResponse = createAasOnRepo(aasJsonContent);
+ assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode());
+
+ AssetAdministrationShellDescriptor actualDescriptor = retrieveDescriptorFromRegistry();
+
+ assertEquals(DUMMY_DESCRIPTOR, actualDescriptor);
+
+ resetRepository();
+ }
+
+ @Test
+ public void deleteAas() throws FileNotFoundException, IOException, ApiException {
+ String aasJsonContent = getAas1JSONString();
+
+ CloseableHttpResponse creationResponse = createAasOnRepo(aasJsonContent);
+ assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode());
+
+ CloseableHttpResponse deleteResponse = deleteAasFromRepo(DUMMY_AAS_ID);
+ assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode());
+
+ assertDescriptionDeletionAtRegistry();
+ }
+
+ private AssetAdministrationShellDescriptor retrieveDescriptorFromRegistry() throws ApiException {
+ RegistryAndDiscoveryInterfaceApi api = new RegistryAndDiscoveryInterfaceApi(aasRegistryUrl);
+
+ return api.getAssetAdministrationShellDescriptorById(DUMMY_AAS_ID);
+ }
+
+ private void resetRepository() throws IOException {
+ CloseableHttpResponse deleteResponse = deleteAasFromRepo(DUMMY_AAS_ID);
+
+ assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode());
+ }
+
+ private CloseableHttpResponse deleteAasFromRepo(String shellId) throws IOException {
+ return BaSyxHttpTestUtils.executeDeleteOnURL(getSpecificAasAccessURL(shellId));
+ }
+
+ private void assertDescriptionDeletionAtRegistry() throws ApiException {
+ RegistryAndDiscoveryInterfaceApi api = new RegistryAndDiscoveryInterfaceApi(aasRegistryUrl);
+
+ GetAssetAdministrationShellDescriptorsResult result = api.getAllAssetAdministrationShellDescriptors(null, null, null, null);
+
+ List actualDescriptors = result.getResult();
+
+ assertTrue(actualDescriptors.isEmpty());
+ }
+
+ private String getAas1JSONString() throws FileNotFoundException, IOException {
+ return BaSyxHttpTestUtils.readJSONStringFromClasspath("AasSimple_1.json");
+ }
+
+ private CloseableHttpResponse createAasOnRepo(String aasJsonContent) throws IOException {
+ return BaSyxHttpTestUtils.executePostOnURL(createAasRepositoryUrl(aasRepoBaseUrl), aasJsonContent);
+ }
+
+ private String getSpecificAasAccessURL(String aasId) {
+ return createAasRepositoryUrl(aasRepoBaseUrl) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(aasId);
+ }
+
+ private static AssetAdministrationShellDescriptor createExpectedDescriptor() {
+
+ AssetAdministrationShellDescriptor descriptor = new AssetAdministrationShellDescriptor();
+
+ descriptor.setId(DUMMY_AAS_ID);
+ descriptor.setIdShort(DUMMY_IDSHORT);
+ descriptor.setAssetKind(AssetKind.INSTANCE);
+ descriptor.setGlobalAssetId(DUMMY_GLOBAL_ASSETID);
+ descriptor.addEndpointsItem(createEndpointItem());
+
+ return descriptor;
+ }
+
+ private static Endpoint createEndpointItem() {
+ Endpoint endpoint = new Endpoint();
+ endpoint.setInterface("AAS-3.0");
+ endpoint.setProtocolInformation(createProtocolInformation());
+
+ return endpoint;
+ }
+
+ private static ProtocolInformation createProtocolInformation() {
+ String href = createHref();
+
+ ProtocolInformation protocolInformation = new ProtocolInformation();
+ protocolInformation.setHref(href);
+ protocolInformation.endpointProtocol(getProtocol(href));
+
+ return protocolInformation;
+ }
+
+ private static String createHref() {
+ return String.format("%s/%s", createAasRepositoryUrl(aasRepoBaseUrl), Base64UrlEncodedIdentifier.encodeIdentifier(DUMMY_AAS_ID));
+ }
+
+ private static String getProtocol(String endpoint) {
+ try {
+ return new URL(endpoint).getProtocol();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ private static String createAasRepositoryUrl(String aasRepositoryBaseURL) {
+
+ try {
+ return new URL(new URL(aasRepositoryBaseURL), AAS_REPOSITORY_PATH).toString();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("The AAS Repository Base url is malformed. " + e.getMessage());
+ }
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryTestLinkApplication.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryTestLinkApplication.java
new file mode 100644
index 000000000..7dbd91dec
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryTestLinkApplication.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import org.junit.internal.TextListener;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+/**
+ * Application for testing the {@link RegistryIntegrationAasRepository} feature.
+ * The first argument is the AAS Repository Base URL, the second argument is the AAS
+ * Registry URL.
+ *
+ * @author schnicke, danish
+ *
+ */
+public class AasRepositoryRegistryTestLinkApplication {
+
+ public static void main(String[] args) throws Exception {
+ String aasRepoBaseUrl = getAasRepositoryBaseUrl(args);
+ String aasRegUrl = getAasRegistryUrl(args);
+
+ Result result = runTests(aasRepoBaseUrl, aasRegUrl);
+
+ printResults(result);
+ }
+
+ private static void printResults(Result result) {
+ System.out.println("Finished. Result: Failures: " + result.getFailureCount() + ". Ignored: " + result.getIgnoreCount() + ". Tests run: " + result.getRunCount() + ". Time: " + result.getRunTime() + "ms.");
+ }
+
+ private static Result runTests(String aasRepoBaseUrl, String aasRegUrl) {
+ AasRepositoryRegistryTestLink.aasRepoBaseUrl = aasRepoBaseUrl;
+ AasRepositoryRegistryTestLink.aasRegistryUrl = aasRegUrl;
+
+ JUnitCore junit = new JUnitCore();
+ junit.addListener(new TextListener(System.out));
+
+ return junit.run(AasRepositoryRegistryTestLink.class);
+ }
+
+ private static String getAasRepositoryBaseUrl(String[] args) {
+ return args[0];
+ }
+
+ private static String getAasRegistryUrl(String[] args) {
+ return args[1];
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationTestHelper.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationTestHelper.java
new file mode 100644
index 000000000..91b5bf930
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationTestHelper.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.AssetKind;
+import org.eclipse.digitaltwin.aas4j.v3.model.EmbeddedDataSpecification;
+import org.eclipse.digitaltwin.aas4j.v3.model.Extension;
+import org.eclipse.digitaltwin.aas4j.v3.model.KeyTypes;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringNameType;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringTextType;
+import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
+import org.eclipse.digitaltwin.aas4j.v3.model.ReferenceTypes;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAdministrativeInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultEmbeddedDataSpecification;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultExtension;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultKey;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultLangStringNameType;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultLangStringTextType;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultReference;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.DataTypeDefXsd;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.Key;
+
+/**
+ * A helper class for testing RegistryIntegration feature
+ *
+ * @author danish
+ */
+public class RegistryIntegrationTestHelper {
+
+ // LangStringTextType AAS4J
+ private static final LangStringTextType AAS4J_LANG_STRING_TEXT_TYPE_1 = new DefaultLangStringTextType.Builder().language("de").text("Ein Beispiel").build();
+ private static final LangStringTextType AAS_LANG_STRING_TEXT_TYPE_2 = new DefaultLangStringTextType.Builder().language("en").text("An Example").build();
+
+ // LangStringTextType AasRegistry
+ private static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringTextType AAS_REG_LANG_STRING_TEXT_TYPE_1 = new org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringTextType().language("de")
+ .text("Ein Beispiel");
+ private static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringTextType AAS_REG_LANG_STRING_TEXT_TYPE_2 = new org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringTextType().language("en")
+ .text("An Example");
+
+ // LangStringNameType AAS4J
+ private static final LangStringNameType AAS4J_LANG_STRING_NAME_TYPE_1 = new DefaultLangStringNameType.Builder().language("en").text("Name type string").build();
+ private static final LangStringNameType AAS4J_LANG_STRING_NAME_TYPE_2 = new DefaultLangStringNameType.Builder().language("de").text("Namenstypzeichenfolge").build();
+
+ // LangStringNameType AasRegistry
+ private static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringNameType AAS_REG_LANG_STRING_NAME_TYPE_1 = new org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringNameType().language("en")
+ .text("Name type string");
+ private static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringNameType AAS_REG_LANG_STRING_NAME_TYPE_2 = new org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringNameType().language("de")
+ .text("Namenstypzeichenfolge");
+
+ // AssetKind AAS4J
+ public static final AssetKind AAS4J_ASSET_KIND = AssetKind.INSTANCE;
+
+ // AssetKind AasRegistry
+ public static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetKind AASREG_ASSET_KIND = org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetKind.INSTANCE;
+
+ // Administration AAS4J
+ private static final Reference AAS4J_DATASPECIFICATION = new DefaultReference.Builder().keys(new DefaultKey.Builder().type(KeyTypes.BLOB).value("BlobValue").build()).type(ReferenceTypes.EXTERNAL_REFERENCE).build();
+ private static final EmbeddedDataSpecification AAS4JEMB_EMBEDDED_DATA_SPECIFICATION = new DefaultEmbeddedDataSpecification.Builder().dataSpecification(AAS4J_DATASPECIFICATION).build();
+
+ // Administration AasRegistry
+ private static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.Reference AAS_REG_DATASPECIFICATION = new org.eclipse.digitaltwin.basyx.aasregistry.client.model.Reference()
+ .keys(Arrays.asList(new Key().type(org.eclipse.digitaltwin.basyx.aasregistry.client.model.KeyTypes.BLOB).value("BlobValue"))).type(org.eclipse.digitaltwin.basyx.aasregistry.client.model.ReferenceTypes.EXTERNALREFERENCE);
+ private static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.EmbeddedDataSpecification AAS_REG_EMBEDDED_DATA_SPECIFICATION = new org.eclipse.digitaltwin.basyx.aasregistry.client.model.EmbeddedDataSpecification()
+ .dataSpecification(AAS_REG_DATASPECIFICATION);
+
+ private static final String VERSION = "1.0.0";
+ private static final String REVISION = "3";
+ private static final String TEMPLATE_ID = "ID2.0";
+
+ // Extension AAS4J
+ private static final Extension AAS4J_EXTENSION = new DefaultExtension.Builder().semanticId(AAS4J_DATASPECIFICATION).name("extension").valueType(org.eclipse.digitaltwin.aas4j.v3.model.DataTypeDefXsd.STRING).value("extensionValue").build();
+
+ // Extension AasRegistry
+ private static final org.eclipse.digitaltwin.basyx.aasregistry.client.model.Extension AAS_REG_EXTENSION = new org.eclipse.digitaltwin.basyx.aasregistry.client.model.Extension().semanticId(AAS_REG_DATASPECIFICATION).name("extension")
+ .valueType(DataTypeDefXsd.STRING).value("extensionValue");
+
+ public static List getAas4jLangStringTextTypes() {
+ return Arrays.asList(AAS4J_LANG_STRING_TEXT_TYPE_1, AAS_LANG_STRING_TEXT_TYPE_2);
+ }
+
+ public static List getAasRegLangStringTextTypes() {
+ return Arrays.asList(AAS_REG_LANG_STRING_TEXT_TYPE_1, AAS_REG_LANG_STRING_TEXT_TYPE_2);
+ }
+
+ public static AdministrativeInformation getAas4jAdministration() {
+ return new DefaultAdministrativeInformation.Builder().embeddedDataSpecifications(AAS4JEMB_EMBEDDED_DATA_SPECIFICATION).version(VERSION).revision(REVISION).templateId(TEMPLATE_ID).build();
+ }
+
+ public static org.eclipse.digitaltwin.basyx.aasregistry.client.model.AdministrativeInformation getAasRegAdministration() {
+ return new org.eclipse.digitaltwin.basyx.aasregistry.client.model.AdministrativeInformation().embeddedDataSpecifications(Arrays.asList(AAS_REG_EMBEDDED_DATA_SPECIFICATION)).version(VERSION).revision(REVISION)
+ .templateId(TEMPLATE_ID);
+ }
+
+ public static List getAas4jLangStringNameTypes() {
+ return Arrays.asList(AAS4J_LANG_STRING_NAME_TYPE_1, AAS4J_LANG_STRING_NAME_TYPE_2);
+ }
+
+ public static List getAasRegLangStringNameTypes() {
+ return Arrays.asList(AAS_REG_LANG_STRING_NAME_TYPE_1, AAS_REG_LANG_STRING_NAME_TYPE_2);
+ }
+
+ public static List getAas4jExtensions() {
+ return Arrays.asList(AAS4J_EXTENSION);
+ }
+
+ public static List getAasRegExtensions() {
+ return Arrays.asList(AAS_REG_EXTENSION);
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/TestAttributeMapper.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/TestAttributeMapper.java
new file mode 100644
index 000000000..6730fec19
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/TestAttributeMapper.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetKind;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.Extension;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringNameType;
+import org.eclipse.digitaltwin.basyx.aasregistry.client.model.LangStringTextType;
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.eclipse.digitaltwin.basyx.http.Aas4JHTTPSerializationExtension;
+import org.eclipse.digitaltwin.basyx.http.BaSyxHTTPConfiguration;
+import org.eclipse.digitaltwin.basyx.http.SerializationExtension;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Unit tests for {@link AttributeMapper}
+ *
+ * @author danish
+ */
+public class TestAttributeMapper {
+
+ private static AttributeMapper attributeMapper = new AttributeMapper(configureObjectMapper());
+
+ @Test
+ public void mapDescriptions() {
+ List expectedDescriptions = RegistryIntegrationTestHelper.getAasRegLangStringTextTypes();
+
+ List actualDescriptions = attributeMapper.mapDescription(RegistryIntegrationTestHelper.getAas4jLangStringTextTypes());
+
+ assertEquals(expectedDescriptions.size(), actualDescriptions.size());
+ assertEquals(expectedDescriptions, actualDescriptions);
+ }
+
+ @Test
+ public void mapDisplayNames() {
+ List expectedDisplayNames = RegistryIntegrationTestHelper.getAasRegLangStringNameTypes();
+
+ List actualDisplayNames = attributeMapper.mapDisplayName(RegistryIntegrationTestHelper.getAas4jLangStringNameTypes());
+
+ assertEquals(expectedDisplayNames.size(), actualDisplayNames.size());
+ assertEquals(expectedDisplayNames, actualDisplayNames);
+ }
+
+ @Test
+ public void mapExtensions() {
+ List expectedExtensions = RegistryIntegrationTestHelper.getAasRegExtensions();
+
+ List actualExtensions = attributeMapper.mapExtensions(RegistryIntegrationTestHelper.getAas4jExtensions());
+
+ assertEquals(expectedExtensions.size(), actualExtensions.size());
+ assertEquals(expectedExtensions, actualExtensions);
+ }
+
+ @Test
+ public void mapAdministration() {
+ AdministrativeInformation expectedAdministrativeInformation = RegistryIntegrationTestHelper.getAasRegAdministration();
+
+ AdministrativeInformation actualAdministrativeInformation = attributeMapper.mapAdministration(RegistryIntegrationTestHelper.getAas4jAdministration());
+
+ assertEquals(expectedAdministrativeInformation, actualAdministrativeInformation);
+ }
+
+ @Test
+ public void mapAssetKind() {
+ AssetKind expectedAssetKind = RegistryIntegrationTestHelper.AASREG_ASSET_KIND;
+
+ AssetKind actualAssetKind = attributeMapper.mapAssetKind(RegistryIntegrationTestHelper.AAS4J_ASSET_KIND);
+
+ assertEquals(expectedAssetKind, actualAssetKind);
+ }
+
+ private static ObjectMapper configureObjectMapper() {
+ List extensions = Arrays.asList(new Aas4JHTTPSerializationExtension());
+
+ return new BaSyxHTTPConfiguration().jackson2ObjectMapperBuilder(extensions).build();
+ }
+
+}
diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/resources/AasSimple_1.json b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/resources/AasSimple_1.json
new file mode 100644
index 000000000..16e79e653
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/resources/AasSimple_1.json
@@ -0,0 +1,9 @@
+{
+ "modelType": "AssetAdministrationShell",
+ "idShort": "ExampleMotor",
+ "id": "customIdentifier",
+ "assetInformation": {
+ "assetKind": "Instance",
+ "globalAssetId": "globalAssetId"
+ }
+}
diff --git a/basyx.aasrepository/basyx.aasrepository.component/pom.xml b/basyx.aasrepository/basyx.aasrepository.component/pom.xml
index fa3ca06a9..eb586e7fb 100644
--- a/basyx.aasrepository/basyx.aasrepository.component/pom.xml
+++ b/basyx.aasrepository/basyx.aasrepository.component/pom.xml
@@ -1,4 +1,6 @@
-
+
4.0.0
@@ -11,7 +13,8 @@
aas-repository
- http://localhost:${docker.host.port}/shells
+
+ http://localhost:${docker.host.port}/shells
@@ -51,6 +54,16 @@
org.eclipse.digitaltwin.basyx
basyx.aasrepository-feature-mqtt
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasrepository-feature-registry-integration
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasrepository-feature-registry-integration
+ tests
+ test
+
org.eclipse.digitaltwin.basyx
basyx.http
@@ -107,7 +120,7 @@
-
+
@@ -127,12 +140,17 @@
- ${docker.host.port}:${docker.container.port}
+
+ ${docker.host.port}:${docker.container.port}
${docker.container.waitForEndpoint}
+
+
+ integration
+
diff --git a/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application-integration.properties b/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application-integration.properties
new file mode 100644
index 000000000..95043a9a8
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application-integration.properties
@@ -0,0 +1,26 @@
+server.port=8081
+server.error.path=/error
+
+spring.application.name=AAS Repository
+basyx.aasrepo.name=aas-repo
+
+basyx.backend = InMemory
+
+basyx.aasrepository.feature.registryintegration=http://host.docker.internal:8050/api/v3.0
+basyx.externalurl=http://localhost:8081
+
+#basyx.backend = MongoDB
+#spring.data.mongodb.host=127.0.0.1
+#spring.data.mongodb.port=27017
+#spring.data.mongodb.database=aas
+#spring.data.mongodb.authentication-database=admin
+#spring.data.mongodb.username=mongoAdmin
+#spring.data.mongodb.password=mongoPassword
+
+
+# basyx.aasrepository.feature.mqtt.enabled = true
+# mqtt.clientId=TestClient
+# mqtt.hostname = localhost
+# mqtt.port = 1883
+
+# basyx.cors.allowed-origins=http://localhost:3000, http://localhost:4000
diff --git a/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties b/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties
index 4e939095a..1213f86ad 100644
--- a/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties
+++ b/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties
@@ -6,6 +6,9 @@ basyx.aasrepo.name=aas-repo
basyx.backend = InMemory
+# basyx.aasrepository.feature.registryintegration=http://localhost:8050/api/v3.0
+# basyx.externalurl=http://localhost:8081
+
#basyx.backend = MongoDB
#spring.data.mongodb.host=127.0.0.1
#spring.data.mongodb.port=27017
@@ -20,4 +23,4 @@ basyx.backend = InMemory
# mqtt.hostname = localhost
# mqtt.port = 1883
-# basyx.cors.allowed-origins=http://localhost:3000, http://localhost:4000
\ No newline at end of file
+# basyx.cors.allowed-origins=http://localhost:3000, http://localhost:4000
diff --git a/basyx.aasrepository/basyx.aasrepository.component/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/component/AASRepositoryRegistryLinkIT.java b/basyx.aasrepository/basyx.aasrepository.component/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/component/AASRepositoryRegistryLinkIT.java
new file mode 100644
index 000000000..f3e3a6162
--- /dev/null
+++ b/basyx.aasrepository/basyx.aasrepository.component/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/component/AASRepositoryRegistryLinkIT.java
@@ -0,0 +1,12 @@
+package org.eclipse.digitaltwin.basyx.aasrepository.component;
+
+import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.AasRepositoryRegistryTestLink;
+
+/**
+ * Integration test for the AAS Repository integration with AAS Registry
+ *
+ * @author danish
+ *
+ */
+public class AASRepositoryRegistryLinkIT extends AasRepositoryRegistryTestLink {
+}
diff --git a/basyx.aasrepository/pom.xml b/basyx.aasrepository/pom.xml
index 57329c5c3..d628ddf59 100644
--- a/basyx.aasrepository/pom.xml
+++ b/basyx.aasrepository/pom.xml
@@ -18,6 +18,7 @@
basyx.aasrepository-backend-mongodb
basyx.aasrepository-feature-aasxupload
basyx.aasrepository-feature-mqtt
+ basyx.aasrepository-feature-registry-integration
basyx.aasrepository-tck
basyx.aasrepository.component
diff --git a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryRegistryLinkException.java b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryRegistryLinkException.java
new file mode 100644
index 000000000..83f6f3769
--- /dev/null
+++ b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryRegistryLinkException.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.core.exceptions;
+
+/**
+ * Indicates failure of automatic link between Repository and Registry
+ *
+ * @author danish
+ *
+ */
+@SuppressWarnings("serial")
+public class RepositoryRegistryLinkException extends RuntimeException {
+ public RepositoryRegistryLinkException() {
+ }
+
+ public RepositoryRegistryLinkException(String id) {
+ super(getMessage(id));
+ }
+
+ private static String getMessage(String id) {
+ return "Unable to link the element with id '" + id + "' with the Registry.";
+ }
+
+}
diff --git a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryRegistryUnlinkException.java b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryRegistryUnlinkException.java
new file mode 100644
index 000000000..8532c3564
--- /dev/null
+++ b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryRegistryUnlinkException.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.core.exceptions;
+
+/**
+ * Indicates failure of automatic unlink between Repository and Registry
+ *
+ * @author danish
+ *
+ */
+@SuppressWarnings("serial")
+public class RepositoryRegistryUnlinkException extends RuntimeException {
+ public RepositoryRegistryUnlinkException() {
+ }
+
+ public RepositoryRegistryUnlinkException(String id) {
+ super(getMessage(id));
+ }
+
+ private static String getMessage(String id) {
+ return "Unable to unlink the element with id '" + id + "' from the Registry.";
+ }
+
+}
diff --git a/basyx.common/basyx.http/src/main/java/org/eclipse/digitaltwin/basyx/http/CustomTypeCloneFactory.java b/basyx.common/basyx.http/src/main/java/org/eclipse/digitaltwin/basyx/http/CustomTypeCloneFactory.java
new file mode 100644
index 000000000..e3a8cdf94
--- /dev/null
+++ b/basyx.common/basyx.http/src/main/java/org/eclipse/digitaltwin/basyx/http/CustomTypeCloneFactory.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.http;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Factory for creating clones for the defined Input and Output type
+ *
+ * @param the Input type
+ * @param the Output type
+ *
+ * @author danish
+ */
+public class CustomTypeCloneFactory {
+
+ private Logger logger = LoggerFactory.getLogger(CustomTypeCloneFactory.class);
+
+ private ObjectMapper mapper;
+
+ private Class elementType;
+
+ public CustomTypeCloneFactory(Class outputElementType, ObjectMapper mapper) {
+ super();
+ this.elementType = outputElementType;
+ this.mapper = mapper;
+ }
+
+ /**
+ * Creates clone for the provided input of {@link List} type
+ *
+ * @param input
+ * @return the cloned result
+ */
+ public List create(List input) {
+ String serializedLangString = "";
+
+ try {
+ serializedLangString = mapper.writeValueAsString(input);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ return mapper.readValue(serializedLangString, mapper.getTypeFactory().constructCollectionType(List.class, elementType));
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+
+ logger.error("Failure occurred while creating the clone");
+
+ return null;
+ }
+
+ }
+
+ /**
+ * Creates clone for the provided input
+ *
+ * @param input
+ * @return the cloned result
+ */
+ public O create(I input) {
+ String serializedLangString = "";
+ try {
+ serializedLangString = mapper.writeValueAsString(input);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ return mapper.readValue(serializedLangString, elementType);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+
+ logger.error("Failure occurred while creating the clone");
+
+ return null;
+ }
+ }
+
+}
diff --git a/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/TestCustomTypeCloneFactory.java b/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/TestCustomTypeCloneFactory.java
new file mode 100644
index 000000000..6e496a30c
--- /dev/null
+++ b/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/TestCustomTypeCloneFactory.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.http;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.digitaltwin.basyx.http.CustomTypeCloneFactory;
+import org.eclipse.digitaltwin.basyx.http.testmodels.CloneFactoryFirstTestModel;
+import org.eclipse.digitaltwin.basyx.http.testmodels.CloneFactorySecondTestModel;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Unit tests for {@link CustomTypeCloneFactory}
+ *
+ * @author danish
+ */
+public class TestCustomTypeCloneFactory {
+
+ @Test
+ public void createCloneOfListType() {
+ List expectedDescriptions = Arrays.asList(new CloneFactorySecondTestModel("Java", "Programming Language"), new CloneFactorySecondTestModel("Deutsch", "Language"));
+
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(CloneFactorySecondTestModel.class, new ObjectMapper());
+
+ List actualDescriptions = cloneFactory.create(Arrays.asList(new CloneFactoryFirstTestModel("Java", "Programming Language"), new CloneFactoryFirstTestModel("Deutsch", "Language")));
+
+ assertEquals(expectedDescriptions.size(), actualDescriptions.size());
+ assertEquals(expectedDescriptions, actualDescriptions);
+ }
+
+ @Test
+ public void createCloneOfNonListType() {
+ CloneFactoryFirstTestModel expectedAssetKind = new CloneFactoryFirstTestModel("Deutsch", "Language");
+
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(CloneFactoryFirstTestModel.class, new ObjectMapper());
+
+ CloneFactoryFirstTestModel actualAssetKind = cloneFactory.create(new CloneFactorySecondTestModel("Deutsch", "Language"));
+
+ assertEquals(expectedAssetKind, actualAssetKind);
+ }
+
+}
diff --git a/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/testmodels/CloneFactoryFirstTestModel.java b/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/testmodels/CloneFactoryFirstTestModel.java
new file mode 100644
index 000000000..afd7630af
--- /dev/null
+++ b/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/testmodels/CloneFactoryFirstTestModel.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.http.testmodels;
+
+import java.util.Objects;
+
+import org.eclipse.digitaltwin.basyx.http.CustomTypeCloneFactory;
+
+/**
+ * Simple model for testing {@link CustomTypeCloneFactory}
+ *
+ * @author danish
+ */
+public class CloneFactoryFirstTestModel {
+
+ private String name;
+ private String type;
+
+ public CloneFactoryFirstTestModel() {}
+
+ public CloneFactoryFirstTestModel(String name, String type) {
+ super();
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, type);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ CloneFactoryFirstTestModel other = (CloneFactoryFirstTestModel) obj;
+ return Objects.equals(name, other.name) && Objects.equals(type, other.type);
+ }
+
+}
diff --git a/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/testmodels/CloneFactorySecondTestModel.java b/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/testmodels/CloneFactorySecondTestModel.java
new file mode 100644
index 000000000..3878eb5e5
--- /dev/null
+++ b/basyx.common/basyx.http/src/test/java/org/eclipse/digitaltwin/basyx/http/testmodels/CloneFactorySecondTestModel.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.http.testmodels;
+
+import java.util.Objects;
+
+/**
+ * Simple model for testing {@link CloneFactory}
+ *
+ * @author danish
+ */
+public class CloneFactorySecondTestModel {
+
+ private String name;
+ private String type;
+
+ public CloneFactorySecondTestModel() {}
+
+ public CloneFactorySecondTestModel(String name, String type) {
+ super();
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, type);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ CloneFactorySecondTestModel other = (CloneFactorySecondTestModel) obj;
+ return Objects.equals(name, other.name) && Objects.equals(type, other.type);
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/Readme.md b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/Readme.md
new file mode 100644
index 000000000..a45b2a3b5
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/Readme.md
@@ -0,0 +1,19 @@
+# Submodel Repository - Registry Integration
+This feature automatically integrates the Descriptor with the Registry while creation of the Submodel at the Repository.
+It also automatically removes the Descriptor from the Registry when the Submodel is removed from the Repository.
+
+To enable this feature, the following two properties should be configured:
+
+```
+basyx.submodelrepository.feature.registryintegration = {Submodel-Registry-Base-Url}
+basyx.externalurl = {Submodel-Repo-Base-Url}
+```
+
+This feature gets enable automatically when both of the above defined properties are configured, i.e., no external enabled/disabled property is required.
+
+An example valid configuration:
+
+```
+basyx.submodelrepository.feature.registryintegration = http://localhost:8060/api/v3.0
+basyx.externalurl = http://localhost:8081
+```
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/pom.xml b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/pom.xml
new file mode 100644
index 000000000..4052ba5ef
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/pom.xml
@@ -0,0 +1,45 @@
+
+ 4.0.0
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelrepository
+ ${revision}
+
+
+ basyx.submodelrepository-feature-registry-integration
+
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelregistry-client-native
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelrepository-core
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.http
+ test
+ tests
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.http
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelrepository-http
+ tests
+ test
+
+
+ org.apache.httpcomponents.client5
+ httpclient5
+ test
+
+
+
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepository.java
new file mode 100644
index 000000000..a25b22acf
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepository.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (C) 2021 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.OperationVariable;
+import org.eclipse.digitaltwin.aas4j.v3.model.Submodel;
+import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement;
+import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.ElementNotAFileException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.RepositoryRegistryLinkException;
+import org.eclipse.digitaltwin.basyx.core.exceptions.RepositoryRegistryUnlinkException;
+import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult;
+import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.ApiException;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor;
+import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelElementValue;
+import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelValueOnly;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Decorator for linking {@link SubmodelRepository} with SubmodelRegistry
+ *
+ * @author danish
+ *
+ */
+public class RegistryIntegrationSubmodelRepository implements SubmodelRepository {
+ private static Logger logger = LoggerFactory.getLogger(RegistryIntegrationSubmodelRepository.class);
+
+ private SubmodelRepository decorated;
+ private SubmodelRepositoryRegistryLink submodelRepositoryRegistryLink;
+ private AttributeMapper attributeMapper;
+
+ public RegistryIntegrationSubmodelRepository(SubmodelRepository decorated, SubmodelRepositoryRegistryLink submodelRepositoryRegistryLink, AttributeMapper attributeMapper) {
+ this.decorated = decorated;
+ this.submodelRepositoryRegistryLink = submodelRepositoryRegistryLink;
+ this.attributeMapper = attributeMapper;
+ }
+
+ @Override
+ public CursorResult> getAllSubmodels(PaginationInfo paginationInfo) {
+ return decorated.getAllSubmodels(paginationInfo);
+ }
+
+ @Override
+ public Submodel getSubmodel(String submodelId) throws ElementDoesNotExistException {
+ return decorated.getSubmodel(submodelId);
+ }
+
+ @Override
+ public void updateSubmodel(String submodelId, Submodel submodel) throws ElementDoesNotExistException {
+ decorated.updateSubmodel(submodelId, submodel);
+ }
+
+ @Override
+ public void createSubmodel(Submodel submodel) throws CollidingIdentifierException {
+ decorated.createSubmodel(submodel);
+
+ integrateSubmodelWithRegistry(submodel, submodelRepositoryRegistryLink.getSubmodelRepositoryBaseURL());
+ }
+
+ @Override
+ public void deleteSubmodel(String submodelId) throws ElementDoesNotExistException {
+ deleteFromRegistry(submodelId);
+
+ decorated.deleteSubmodel(submodelId);
+ }
+
+ @Override
+ public CursorResult> getSubmodelElements(String submodelId, PaginationInfo paginationInfo) throws ElementDoesNotExistException {
+ return decorated.getSubmodelElements(submodelId, paginationInfo);
+ }
+
+ @Override
+ public SubmodelElement getSubmodelElement(String submodelId, String submodelElementIdShort) throws ElementDoesNotExistException {
+ return decorated.getSubmodelElement(submodelId, submodelElementIdShort);
+ }
+
+ @Override
+ public SubmodelElementValue getSubmodelElementValue(String submodelId, String submodelElementIdShort) throws ElementDoesNotExistException {
+ return decorated.getSubmodelElementValue(submodelId, submodelElementIdShort);
+ }
+
+ @Override
+ public void setSubmodelElementValue(String submodelId, String idShortPath, SubmodelElementValue value) throws ElementDoesNotExistException {
+ decorated.setSubmodelElementValue(submodelId, idShortPath, value);
+ }
+
+ @Override
+ public void createSubmodelElement(String submodelId, SubmodelElement submodelElement) {
+ decorated.createSubmodelElement(submodelId, submodelElement);
+ }
+
+ @Override
+ public void createSubmodelElement(String submodelId, String idShortPath, SubmodelElement submodelElement) throws ElementDoesNotExistException {
+ decorated.createSubmodelElement(submodelId, submodelElement);
+ }
+
+ @Override
+ public void deleteSubmodelElement(String submodelId, String idShortPath) throws ElementDoesNotExistException {
+ decorated.deleteSubmodelElement(submodelId, idShortPath);
+ }
+
+ @Override
+ public OperationVariable[] invokeOperation(String submodelId, String idShortPath, OperationVariable[] input) throws ElementDoesNotExistException {
+ return decorated.invokeOperation(submodelId, idShortPath, input);
+ }
+
+ @Override
+ public SubmodelValueOnly getSubmodelByIdValueOnly(String submodelId) throws ElementDoesNotExistException {
+ return decorated.getSubmodelByIdValueOnly(submodelId);
+ }
+
+ @Override
+ public Submodel getSubmodelByIdMetadata(String submodelId) throws ElementDoesNotExistException {
+ return decorated.getSubmodelByIdMetadata(submodelId);
+ }
+
+ @Override
+ public File getFileByPathSubmodel(String submodelId, String idShortPath) throws ElementDoesNotExistException, ElementNotAFileException, FileDoesNotExistException {
+ return decorated.getFileByPathSubmodel(submodelId, idShortPath);
+ }
+
+ @Override
+ public void setFileValue(String submodelId, String idShortPath, String fileName, InputStream inputStream) throws ElementDoesNotExistException, ElementNotAFileException {
+ decorated.setFileValue(submodelId, idShortPath, fileName, inputStream);
+ }
+
+ @Override
+ public void deleteFileValue(String submodelId, String idShortPath) throws ElementDoesNotExistException, ElementNotAFileException, FileDoesNotExistException {
+ decorated.deleteFileValue(submodelId, idShortPath);
+ }
+
+ private void integrateSubmodelWithRegistry(Submodel submodel, String submodelRepositoryURL) {
+ SubmodelDescriptor descriptor = new SubmodelDescriptorFactory(submodel, submodelRepositoryURL, attributeMapper).create();
+
+ SubmodelRegistryApi registryApi = submodelRepositoryRegistryLink.getRegistryApi();
+
+ try {
+ registryApi.postSubmodelDescriptor(descriptor);
+
+ logger.info("Submodel '{}' has been automatically linked with the Registry", submodel.getId());
+ } catch (ApiException e) {
+ e.printStackTrace();
+
+ throw new RepositoryRegistryLinkException(submodel.getId());
+ }
+ }
+
+ private void deleteFromRegistry(String submodelId) {
+ SubmodelRegistryApi registryApi = submodelRepositoryRegistryLink.getRegistryApi();
+
+ if (!submodelExistsOnRegistry(submodelId, registryApi)) {
+ logger.error("Unable to un-link the Submodel descriptor '{}' from the Registry because it does not exist on the Registry.", submodelId);
+
+ return;
+ }
+
+ try {
+ registryApi.deleteSubmodelDescriptorById(submodelId);
+
+ logger.info("Submodel '{}' has been automatically un-linked from the Registry.", submodelId);
+ } catch (ApiException e) {
+ e.printStackTrace();
+
+ throw new RepositoryRegistryUnlinkException(submodelId);
+ }
+ }
+
+ private boolean submodelExistsOnRegistry(String submodelId, SubmodelRegistryApi registryApi) {
+ try {
+ registryApi.getSubmodelDescriptorById(submodelId);
+
+ return true;
+ } catch (ApiException e) {
+ return false;
+ }
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryConfiguration.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryConfiguration.java
new file mode 100644
index 000000000..abb3341e2
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryConfiguration.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi;
+import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Configuration for integrating {@link SubmodelRepository} with SubmodelRegistry
+ *
+ * @author danish
+ */
+@Configuration
+@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${basyx.submodelrepository.feature.registryintegration:}') && !T(org.springframework.util.StringUtils).isEmpty('${basyx.externalurl:}')")
+public class RegistryIntegrationSubmodelRepositoryConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public SubmodelRepositoryRegistryLink getSubmodelRepositoryRegistryLink(@Value("${basyx.submodelrepository.feature.registryintegration}") String registryBasePath, @Value("${basyx.externalurl}") String submodelRepositoryBaseURL) {
+
+ return new SubmodelRepositoryRegistryLink(new SubmodelRegistryApi(registryBasePath), submodelRepositoryBaseURL);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public AttributeMapper getSubmodelAttributeMapper(ObjectMapper objectMapper) {
+
+ return new AttributeMapper(objectMapper);
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryFactory.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryFactory.java
new file mode 100644
index 000000000..7a01eac01
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryFactory.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
+import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepositoryFactory;
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper;
+
+/**
+ * Factory for creating {@link RegistryIntegrationSubmodelRepository}
+ *
+ * @author danish
+ */
+public class RegistryIntegrationSubmodelRepositoryFactory implements SubmodelRepositoryFactory {
+
+ private SubmodelRepositoryFactory decorated;
+ private SubmodelRepositoryRegistryLink submodelRepositoryRegistryLink;
+ private AttributeMapper attributeMapper;
+
+ public RegistryIntegrationSubmodelRepositoryFactory(SubmodelRepositoryFactory decorated, SubmodelRepositoryRegistryLink submodelRepositoryRegistryLink, AttributeMapper attributeMapper) {
+ this.decorated = decorated;
+ this.submodelRepositoryRegistryLink = submodelRepositoryRegistryLink;
+ this.attributeMapper = attributeMapper;
+ }
+
+ @Override
+ public SubmodelRepository create() {
+ return new RegistryIntegrationSubmodelRepository(decorated.create(), submodelRepositoryRegistryLink, attributeMapper);
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryFeature.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryFeature.java
new file mode 100644
index 000000000..bdf50882a
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepositoryFeature.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepositoryFactory;
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.SubmodelRepositoryFeature;
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.stereotype.Component;
+
+/**
+ * Feature for integrating Registry with {@link AasRepository}
+ *
+ * @author danish
+ */
+@Component
+@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${basyx.submodelrepository.feature.registryintegration:}') && !T(org.springframework.util.StringUtils).isEmpty('${basyx.externalurl:}')")
+public class RegistryIntegrationSubmodelRepositoryFeature implements SubmodelRepositoryFeature {
+ public static final String FEATURENAME = "basyx.submodelrepository.feature.registryintegration";
+
+ private SubmodelRepositoryRegistryLink submodelRepositoryRegistryLink;
+
+ @Value("${" + FEATURENAME + ":}")
+ private String registryBaseURL;
+
+ @Value("${basyx.externalurl:}")
+ private String submodelRepositoryExternalBaseURL;
+
+ private AttributeMapper attributeMapper;
+
+ @Autowired
+ public RegistryIntegrationSubmodelRepositoryFeature(SubmodelRepositoryRegistryLink submodelRepositoryRegistryLink, AttributeMapper attributeMapper) {
+ this.submodelRepositoryRegistryLink = submodelRepositoryRegistryLink;
+ this.attributeMapper = attributeMapper;
+ }
+
+ @Override
+ public SubmodelRepositoryFactory decorate(SubmodelRepositoryFactory submodelRepositoryFactory) {
+ return new RegistryIntegrationSubmodelRepositoryFactory(submodelRepositoryFactory, submodelRepositoryRegistryLink, attributeMapper);
+ }
+
+ @Override
+ public void initialize() {
+ }
+
+ @Override
+ public void cleanUp() {
+
+ }
+
+ @Override
+ public String getName() {
+ return "SubmodelRepository Registry Integration";
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return !registryBaseURL.isBlank() && !submodelRepositoryExternalBaseURL.isBlank();
+ }
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelDescriptorFactory.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelDescriptorFactory.java
new file mode 100644
index 000000000..572fb8e31
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelDescriptorFactory.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.Extension;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringNameType;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringTextType;
+import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
+import org.eclipse.digitaltwin.aas4j.v3.model.Submodel;
+import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Endpoint;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.ProtocolInformation;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor;
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper;
+
+/**
+ * Factory for creating the {@link SubmodelDescriptor}
+ *
+ * @author danish
+ */
+public class SubmodelDescriptorFactory {
+
+ private static final String SUBMODEL_INTERFACE = "SUBMODEL-3.0";
+ private static final String SUBMODEL_REPOSITORY_PATH = "/submodels";
+
+ private Submodel submodel;
+ private String submodelRepositoryURL;
+
+ private AttributeMapper attributeMapper;
+
+ public SubmodelDescriptorFactory(Submodel submodel, String submodelRepositoryBaseURL, AttributeMapper attributeMapper) {
+ super();
+ this.submodel = submodel;
+ this.submodelRepositoryURL = createSubmodelRepositoryUrl(submodelRepositoryBaseURL);
+ this.attributeMapper = attributeMapper;
+ }
+
+ /**
+ * Creates {@link SubmodelDescriptor}
+ *
+ * @return the created {@link SubmodelDescriptor}
+ */
+ public SubmodelDescriptor create() {
+
+ SubmodelDescriptor descriptor = new SubmodelDescriptor();
+
+ setId(submodel.getId(), descriptor);
+
+ setIdShort(submodel.getIdShort(), descriptor);
+
+ setEndpointItem(submodel.getId(), descriptor);
+
+ setDescription(submodel.getDescription(), descriptor);
+
+ setDisplayName(submodel.getDisplayName(), descriptor);
+
+ setExtensions(submodel.getExtensions(), descriptor);
+
+ setAdministration(submodel.getAdministration(), descriptor);
+
+ setSemanticId(submodel.getSemanticId(), descriptor);
+
+ setSupplementalSemanticId(submodel.getSupplementalSemanticIds(), descriptor);
+
+ return descriptor;
+ }
+
+ private void setDescription(List descriptions, SubmodelDescriptor descriptor) {
+
+ if (descriptions == null || descriptions.isEmpty())
+ return;
+
+ descriptor.setDescription(attributeMapper.mapDescription(descriptions));
+ }
+
+ private void setDisplayName(List displayNames, SubmodelDescriptor descriptor) {
+
+ if (displayNames == null || displayNames.isEmpty())
+ return;
+
+ descriptor.setDisplayName(attributeMapper.mapDisplayName(displayNames));
+ }
+
+ private void setExtensions(List extensions, SubmodelDescriptor descriptor) {
+
+ if (extensions == null || extensions.isEmpty())
+ return;
+
+ descriptor.setExtensions(attributeMapper.mapExtensions(extensions));
+ }
+
+ private void setAdministration(AdministrativeInformation administration, SubmodelDescriptor descriptor) {
+
+ if (administration == null)
+ return;
+
+ descriptor.setAdministration(attributeMapper.mapAdministration(administration));
+ }
+
+ private void setSemanticId(Reference reference, SubmodelDescriptor descriptor) {
+
+ if (reference == null)
+ return;
+
+ descriptor.setSemanticId(attributeMapper.mapSemanticId(reference));
+ }
+
+ private void setSupplementalSemanticId(List supplementalSemanticIds, SubmodelDescriptor descriptor) {
+
+ if (supplementalSemanticIds == null || supplementalSemanticIds.isEmpty())
+ return;
+
+ descriptor.setSupplementalSemanticId(attributeMapper.mapSupplementalSemanticId(supplementalSemanticIds));
+ }
+
+ private void setEndpointItem(String shellId, SubmodelDescriptor descriptor) {
+
+ Endpoint endpoint = new Endpoint();
+ endpoint.setInterface(SUBMODEL_INTERFACE);
+ ProtocolInformation protocolInformation = createProtocolInformation(shellId);
+ endpoint.setProtocolInformation(protocolInformation);
+
+ descriptor.addEndpointsItem(endpoint);
+ }
+
+ private ProtocolInformation createProtocolInformation(String shellId) {
+ String href = String.format("%s/%s", submodelRepositoryURL, Base64UrlEncodedIdentifier.encodeIdentifier(shellId));
+
+ ProtocolInformation protocolInformation = new ProtocolInformation();
+ protocolInformation.endpointProtocol(getProtocol(href));
+ protocolInformation.setHref(href);
+
+ return protocolInformation;
+ }
+
+ private void setIdShort(String idShort, SubmodelDescriptor descriptor) {
+ descriptor.setIdShort(idShort);
+ }
+
+ private void setId(String shellId, SubmodelDescriptor descriptor) {
+ descriptor.setId(shellId);
+ }
+
+ private String getProtocol(String endpoint) {
+ try {
+ return new URL(endpoint).getProtocol();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ private String createSubmodelRepositoryUrl(String submodelRepositoryBaseURL) {
+
+ try {
+ return new URL(new URL(submodelRepositoryBaseURL), SUBMODEL_REPOSITORY_PATH).toString();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("The Submodel Repository Base url is malformed.\n" + e.getMessage());
+ }
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLink.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLink.java
new file mode 100644
index 000000000..56b1198ca
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLink.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi;
+import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
+
+/**
+ * Represents information for linking {@link SubmodelRepository} with SubmodelRegistry
+ *
+ * @author danish
+ */
+public class SubmodelRepositoryRegistryLink {
+
+ private SubmodelRegistryApi registryApi;
+ private String submodelRepositoryBaseURL;
+
+ public SubmodelRepositoryRegistryLink(SubmodelRegistryApi registryApi, String submodelRepositoryBaseURL) {
+ super();
+ this.registryApi = registryApi;
+ this.submodelRepositoryBaseURL = submodelRepositoryBaseURL;
+ }
+
+ public SubmodelRegistryApi getRegistryApi() {
+ return registryApi;
+ }
+
+ public String getSubmodelRepositoryBaseURL() {
+ return submodelRepositoryBaseURL;
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/mapper/AttributeMapper.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/mapper/AttributeMapper.java
new file mode 100644
index 000000000..baad951d3
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/mapper/AttributeMapper.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper;
+
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.Submodel;
+import org.eclipse.digitaltwin.basyx.http.CustomTypeCloneFactory;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Extension;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringNameType;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringTextType;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Maps the models defined in AAS4J to the SubmodelRegistry client models
+ *
+ * @author danish
+ */
+public class AttributeMapper {
+
+ private Logger logger = LoggerFactory.getLogger(AttributeMapper.class);
+
+ private ObjectMapper mapper;
+
+ public AttributeMapper(ObjectMapper mapper) {
+ this.mapper = mapper;
+ }
+
+ /**
+ * Maps {@link Submodel#getDescription()} from AAS4J to SubmodelRegistry client
+ *
+ * @param descriptions
+ * @return the mapped descriptions
+ */
+ public List mapDescription(List descriptions) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(LangStringTextType.class, mapper);
+
+ List mappedDescriptions = cloneFactory.create(descriptions);
+
+ if (mappedDescriptions == null)
+ logger.error("Descriptions could not be mapped due to a failure.");
+
+ return mappedDescriptions;
+ }
+
+ /**
+ * Maps {@link Submodel#getDisplayName()} from AAS4J to SubmodelRegistry client
+ *
+ * @param displayNames
+ * @return the mapped displayNames
+ */
+ public List mapDisplayName(List displayNames) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(LangStringNameType.class, mapper);
+
+ List mappedDisplayNames = cloneFactory.create(displayNames);
+
+ if (mappedDisplayNames == null)
+ logger.error("DisplayNames could not be mapped due to a failure.");
+
+ return mappedDisplayNames;
+ }
+
+ /**
+ * Maps {@link Submodel#getExtensions()} from AAS4J to SubmodelRegistry client
+ *
+ * @param extensions
+ * @return the mapped extensions
+ */
+ public List mapExtensions(List extensions) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(Extension.class, mapper);
+
+ List mappedExtensions = cloneFactory.create(extensions);
+
+ if (mappedExtensions == null)
+ logger.error("Extensions could not be mapped due to a failure.");
+
+ return cloneFactory.create(extensions);
+ }
+
+ /**
+ * Maps {@link Submodel#getAdministration()} from AAS4J to SubmodelRegistry
+ * client
+ *
+ * @param administrativeInformation
+ * @return the mapped administrativeInformation
+ */
+ public AdministrativeInformation mapAdministration(org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation administrativeInformation) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(AdministrativeInformation.class, mapper);
+
+ AdministrativeInformation mappedAdministrativeInformation = cloneFactory.create(administrativeInformation);
+
+ if (mappedAdministrativeInformation == null)
+ logger.error("AdministrativeInformation could not be mapped due to a failure.");
+
+ return mappedAdministrativeInformation;
+ }
+
+ /**
+ * Maps {@link Submodel#getSemanticID()} from AAS4J to SubmodelRegistry client
+ *
+ * @param semanticId
+ * @return the mapped semanticId
+ */
+ public Reference mapSemanticId(org.eclipse.digitaltwin.aas4j.v3.model.Reference semanticId) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(Reference.class, mapper);
+
+ Reference mappedSemanticId = cloneFactory.create(semanticId);
+
+ if (mappedSemanticId == null)
+ logger.error("SemanticId could not be mapped due to a failure.");
+
+ return mappedSemanticId;
+ }
+
+ /**
+ * Maps {@link Submodel#getSupplementalSemanticIds()} from AAS4J to
+ * SubmodelRegistry client
+ *
+ * @param supplementalSemanticIds
+ * @return the mapped supplementalSemanticIds
+ */
+ public List mapSupplementalSemanticId(List supplementalSemanticIds) {
+ CustomTypeCloneFactory cloneFactory = new CustomTypeCloneFactory<>(Reference.class, mapper);
+
+ List mappedSupplementalSemanticId = cloneFactory.create(supplementalSemanticIds);
+
+ if (mappedSupplementalSemanticId == null)
+ logger.error("SupplementalSemanticId could not be mapped due to a failure.");
+
+ return mappedSupplementalSemanticId;
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationTestHelper.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationTestHelper.java
new file mode 100644
index 000000000..fb0de5ec0
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationTestHelper.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.EmbeddedDataSpecification;
+import org.eclipse.digitaltwin.aas4j.v3.model.Extension;
+import org.eclipse.digitaltwin.aas4j.v3.model.KeyTypes;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringNameType;
+import org.eclipse.digitaltwin.aas4j.v3.model.LangStringTextType;
+import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
+import org.eclipse.digitaltwin.aas4j.v3.model.ReferenceTypes;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAdministrativeInformation;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultEmbeddedDataSpecification;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultExtension;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultKey;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultLangStringNameType;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultLangStringTextType;
+import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultReference;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.DataTypeDefXsd;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Key;
+
+/**
+ * A helper class for testing RegistryIntegration feature
+ *
+ * @author danish
+ */
+public class RegistryIntegrationTestHelper {
+
+ // LangStringTextType AAS4J
+ private static final LangStringTextType AAS4J_LANG_STRING_TEXT_TYPE_1 = new DefaultLangStringTextType.Builder().language("de").text("Ein Beispiel").build();
+ private static final LangStringTextType AAS4J_LANG_STRING_TEXT_TYPE_2 = new DefaultLangStringTextType.Builder().language("en").text("An Example").build();
+
+ // LangStringTextType SMRegistry
+ private static final org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringTextType SUBMODEL_REG_LANG_STRING_TEXT_TYPE_1 = new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringTextType().language("de")
+ .text("Ein Beispiel");
+ private static final org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringTextType SUBMODEL_REG_LANG_STRING_TEXT_TYPE_2 = new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringTextType().language("en")
+ .text("An Example");
+
+ // LangStringNameType AAS4J
+ private static final LangStringNameType AAS4J_LANG_STRING_NAME_TYPE_1 = new DefaultLangStringNameType.Builder().language("en").text("Name type string").build();
+ private static final LangStringNameType AAS4J_LANG_STRING_NAME_TYPE_2 = new DefaultLangStringNameType.Builder().language("de").text("Namenstypzeichenfolge").build();
+
+ // LangStringNameType SMRegistry
+ private static final org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringNameType SUBMODEL_REG_LANG_STRING_NAME_TYPE_1 = new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringNameType().language("en")
+ .text("Name type string");
+ private static final org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringNameType SUBMODEL_REG_LANG_STRING_NAME_TYPE_2 = new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringNameType().language("de")
+ .text("Namenstypzeichenfolge");
+
+ // Administration AAS4J
+ private static final Reference AAS4J_DATASPECIFICATION = new DefaultReference.Builder().keys(new DefaultKey.Builder().type(KeyTypes.BLOB).value("BlobValue").build()).type(ReferenceTypes.EXTERNAL_REFERENCE).build();
+ private static final EmbeddedDataSpecification AAS4JEMB_EMBEDDED_DATA_SPECIFICATION = new DefaultEmbeddedDataSpecification.Builder().dataSpecification(AAS4J_DATASPECIFICATION).build();
+
+ // Administration SMRegistry
+ private static final org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Reference SUBMODEL_REG_DATASPECIFICATION = new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Reference()
+ .keys(Arrays.asList(new Key().type(org.eclipse.digitaltwin.basyx.submodelregistry.client.model.KeyTypes.BLOB).value("BlobValue"))).type(org.eclipse.digitaltwin.basyx.submodelregistry.client.model.ReferenceTypes.EXTERNALREFERENCE);
+ private static final org.eclipse.digitaltwin.basyx.submodelregistry.client.model.EmbeddedDataSpecification SUBMODEL_REG_EMBEDDED_DATA_SPECIFICATION = new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.EmbeddedDataSpecification()
+ .dataSpecification(SUBMODEL_REG_DATASPECIFICATION);
+
+ private static final String VERSION = "1.0.0";
+ private static final String REVISION = "3";
+ private static final String TEMPLATEID = "ID2.0";
+
+ // Extension AAS4J
+ private static final Extension AAS4J_EXTENSION = new DefaultExtension.Builder().semanticId(AAS4J_DATASPECIFICATION).name("extension").valueType(org.eclipse.digitaltwin.aas4j.v3.model.DataTypeDefXsd.STRING).value("extensionValue").build();
+
+ // Extension SMRegistry
+ private static final org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Extension SUBMODEL_REG_EXTENSION = new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Extension().semanticId(SUBMODEL_REG_DATASPECIFICATION).name("extension")
+ .valueType(DataTypeDefXsd.STRING).value("extensionValue");
+
+ public static List getAas4jLangStringTextTypes() {
+ return Arrays.asList(AAS4J_LANG_STRING_TEXT_TYPE_1, AAS4J_LANG_STRING_TEXT_TYPE_2);
+ }
+
+ public static List getSubmodelRegLangStringTextTypes() {
+ return Arrays.asList(SUBMODEL_REG_LANG_STRING_TEXT_TYPE_1, SUBMODEL_REG_LANG_STRING_TEXT_TYPE_2);
+ }
+
+ public static AdministrativeInformation getAas4jAdministration() {
+ return new DefaultAdministrativeInformation.Builder().embeddedDataSpecifications(AAS4JEMB_EMBEDDED_DATA_SPECIFICATION).version(VERSION).revision(REVISION).templateId(TEMPLATEID).build();
+ }
+
+ public static org.eclipse.digitaltwin.basyx.submodelregistry.client.model.AdministrativeInformation getSubmodelRegAdministration() {
+ return new org.eclipse.digitaltwin.basyx.submodelregistry.client.model.AdministrativeInformation().embeddedDataSpecifications(Arrays.asList(SUBMODEL_REG_EMBEDDED_DATA_SPECIFICATION)).version(VERSION).revision(REVISION)
+ .templateId(TEMPLATEID);
+ }
+
+ public static List getAas4jLangStringNameTypes() {
+ return Arrays.asList(AAS4J_LANG_STRING_NAME_TYPE_1, AAS4J_LANG_STRING_NAME_TYPE_2);
+ }
+
+ public static List getSubmodelRegLangStringNameTypes() {
+ return Arrays.asList(SUBMODEL_REG_LANG_STRING_NAME_TYPE_1, SUBMODEL_REG_LANG_STRING_NAME_TYPE_2);
+ }
+
+ public static List getAas4jExtensions() {
+ return Arrays.asList(AAS4J_EXTENSION);
+ }
+
+ public static List getSubmodelRegExtensions() {
+ return Arrays.asList(SUBMODEL_REG_EXTENSION);
+ }
+
+ public static Reference getAas4jSemanticId() {
+ return AAS4J_DATASPECIFICATION;
+ }
+
+ public static org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Reference getSubmodelRegSemanticId() {
+ return SUBMODEL_REG_DATASPECIFICATION;
+ }
+
+ public static List getAas4jSupplementalSemanticIds() {
+ return Arrays.asList(AAS4J_DATASPECIFICATION, AAS4J_DATASPECIFICATION);
+ }
+
+ public static List getSubmodelRegSupplementalSemanticIds() {
+ return Arrays.asList(SUBMODEL_REG_DATASPECIFICATION, SUBMODEL_REG_DATASPECIFICATION);
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryTestLink.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryTestLink.java
new file mode 100644
index 000000000..eb8bfe2ae
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryTestLink.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier;
+import org.eclipse.digitaltwin.basyx.http.serialization.BaSyxHttpTestUtils;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.ApiException;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Endpoint;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.GetSubmodelDescriptorsResult;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Key;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.KeyTypes;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.ProtocolInformation;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Reference;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.ReferenceTypes;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor;
+import org.junit.Test;
+import org.springframework.http.HttpStatus;
+
+/**
+ * Integration test for {@link RegistryIntegrationSubmodelRepository} feature
+ *
+ * @author danish
+ */
+public class SubmodelRepositoryRegistryTestLink {
+
+ private static final String SUBMODEL_REPOSITORY_PATH = "/submodels";
+
+ private static final String SUMMY_SUBMODEL_IDSHORT = "TechnicalData";
+ private static final String DUMMY_SUBMODEL_ID = "7A7104BDAB57E184";
+
+ public static String submodelRepoBaseUrl = "http://localhost:8081";
+ public static String submodelRegistryUrl = "http://localhost:8060/api/v3.0";
+
+ private static final SubmodelDescriptor DUMMY_DESCRIPTOR = createExpectedDescriptor();
+
+ @Test
+ public void createSubmodel() throws FileNotFoundException, IOException, ApiException {
+ String submodelJsonContent = getSubmodelJSONString();
+
+ CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent);
+ assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode());
+
+ SubmodelDescriptor actualDescriptor = retrieveDescriptorFromRegistry();
+
+ assertEquals(DUMMY_DESCRIPTOR, actualDescriptor);
+
+ resetRepository();
+ }
+
+ @Test
+ public void deleteSubmodel() throws FileNotFoundException, IOException, ApiException {
+ String submodelJsonContent = getSubmodelJSONString();
+
+ CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent);
+ assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode());
+
+ CloseableHttpResponse deleteResponse = deleteSubmodelFromRepo(DUMMY_SUBMODEL_ID);
+ assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode());
+
+ assertDescriptionDeletionAtRegistry();
+ }
+
+ private SubmodelDescriptor retrieveDescriptorFromRegistry() throws ApiException {
+ SubmodelRegistryApi api = new SubmodelRegistryApi(submodelRegistryUrl);
+
+ return api.getSubmodelDescriptorById(DUMMY_SUBMODEL_ID);
+ }
+
+ private void resetRepository() throws IOException {
+ CloseableHttpResponse deleteResponse = deleteSubmodelFromRepo(DUMMY_SUBMODEL_ID);
+
+ assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode());
+ }
+
+ private CloseableHttpResponse deleteSubmodelFromRepo(String shellId) throws IOException {
+ return BaSyxHttpTestUtils.executeDeleteOnURL(getSpecificSubmodelAccessURL(shellId));
+ }
+
+ private void assertDescriptionDeletionAtRegistry() throws ApiException {
+ SubmodelRegistryApi api = new SubmodelRegistryApi(submodelRegistryUrl);
+
+ GetSubmodelDescriptorsResult result = api.getAllSubmodelDescriptors(null, null);
+
+ List actualDescriptors = result.getResult();
+
+ assertTrue(actualDescriptors.isEmpty());
+ }
+
+ private String getSubmodelJSONString() throws FileNotFoundException, IOException {
+ return BaSyxHttpTestUtils.readJSONStringFromClasspath("SingleSubmodel.json");
+ }
+
+ private CloseableHttpResponse createSubmodelOnRepo(String aasJsonContent) throws IOException {
+ return BaSyxHttpTestUtils.executePostOnURL(createSubmodelRepositoryUrl(submodelRepoBaseUrl), aasJsonContent);
+ }
+
+ private String getSpecificSubmodelAccessURL(String aasId) {
+ return createSubmodelRepositoryUrl(submodelRepoBaseUrl) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(aasId);
+ }
+
+ private static SubmodelDescriptor createExpectedDescriptor() {
+
+ SubmodelDescriptor descriptor = new SubmodelDescriptor();
+
+ descriptor.setId(DUMMY_SUBMODEL_ID);
+ descriptor.setIdShort(SUMMY_SUBMODEL_IDSHORT);
+ descriptor.setSemanticId(createSemanticId());
+ descriptor.addEndpointsItem(createEndpointItem());
+
+ return descriptor;
+ }
+
+ private static Reference createSemanticId() {
+ return new Reference().keys(Arrays.asList(new Key().type(KeyTypes.GLOBALREFERENCE).value("0173-1#01-AFZ615#016"))).type(ReferenceTypes.EXTERNALREFERENCE);
+ }
+
+ private static Endpoint createEndpointItem() {
+ Endpoint endpoint = new Endpoint();
+ endpoint.setInterface("SUBMODEL-3.0");
+ endpoint.setProtocolInformation(createProtocolInformation());
+
+ return endpoint;
+ }
+
+ private static ProtocolInformation createProtocolInformation() {
+ String href = createHref();
+
+ ProtocolInformation protocolInformation = new ProtocolInformation();
+ protocolInformation.setHref(href);
+ protocolInformation.endpointProtocol(getProtocol(href));
+
+ return protocolInformation;
+ }
+
+ private static String createHref() {
+ return String.format("%s/%s", createSubmodelRepositoryUrl(submodelRepoBaseUrl), Base64UrlEncodedIdentifier.encodeIdentifier(DUMMY_SUBMODEL_ID));
+ }
+
+ private static String getProtocol(String endpoint) {
+ try {
+ return new URL(endpoint).getProtocol();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ private static String createSubmodelRepositoryUrl(String smRepositoryBaseURL) {
+
+ try {
+ return new URL(new URL(smRepositoryBaseURL), SUBMODEL_REPOSITORY_PATH).toString();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("The Submodel Repository Base url is malformed.\n " + e.getMessage());
+ }
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryTestLinkApplication.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryTestLinkApplication.java
new file mode 100644
index 000000000..6b1cd2687
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryTestLinkApplication.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import org.junit.internal.TextListener;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+/**
+ * Application for testing the {@link RegistryIntegrationSubmodelRepository}
+ * feature. The first argument is the Submodel Repository Base URL, the second
+ * argument is the Submodel Registry URL.
+ *
+ * @author schnicke, danish
+ *
+ */
+public class SubmodelRepositoryRegistryTestLinkApplication {
+
+ public static void main(String[] args) throws Exception {
+ String submodelRepoBaseUrl = getSubmodelRepositoryBaseUrl(args);
+ String submodelRegUrl = getSubmodelRegistryUrl(args);
+
+ Result result = runTests(submodelRepoBaseUrl, submodelRegUrl);
+
+ printResults(result);
+ }
+
+ private static void printResults(Result result) {
+ System.out.println("Finished. Result: Failures: " + result.getFailureCount() + ". Ignored: " + result.getIgnoreCount() + ". Tests run: " + result.getRunCount() + ". Time: " + result.getRunTime() + "ms.");
+ }
+
+ private static Result runTests(String submodelRepoBaseUrl, String submodelRegUrl) {
+ SubmodelRepositoryRegistryTestLink.submodelRepoBaseUrl = submodelRepoBaseUrl;
+ SubmodelRepositoryRegistryTestLink.submodelRegistryUrl = submodelRegUrl;
+
+ JUnitCore junit = new JUnitCore();
+ junit.addListener(new TextListener(System.out));
+
+ return junit.run(SubmodelRepositoryRegistryTestLink.class);
+ }
+
+ private static String getSubmodelRepositoryBaseUrl(String[] args) {
+ return args[0];
+ }
+
+ private static String getSubmodelRegistryUrl(String[] args) {
+ return args[1];
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/TestAttributeMapper.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/TestAttributeMapper.java
new file mode 100644
index 000000000..70c6c24cc
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/TestAttributeMapper.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (C) 2023 the Eclipse BaSyx Authors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ ******************************************************************************/
+
+package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.digitaltwin.basyx.http.Aas4JHTTPSerializationExtension;
+import org.eclipse.digitaltwin.basyx.http.BaSyxHTTPConfiguration;
+import org.eclipse.digitaltwin.basyx.http.SerializationExtension;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.AdministrativeInformation;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Extension;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringNameType;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.LangStringTextType;
+import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Reference;
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Unit tests for {@link AttributeMapper}
+ *
+ * @author danish
+ */
+public class TestAttributeMapper {
+
+ private static AttributeMapper attributeMapper = new AttributeMapper(configureObjectMapper());
+
+ @Test
+ public void mapDescriptions() {
+ List expectedDescriptions = RegistryIntegrationTestHelper.getSubmodelRegLangStringTextTypes();
+
+ List actualDescriptions = attributeMapper.mapDescription(RegistryIntegrationTestHelper.getAas4jLangStringTextTypes());
+
+ assertEquals(expectedDescriptions.size(), actualDescriptions.size());
+ assertEquals(expectedDescriptions, actualDescriptions);
+ }
+
+ @Test
+ public void mapDisplayNames() {
+ List expectedDisplayNames = RegistryIntegrationTestHelper.getSubmodelRegLangStringNameTypes();
+
+ List actualDisplayNames = attributeMapper.mapDisplayName(RegistryIntegrationTestHelper.getAas4jLangStringNameTypes());
+
+ assertEquals(expectedDisplayNames.size(), actualDisplayNames.size());
+ assertEquals(expectedDisplayNames, actualDisplayNames);
+ }
+
+ @Test
+ public void mapExtensions() {
+ List expectedExtensions = RegistryIntegrationTestHelper.getSubmodelRegExtensions();
+
+ List actualExtensions = attributeMapper.mapExtensions(RegistryIntegrationTestHelper.getAas4jExtensions());
+
+ assertEquals(expectedExtensions.size(), actualExtensions.size());
+ assertEquals(expectedExtensions, actualExtensions);
+ }
+
+ @Test
+ public void mapAdministration() {
+ AdministrativeInformation expectedAdministrativeInformation = RegistryIntegrationTestHelper.getSubmodelRegAdministration();
+
+ AdministrativeInformation actualAdministrativeInformation = attributeMapper.mapAdministration(RegistryIntegrationTestHelper.getAas4jAdministration());
+
+ assertEquals(expectedAdministrativeInformation, actualAdministrativeInformation);
+ }
+
+ @Test
+ public void mapSemanticId() {
+ Reference expectedSemanticId = RegistryIntegrationTestHelper.getSubmodelRegSemanticId();
+
+ Reference actualSemanticId = attributeMapper.mapSemanticId(RegistryIntegrationTestHelper.getAas4jSemanticId());
+
+ assertEquals(expectedSemanticId, actualSemanticId);
+ }
+
+ @Test
+ public void mapSupplementalSemanticId() {
+ List expectedSupplementalSemanticId = RegistryIntegrationTestHelper.getSubmodelRegSupplementalSemanticIds();
+
+ List actualSupplementalSemanticId = attributeMapper.mapSupplementalSemanticId(RegistryIntegrationTestHelper.getAas4jSupplementalSemanticIds());
+
+ assertEquals(expectedSupplementalSemanticId.size(), actualSupplementalSemanticId.size());
+ assertEquals(expectedSupplementalSemanticId, actualSupplementalSemanticId);
+ }
+
+ private static ObjectMapper configureObjectMapper() {
+ List extensions = Arrays.asList(new Aas4JHTTPSerializationExtension());
+
+ return new BaSyxHTTPConfiguration().jackson2ObjectMapperBuilder(extensions).build();
+ }
+
+}
diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/resources/SingleSubmodel.json b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/resources/SingleSubmodel.json
new file mode 100644
index 000000000..3391b2db6
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/resources/SingleSubmodel.json
@@ -0,0 +1,405 @@
+{
+ "modelType": "Submodel",
+ "id": "7A7104BDAB57E184",
+ "idShort": "TechnicalData",
+ "kind": "Instance",
+ "submodelElements": [
+ {
+ "modelType": "Property",
+ "value": "5000",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "MaxRotationSpeed",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Range",
+ "max": "300",
+ "min": "200",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "RotationSpeedRange",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "MultiLanguageProperty",
+ "category": "PARAM",
+ "idShort": "MultiLanguage",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ },
+ "value": [
+ {
+ "language": "en",
+ "text": "Hello"
+ },
+ {
+ "language": "de",
+ "text": "Hallo"
+ }
+ ]
+ },
+ {
+ "modelType": "File",
+ "contentType": "application/json",
+ "value": "testFile.json",
+ "category": "PARAMETER",
+ "idShort": "FileData",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Entity",
+ "entityType": "CoManagedEntity",
+ "specificAssetIds": [
+ {
+ "name": "specificAssetIdName",
+ "value": "specificValue"
+ }
+ ],
+ "statements": [
+ {
+ "modelType": "Property",
+ "value": "5000",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "MaxRotationSpeed",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Range",
+ "max": "300",
+ "min": "200",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "RotationSpeedRange",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ }
+ ],
+ "category": "Entity",
+ "idShort": "EntityData",
+ "globalAssetId": "globalAssetID",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "ReferenceElement",
+ "category": "PARAMETER",
+ "idShort": "ReferenceElement",
+ "value": {
+ "keys": [
+ {
+ "type": "DataElement",
+ "value": "DataElement"
+ }
+ ],
+ "type": "ModelReference"
+ },
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "RelationshipElement",
+ "category": "PARAMETER",
+ "idShort": "RelationshipElement",
+ "first": {
+ "keys": [
+ {
+ "type": "DataElement",
+ "value": "DataElement"
+ }
+ ],
+ "type": "ModelReference"
+ },
+ "second": {
+ "keys": [
+ {
+ "type": "BasicEventElement",
+ "value": "BasicEventElement"
+ }
+ ],
+ "type": "ExternalReference"
+ },
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "AnnotatedRelationshipElement",
+ "category": "PARAMETER",
+ "idShort": "AnnotatedRelationshipElement",
+ "first": {
+ "keys": [
+ {
+ "type": "DataElement",
+ "value": "DataElement"
+ }
+ ],
+ "type": "ModelReference"
+ },
+ "second": {
+ "keys": [
+ {
+ "type": "BasicEventElement",
+ "value": "BasicEventElement"
+ }
+ ],
+ "type": "ExternalReference"
+ },
+ "annotations": [
+ {
+ "modelType": "Property",
+ "value": "5000",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "MaxRotationSpeed",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Range",
+ "max": "300",
+ "min": "200",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "RotationSpeedRange",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ }
+ ],
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Blob",
+ "contentType": "application/xml",
+ "value": "VGVzdCBjb250ZW50IG9mIFhNTCBmaWxl",
+ "category": "PARAMETER",
+ "idShort": "BlobData",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "SubmodelElementCollection",
+ "category": "PARAMETER",
+ "idShort": "SubmodelElementCollection",
+ "value": [
+ {
+ "modelType": "File",
+ "contentType": "application/json",
+ "value": "testFile.json",
+ "category": "PARAMETER",
+ "idShort": "FileData",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Property",
+ "value": "5000",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "MaxRotationSpeed",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ }
+ ],
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "SubmodelElementList",
+ "category": "PARAMETER",
+ "idShort": "SubmodelElementList",
+ "orderRelevant": true,
+ "value": [
+ {
+ "modelType": "Range",
+ "max": "300",
+ "min": "200",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "RotationSpeedRange",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Property",
+ "value": "5000",
+ "valueType": "xs:integer",
+ "category": "PARAMETER",
+ "idShort": "MaxRotationSpeed",
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ }
+ ],
+ "semanticId": {
+ "keys": [
+ {
+ "type": "ConceptDescription",
+ "value": "0173-1#02-BAA120#008"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+ },
+ {
+ "modelType": "Operation",
+ "idShort": "square",
+ "inputVariables": [
+ {
+ "value": {
+ "modelType": "Property",
+ "valueType": "xs:int",
+ "idShort": "input"
+ }
+ }
+ ],
+ "outputVariables": [
+ {
+ "value": {
+ "modelType": "Property",
+ "valueType": "xs:int",
+ "idShort": "result"
+ }
+ }
+ ]
+ }
+ ],
+ "semanticId": {
+ "keys": [
+ {
+ "type": "GlobalReference",
+ "value": "0173-1#01-AFZ615#016"
+ }
+ ],
+ "type": "ExternalReference"
+ }
+}
\ No newline at end of file
diff --git a/basyx.submodelrepository/basyx.submodelrepository.component/pom.xml b/basyx.submodelrepository/basyx.submodelrepository.component/pom.xml
index d8591fdc7..da656eaa7 100644
--- a/basyx.submodelrepository/basyx.submodelrepository.component/pom.xml
+++ b/basyx.submodelrepository/basyx.submodelrepository.component/pom.xml
@@ -1,4 +1,6 @@
-
+
4.0.0
@@ -8,10 +10,11 @@
basyx.submodelrepository.component
-
+
submodel-repository
- http://localhost:${docker.host.port}/submodels
+
+ http://localhost:${docker.host.port}/submodels
@@ -35,6 +38,16 @@
org.eclipse.digitaltwin.basyx
basyx.submodelrepository-feature-mqtt
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelrepository-feature-registry-integration
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelrepository-feature-registry-integration
+ tests
+ test
+
org.eclipse.digitaltwin.basyx
basyx.submodelrepository-http
@@ -62,7 +75,7 @@
org.springframework.boot
spring-boot-starter-actuator
-
+
org.eclipse.digitaltwin.basyx
basyx.submodelservice-core
@@ -113,7 +126,7 @@
-
+
@@ -133,12 +146,17 @@
- ${docker.host.port}:${docker.container.port}
+
+ ${docker.host.port}:${docker.container.port}
${docker.container.waitForEndpoint}
+
+
+ integration
+
@@ -171,7 +189,7 @@
-
+
docker
diff --git a/basyx.submodelrepository/basyx.submodelrepository.component/src/main/resources/application-integration.properties b/basyx.submodelrepository/basyx.submodelrepository.component/src/main/resources/application-integration.properties
new file mode 100644
index 000000000..5ae73e3f3
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository.component/src/main/resources/application-integration.properties
@@ -0,0 +1,26 @@
+server.port=8081
+server.error.path=/error
+
+spring.application.name=AAS Repository
+basyx.smrepo.name = sm-repo
+
+basyx.backend = InMemory
+
+basyx.submodelrepository.feature.registryintegration=http://host.docker.internal:8060/api/v3.0
+basyx.externalurl=http://localhost:8081
+
+#basyx.backend = MongoDB
+#spring.data.mongodb.host=mongo
+# or spring.data.mongodb.host=127.0.0.1
+#spring.data.mongodb.port=27017
+#spring.data.mongodb.database=submodels
+#spring.data.mongodb.authentication-database=admin
+#spring.data.mongodb.username=mongoAdmin
+#spring.data.mongodb.password=mongoPassword
+
+# basyx.submodelrepository.feature.mqtt.enabled = true
+# mqtt.clientId=TestClient
+# mqtt.hostname = localhost
+# mqtt.port = 1883
+
+# basyx.cors.allowed-origins=http://localhost:3000, http://localhost:4000
diff --git a/basyx.submodelrepository/basyx.submodelrepository.component/src/main/resources/application.properties b/basyx.submodelrepository/basyx.submodelrepository.component/src/main/resources/application.properties
index cbbabfbc1..1656e4e7c 100644
--- a/basyx.submodelrepository/basyx.submodelrepository.component/src/main/resources/application.properties
+++ b/basyx.submodelrepository/basyx.submodelrepository.component/src/main/resources/application.properties
@@ -4,6 +4,9 @@ spring.application.name=Submodel Repository
basyx.smrepo.name = sm-repo
basyx.backend = InMemory
+# basyx.submodelrepository.feature.registryintegration=http://localhost:8060/api/v3.0
+# basyx.externalurl=http://localhost:8081
+
#basyx.backend = MongoDB
#spring.data.mongodb.host=mongo
# or spring.data.mongodb.host=127.0.0.1
diff --git a/basyx.submodelrepository/basyx.submodelrepository.component/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/component/SubmodelRepositoryRegistryLinkIT.java b/basyx.submodelrepository/basyx.submodelrepository.component/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/component/SubmodelRepositoryRegistryLinkIT.java
new file mode 100644
index 000000000..a0cfaea88
--- /dev/null
+++ b/basyx.submodelrepository/basyx.submodelrepository.component/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/component/SubmodelRepositoryRegistryLinkIT.java
@@ -0,0 +1,12 @@
+package org.eclipse.digitaltwin.basyx.submodelrepository.component;
+
+import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.SubmodelRepositoryRegistryTestLink;
+
+/**
+ * Integration test for the Submodel Repository integration with Submodel Registry
+ *
+ * @author danish
+ *
+ */
+public class SubmodelRepositoryRegistryLinkIT extends SubmodelRepositoryRegistryTestLink {
+}
diff --git a/basyx.submodelrepository/pom.xml b/basyx.submodelrepository/pom.xml
index f1d918803..c38c3d1fb 100644
--- a/basyx.submodelrepository/pom.xml
+++ b/basyx.submodelrepository/pom.xml
@@ -16,6 +16,7 @@
basyx.submodelrepository-http
basyx.submodelrepository-backend-inmemory
basyx.submodelrepository-feature-mqtt
+ basyx.submodelrepository-feature-registry-integration
basyx.submodelrepository-tck
basyx.submodelrepository.component
basyx.submodelrepository-backend-mongodb
diff --git a/docker-compose.yml b/docker-compose.yml
index cfb37a409..9408a3afb 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -73,6 +73,24 @@ services:
condition: service_healthy
networks:
- basyx-java-server-sdk
+
+ aas-registry-log-mem:
+ image: eclipsebasyx/aas-registry-log-mem:2.0.0-SNAPSHOT
+ container_name: aas-registry-log-mem
+ ports:
+ - "8050:8080"
+ restart: always
+ networks:
+ - basyx-java-server-sdk
+
+ sm-registry-log-mem:
+ image: eclipsebasyx/submodel-registry-log-mem:2.0.0-SNAPSHOT
+ container_name: sm-registry-log-mem
+ ports:
+ - "8060:8080"
+ restart: always
+ networks:
+ - basyx-java-server-sdk
networks:
basyx-java-server-sdk:
diff --git a/pom.xml b/pom.xml
index 8d725b726..184eceb72 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
basyx.aasregistry
basyx.aasenvironment
basyx.conceptdescriptionrepository
- basyx.aasxfileserver
+ basyx.aasxfileserver
basyx.aasdiscoveryservice
BaSyx Parent
@@ -288,14 +288,14 @@
${revision}
- org.eclipse.digitaltwin.basyx
- basyx.submodelservice.component
- ${revision}
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelservice.component
+ ${revision}
- org.eclipse.digitaltwin.basyx
- basyx.submodelservice-http
- ${revision}
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelservice-http
+ ${revision}
@@ -323,6 +323,11 @@
basyx.submodelrepository-feature-mqtt
${revision}
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelrepository-feature-registry-integration
+ ${revision}
+
org.eclipse.digitaltwin.basyx
basyx.submodelrepository.component
@@ -390,6 +395,11 @@
basyx.aasrepository-feature-mqtt
${revision}
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasrepository-feature-registry-integration
+ ${revision}
+
org.eclipse.digitaltwin.basyx
basyx.aasrepository.component
@@ -441,7 +451,7 @@
org.eclipse.digitaltwin.basyx
basyx.conceptdescriptionrepository.component
${revision}
-
+
org.eclipse.digitaltwin.basyx
@@ -478,7 +488,7 @@
org.eclipse.digitaltwin.basyx
basyx.aasxfileserver-core
${revision}
-
+
org.eclipse.digitaltwin.basyx
basyx.aasxfileserver-backend-inmemory
@@ -489,6 +499,17 @@
basyx.aasxfileserver.component
${revision}
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasregistry-client-native
+ ${revision}
+
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelregistry-client-native
+ ${revision}
+
@@ -518,16 +539,16 @@
tests
- org.eclipse.digitaltwin.basyx
- basyx.submodelservice.component
- ${revision}
- tests
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelservice.component
+ ${revision}
+ tests
- org.eclipse.digitaltwin.basyx
- basyx.submodelservice-http
- ${revision}
- tests
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelservice-http
+ ${revision}
+ tests
@@ -566,6 +587,12 @@
${revision}
tests
+
+ org.eclipse.digitaltwin.basyx
+ basyx.submodelrepository-feature-registry-integration
+ ${revision}
+ tests
+
org.eclipse.digitaltwin.basyx
@@ -634,6 +661,12 @@
${revision}
tests
+
+ org.eclipse.digitaltwin.basyx
+ basyx.aasrepository-feature-registry-integration
+ ${revision}
+ tests
+
org.eclipse.digitaltwin.basyx
basyx.aasrepository.component
@@ -695,7 +728,7 @@
basyx.conceptdescriptionrepository.component
${revision}
tests
-
+
org.eclipse.digitaltwin.basyx
@@ -732,7 +765,7 @@
basyx.aasdiscoveryservice.component
${revision}
tests
-
+
org.eclipse.digitaltwin.basyx