From a5696ff85782761cee61eb49258b0a2025e344f0 Mon Sep 17 00:00:00 2001 From: Gerhard Sonnenberg <53293048+geso02@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:11:01 +0200 Subject: [PATCH 01/10] Allow multiple descriptor endpoints (#356) * Allow multiple descriptor endpoints refs #272 * Add multi endpoint auto registration tests refs #272 * Remove cleanup functionality it is not really needed and could affect the authorization test --- .../client/ConnectedAasManagerHelper.java | 10 ++- .../integration/AasDescriptorFactory.java | 41 ++++++---- .../AasRepositoryRegistryLink.java | 12 +-- .../RegistryIntegrationAasRepository.java | 6 +- ...IntegrationAasRepositoryConfiguration.java | 9 ++- .../AasRepositoryRegistryLinkTest.java | 4 +- .../AasRepositoryRegistryLinkTestSuite.java | 53 +++++++----- ...thorizedAasRepositoryRegistryLinkTest.java | 4 +- .../DummyAasDescriptorFactory.java | 7 +- ...MultiUrlAasRepositoryRegistryLinkTest.java | 80 +++++++++++++++++++ .../resources/application-multiurl.properties | 35 ++++++++ ...RegistryIntegrationSubmodelRepository.java | 6 +- ...rationSubmodelRepositoryConfiguration.java | 11 +-- .../SubmodelDescriptorFactory.java | 34 +++++--- .../SubmodelRepositoryRegistryLink.java | 12 +-- ...zedSubmodelRepositoryRegistryLinkTest.java | 4 +- .../DummySubmodelDescriptorFactory.java | 10 ++- ...UrlSubmodelRepositoryRegistryLinkTest.java | 76 ++++++++++++++++++ .../SubmodelRepositoryRegistryLinkTest.java | 4 +- ...bmodelRepositoryRegistryLinkTestSuite.java | 50 +++++++----- .../resources/application-multiurl.properties | 34 ++++++++ examples/BaSyxMinimal/aas-env.properties | 2 +- 22 files changed, 393 insertions(+), 111 deletions(-) create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/MultiUrlAasRepositoryRegistryLinkTest.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/resources/application-multiurl.properties create mode 100644 basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/MultiUrlSubmodelRepositoryRegistryLinkTest.java create mode 100644 basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/resources/application-multiurl.properties diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java index ab6044d7f..8290ba0f9 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java +++ b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java @@ -26,6 +26,8 @@ package org.eclipse.digitaltwin.basyx.aasenvironment.client; +import java.util.List; + import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.AasDescriptorFactory; import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper; import org.eclipse.digitaltwin.basyx.http.Aas4JHTTPSerializationExtension; @@ -55,16 +57,16 @@ static ObjectMapper buildObjectMapper() { return builder.build(); } - static AasDescriptorFactory buildAasDescriptorFactory(String aasRepositoryBaseUrl) { + static AasDescriptorFactory buildAasDescriptorFactory(String... aasRepositoryBaseUrls) { AttributeMapper attributeMapper = new AttributeMapper(objectMapper); - return new AasDescriptorFactory(null, aasRepositoryBaseUrl, attributeMapper); + return new AasDescriptorFactory(null, List.of(aasRepositoryBaseUrls), attributeMapper); } - static SubmodelDescriptorFactory buildSmDescriptorFactory(String aasRepositoryBaseUrl) { + static SubmodelDescriptorFactory buildSmDescriptorFactory(String... aasRepositoryBaseUrls) { org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper attributeMapperSm = new org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper( objectMapper); - return new SubmodelDescriptorFactory(null, aasRepositoryBaseUrl, attributeMapperSm); + return new SubmodelDescriptorFactory(null, List.of(aasRepositoryBaseUrls), attributeMapperSm); } } 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 index fa26f48a2..a28948c34 100644 --- 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 @@ -27,6 +27,7 @@ import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation; @@ -50,16 +51,16 @@ 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 List aasRepositoryURLs; private AttributeMapper attributeMapper; - - public AasDescriptorFactory(AssetAdministrationShell shell, String aasRepositoryBaseURL, AttributeMapper attributeMapper) { - super(); + + public AasDescriptorFactory(AssetAdministrationShell shell, List aasRepositoryBaseURLs, + AttributeMapper attributeMapper) { this.shell = shell; - this.aasRepositoryURL = createAasRepositoryUrl(aasRepositoryBaseURL); + this.aasRepositoryURLs = createAasRepositoryUrls(aasRepositoryBaseURLs); this.attributeMapper = attributeMapper; } @@ -124,7 +125,8 @@ private void setExtensions(List extensions, AssetAdministrationShellD descriptor.setExtensions(attributeMapper.mapExtensions(extensions)); } - private void setAdministration(AdministrativeInformation administration, AssetAdministrationShellDescriptor descriptor) { + private void setAdministration(AdministrativeInformation administration, + AssetAdministrationShellDescriptor descriptor) { if (administration == null) return; @@ -157,17 +159,18 @@ private void setGlobalAssetId(AssetInformation assetInformation, AssetAdministra } private void setEndpointItem(String shellId, AssetAdministrationShellDescriptor descriptor) { + for (String eachUrl : aasRepositoryURLs) { + Endpoint endpoint = new Endpoint(); + endpoint.setInterface(AAS_INTERFACE); + ProtocolInformation protocolInformation = createProtocolInformation(shellId, eachUrl); + endpoint.setProtocolInformation(protocolInformation); - Endpoint endpoint = new Endpoint(); - endpoint.setInterface(AAS_INTERFACE); - ProtocolInformation protocolInformation = createProtocolInformation(shellId); - endpoint.setProtocolInformation(protocolInformation); - - descriptor.addEndpointsItem(endpoint); + descriptor.addEndpointsItem(endpoint); + } } - private ProtocolInformation createProtocolInformation(String shellId) { - String href = String.format("%s/%s", aasRepositoryURL, Base64UrlEncodedIdentifier.encodeIdentifier(shellId)); + private ProtocolInformation createProtocolInformation(String shellId, String url) { + String href = String.format("%s/%s", url, Base64UrlEncodedIdentifier.encodeIdentifier(shellId)); ProtocolInformation protocolInformation = new ProtocolInformation(); protocolInformation.endpointProtocol(getProtocol(href)); @@ -192,6 +195,14 @@ private String getProtocol(String endpoint) { } } + private List createAasRepositoryUrls(List aasRepositoryBaseURLs) { + List toReturn = new ArrayList<>(aasRepositoryBaseURLs.size()); + for (String eachUrl : aasRepositoryBaseURLs) { + toReturn.add(createAasRepositoryUrl(eachUrl)); + } + return toReturn; + } + private String createAasRepositoryUrl(String aasRepositoryBaseURL) { try { 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 index 9210e24cd..d22a91eb6 100644 --- 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 @@ -25,6 +25,8 @@ package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; +import java.util.List; + import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi; import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; @@ -36,20 +38,20 @@ public class AasRepositoryRegistryLink { private RegistryAndDiscoveryInterfaceApi registryApi; - private String aasRepositoryBaseURL; + private List aasRepositoryBaseURLs; - public AasRepositoryRegistryLink(RegistryAndDiscoveryInterfaceApi registryApi, String aasRepositoryBaseURL) { + public AasRepositoryRegistryLink(RegistryAndDiscoveryInterfaceApi registryApi, List aasRepositoryBaseURLs) { super(); this.registryApi = registryApi; - this.aasRepositoryBaseURL = aasRepositoryBaseURL; + this.aasRepositoryBaseURLs = aasRepositoryBaseURLs; } public RegistryAndDiscoveryInterfaceApi getRegistryApi() { return registryApi; } - public String getAasRepositoryBaseURL() { - return aasRepositoryBaseURL; + public List getAasRepositoryBaseURLs() { + return aasRepositoryBaseURLs; } } 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 index ba9457e3e..a2233b0d9 100644 --- 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 @@ -79,7 +79,7 @@ public AssetAdministrationShell getAas(String shellId) throws ElementDoesNotExis public void createAas(AssetAdministrationShell shell) throws CollidingIdentifierException { decorated.createAas(shell); - integrateAasWithRegistry(shell, aasRepositoryRegistryLink.getAasRepositoryBaseURL()); + integrateAasWithRegistry(shell, aasRepositoryRegistryLink.getAasRepositoryBaseURLs()); } @Override @@ -124,8 +124,8 @@ public AssetInformation getAssetInformation(String shellId) throws ElementDoesNo return decorated.getAssetInformation(shellId); } - private void integrateAasWithRegistry(AssetAdministrationShell shell, String aasRepositoryURL) { - AssetAdministrationShellDescriptor descriptor = new AasDescriptorFactory(shell, aasRepositoryURL, attributeMapper).create(); + private void integrateAasWithRegistry(AssetAdministrationShell shell, List aasRepositoryURLs) { + AssetAdministrationShellDescriptor descriptor = new AasDescriptorFactory(shell, aasRepositoryURLs, attributeMapper).create(); RegistryAndDiscoveryInterfaceApi registryApi = aasRepositoryRegistryLink.getRegistryApi(); 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 index a3e78e837..a468b5dd1 100644 --- 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 @@ -26,6 +26,7 @@ package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; import java.util.Collection; +import java.util.List; import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi; import org.eclipse.digitaltwin.basyx.aasregistry.main.client.AuthorizedConnectedAasRegistry; @@ -55,8 +56,8 @@ public class RegistryIntegrationAasRepositoryConfiguration { @Value("${basyx.aasrepository.feature.registryintegration:#{null}}") private String registryBasePath; - @Value("${basyx.externalurl:#{null}}") - private String aasRepositoryBaseURL; + @Value("#{'${basyx.externalurl}'.split(',')}") + private List aasRepositoryBaseURLs; @Value("${basyx.aasrepository.feature.registryintegration.authorization.enabled:false}") private boolean isAuthorizationEnabledOnRegistry; @@ -87,11 +88,11 @@ public class RegistryIntegrationAasRepositoryConfiguration { public AasRepositoryRegistryLink getAasRepositoryRegistryLink() { if (!isAuthorizationEnabledOnRegistry) - return new AasRepositoryRegistryLink(new RegistryAndDiscoveryInterfaceApi(registryBasePath), aasRepositoryBaseURL); + return new AasRepositoryRegistryLink(new RegistryAndDiscoveryInterfaceApi(registryBasePath), aasRepositoryBaseURLs); TokenManager tokenManager = new TokenManager(authenticationServerTokenEndpoint, createAccessTokenProvider()); - return new AasRepositoryRegistryLink(new AuthorizedConnectedAasRegistry(registryBasePath, tokenManager), aasRepositoryBaseURL); + return new AasRepositoryRegistryLink(new AuthorizedConnectedAasRegistry(registryBasePath, tokenManager), aasRepositoryBaseURLs); } @Bean diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTest.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTest.java index 4c563eb38..e35a8130a 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTest.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTest.java @@ -59,8 +59,8 @@ public static void tearDown() { } @Override - protected String getAasRepoBaseUrl() { - return AAS_REPO_URL; + protected String[] getAasRepoBaseUrls() { + return new String[] { AAS_REPO_URL}; } @Override diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java index a289abfa0..3c169f084 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java @@ -41,6 +41,8 @@ import org.eclipse.digitaltwin.basyx.aasregistry.client.model.GetAssetAdministrationShellDescriptorsResult; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; import org.eclipse.digitaltwin.basyx.http.serialization.BaSyxHttpTestUtils; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpStatus; @@ -56,36 +58,41 @@ public abstract class AasRepositoryRegistryLinkTestSuite { private static final String DUMMY_IDSHORT = "ExampleMotor"; private static final String DUMMY_AAS_ID = "customIdentifier"; - protected abstract String getAasRepoBaseUrl(); - protected abstract String getAasRegistryUrl(); - protected abstract RegistryAndDiscoveryInterfaceApi getAasRegistryApi(); + protected abstract String[] getAasRepoBaseUrls(); - private final AssetAdministrationShellDescriptor DUMMY_DESCRIPTOR = DummyAasDescriptorFactory.createDummyDescriptor(DUMMY_AAS_ID, DUMMY_IDSHORT, DUMMY_GLOBAL_ASSETID, getAasRepoBaseUrl()); + protected abstract String getAasRegistryUrl(); + + protected abstract RegistryAndDiscoveryInterfaceApi getAasRegistryApi(); + + private final AssetAdministrationShellDescriptor DUMMY_DESCRIPTOR = DummyAasDescriptorFactory + .createDummyDescriptor(DUMMY_AAS_ID, DUMMY_IDSHORT, DUMMY_GLOBAL_ASSETID, getAasRepoBaseUrls()); @Test public void createAas() throws FileNotFoundException, IOException, ApiException { String aasJsonContent = getAas1JSONString(); - CloseableHttpResponse creationResponse = createAasOnRepo(aasJsonContent); - assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); + try (CloseableHttpResponse creationResponse = createAasOnRepo(aasJsonContent)) { + assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); - AssetAdministrationShellDescriptor actualDescriptor = retrieveDescriptorFromRegistry(); + AssetAdministrationShellDescriptor actualDescriptor = retrieveDescriptorFromRegistry(); - assertEquals(DUMMY_DESCRIPTOR, actualDescriptor); + assertEquals(DUMMY_DESCRIPTOR, actualDescriptor); - resetRepository(); + 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()); + try (CloseableHttpResponse creationResponse = createAasOnRepo(aasJsonContent)) { + assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); + } + try (CloseableHttpResponse deleteResponse = deleteAasFromRepo(DUMMY_AAS_ID)) { + assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode()); + } assertDescriptionDeletionAtRegistry(); } @@ -96,9 +103,9 @@ private AssetAdministrationShellDescriptor retrieveDescriptorFromRegistry() thro } private void resetRepository() throws IOException { - CloseableHttpResponse deleteResponse = deleteAasFromRepo(DUMMY_AAS_ID); - - assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode()); + try (CloseableHttpResponse deleteResponse = deleteAasFromRepo(DUMMY_AAS_ID)) { + assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode()); + } } private CloseableHttpResponse deleteAasFromRepo(String shellId) throws IOException { @@ -108,7 +115,8 @@ private CloseableHttpResponse deleteAasFromRepo(String shellId) throws IOExcepti private void assertDescriptionDeletionAtRegistry() throws ApiException { RegistryAndDiscoveryInterfaceApi api = getAasRegistryApi(); - GetAssetAdministrationShellDescriptorsResult result = api.getAllAssetAdministrationShellDescriptors(null, null, null, null); + GetAssetAdministrationShellDescriptorsResult result = api.getAllAssetAdministrationShellDescriptors(null, null, + null, null); List actualDescriptors = result.getResult(); @@ -120,11 +128,16 @@ private String getAas1JSONString() throws FileNotFoundException, IOException { } private CloseableHttpResponse createAasOnRepo(String aasJsonContent) throws IOException { - return BaSyxHttpTestUtils.executePostOnURL(createAasRepositoryUrl(getAasRepoBaseUrl()), aasJsonContent); + return BaSyxHttpTestUtils.executePostOnURL(createAasRepositoryUrl(getFirstAasRepoBaseUrl()), aasJsonContent); } private String getSpecificAasAccessURL(String aasId) { - return createAasRepositoryUrl(getAasRepoBaseUrl()) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(aasId); + return createAasRepositoryUrl(getFirstAasRepoBaseUrl()) + "/" + + Base64UrlEncodedIdentifier.encodeIdentifier(aasId); + } + + private String getFirstAasRepoBaseUrl() { + return getAasRepoBaseUrls()[0]; } private static String createAasRepositoryUrl(String aasRepositoryBaseURL) { diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AuthorizedAasRepositoryRegistryLinkTest.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AuthorizedAasRepositoryRegistryLinkTest.java index 5829e7ee1..c56d5db09 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AuthorizedAasRepositoryRegistryLinkTest.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AuthorizedAasRepositoryRegistryLinkTest.java @@ -89,8 +89,8 @@ public void sendUnauthorizedRequest() throws IOException { } @Override - protected String getAasRepoBaseUrl() { - return AAS_REPO_URL; + protected String[] getAasRepoBaseUrls() { + return new String[] {AAS_REPO_URL}; } @Override diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/DummyAasDescriptorFactory.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/DummyAasDescriptorFactory.java index 9a832d3c6..d134100b1 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/DummyAasDescriptorFactory.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/DummyAasDescriptorFactory.java @@ -43,7 +43,7 @@ public class DummyAasDescriptorFactory { private static final String AAS_REPOSITORY_PATH = "/shells"; - public static AssetAdministrationShellDescriptor createDummyDescriptor(String aasId, String idShort, String globalAssetId, String aasRepoBaseUrl) { + public static AssetAdministrationShellDescriptor createDummyDescriptor(String aasId, String idShort, String globalAssetId, String... aasRepoBaseUrls) { AssetAdministrationShellDescriptor descriptor = new AssetAdministrationShellDescriptor(); @@ -51,8 +51,9 @@ public static AssetAdministrationShellDescriptor createDummyDescriptor(String aa descriptor.setIdShort(idShort); descriptor.setAssetKind(AssetKind.INSTANCE); descriptor.setGlobalAssetId(globalAssetId); - descriptor.addEndpointsItem(createEndpointItem(aasId, aasRepoBaseUrl)); - + for (String eachUrl : aasRepoBaseUrls) { + descriptor.addEndpointsItem(createEndpointItem(aasId, eachUrl)); + } return descriptor; } diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/MultiUrlAasRepositoryRegistryLinkTest.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/MultiUrlAasRepositoryRegistryLinkTest.java new file mode 100644 index 000000000..ef9ac377d --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/MultiUrlAasRepositoryRegistryLinkTest.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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.io.FileNotFoundException; +import java.io.IOException; + +import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Integration test for {@link RegistryIntegrationAasRepository} feature + * + * @author danish + */ +public class MultiUrlAasRepositoryRegistryLinkTest extends AasRepositoryRegistryLinkTestSuite { + + private static final String[] AAS_REPO_URLS = new String []{"http://localhost:8081","https://aas-repo.example.org","http://aas-repo:8081"}; + private static final String AAS_REGISTRY_BASE_URL = "http://localhost:8050"; + private static ConfigurableApplicationContext appContext; + private static AasRepositoryRegistryLink aasRepositoryRegistryLink; + + @BeforeClass + public static void setUp() throws FileNotFoundException, IOException { + SpringApplication application = new SpringApplication(DummyAasRepositoryIntegrationComponent.class); + application.setAdditionalProfiles("multiurl"); + + appContext = application.run(new String[] {}); + + aasRepositoryRegistryLink = appContext.getBean(AasRepositoryRegistryLink.class); + } + + @AfterClass + public static void tearDown() { + appContext.close(); + } + + @Override + protected String[] getAasRepoBaseUrls() { + return AAS_REPO_URLS; + } + + @Override + protected String getAasRegistryUrl() { + return AAS_REGISTRY_BASE_URL; + } + + @Override + protected RegistryAndDiscoveryInterfaceApi getAasRegistryApi() { + + return aasRepositoryRegistryLink.getRegistryApi(); + } + +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/resources/application-multiurl.properties b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/resources/application-multiurl.properties new file mode 100644 index 000000000..323b793be --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/resources/application-multiurl.properties @@ -0,0 +1,35 @@ +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://localhost:8050 +basyx.externalurl=http://localhost:8081,https://aas-repo.example.org,http://aas-repo: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 + +#################################################################################### +# Authorization +#################################################################################### +#basyx.feature.authorization.enabled = true +#basyx.feature.authorization.type = rbac +#basyx.feature.authorization.jwtBearerTokenProvider = keycloak +#basyx.feature.authorization.rbac.file = classpath:rbac_rules.json +#spring.security.oauth2.resourceserver.jwt.issuer-uri= http://localhost:9096/realms/BaSyx 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 index ef09a1ec4..4f51226db 100644 --- 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 @@ -87,7 +87,7 @@ public void updateSubmodel(String submodelId, Submodel submodel) throws ElementD public void createSubmodel(Submodel submodel) throws CollidingIdentifierException { decorated.createSubmodel(submodel); - integrateSubmodelWithRegistry(submodel, submodelRepositoryRegistryLink.getSubmodelRepositoryBaseURL()); + integrateSubmodelWithRegistry(submodel, submodelRepositoryRegistryLink.getSubmodelRepositoryBaseURLs()); } @Override @@ -167,8 +167,8 @@ public void deleteFileValue(String submodelId, String idShortPath) throws Elemen decorated.deleteFileValue(submodelId, idShortPath); } - private void integrateSubmodelWithRegistry(Submodel submodel, String submodelRepositoryURL) { - SubmodelDescriptor descriptor = new SubmodelDescriptorFactory(submodel, submodelRepositoryURL, attributeMapper).create(); + private void integrateSubmodelWithRegistry(Submodel submodel, List submodelRepositoryURLs) { + SubmodelDescriptor descriptor = new SubmodelDescriptorFactory(submodel, submodelRepositoryURLs, attributeMapper).create(); SubmodelRegistryApi registryApi = submodelRepositoryRegistryLink.getRegistryApi(); 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 index b0ff9e81d..1c8390618 100644 --- 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 @@ -26,6 +26,7 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; import java.util.Collection; +import java.util.List; import org.eclipse.digitaltwin.basyx.client.internal.authorization.AccessTokenProviderFactory; import org.eclipse.digitaltwin.basyx.client.internal.authorization.TokenManager; @@ -55,8 +56,8 @@ public class RegistryIntegrationSubmodelRepositoryConfiguration { @Value("${basyx.submodelrepository.feature.registryintegration:#{null}}") private String registryBasePath; - @Value("${basyx.externalurl:#{null}}") - private String submodelRepositoryBaseURL; + @Value("#{'${basyx.externalurl}'.split(',')}") + private List submodelRepositoryBaseURLs; @Value("${basyx.submodelrepository.feature.registryintegration.authorization.enabled:false}") private boolean isAuthorizationEnabledOnRegistry; @@ -84,14 +85,14 @@ public class RegistryIntegrationSubmodelRepositoryConfiguration { @Bean @ConditionalOnMissingBean - public SubmodelRepositoryRegistryLink getSubmodelRepositoryRegistryLink(@Value("${basyx.submodelrepository.feature.registryintegration}") String registryBasePath, @Value("${basyx.externalurl}") String submodelRepositoryBaseURL) { + public SubmodelRepositoryRegistryLink getSubmodelRepositoryRegistryLink() { if (!isAuthorizationEnabledOnRegistry) - return new SubmodelRepositoryRegistryLink(new SubmodelRegistryApi(registryBasePath), submodelRepositoryBaseURL); + return new SubmodelRepositoryRegistryLink(new SubmodelRegistryApi(registryBasePath), submodelRepositoryBaseURLs); TokenManager tokenManager = new TokenManager(authenticationServerTokenEndpoint, createAccessTokenProvider()); - return new SubmodelRepositoryRegistryLink(new AuthorizedConnectedSubmodelRegistry(registryBasePath, tokenManager), submodelRepositoryBaseURL); + return new SubmodelRepositoryRegistryLink(new AuthorizedConnectedSubmodelRegistry(registryBasePath, tokenManager), submodelRepositoryBaseURLs); } @Bean 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 index fc96f639e..ec2dbff4a 100644 --- 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 @@ -27,6 +27,7 @@ import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.List; import org.eclipse.digitaltwin.aas4j.v3.model.AdministrativeInformation; @@ -52,14 +53,14 @@ public class SubmodelDescriptorFactory { private static final String SUBMODEL_REPOSITORY_PATH = "submodels"; private Submodel submodel; - private String submodelRepositoryURL; + private List submodelRepositoryURLs; private AttributeMapper attributeMapper; - public SubmodelDescriptorFactory(Submodel submodel, String submodelRepositoryBaseURL, AttributeMapper attributeMapper) { - super(); + public SubmodelDescriptorFactory(Submodel submodel, List submodelRepositoryBaseURLs, + AttributeMapper attributeMapper) { this.submodel = submodel; - this.submodelRepositoryURL = createSubmodelRepositoryUrl(submodelRepositoryBaseURL); + this.submodelRepositoryURLs = createSubmodelRepositoryUrls(submodelRepositoryBaseURLs); this.attributeMapper = attributeMapper; } @@ -148,16 +149,19 @@ private void setSupplementalSemanticId(List supplementalSemanticIds, private void setEndpointItem(String shellId, SubmodelDescriptor descriptor) { - Endpoint endpoint = new Endpoint(); - endpoint.setInterface(SUBMODEL_INTERFACE); - ProtocolInformation protocolInformation = createProtocolInformation(shellId); - endpoint.setProtocolInformation(protocolInformation); + for (String eachUrl : submodelRepositoryURLs) { + Endpoint endpoint = new Endpoint(); + endpoint.setInterface(SUBMODEL_INTERFACE); + ProtocolInformation protocolInformation = createProtocolInformation(shellId, eachUrl); + endpoint.setProtocolInformation(protocolInformation); - descriptor.addEndpointsItem(endpoint); + descriptor.addEndpointsItem(endpoint); + } } - private ProtocolInformation createProtocolInformation(String shellId) { - String href = String.format("%s/%s", submodelRepositoryURL, Base64UrlEncodedIdentifier.encodeIdentifier(shellId)); + private ProtocolInformation createProtocolInformation(String shellId, String url) { + String href = String.format("%s/%s", url, + Base64UrlEncodedIdentifier.encodeIdentifier(shellId)); ProtocolInformation protocolInformation = new ProtocolInformation(); protocolInformation.endpointProtocol(getProtocol(href)); @@ -182,6 +186,14 @@ private String getProtocol(String endpoint) { } } + private List createSubmodelRepositoryUrls(List submodelRepositoryBaseURLs) { + List toReturn = new ArrayList<>(submodelRepositoryBaseURLs.size()); + for (String eachUrl : submodelRepositoryBaseURLs) { + toReturn.add(createSubmodelRepositoryUrl(eachUrl)); + } + return toReturn; + } + private String createSubmodelRepositoryUrl(String submodelRepositoryBaseURL) { try { 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 index 56b1198ca..5ba4fc175 100644 --- 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 @@ -25,6 +25,8 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; +import java.util.List; + import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository; @@ -36,20 +38,20 @@ public class SubmodelRepositoryRegistryLink { private SubmodelRegistryApi registryApi; - private String submodelRepositoryBaseURL; + private List submodelRepositoryBaseURLs; - public SubmodelRepositoryRegistryLink(SubmodelRegistryApi registryApi, String submodelRepositoryBaseURL) { + public SubmodelRepositoryRegistryLink(SubmodelRegistryApi registryApi, List submodelRepositoryBaseURLs) { super(); this.registryApi = registryApi; - this.submodelRepositoryBaseURL = submodelRepositoryBaseURL; + this.submodelRepositoryBaseURLs = submodelRepositoryBaseURLs; } public SubmodelRegistryApi getRegistryApi() { return registryApi; } - public String getSubmodelRepositoryBaseURL() { - return submodelRepositoryBaseURL; + public List getSubmodelRepositoryBaseURLs() { + return submodelRepositoryBaseURLs; } } diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/AuthorizedSubmodelRepositoryRegistryLinkTest.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/AuthorizedSubmodelRepositoryRegistryLinkTest.java index 8e2bbe8b8..87f3836b2 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/AuthorizedSubmodelRepositoryRegistryLinkTest.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/AuthorizedSubmodelRepositoryRegistryLinkTest.java @@ -90,8 +90,8 @@ public void sendUnauthorizedRequest() throws IOException { } @Override - protected String getSubmodelRepoBaseUrl() { - return SUBMODEL_REPO_URL; + protected String[] getSubmodelRepoBaseUrls() { + return new String[] { SUBMODEL_REPO_URL }; } @Override diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/DummySubmodelDescriptorFactory.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/DummySubmodelDescriptorFactory.java index 4e821bc9b..5d00fb86e 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/DummySubmodelDescriptorFactory.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/DummySubmodelDescriptorFactory.java @@ -48,14 +48,18 @@ public class DummySubmodelDescriptorFactory { private static final String SUBMODEL_REPOSITORY_PATH = "/submodels"; public static SubmodelDescriptor createDummyDescriptor(String smId, String idShort, String smRepoBaseUrl, Reference semanticId) { - + return createDummyDescriptor(smId, idShort, new String[] {smRepoBaseUrl}, semanticId); + } + + public static SubmodelDescriptor createDummyDescriptor(String smId, String idShort, String[] smRepoBaseUrls, Reference semanticId) { SubmodelDescriptor descriptor = new SubmodelDescriptor(); descriptor.setId(smId); descriptor.setIdShort(idShort); descriptor.setSemanticId(semanticId); - descriptor.addEndpointsItem(createEndpointItem(smId, smRepoBaseUrl)); - + for (String eachUrl : smRepoBaseUrls) { + descriptor.addEndpointsItem(createEndpointItem(smId, eachUrl)); + } return descriptor; } diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/MultiUrlSubmodelRepositoryRegistryLinkTest.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/MultiUrlSubmodelRepositoryRegistryLinkTest.java new file mode 100644 index 000000000..e34ae3d07 --- /dev/null +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/MultiUrlSubmodelRepositoryRegistryLinkTest.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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.io.FileNotFoundException; +import java.io.IOException; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Integration test for {@link RegistryIntegrationSubmodelRepository} feature + * + * @author danish + */ +public class MultiUrlSubmodelRepositoryRegistryLinkTest extends SubmodelRepositoryRegistryLinkTestSuite { + + private static final String[] SUBMODEL_REPO_URLS = new String[] {"http://localhost:8081", "https://sm-repo.example.org", "http://sm-repo:8081"}; + private static final String SUBMODEL_REGISTRY_BASE_URL = "http://localhost:8060"; + private static ConfigurableApplicationContext appContext; + private static SubmodelRepositoryRegistryLink submodelRepositoryRegistryLink; + + @BeforeClass + public static void setUp() throws FileNotFoundException, IOException { + SpringApplication application = new SpringApplication(DummySubmodelRepositoryIntegrationComponent.class); + application.setAdditionalProfiles("multiurl"); + appContext = application.run(new String[] {}); + submodelRepositoryRegistryLink = appContext.getBean(SubmodelRepositoryRegistryLink.class); + } + + @AfterClass + public static void tearDown() { + appContext.close(); + } + + @Override + protected String[] getSubmodelRepoBaseUrls() { + return SUBMODEL_REPO_URLS; + } + @Override + protected String getSubmodelRegistryUrl() { + return SUBMODEL_REGISTRY_BASE_URL; + } + @Override + protected SubmodelRegistryApi getSubmodelRegistryApi() { + + return submodelRepositoryRegistryLink.getRegistryApi(); + } + + +} diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTest.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTest.java index 8b08db14d..35f7b1831 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTest.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTest.java @@ -58,8 +58,8 @@ public static void tearDown() { } @Override - protected String getSubmodelRepoBaseUrl() { - return SUBMODEL_REPO_URL; + protected String[] getSubmodelRepoBaseUrls() { + return new String[] { SUBMODEL_REPO_URL }; } @Override protected String getSubmodelRegistryUrl() { diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java index 54b704301..d64e98328 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java @@ -42,6 +42,8 @@ import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi; import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.GetSubmodelDescriptorsResult; import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.springframework.http.HttpStatus; @@ -57,19 +59,19 @@ public abstract class SubmodelRepositoryRegistryLinkTestSuite { private static final String DUMMY_SUBMODEL_IDSHORT = "TechnicalData"; private static final String DUMMY_SUBMODEL_ID = "7A7104BDAB57E184"; - protected abstract String getSubmodelRepoBaseUrl(); + protected abstract String[] getSubmodelRepoBaseUrls(); protected abstract String getSubmodelRegistryUrl(); protected abstract SubmodelRegistryApi getSubmodelRegistryApi(); - private final SubmodelDescriptor DUMMY_DESCRIPTOR = DummySubmodelDescriptorFactory.createDummyDescriptor(DUMMY_SUBMODEL_ID, DUMMY_SUBMODEL_IDSHORT, getSubmodelRepoBaseUrl(), DummySubmodelDescriptorFactory.createSemanticId()); - + private final SubmodelDescriptor DUMMY_DESCRIPTOR = DummySubmodelDescriptorFactory.createDummyDescriptor(DUMMY_SUBMODEL_ID, DUMMY_SUBMODEL_IDSHORT, getSubmodelRepoBaseUrls(), DummySubmodelDescriptorFactory.createSemanticId()); + @Test public void createSubmodel() throws FileNotFoundException, IOException, ApiException { String submodelJsonContent = getSubmodelJSONString(); - CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent); - assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); - + try (CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent)) { + assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); + } SubmodelDescriptor actualDescriptor = retrieveDescriptorFromRegistry(); assertEquals(DUMMY_DESCRIPTOR, actualDescriptor); @@ -82,14 +84,14 @@ public void createSubmodelElementInSubmodelElementCollection() throws FileNotFou String submodelJsonContent = getSubmodelJSONString(); String submodelElementJsonContent = getSinglePropertyJSONString(); - CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent); - assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); + try (CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent)) { + assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); + } createSubmodelElementOnRepo(submodelElementJsonContent); - CloseableHttpResponse getResponse = BaSyxHttpTestUtils.executeGetOnURL(getSpecificSubmodelAccessURL(DUMMY_SUBMODEL_ID)); - - BaSyxHttpTestUtils.assertSameJSONContent(getExpectedSubmodel(), BaSyxHttpTestUtils.getResponseAsString(getResponse)); - + try (CloseableHttpResponse getResponse = BaSyxHttpTestUtils.executeGetOnURL(getSpecificSubmodelAccessURL(DUMMY_SUBMODEL_ID))) { + BaSyxHttpTestUtils.assertSameJSONContent(getExpectedSubmodel(), BaSyxHttpTestUtils.getResponseAsString(getResponse)); + } resetRepository(); } @@ -97,11 +99,13 @@ public void createSubmodelElementInSubmodelElementCollection() throws FileNotFou public void deleteSubmodel() throws FileNotFoundException, IOException, ApiException { String submodelJsonContent = getSubmodelJSONString(); - CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent); - assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); + try (CloseableHttpResponse creationResponse = createSubmodelOnRepo(submodelJsonContent)) { + assertEquals(HttpStatus.CREATED.value(), creationResponse.getCode()); + } - CloseableHttpResponse deleteResponse = deleteSubmodelFromRepo(DUMMY_SUBMODEL_ID); - assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode()); + try (CloseableHttpResponse deleteResponse = deleteSubmodelFromRepo(DUMMY_SUBMODEL_ID)) { + assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode()); + } assertDescriptionDeletionAtRegistry(); } @@ -113,9 +117,9 @@ private SubmodelDescriptor retrieveDescriptorFromRegistry() throws ApiException } private void resetRepository() throws IOException { - CloseableHttpResponse deleteResponse = deleteSubmodelFromRepo(DUMMY_SUBMODEL_ID); - - assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode()); + try (CloseableHttpResponse deleteResponse = deleteSubmodelFromRepo(DUMMY_SUBMODEL_ID)) { + assertEquals(HttpStatus.NO_CONTENT.value(), deleteResponse.getCode()); + } } private CloseableHttpResponse deleteSubmodelFromRepo(String shellId) throws IOException { @@ -145,7 +149,11 @@ private String getExpectedSubmodel() throws FileNotFoundException, IOException { } private CloseableHttpResponse createSubmodelOnRepo(String submodelJsonContent) throws IOException { - return BaSyxHttpTestUtils.executePostOnURL(createSubmodelRepositoryUrl(getSubmodelRepoBaseUrl()), submodelJsonContent); + return BaSyxHttpTestUtils.executePostOnURL(createSubmodelRepositoryUrl(getFirstSubmodeRepoBaseUrl()), submodelJsonContent); + } + + private String getFirstSubmodeRepoBaseUrl() { + return getSubmodelRepoBaseUrls()[0]; } private CloseableHttpResponse createSubmodelElementOnRepo(String submodelElementJsonContent) throws IOException { @@ -155,7 +163,7 @@ private CloseableHttpResponse createSubmodelElementOnRepo(String submodelElement } private String getSpecificSubmodelAccessURL(String submodelId) { - return createSubmodelRepositoryUrl(getSubmodelRepoBaseUrl()) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(submodelId); + return createSubmodelRepositoryUrl(getFirstSubmodeRepoBaseUrl()) + "/" + Base64UrlEncodedIdentifier.encodeIdentifier(submodelId); } private static String createSubmodelRepositoryUrl(String smRepositoryBaseURL) { diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/resources/application-multiurl.properties b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/resources/application-multiurl.properties new file mode 100644 index 000000000..dd734fda8 --- /dev/null +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/resources/application-multiurl.properties @@ -0,0 +1,34 @@ +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://localhost:8060 +basyx.externalurl=http://localhost:8081,https://sm-repo.example.org,http://sm-repo: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 + +#################################################################################### +# Authorization +#################################################################################### +#basyx.feature.authorization.enabled = true +#basyx.feature.authorization.type = rbac +#basyx.feature.authorization.jwtBearerTokenProvider = keycloak +#basyx.feature.authorization.rbac.file = classpath:rbac_rules.json diff --git a/examples/BaSyxMinimal/aas-env.properties b/examples/BaSyxMinimal/aas-env.properties index 9e1f52f44..7cbcf180e 100644 --- a/examples/BaSyxMinimal/aas-env.properties +++ b/examples/BaSyxMinimal/aas-env.properties @@ -20,4 +20,4 @@ basyx.cors.allowed-methods=GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD basyx.aasrepository.feature.registryintegration = http://aas-registry:8080 basyx.submodelrepository.feature.registryintegration = http://sm-registry:8080 -basyx.externalurl = http://localhost:8081 +basyx.externalurl = http://localhost:8081,http://aas-env:8081 From 25be0cfa38f9e89c79210f61885c4d3d61e0b7b9 Mon Sep 17 00:00:00 2001 From: Jannik Fried Date: Tue, 20 Aug 2024 14:22:31 +0200 Subject: [PATCH 02/10] Fixes bug with nested Submodel Elements when MQTT is enabled (#393) * Fixes bug with nested Submodel Elements when MQTT is enabled * Empty-Commit --- .../submodelrepository/feature/mqtt/MqttSubmodelRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java index eb6090bbe..5eab00484 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java @@ -102,7 +102,7 @@ public void createSubmodelElement(String submodelId, SubmodelElement smElement) @Override public void createSubmodelElement(String submodelId, String idShortPath, SubmodelElement smElement) throws ElementDoesNotExistException { - decorated.createSubmodelElement(submodelId, smElement); + decorated.createSubmodelElement(submodelId, idShortPath, smElement); SubmodelElement submodelElement = decorated.getSubmodelElement(submodelId, idShortPath); submodelElementCreated(submodelElement, getName(), submodelId, idShortPath); } From 7ea63375a2ce680272307805523ae56cc62b4160 Mon Sep 17 00:00:00 2001 From: Vivek Agarwal Date: Wed, 21 Aug 2024 10:15:11 +0200 Subject: [PATCH 03/10] Added test methods for submodelrepository and submodelservice (#335) * Added test methods for submodelrepository and submodelservice * Fixing test methods * Attend review remarks * minor changes * Attend review remarks * minor change * minor changes --- .../core/SubmodelRepositorySuite.java | 59 ++++++++++++++++ .../submodelservice/SubmodelServiceSuite.java | 68 +++++++++++++++---- 2 files changed, 113 insertions(+), 14 deletions(-) diff --git a/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java b/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java index cc38fe32f..77b7a99d3 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java +++ b/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java @@ -26,6 +26,7 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.core; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -33,11 +34,13 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; import org.eclipse.digitaltwin.aas4j.v3.model.DataTypeDefXsd; import org.eclipse.digitaltwin.aas4j.v3.model.OperationVariable; import org.eclipse.digitaltwin.aas4j.v3.model.Property; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; +import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultProperty; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel; import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException; @@ -53,8 +56,12 @@ import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceHelper; import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceSuite; import org.eclipse.digitaltwin.basyx.submodelservice.value.PropertyValue; +import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelValueOnly; import org.junit.Test; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + /** * Testsuite for implementations of the SubmodelRepository interface * @@ -65,6 +72,7 @@ public abstract class SubmodelRepositorySuite extends SubmodelServiceSuite { private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(null, null); private static final String EMPTY_ID = " "; private static final String NULL_ID = null; + private static final String ID = "testId"; protected abstract SubmodelRepository getSubmodelRepository(); @@ -259,6 +267,57 @@ public void getPaginatedSubmodel() { assertEquals(1, cursorResult.getResult().size()); } + @Test + public void getSubmodelByIdMetadata() throws JsonProcessingException { + SubmodelRepository repo = getSubmodelRepository(); + Submodel expectedSubmodel = buildDummySubmodelWithNoSmElement(ID); + expectedSubmodel.setSubmodelElements(null); + repo.createSubmodel(expectedSubmodel); + + Submodel retrievedSubmodelMetadata = repo.getSubmodelByIdMetadata(ID); + retrievedSubmodelMetadata.setSubmodelElements(null); + + assertEquals(expectedSubmodel, retrievedSubmodelMetadata); + } + + @Test + public void getSubmodelByIdValueOnly() throws JsonProcessingException { + SubmodelRepository repo = getSubmodelRepository(); + Submodel submodel = buildDummySubmodelWithNoSmElement(ID); + + List submodelElements = buildDummySubmodelElements(); + submodel.setSubmodelElements(submodelElements); + repo.createSubmodel(submodel); + + SubmodelValueOnly expectedSmValueOnly = new SubmodelValueOnly(submodelElements); + SubmodelValueOnly retrievedSmValueOnly = repo.getSubmodelByIdValueOnly(ID); + + ObjectMapper mapper = new ObjectMapper(); + String expectedSmValueOnlyJSONContent = mapper.writeValueAsString(expectedSmValueOnly); + String retrievedSmValueOnlyJSONContent = mapper.writeValueAsString(retrievedSmValueOnly); + + assertEquals(expectedSmValueOnlyJSONContent, retrievedSmValueOnlyJSONContent); + } + + @Override + @Test + public void patchSubmodelElements() { + SubmodelRepository repo = getSubmodelRepository(); + Submodel submodel = buildDummySubmodelWithNoSmElement(ID); + + List submodelElements = buildDummySubmodelElements(); + submodel.setSubmodelElements(submodelElements); + repo.createSubmodel(submodel); + + List submodelElementsPatch = buildDummySubmodelElementsToPatch(); + repo.patchSubmodelElements(ID, submodelElementsPatch); + + Submodel patchedSubmodel = repo.getSubmodel(ID); + + assertEquals(submodel.getSubmodelElements().size(), patchedSubmodel.getSubmodelElements().size()); + assertEquals(submodelElementsPatch, patchedSubmodel.getSubmodelElements()); + } + // Has to be overwritten if backend does not support operations @Test public void invokeOperation() { diff --git a/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java b/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java index 495533893..9e73e7d40 100644 --- a/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java +++ b/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java @@ -52,8 +52,10 @@ import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElementCollection; import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElementList; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultEntity; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultFile; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultLangStringTextType; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultProperty; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodelElementCollection; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodelElementList; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; @@ -89,6 +91,7 @@ public abstract class SubmodelServiceSuite { private static final String DUMMY_JSON_1 = "{\"name\":\"SampleJsonFile\",\"description\":\"A JSON file for verification\",\"version\":1}"; private static final String DUMMY_JSON_2 = "{\"name\":\"SampleJsonFile\",\"description\":\"A JSON file for verification\",\"version\":2}"; + private static final String ID = "testId"; @Test public void getSubmodel() { @@ -363,22 +366,22 @@ public void updateNonFileSME() { } @Test - public void updateNonNestedSME() { - Submodel technicalSubmodel = DummySubmodelFactory.createTechnicalDataSubmodel(); - SubmodelService submodelService = getSubmodelService(technicalSubmodel); - + public void updateNonNestedSME() { + Submodel technicalSubmodel = DummySubmodelFactory.createTechnicalDataSubmodel(); + SubmodelService submodelService = getSubmodelService(technicalSubmodel); + String idShortPath = "dummyProperty"; - Property property = createDummyProperty(idShortPath); - submodelService.createSubmodelElement(property); - - Property expectedUpdatedProperty = SubmodelServiceHelper.createDummyProperty(idShortPath, "arbitraryValue", DataTypeDefXsd.STRING); - submodelService.updateSubmodelElement(idShortPath, expectedUpdatedProperty); + Property property = createDummyProperty(idShortPath); + submodelService.createSubmodelElement(property); + + Property expectedUpdatedProperty = SubmodelServiceHelper.createDummyProperty(idShortPath, "arbitraryValue", DataTypeDefXsd.STRING); + submodelService.updateSubmodelElement(idShortPath, expectedUpdatedProperty); + + Property actualUpdatedProperty = (Property) submodelService.getSubmodelElement(idShortPath); + assertEquals(expectedUpdatedProperty, actualUpdatedProperty); + } - Property actualUpdatedProperty = (Property) submodelService.getSubmodelElement(idShortPath); - assertEquals(expectedUpdatedProperty, actualUpdatedProperty); - } - @Test public void updateNonFileSMEWithFileSME() { Submodel technicalSubmodel = DummySubmodelFactory.createTechnicalDataSubmodel(); @@ -606,6 +609,44 @@ public void deleteNonExistingFile() throws IOException { submodelService.deleteFileValue(SubmodelServiceHelper.SUBMODEL_TECHNICAL_DATA_FILE_ID_SHORT); } + @Test + public void patchSubmodelElements() { + + List submodelElements = buildDummySubmodelElements(); + Submodel submodel = buildDummySubmodelWithSmElement(ID, submodelElements); + SubmodelService submodelService = getSubmodelService(submodel); + + List submodelElementsPatch = buildDummySubmodelElementsToPatch(); + submodelService.patchSubmodelElements(submodelElementsPatch); + + Submodel patchedSubmodel = submodelService.getSubmodel(); + + assertEquals(submodel.getSubmodelElements().size(), patchedSubmodel.getSubmodelElements().size()); + assertEquals(submodelElementsPatch, patchedSubmodel.getSubmodelElements()); + } + + protected Submodel buildDummySubmodelWithSmElement(String id, List submodelElements) { + return new DefaultSubmodel.Builder().id(id).submodelElements(submodelElements).build(); + } + + protected Submodel buildDummySubmodelWithNoSmElement(String id) { + return new DefaultSubmodel.Builder().id(id).build(); + } + + protected List buildDummySubmodelElements() { + Property prop = new DefaultProperty.Builder().idShort("propId").value("propValue").build(); + File file = new DefaultFile.Builder().idShort("fileId").contentType("contentTypeValue").value("fileValue").build(); + + return Arrays.asList(prop, file); + } + + protected List buildDummySubmodelElementsToPatch() { + Property prop = new DefaultProperty.Builder().idShort("propId").value("propNewValue").build(); + File file = new DefaultFile.Builder().idShort("fileId").contentType("contentTypeNewValue").value("fileNewValue").build(); + + return Arrays.asList(prop, file); + } + private void assertStoredFileContentEquals(SubmodelService submodelService, String fileIdShort, String content) throws IOException { java.io.File retrievedValue = submodelService.getFileByPath(fileIdShort); @@ -671,7 +712,6 @@ private String getExtension(String filename) { return FilenameUtils.getExtension(filename); } - private void deleteFileIfExisted(SubmodelService service, String idShort) { try { service.getFileByPath(idShort); From 45f2d52396dd29b7d93eef40f9fc493cde439200 Mon Sep 17 00:00:00 2001 From: Mateus Molina Date: Thu, 22 Aug 2024 10:44:01 +0200 Subject: [PATCH 04/10] Move Aas/SmDescriptorFactories to registry-clients; Remove aasenvironment-client dep. to registry-integration (#375) * Move *DescriptorFactories to *registry-client * Rename test helpers * Move Dummy*DescriptorFactories to *registry-client:tests * Remove aasenviornment-client dependency to feature-registry-integration * Add *registry-client classifier tests to poms * Move *DescriptorFactory to .factory package --- .../basyx.aasenvironment-client/pom.xml | 22 ++---- .../client/ConnectedAasManager.java | 4 +- .../client/ConnectedAasManagerHelper.java | 8 +-- .../aasenvironment/client/TestFixture.java | 6 +- .../client/factory}/AasDescriptorFactory.java | 12 ++-- .../main/client}/mapper/AttributeMapper.java | 2 +- .../client/mapper/AttributeMapperFixture.java | 13 ++-- .../mapper}/DummyAasDescriptorFactory.java | 2 +- .../client/mapper}/TestAttributeMapper.java | 55 ++++++++------- .../pom.xml | 6 ++ .../RegistryIntegrationAasRepository.java | 3 +- ...IntegrationAasRepositoryConfiguration.java | 2 +- ...gistryIntegrationAasRepositoryFactory.java | 2 +- ...gistryIntegrationAasRepositoryFeature.java | 2 +- .../AasRepositoryRegistryLinkTestSuite.java | 1 + .../factory}/SubmodelDescriptorFactory.java | 10 ++- .../client}/mapper/AttributeMapper.java | 2 +- .../client/mapper/AttributeMapperFixture.java | 46 +++++++------ .../DummySubmodelDescriptorFactory.java | 4 +- .../client/mapper}/TestAttributeMapper.java | 67 +++++++++---------- .../pom.xml | 6 ++ ...RegistryIntegrationSubmodelRepository.java | 3 +- ...rationSubmodelRepositoryConfiguration.java | 2 +- ...yIntegrationSubmodelRepositoryFactory.java | 2 +- ...yIntegrationSubmodelRepositoryFeature.java | 2 +- ...bmodelRepositoryRegistryLinkTestSuite.java | 1 + pom.xml | 12 ++++ 27 files changed, 157 insertions(+), 140 deletions(-) rename {basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration => basyx.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/factory}/AasDescriptorFactory.java (95%) rename {basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration => basyx.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client}/mapper/AttributeMapper.java (98%) rename basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationTestHelper.java => basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/AttributeMapperFixture.java (97%) rename {basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration => basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper}/DummyAasDescriptorFactory.java (97%) rename {basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration => basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper}/TestAttributeMapper.java (76%) rename {basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration => basyx.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/factory}/SubmodelDescriptorFactory.java (94%) rename {basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration => basyx.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client}/mapper/AttributeMapper.java (98%) rename basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationTestHelper.java => basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/AttributeMapperFixture.java (90%) rename {basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration => basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper}/DummySubmodelDescriptorFactory.java (97%) rename {basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration => basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper}/TestAttributeMapper.java (74%) diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml b/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml index f0ceddf4f..24c08e7dc 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml +++ b/basyx.aasenvironment/basyx.aasenvironment-client/pom.xml @@ -34,41 +34,33 @@ org.eclipse.digitaltwin.basyx - basyx.aasrepository-feature-registry-integration + basyx.submodelrepository-client org.eclipse.digitaltwin.basyx - basyx.aasrepository-feature-registry-integration + basyx.aasenvironment-core tests test org.eclipse.digitaltwin.basyx - basyx.submodelrepository-client + basyx.aasregistry-client-native org.eclipse.digitaltwin.basyx - basyx.submodelrepository-feature-registry-integration + basyx.submodelregistry-client-native org.eclipse.digitaltwin.basyx - basyx.submodelrepository-feature-registry-integration - tests + basyx.aasregistry-client-native test - - - org.eclipse.digitaltwin.basyx - basyx.aasenvironment-core tests - test - - - org.eclipse.digitaltwin.basyx - basyx.aasregistry-client-native org.eclipse.digitaltwin.basyx basyx.submodelregistry-client-native + test + tests org.mockito diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java index f71b13014..f28480ed7 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java +++ b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManager.java @@ -43,14 +43,14 @@ import org.eclipse.digitaltwin.basyx.aasenvironment.client.resolvers.SubmodelDescriptorResolver; import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi; import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetAdministrationShellDescriptor; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.factory.AasDescriptorFactory; import org.eclipse.digitaltwin.basyx.aasrepository.client.ConnectedAasRepository; -import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.AasDescriptorFactory; import org.eclipse.digitaltwin.basyx.aasservice.client.ConnectedAasService; import org.eclipse.digitaltwin.basyx.client.internal.resolver.DescriptorResolver; import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.factory.SubmodelDescriptorFactory; import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor; import org.eclipse.digitaltwin.basyx.submodelrepository.client.ConnectedSubmodelRepository; -import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.SubmodelDescriptorFactory; import org.eclipse.digitaltwin.basyx.submodelservice.client.ConnectedSubmodelService; /** diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java index 8290ba0f9..d6e0ab8c6 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java +++ b/basyx.aasenvironment/basyx.aasenvironment-client/src/main/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/ConnectedAasManagerHelper.java @@ -28,10 +28,10 @@ import java.util.List; -import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.AasDescriptorFactory; -import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.factory.AasDescriptorFactory; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.AttributeMapper; import org.eclipse.digitaltwin.basyx.http.Aas4JHTTPSerializationExtension; -import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.SubmodelDescriptorFactory; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.factory.SubmodelDescriptorFactory; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import com.fasterxml.jackson.annotation.JsonInclude; @@ -64,7 +64,7 @@ static AasDescriptorFactory buildAasDescriptorFactory(String... aasRepositoryBas } static SubmodelDescriptorFactory buildSmDescriptorFactory(String... aasRepositoryBaseUrls) { - org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper attributeMapperSm = new org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper( + org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper attributeMapperSm = new org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper( objectMapper); return new SubmodelDescriptorFactory(null, List.of(aasRepositoryBaseUrls), attributeMapperSm); } diff --git a/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/TestFixture.java b/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/TestFixture.java index 359b5eb9b..275f54eb2 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/TestFixture.java +++ b/basyx.aasenvironment/basyx.aasenvironment-client/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/client/TestFixture.java @@ -38,11 +38,11 @@ import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultReference; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel; import org.eclipse.digitaltwin.basyx.aasregistry.client.model.AssetAdministrationShellDescriptor; -import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.DummyAasDescriptorFactory; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.DummyAasDescriptorFactory; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncoder; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.DummySubmodelDescriptorFactory; import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor; -import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.DummySubmodelDescriptorFactory; -import org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper.AttributeMapper; /** * Test fixture for {@link ConnectedAasManager} and related Components 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.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/factory/AasDescriptorFactory.java similarity index 95% rename from basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasDescriptorFactory.java rename to basyx.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/factory/AasDescriptorFactory.java index a28948c34..c1091086e 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasDescriptorFactory.java +++ b/basyx.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/factory/AasDescriptorFactory.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.aasregistry.main.client.factory; import java.net.MalformedURLException; import java.net.URL; @@ -39,7 +39,7 @@ 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.aasregistry.main.client.mapper.AttributeMapper; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; /** @@ -56,9 +56,8 @@ public class AasDescriptorFactory { private List aasRepositoryURLs; private AttributeMapper attributeMapper; - - public AasDescriptorFactory(AssetAdministrationShell shell, List aasRepositoryBaseURLs, - AttributeMapper attributeMapper) { + + public AasDescriptorFactory(AssetAdministrationShell shell, List aasRepositoryBaseURLs, AttributeMapper attributeMapper) { this.shell = shell; this.aasRepositoryURLs = createAasRepositoryUrls(aasRepositoryBaseURLs); this.attributeMapper = attributeMapper; @@ -125,8 +124,7 @@ private void setExtensions(List extensions, AssetAdministrationShellD descriptor.setExtensions(attributeMapper.mapExtensions(extensions)); } - private void setAdministration(AdministrativeInformation administration, - AssetAdministrationShellDescriptor descriptor) { + private void setAdministration(AdministrativeInformation administration, AssetAdministrationShellDescriptor descriptor) { if (administration == null) return; 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.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/AttributeMapper.java similarity index 98% rename from basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/mapper/AttributeMapper.java rename to basyx.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/AttributeMapper.java index f2352601a..2a9a46b7d 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/mapper/AttributeMapper.java +++ b/basyx.aasregistry/basyx.aasregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/AttributeMapper.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper; +package org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper; import java.util.List; 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.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/AttributeMapperFixture.java similarity index 97% rename from basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationTestHelper.java rename to basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/AttributeMapperFixture.java index 91b5bf930..72fdbcc27 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/RegistryIntegrationTestHelper.java +++ b/basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/AttributeMapperFixture.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper; import java.util.Arrays; import java.util.List; @@ -48,11 +48,11 @@ import org.eclipse.digitaltwin.basyx.aasregistry.client.model.Key; /** - * A helper class for testing RegistryIntegration feature + * A fixture for TestAttributeMapper * - * @author danish + * @author danish, mateusmolina */ -public class RegistryIntegrationTestHelper { +public class AttributeMapperFixture { // LangStringTextType AAS4J private static final LangStringTextType AAS4J_LANG_STRING_TEXT_TYPE_1 = new DefaultLangStringTextType.Builder().language("de").text("Ein Beispiel").build(); @@ -89,13 +89,14 @@ public class RegistryIntegrationTestHelper { .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(); + 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") diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/DummyAasDescriptorFactory.java b/basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/DummyAasDescriptorFactory.java similarity index 97% rename from basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/DummyAasDescriptorFactory.java rename to basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/DummyAasDescriptorFactory.java index d134100b1..7441ce29c 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/DummyAasDescriptorFactory.java +++ b/basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/DummyAasDescriptorFactory.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper; import java.net.MalformedURLException; import java.net.URL; 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.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/TestAttributeMapper.java similarity index 76% rename from basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/TestAttributeMapper.java rename to basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/TestAttributeMapper.java index 6730fec19..2605ef956 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/TestAttributeMapper.java +++ b/basyx.aasregistry/basyx.aasregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/main/client/mapper/TestAttributeMapper.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper; import static org.junit.Assert.assertEquals; @@ -35,7 +35,6 @@ 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; @@ -49,57 +48,57 @@ * @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()); - + List expectedDescriptions = AttributeMapperFixture.getAasRegLangStringTextTypes(); + + List actualDescriptions = attributeMapper.mapDescription(AttributeMapperFixture.getAas4jLangStringTextTypes()); + assertEquals(expectedDescriptions.size(), actualDescriptions.size()); assertEquals(expectedDescriptions, actualDescriptions); } - + @Test public void mapDisplayNames() { - List expectedDisplayNames = RegistryIntegrationTestHelper.getAasRegLangStringNameTypes(); - - List actualDisplayNames = attributeMapper.mapDisplayName(RegistryIntegrationTestHelper.getAas4jLangStringNameTypes()); - + List expectedDisplayNames = AttributeMapperFixture.getAasRegLangStringNameTypes(); + + List actualDisplayNames = attributeMapper.mapDisplayName(AttributeMapperFixture.getAas4jLangStringNameTypes()); + assertEquals(expectedDisplayNames.size(), actualDisplayNames.size()); assertEquals(expectedDisplayNames, actualDisplayNames); } - + @Test public void mapExtensions() { - List expectedExtensions = RegistryIntegrationTestHelper.getAasRegExtensions(); - - List actualExtensions = attributeMapper.mapExtensions(RegistryIntegrationTestHelper.getAas4jExtensions()); - + List expectedExtensions = AttributeMapperFixture.getAasRegExtensions(); + + List actualExtensions = attributeMapper.mapExtensions(AttributeMapperFixture.getAas4jExtensions()); + assertEquals(expectedExtensions.size(), actualExtensions.size()); assertEquals(expectedExtensions, actualExtensions); } - + @Test public void mapAdministration() { - AdministrativeInformation expectedAdministrativeInformation = RegistryIntegrationTestHelper.getAasRegAdministration(); - - AdministrativeInformation actualAdministrativeInformation = attributeMapper.mapAdministration(RegistryIntegrationTestHelper.getAas4jAdministration()); - + AdministrativeInformation expectedAdministrativeInformation = AttributeMapperFixture.getAasRegAdministration(); + + AdministrativeInformation actualAdministrativeInformation = attributeMapper.mapAdministration(AttributeMapperFixture.getAas4jAdministration()); + assertEquals(expectedAdministrativeInformation, actualAdministrativeInformation); } - + @Test public void mapAssetKind() { - AssetKind expectedAssetKind = RegistryIntegrationTestHelper.AASREG_ASSET_KIND; - - AssetKind actualAssetKind = attributeMapper.mapAssetKind(RegistryIntegrationTestHelper.AAS4J_ASSET_KIND); + AssetKind expectedAssetKind = AttributeMapperFixture.AASREG_ASSET_KIND; + + AssetKind actualAssetKind = attributeMapper.mapAssetKind(AttributeMapperFixture.AAS4J_ASSET_KIND); assertEquals(expectedAssetKind, actualAssetKind); } - + private static ObjectMapper configureObjectMapper() { List extensions = Arrays.asList(new Aas4JHTTPSerializationExtension()); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/pom.xml b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/pom.xml index ad65b801d..418c7ed75 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/pom.xml +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/pom.xml @@ -32,6 +32,12 @@ org.eclipse.digitaltwin.basyx basyx.http + + org.eclipse.digitaltwin.basyx + basyx.aasregistry-client-native + tests + test + org.eclipse.digitaltwin.basyx basyx.aasrepository-http 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 index a2233b0d9..17d93879d 100644 --- 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 @@ -34,8 +34,9 @@ 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.main.client.factory.AasDescriptorFactory; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.AttributeMapper; 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; 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 index a468b5dd1..62f1a39b4 100644 --- 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 @@ -30,8 +30,8 @@ import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi; import org.eclipse.digitaltwin.basyx.aasregistry.main.client.AuthorizedConnectedAasRegistry; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.AttributeMapper; import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; -import org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration.mapper.AttributeMapper; import org.eclipse.digitaltwin.basyx.client.internal.authorization.AccessTokenProviderFactory; import org.eclipse.digitaltwin.basyx.client.internal.authorization.TokenManager; import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.AccessTokenProvider; 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 index 4ef1d37dd..23f72f86f 100644 --- 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 @@ -25,9 +25,9 @@ package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.AttributeMapper; 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} 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 index 0023d0b59..51e896f9a 100644 --- 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 @@ -26,10 +26,10 @@ package org.eclipse.digitaltwin.basyx.aasrepository.feature.registry.integration; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.AttributeMapper; 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; diff --git a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java index 3c169f084..19629dcb7 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/registry/integration/AasRepositoryRegistryLinkTestSuite.java @@ -39,6 +39,7 @@ 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.GetAssetAdministrationShellDescriptorsResult; +import org.eclipse.digitaltwin.basyx.aasregistry.main.client.mapper.DummyAasDescriptorFactory; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; import org.eclipse.digitaltwin.basyx.http.serialization.BaSyxHttpTestUtils; import org.junit.After; 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.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/factory/SubmodelDescriptorFactory.java similarity index 94% rename from basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelDescriptorFactory.java rename to basyx.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/factory/SubmodelDescriptorFactory.java index ec2dbff4a..7ba46b67d 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelDescriptorFactory.java +++ b/basyx.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/factory/SubmodelDescriptorFactory.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.submodelregistry.client.factory; import java.net.MalformedURLException; import java.net.URL; @@ -37,10 +37,10 @@ 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.mapper.AttributeMapper; 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} @@ -57,8 +57,7 @@ public class SubmodelDescriptorFactory { private AttributeMapper attributeMapper; - public SubmodelDescriptorFactory(Submodel submodel, List submodelRepositoryBaseURLs, - AttributeMapper attributeMapper) { + public SubmodelDescriptorFactory(Submodel submodel, List submodelRepositoryBaseURLs, AttributeMapper attributeMapper) { this.submodel = submodel; this.submodelRepositoryURLs = createSubmodelRepositoryUrls(submodelRepositoryBaseURLs); this.attributeMapper = attributeMapper; @@ -160,8 +159,7 @@ private void setEndpointItem(String shellId, SubmodelDescriptor descriptor) { } private ProtocolInformation createProtocolInformation(String shellId, String url) { - String href = String.format("%s/%s", url, - Base64UrlEncodedIdentifier.encodeIdentifier(shellId)); + String href = String.format("%s/%s", url, Base64UrlEncodedIdentifier.encodeIdentifier(shellId)); ProtocolInformation protocolInformation = new ProtocolInformation(); protocolInformation.endpointProtocol(getProtocol(href)); 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.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/AttributeMapper.java similarity index 98% rename from basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/mapper/AttributeMapper.java rename to basyx.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/AttributeMapper.java index 4258a1703..75f3a4beb 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/mapper/AttributeMapper.java +++ b/basyx.submodelregistry/basyx.submodelregistry-client-native/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/AttributeMapper.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration.mapper; +package org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper; import java.util.List; 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.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/AttributeMapperFixture.java similarity index 90% rename from basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationTestHelper.java rename to basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/AttributeMapperFixture.java index fb0de5ec0..d4db0b313 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationTestHelper.java +++ b/basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/AttributeMapperFixture.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper; import java.util.Arrays; import java.util.List; @@ -47,31 +47,31 @@ import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.Key; /** - * A helper class for testing RegistryIntegration feature + * A fixture for TestAttributeMapper * - * @author danish + * @author danish, mateusmolina */ -public class RegistryIntegrationTestHelper { +public class AttributeMapperFixture { // 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"); + 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"); + 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(); @@ -79,21 +79,23 @@ public class RegistryIntegrationTestHelper { // 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); + .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(); + 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"); - + 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); } @@ -126,19 +128,19 @@ public static List getAas4jExtensions() { 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/DummySubmodelDescriptorFactory.java b/basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/DummySubmodelDescriptorFactory.java similarity index 97% rename from basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/DummySubmodelDescriptorFactory.java rename to basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/DummySubmodelDescriptorFactory.java index 5d00fb86e..d6755f00e 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/DummySubmodelDescriptorFactory.java +++ b/basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/DummySubmodelDescriptorFactory.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper; import java.net.MalformedURLException; import java.net.URL; @@ -39,7 +39,7 @@ import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor; /** - * Factory for dummy SubmodelDescriptorss + * Factory for dummy SubmodelDescriptors * * @author mateusmolina * 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.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/TestAttributeMapper.java similarity index 74% rename from basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/TestAttributeMapper.java rename to basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/TestAttributeMapper.java index 70c6c24cc..e8f31bbed 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/TestAttributeMapper.java +++ b/basyx.submodelregistry/basyx.submodelregistry-client-native/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/client/mapper/TestAttributeMapper.java @@ -23,7 +23,7 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; +package org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper; import static org.junit.Assert.assertEquals; @@ -38,7 +38,6 @@ 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; @@ -49,67 +48,67 @@ * @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()); - + List expectedDescriptions = AttributeMapperFixture.getSubmodelRegLangStringTextTypes(); + + List actualDescriptions = attributeMapper.mapDescription(AttributeMapperFixture.getAas4jLangStringTextTypes()); + assertEquals(expectedDescriptions.size(), actualDescriptions.size()); assertEquals(expectedDescriptions, actualDescriptions); } - + @Test public void mapDisplayNames() { - List expectedDisplayNames = RegistryIntegrationTestHelper.getSubmodelRegLangStringNameTypes(); - - List actualDisplayNames = attributeMapper.mapDisplayName(RegistryIntegrationTestHelper.getAas4jLangStringNameTypes()); - + List expectedDisplayNames = AttributeMapperFixture.getSubmodelRegLangStringNameTypes(); + + List actualDisplayNames = attributeMapper.mapDisplayName(AttributeMapperFixture.getAas4jLangStringNameTypes()); + assertEquals(expectedDisplayNames.size(), actualDisplayNames.size()); assertEquals(expectedDisplayNames, actualDisplayNames); } - + @Test public void mapExtensions() { - List expectedExtensions = RegistryIntegrationTestHelper.getSubmodelRegExtensions(); - - List actualExtensions = attributeMapper.mapExtensions(RegistryIntegrationTestHelper.getAas4jExtensions()); - + List expectedExtensions = AttributeMapperFixture.getSubmodelRegExtensions(); + + List actualExtensions = attributeMapper.mapExtensions(AttributeMapperFixture.getAas4jExtensions()); + assertEquals(expectedExtensions.size(), actualExtensions.size()); assertEquals(expectedExtensions, actualExtensions); } - + @Test public void mapAdministration() { - AdministrativeInformation expectedAdministrativeInformation = RegistryIntegrationTestHelper.getSubmodelRegAdministration(); - - AdministrativeInformation actualAdministrativeInformation = attributeMapper.mapAdministration(RegistryIntegrationTestHelper.getAas4jAdministration()); - + AdministrativeInformation expectedAdministrativeInformation = AttributeMapperFixture.getSubmodelRegAdministration(); + + AdministrativeInformation actualAdministrativeInformation = attributeMapper.mapAdministration(AttributeMapperFixture.getAas4jAdministration()); + assertEquals(expectedAdministrativeInformation, actualAdministrativeInformation); } - + @Test public void mapSemanticId() { - Reference expectedSemanticId = RegistryIntegrationTestHelper.getSubmodelRegSemanticId(); - - Reference actualSemanticId = attributeMapper.mapSemanticId(RegistryIntegrationTestHelper.getAas4jSemanticId()); - + Reference expectedSemanticId = AttributeMapperFixture.getSubmodelRegSemanticId(); + + Reference actualSemanticId = attributeMapper.mapSemanticId(AttributeMapperFixture.getAas4jSemanticId()); + assertEquals(expectedSemanticId, actualSemanticId); } - + @Test public void mapSupplementalSemanticId() { - List expectedSupplementalSemanticId = RegistryIntegrationTestHelper.getSubmodelRegSupplementalSemanticIds(); - - List actualSupplementalSemanticId = attributeMapper.mapSupplementalSemanticId(RegistryIntegrationTestHelper.getAas4jSupplementalSemanticIds()); - + List expectedSupplementalSemanticId = AttributeMapperFixture.getSubmodelRegSupplementalSemanticIds(); + + List actualSupplementalSemanticId = attributeMapper.mapSupplementalSemanticId(AttributeMapperFixture.getAas4jSupplementalSemanticIds()); + assertEquals(expectedSupplementalSemanticId.size(), actualSupplementalSemanticId.size()); assertEquals(expectedSupplementalSemanticId, actualSupplementalSemanticId); } - + private static ObjectMapper configureObjectMapper() { List extensions = Arrays.asList(new Aas4JHTTPSerializationExtension()); diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/pom.xml b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/pom.xml index ea4e2a275..dbccc990a 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/pom.xml +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/pom.xml @@ -33,6 +33,12 @@ org.eclipse.digitaltwin.basyx basyx.http + + org.eclipse.digitaltwin.basyx + basyx.submodelregistry-client-native + tests + test + org.eclipse.digitaltwin.basyx basyx.submodelrepository-http 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 index 4f51226db..43a6c87c0 100644 --- 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 @@ -41,9 +41,10 @@ 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.factory.SubmodelDescriptorFactory; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper; 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; 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 index 1c8390618..e052c8792 100644 --- 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 @@ -34,8 +34,8 @@ import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.GrantType; import org.eclipse.digitaltwin.basyx.submodelregistry.client.AuthorizedConnectedSubmodelRegistry; import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper; 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; 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 index 7a01eac01..2913e9742 100644 --- 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 @@ -25,9 +25,9 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper; 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} 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 index 1fb925617..021e72de1 100644 --- 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 @@ -25,10 +25,10 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.feature.registry.integration; +import org.eclipse.digitaltwin.basyx.submodelregistry.client.mapper.AttributeMapper; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository; 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; diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java index d64e98328..2c02ef48f 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/SubmodelRepositoryRegistryLinkTestSuite.java @@ -40,6 +40,7 @@ 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.mapper.DummySubmodelDescriptorFactory; import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.GetSubmodelDescriptorsResult; import org.eclipse.digitaltwin.basyx.submodelregistry.client.model.SubmodelDescriptor; import org.junit.After; diff --git a/pom.xml b/pom.xml index 5801f1dae..f47392382 100644 --- a/pom.xml +++ b/pom.xml @@ -1100,12 +1100,24 @@ ${revision} tests + + org.eclipse.digitaltwin.basyx + basyx.aasregistry-client-native + ${revision} + tests + org.eclipse.digitaltwin.basyx basyx.submodelregistry-feature-authorization ${revision} tests + + org.eclipse.digitaltwin.basyx + basyx.submodelregistry-client-native + ${revision} + tests + org.eclipse.digitaltwin.basyx basyx.conceptdescriptionrepository.component From 625c98be5ca360c13b5f93d293972352c773a11c Mon Sep 17 00:00:00 2001 From: Jannik Fried Date: Thu, 22 Aug 2024 14:48:12 +0200 Subject: [PATCH 05/10] Fixes 'same Submodel Reference can be applied to same AAS again without throwing 409' (#388) * Fixes Duplicate Submodel Reference not throwing 409 * Adds missing files * Applies small refactoring * Changes Year from '23 to '24 --- .../aasrepository/AasRepositorySuite.java | 15 ++++--- .../TestAuthorizedAasRepository.java | 12 +++--- .../http/AasRepositoryApiHTTPController.java | 9 ++++- .../http/AasRepositoryHTTPSuite.java | 21 +++++++--- .../resources/PaginatedSingleSMReference.json | 2 +- .../resources/SingleSubmodelReference_1.json} | 2 +- ...ce.json => SingleSubmodelReference_2.json} | 2 +- .../backend/InMemoryAasService.java | 33 +++++++++++++-- .../client/ConnectedAasService.java | 5 +++ .../basyx/aasservice/AasServiceSuite.java | 21 +++++----- .../CollidingSubmodelReferenceException.java | 40 +++++++++++++++++++ .../exceptions/MissingKeyTypeException.java | 35 ++++++++++++++++ 12 files changed, 161 insertions(+), 36 deletions(-) rename basyx.aasrepository/{basyx.aasrepository-feature-authorization/src/test/resources/authorization/SingleSubmodelReference.json => basyx.aasrepository-http/src/test/resources/SingleSubmodelReference_1.json} (55%) rename basyx.aasrepository/basyx.aasrepository-http/src/test/resources/{SingleSubmodelReference.json => SingleSubmodelReference_2.json} (55%) create mode 100644 basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/CollidingSubmodelReferenceException.java create mode 100644 basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/MissingKeyTypeException.java diff --git a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java index e6af8282e..0020d6ba3 100644 --- a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java +++ b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors + * Copyright (C) 2024 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 @@ -39,10 +39,7 @@ import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell; import org.eclipse.digitaltwin.basyx.aasservice.AasService; import org.eclipse.digitaltwin.basyx.aasservice.AasServiceSuite; -import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException; -import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; -import org.eclipse.digitaltwin.basyx.core.exceptions.IdentificationMismatchException; -import org.eclipse.digitaltwin.basyx.core.exceptions.MissingIdentifierException; +import org.eclipse.digitaltwin.basyx.core.exceptions.*; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.junit.Test; @@ -145,6 +142,14 @@ public void addSubmodelReferenceToNonExistingAas() { aasRepo.addSubmodelReference("doesNotMatter", reference); } + @Test(expected = CollidingSubmodelReferenceException.class) + public void duplicateSubmodelReference() { + AssetAdministrationShell aas = DummyAasFactory.createAasWithSubmodelReference(); + AasRepository aasRepo = getAasRepository(Collections.singleton(aas)); + Reference reference = DummyAasFactory.createDummyReference(DummyAasFactory.DUMMY_SUBMODEL_ID); + aasRepo.addSubmodelReference(aas.getId(), reference); + } + @Test(expected = ElementDoesNotExistException.class) public void removeSubmodelReferenceOfNonExistingAas() { AasRepository aasRepo = getAasRepository(); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java b/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java index afad4e93a..4533bd801 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/authorization/TestAuthorizedAasRepository.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors + * Copyright (C) 2024 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 @@ -355,7 +355,7 @@ public void getSubmodelReferencesWithNoAuthorization() throws IOException { public void addSubmodelReferenceWithCorrectRoleAndPermission() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_UPDATER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference_1.json"), accessToken); assertEquals(HttpStatus.CREATED.value(), retrievalResponse.getCode()); } @@ -363,7 +363,7 @@ public void addSubmodelReferenceWithCorrectRoleAndPermission() throws IOExceptio public void addSubmodelReferenceWithCorrectRoleAndSpecificAasPermission() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference_2.json"), accessToken); assertEquals(HttpStatus.CREATED.value(), retrievalResponse.getCode()); } @@ -371,7 +371,7 @@ public void addSubmodelReferenceWithCorrectRoleAndSpecificAasPermission() throws public void addSubmodelReferenceWithCorrectRoleAndUnauthorizedSpecificAas() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_UPDATER_TWO_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID_2), getAasJSONString("SingleSubmodelReference.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID_2), getAasJSONString("SingleSubmodelReference_1.json"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @@ -379,13 +379,13 @@ public void addSubmodelReferenceWithCorrectRoleAndUnauthorizedSpecificAas() thro public void addSubmodelReferenceWithInsufficientPermissionRole() throws IOException { String accessToken = getAccessToken(DummyCredentialStore.BASYX_READER_CREDENTIAL); - CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference.json"), accessToken); + CloseableHttpResponse retrievalResponse = updateElementWithAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference_1.json"), accessToken); assertEquals(HttpStatus.FORBIDDEN.value(), retrievalResponse.getCode()); } @Test public void addSubmodelReferenceWithNoAuthorization() throws IOException { - CloseableHttpResponse retrievalResponse = updateElementWithNoAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference.json")); + CloseableHttpResponse retrievalResponse = updateElementWithNoAuthorizationPostRequest(getSpecificAasSubmodelRefAccessURL(SPECIFIC_SHELL_ID), getAasJSONString("SingleSubmodelReference_1.json")); assertEquals(HttpStatus.UNAUTHORIZED.value(), retrievalResponse.getCode()); } diff --git a/basyx.aasrepository/basyx.aasrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryApiHTTPController.java b/basyx.aasrepository/basyx.aasrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryApiHTTPController.java index 6c0be88c3..53f79cdc5 100644 --- a/basyx.aasrepository/basyx.aasrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryApiHTTPController.java +++ b/basyx.aasrepository/basyx.aasrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryApiHTTPController.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors + * Copyright (C) 2024 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 @@ -38,6 +38,7 @@ import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; import org.eclipse.digitaltwin.basyx.aasrepository.http.pagination.GetAssetAdministrationShellsResult; import org.eclipse.digitaltwin.basyx.aasrepository.http.pagination.GetReferencesResult; +import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingSubmodelReferenceException; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; @@ -156,7 +157,11 @@ public ResponseEntity getAllSubmodelReferencesAasRepository(Base64U @Override public ResponseEntity postSubmodelReferenceAasRepository(Base64UrlEncodedIdentifier aasIdentifier, @Valid Reference body) { - aasRepository.addSubmodelReference(aasIdentifier.getIdentifier(), body); + try { + aasRepository.addSubmodelReference(aasIdentifier.getIdentifier(), body); + }catch(CollidingSubmodelReferenceException e){ + return new ResponseEntity(HttpStatus.CONFLICT); + } return new ResponseEntity(body, HttpStatus.CREATED); } diff --git a/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryHTTPSuite.java b/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryHTTPSuite.java index ec24bec5e..4e8bb589b 100644 --- a/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryHTTPSuite.java +++ b/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/AasRepositoryHTTPSuite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors + * Copyright (C) 2024 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 @@ -206,6 +206,17 @@ public void createSubmodelReference() throws FileNotFoundException, IOException, BaSyxHttpTestUtils.assertSameJSONContent(getPaginatedSingleSMReferenceJson(), BaSyxHttpTestUtils.getResponseAsString(getResponse)); } + @Test + public void duplicateSubmodelReference() throws FileNotFoundException, IOException, ParseException { + createDummyAasOnServer(getAas1JSONString()); + + String json = getSingleSubmodelReference(); + + addSubmodelReferenceToDummyAas(json); + CloseableHttpResponse response = addSubmodelReferenceToDummyAas(json); + assertEquals(response.getCode(), HttpStatus.CONFLICT.value()); + } + @Test public void removeSubmodelReference() throws FileNotFoundException, IOException, ParseException { createDummyAasOnServer(getAas1JSONString()); @@ -408,7 +419,7 @@ private String requestSpecificAasJSON(String aasId) throws IOException, ParseExc } private String getSpecificSubmodelReferenceUrl() { - Base64UrlEncodedIdentifier identifier = new Base64UrlEncodedIdentifier("http://i40.customer.com/type/1/1/testSubmodel"); + Base64UrlEncodedIdentifier identifier = new Base64UrlEncodedIdentifier("http://i40.customer.com/type/1/1/testSubmodelNew"); return getSpecificAasSubmodelRefAccessURL(dummyAasId) + "/" + identifier.getEncodedIdentifier(); } @@ -420,8 +431,8 @@ private String getSpecificAssetInformationAccessURL(String aasID) { return getSpecificAasAccessURL(aasID) + "/asset-information"; } - private void addSubmodelReferenceToDummyAas(String json) throws FileNotFoundException, IOException { - BaSyxHttpTestUtils.executePostOnURL(getSpecificAasSubmodelRefAccessURL(dummyAasId), json); + private CloseableHttpResponse addSubmodelReferenceToDummyAas(String json) throws FileNotFoundException, IOException { + return BaSyxHttpTestUtils.executePostOnURL(getSpecificAasSubmodelRefAccessURL(dummyAasId), json); } protected String getSpecificAasAccessURL(String aasId) { @@ -473,7 +484,7 @@ private String getAas2JSONString() throws FileNotFoundException, IOException { } private String getSingleSubmodelReference() throws FileNotFoundException, IOException { - return BaSyxHttpTestUtils.readJSONStringFromClasspath("SingleSubmodelReference.json"); + return BaSyxHttpTestUtils.readJSONStringFromClasspath("SingleSubmodelReference_1.json"); } private String getSMReferenceRemovalJson() throws FileNotFoundException, IOException { diff --git a/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/PaginatedSingleSMReference.json b/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/PaginatedSingleSMReference.json index 386db3288..acff22e79 100644 --- a/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/PaginatedSingleSMReference.json +++ b/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/PaginatedSingleSMReference.json @@ -6,7 +6,7 @@ "keys": [ { "type": "Submodel", - "value": "http://i40.customer.com/type/1/1/testSubmodel" + "value": "http://i40.customer.com/type/1/1/testSubmodelNew" } ], "type": "ExternalReference" diff --git a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/resources/authorization/SingleSubmodelReference.json b/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference_1.json similarity index 55% rename from basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/resources/authorization/SingleSubmodelReference.json rename to basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference_1.json index 0758b3be1..25657efe7 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-authorization/src/test/resources/authorization/SingleSubmodelReference.json +++ b/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference_1.json @@ -2,7 +2,7 @@ "keys": [ { "type": "Submodel", - "value": "http://i40.customer.com/type/1/1/testSubmodel256" + "value": "http://i40.customer.com/type/1/1/testSubmodelNew" } ], "type": "ExternalReference" diff --git a/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference.json b/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference_2.json similarity index 55% rename from basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference.json rename to basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference_2.json index a4dc8f9b7..31198293f 100644 --- a/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference.json +++ b/basyx.aasrepository/basyx.aasrepository-http/src/test/resources/SingleSubmodelReference_2.json @@ -2,7 +2,7 @@ "keys": [ { "type": "Submodel", - "value": "http://i40.customer.com/type/1/1/testSubmodel" + "value": "http://i40.customer.com/type/1/1/testSubmodelNew_2" } ], "type": "ExternalReference" diff --git a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java index 892edacd1..563dfc8f4 100644 --- a/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java +++ b/basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasService.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors + * Copyright (C) 2024 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 @@ -30,6 +30,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.List; +import java.util.Optional; import java.util.TreeMap; import java.util.function.Function; import java.util.stream.Collectors; @@ -42,9 +43,7 @@ import org.eclipse.digitaltwin.aas4j.v3.model.Resource; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultResource; import org.eclipse.digitaltwin.basyx.aasservice.AasService; -import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; -import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; -import org.eclipse.digitaltwin.basyx.core.exceptions.FileHandlingException; +import org.eclipse.digitaltwin.basyx.core.exceptions.*; import org.eclipse.digitaltwin.basyx.core.filerepository.FileMetadata; import org.eclipse.digitaltwin.basyx.core.filerepository.FileRepository; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; @@ -94,6 +93,8 @@ public CursorResult> getSubmodelReferences(PaginationInfo pInfo) @Override public void addSubmodelReference(Reference submodelReference) { + throwExceptionIfReferenceIsAlreadyPresent(submodelReference); + aas.getSubmodels().add(submodelReference); } @@ -212,4 +213,28 @@ private File getResourceContent(Resource resource) throws IOException { return new java.io.File(filePath); } + private void throwExceptionIfReferenceIsAlreadyPresent(Reference submodelReference) { + Optional submodelIdKey = getSubmodelTypeKey(submodelReference); + if(submodelIdKey.isEmpty()) + return; + String submodelId = submodelIdKey.get().getValue(); + if (isSubmodelIdAlreadyReferenced(submodelId)) { + throw new CollidingSubmodelReferenceException(submodelId); + } + } + + private boolean isSubmodelIdAlreadyReferenced(String submodelId) { + return aas.getSubmodels().stream().anyMatch(ref -> ref.getKeys().stream().anyMatch(key -> key.getValue().equals(submodelId))); + } + + private static Optional getSubmodelTypeKey(Reference submodelReference) { + Optional submodelIdKey = submodelReference.getKeys().stream().filter(key -> { + KeyTypes type = key.getType(); + if(type == null) + throw new MissingKeyTypeException(); + return type.equals(KeyTypes.SUBMODEL); + }).findFirst(); + return submodelIdKey; + } + } diff --git a/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java b/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java index b2ad3aa4a..df9095b15 100644 --- a/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java +++ b/basyx.aasservice/basyx.aasservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/client/ConnectedAasService.java @@ -36,6 +36,7 @@ import org.eclipse.digitaltwin.basyx.aasservice.AasService; import org.eclipse.digitaltwin.basyx.aasservice.client.internal.AssetAdministrationShellServiceApi; import org.eclipse.digitaltwin.basyx.client.internal.ApiException; +import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingSubmodelReferenceException; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementNotAFileException; import org.eclipse.digitaltwin.basyx.core.exceptions.FileDoesNotExistException; @@ -168,6 +169,10 @@ private RuntimeException mapAasAccess(ApiException e) { return new ElementDoesNotExistException(); } + if(e.getCode() == HttpStatus.CONFLICT.value()) { + return new CollidingSubmodelReferenceException(); + } + return e; } diff --git a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java index 291fa47df..0c7e4cbf0 100644 --- a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java +++ b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors + * Copyright (C) 2024 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 @@ -38,18 +38,13 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.imageio.ImageIO; import org.apache.commons.io.IOUtils; -import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; -import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; -import org.eclipse.digitaltwin.aas4j.v3.model.AssetKind; -import org.eclipse.digitaltwin.aas4j.v3.model.KeyTypes; -import org.eclipse.digitaltwin.aas4j.v3.model.Reference; -import org.eclipse.digitaltwin.aas4j.v3.model.ReferenceTypes; -import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; +import org.eclipse.digitaltwin.aas4j.v3.model.*; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetInformation; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultKey; @@ -99,14 +94,17 @@ public void addSubmodelReference() { Submodel submodel = createDummySubmodel(); - aasService.addSubmodelReference(submodel.getSemanticId()); + Reference ref = new DefaultReference(); + Key submodelKey = new DefaultKey.Builder().value(submodel.getId()).type(KeyTypes.SUBMODEL).build(); + ref.setKeys(Arrays.asList(submodelKey)); + + aasService.addSubmodelReference(ref); List submodelReferences = aasService.getSubmodelReferences(NO_LIMIT_PAGINATION_INFO).getResult(); Reference submodelReference = getFirstSubmodelReference(submodelReferences); - assertTrue( - submodelReference.getKeys().stream().filter(ref -> ref.getValue().equals("testKey")).findAny().isPresent()); + assertTrue(submodelReference.getKeys().contains(submodelKey)); } @Test @@ -233,6 +231,7 @@ private Reference getFirstSubmodelReference(List submodelReferences) private DefaultSubmodel createDummySubmodel() { return new DefaultSubmodel.Builder() + .id("testId") .semanticId( new DefaultReference.Builder().keys(new DefaultKey.Builder().value("testKey").build()).build()) .build(); diff --git a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/CollidingSubmodelReferenceException.java b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/CollidingSubmodelReferenceException.java new file mode 100644 index 000000000..55e40555f --- /dev/null +++ b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/CollidingSubmodelReferenceException.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (C) 2024 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; + +public class CollidingSubmodelReferenceException extends RuntimeException { + public CollidingSubmodelReferenceException() { + } + + public CollidingSubmodelReferenceException(String submodelIdentifier) { + super(getMessage(submodelIdentifier)); + } + + private static String getMessage(String submodelIdentifier) { + return "Submodel Reference with id " + submodelIdentifier + " already exists"; + } + +} diff --git a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/MissingKeyTypeException.java b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/MissingKeyTypeException.java new file mode 100644 index 000000000..8fc53b7ce --- /dev/null +++ b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/MissingKeyTypeException.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (C) 2024 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; + +public class MissingKeyTypeException extends RuntimeException { + public MissingKeyTypeException() { + } + + public MissingKeyTypeException(String msg) { + super(msg); + } +} From c44663d5c4f0d89350ddde95aaa2869900bad851 Mon Sep 17 00:00:00 2001 From: Mateus Molina Date: Fri, 23 Aug 2024 14:28:12 +0200 Subject: [PATCH 06/10] Change examples/BaSyxSecured/keycloak to use an arm64 compatible image for the build stage (#397) --- examples/BaSyxSecured/keycloak/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/BaSyxSecured/keycloak/Dockerfile b/examples/BaSyxSecured/keycloak/Dockerfile index f7f0af270..e9a06667c 100644 --- a/examples/BaSyxSecured/keycloak/Dockerfile +++ b/examples/BaSyxSecured/keycloak/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM maven:3-eclipse-temurin-17-alpine as build +FROM maven:3-eclipse-temurin-17 AS build WORKDIR /workspace COPY ./initializer/pom.xml /workspace/pom.xml COPY ./initializer/src /workspace/src From 68f1b42a05a37f95ffef1334733ef4a50e62af06 Mon Sep 17 00:00:00 2001 From: Mateus Molina Date: Mon, 26 Aug 2024 08:20:38 +0200 Subject: [PATCH 07/10] Thread-Safe implementation of the *InmemoryBackends (#400) * Refactor *InMemoryBackends to be thread-safe * Refactor AASXFileServerInMemory Backend to be thread-safe --- .../AasDiscoveryInMemoryCrudRepository.java | 99 +++++++------------ .../backend/inmemory/AasInMemoryBackend.java | 30 +++--- .../AASXFileServerInMemoryCrudRepository.java | 36 +++---- .../ConceptDescriptionInMemoryBackend.java | 32 +++--- .../SubmodelInMemoryBackend.java | 30 +++--- 5 files changed, 103 insertions(+), 124 deletions(-) diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryCrudRepository.java b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryCrudRepository.java index e1b16bbef..7fdf732c7 100644 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryCrudRepository.java +++ b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryCrudRepository.java @@ -27,99 +27,63 @@ import java.util.ArrayList; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.stream.StreamSupport; import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.backend.AasDiscoveryDocument; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.model.AssetLink; import org.springframework.data.repository.CrudRepository; +import org.springframework.lang.NonNull; /** * In-memory implementation of the {@link CrudRepository} for the AAS Discovery * - * @author zielstor, fried + * @author zielstor, fried, mateusmolina */ public class AasDiscoveryInMemoryCrudRepository implements CrudRepository { - private final Map> assetLinks = new LinkedHashMap<>(); - private final Map> assetIds = new LinkedHashMap<>(); + private final ConcurrentMap> assetLinks = new ConcurrentHashMap<>(); + private final ConcurrentMap> assetIds = new ConcurrentHashMap<>(); @Override - public S save(S entity) { - Set assetLinks = entity.getAssetLinks(); - List assetIds = entity.getSpecificAssetIds(); + public synchronized @NonNull S save(@NonNull S entity) { String shellId = entity.getShellIdentifier(); - this.assetLinks.put(shellId, assetLinks); - this.assetIds.put(shellId, assetIds); + this.assetLinks.put(shellId, entity.getAssetLinks()); + this.assetIds.put(shellId, entity.getSpecificAssetIds()); + return entity; } @Override - public Iterable saveAll(Iterable entities) { - for (S entity : entities) { - this.save(entity); - } + public @NonNull Iterable saveAll(@NonNull Iterable entities) { + entities.forEach(this::save); return entities; } @Override - public Optional findById(String id) { - Set assetLinks = this.assetLinks.get(id); - List assetIds = this.assetIds.get(id); - if (assetIds == null) { - assetIds = new ArrayList<>(); - } - - if (assetLinks == null) { - assetLinks = new HashSet<>(); - } - return Optional.of(new AasDiscoveryDocument(id, assetLinks, assetIds)); + public @NonNull Optional findById(@NonNull String id) { + return Optional.ofNullable(buildAasDiscoveryDocument(id)); } @Override - public boolean existsById(String id) { + public boolean existsById(@NonNull String id) { return this.assetLinks.containsKey(id); } @Override - public Iterable findAll() { - List result = new ArrayList<>(); - for (String shellId : this.assetLinks.keySet()) { - Set assetLinks = this.assetLinks.get(shellId); - List assetIds = this.assetIds.get(shellId); - if (assetIds == null) { - assetIds = new ArrayList<>(); - } - - if (assetLinks == null) { - assetLinks = new HashSet<>(); - } - result.add(new AasDiscoveryDocument(shellId, assetLinks, assetIds)); - } - return result; + public @NonNull Iterable findAll() { + return assetLinks.keySet().stream().map(this::buildAasDiscoveryDocument).toList(); } @Override - public Iterable findAllById(Iterable ids) { - List result = new ArrayList<>(); - for (String id : ids) { - Set assetLinks = this.assetLinks.get(id); - List assetIds = this.assetIds.get(id); - if (assetIds == null) { - assetIds = new ArrayList<>(); - } - - if (assetLinks == null) { - assetLinks = new HashSet<>(); - } - result.add(new AasDiscoveryDocument(id, assetLinks, assetIds)); - } - return result; + public @NonNull Iterable findAllById(@NonNull Iterable ids) { + return StreamSupport.stream(ids.spliterator(), false).map(this::buildAasDiscoveryDocument).toList(); } @Override @@ -128,34 +92,47 @@ public long count() { } @Override - public void deleteById(String id) { + public synchronized void deleteById(@NonNull String id) { this.assetLinks.remove(id); this.assetIds.remove(id); } @Override - public void delete(AasDiscoveryDocument entity) { + public void delete(@NonNull AasDiscoveryDocument entity) { this.deleteById(entity.getShellIdentifier()); } @Override - public void deleteAllById(Iterable ids) { + public void deleteAllById(@NonNull Iterable ids) { for (String id : ids) { this.deleteById(id); } } @Override - public void deleteAll(Iterable entities) { + public void deleteAll(@NonNull Iterable entities) { for (AasDiscoveryDocument entity : entities) { this.deleteById(entity.getShellIdentifier()); } } @Override - public void deleteAll() { + public synchronized void deleteAll() { this.assetLinks.clear(); this.assetIds.clear(); } + private synchronized AasDiscoveryDocument buildAasDiscoveryDocument(String shellId) { + Set assetLinksSet = assetLinks.get(shellId); + List assetIdsList = assetIds.get(shellId); + + if (assetIdsList == null) + assetIdsList = new ArrayList<>(); + + if (assetLinksSet == null) + assetLinksSet = new HashSet<>(); + + return new AasDiscoveryDocument(shellId, assetLinksSet, assetIdsList); + } + } diff --git a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackend.java b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackend.java index 1aaa6a7ef..aeb02fd99 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackend.java +++ b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackend.java @@ -25,15 +25,16 @@ package org.eclipse.digitaltwin.basyx.aasrepository.backend.inmemory; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.springframework.data.repository.CrudRepository; +import org.springframework.lang.NonNull; /** * InMemory implementation for the AAS backend @@ -43,40 +44,39 @@ */ public class AasInMemoryBackend implements CrudRepository { - private Map inMemoryStore = new LinkedHashMap<>(); + private final ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); @Override - public S save(S entity) { + public @NonNull S save(@NonNull S entity) { inMemoryStore.put(entity.getId(), entity); return entity; } @Override - public Iterable saveAll(Iterable entities) { - for (S entity : entities) - inMemoryStore.put(entity.getId(), entity); + public @NonNull Iterable saveAll(@NonNull Iterable entities) { + entities.forEach(this::save); return entities; } @Override - public Optional findById(String id) { + public @NonNull Optional findById(@NonNull String id) { return Optional.ofNullable(inMemoryStore.get(id)); } @Override - public boolean existsById(String id) { + public boolean existsById(@NonNull String id) { return inMemoryStore.containsKey(id); } @Override - public Iterable findAll() { + public @NonNull Iterable findAll() { return inMemoryStore.values(); } @Override - public Iterable findAllById(Iterable ids) { + public @NonNull Iterable findAllById(@NonNull Iterable ids) { return StreamSupport.stream(ids.spliterator(), false).map(inMemoryStore::get).filter(Objects::nonNull).collect(Collectors.toList()); } @@ -86,23 +86,23 @@ public long count() { } @Override - public void deleteById(String id) { + public void deleteById(@NonNull String id) { inMemoryStore.remove(id); } @Override - public void delete(AssetAdministrationShell entity) { + public void delete(@NonNull AssetAdministrationShell entity) { inMemoryStore.remove(entity.getId()); } @Override - public void deleteAllById(Iterable ids) { + public void deleteAllById(@NonNull Iterable ids) { for (String id : ids) inMemoryStore.remove(id); } @Override - public void deleteAll(Iterable entities) { + public void deleteAll(@NonNull Iterable entities) { for (AssetAdministrationShell entity : entities) inMemoryStore.remove(entity.getId()); } diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryCrudRepository.java b/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryCrudRepository.java index d3bb71382..f1c61802a 100644 --- a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryCrudRepository.java +++ b/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryCrudRepository.java @@ -25,53 +25,55 @@ package org.eclipse.digitaltwin.basyx.aasxfileserver; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.eclipse.digitaltwin.basyx.aasxfileserver.model.Package; import org.springframework.data.repository.CrudRepository; +import org.springframework.lang.NonNull; public class AASXFileServerInMemoryCrudRepository implements CrudRepository { - private Map packageMap = new LinkedHashMap<>(); + private final ConcurrentMap packageMap = new ConcurrentHashMap<>(); @Override - public S save(S entity) { + public @NonNull S save(@NonNull S entity) { packageMap.put(entity.getPackageId(), entity); + return entity; } @Override - public Iterable saveAll(Iterable entities) { - for (Package entity : entities) { - save(entity); - } + public @NonNull Iterable saveAll(@NonNull Iterable entities) { + entities.forEach(this::save); + return entities; } @Override - public Optional findById(String id) { + public @NonNull Optional findById(@NonNull String id) { return Optional.ofNullable(packageMap.get(id)); } @Override - public boolean existsById(String id) { + public boolean existsById(@NonNull String id) { return packageMap.containsKey(id); } @Override - public Iterable findAll() { + public @NonNull Iterable findAll() { return packageMap.values(); } @Override - public Iterable findAllById(Iterable ids) { + public @NonNull Iterable findAllById(@NonNull Iterable ids) { List idList = StreamSupport.stream(ids.spliterator(), false).collect(Collectors.toList()); - return packageMap.entrySet().stream().filter(entry -> idList.contains(entry.getKey())).map(entry -> entry.getValue()).collect(Collectors.toList()); + return packageMap.entrySet().stream().filter(entry -> idList.contains(entry.getKey())).map(Entry::getValue).collect(Collectors.toList()); } @Override @@ -80,23 +82,23 @@ public long count() { } @Override - public void deleteById(String id) { + public void deleteById(@NonNull String id) { packageMap.remove(id); } @Override - public void delete(Package entity) { + public void delete(@NonNull Package entity) { packageMap.remove(entity.getPackageId()); } @Override - public void deleteAllById(Iterable ids) { + public void deleteAllById(@NonNull Iterable ids) { List idList = StreamSupport.stream(ids.spliterator(), false).collect(Collectors.toList()); packageMap.keySet().removeAll(idList); } @Override - public void deleteAll(Iterable entities) { + public void deleteAll(@NonNull Iterable entities) { List idList = StreamSupport.stream(entities.spliterator(), false).map(Package::getPackageId).collect(Collectors.toList()); packageMap.keySet().removeAll(idList); } diff --git a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackend.java b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackend.java index 40e61b598..38d8afa27 100644 --- a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackend.java +++ b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackend.java @@ -25,58 +25,58 @@ package org.eclipse.digitaltwin.basyx.conceptdescriptionrepository; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.eclipse.digitaltwin.aas4j.v3.model.ConceptDescription; import org.springframework.data.repository.CrudRepository; +import org.springframework.lang.NonNull; /** * InMemory implementation for the {@link ConceptDescription} backend * - * @author danish + * @author danish, mateusmolina * */ public class ConceptDescriptionInMemoryBackend implements CrudRepository { - private Map inMemoryStore = new LinkedHashMap<>(); + private final ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); @Override - public S save(S entity) { + public @NonNull S save(@NonNull S entity) { inMemoryStore.put(entity.getId(), entity); return entity; } @Override - public Iterable saveAll(Iterable entities) { - for (S entity : entities) - inMemoryStore.put(entity.getId(), entity); + public @NonNull Iterable saveAll(@NonNull Iterable entities) { + entities.forEach(this::save); return entities; } @Override - public Optional findById(String id) { + public @NonNull Optional findById(@NonNull String id) { return Optional.ofNullable(inMemoryStore.get(id)); } @Override - public boolean existsById(String id) { + public boolean existsById(@NonNull String id) { return inMemoryStore.containsKey(id); } @Override - public Iterable findAll() { + public @NonNull Iterable findAll() { return inMemoryStore.values(); } @Override - public Iterable findAllById(Iterable ids) { + public @NonNull Iterable findAllById(@NonNull Iterable ids) { return StreamSupport.stream(ids.spliterator(), false).map(inMemoryStore::get).filter(Objects::nonNull).collect(Collectors.toList()); } @@ -86,23 +86,23 @@ public long count() { } @Override - public void deleteById(String id) { + public void deleteById(@NonNull String id) { inMemoryStore.remove(id); } @Override - public void delete(ConceptDescription entity) { + public void delete(@NonNull ConceptDescription entity) { inMemoryStore.remove(entity.getId()); } @Override - public void deleteAllById(Iterable ids) { + public void deleteAllById(@NonNull Iterable ids) { for (String id : ids) inMemoryStore.remove(id); } @Override - public void deleteAll(Iterable entities) { + public void deleteAll(@NonNull Iterable entities) { for (ConceptDescription entity : entities) inMemoryStore.remove(entity.getId()); } diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackend.java b/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackend.java index c9a506740..91afca35d 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackend.java +++ b/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackend.java @@ -25,15 +25,16 @@ package org.eclipse.digitaltwin.basyx.submodelrepository; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; import org.springframework.data.repository.CrudRepository; +import org.springframework.lang.NonNull; /** * InMemory implementation for the Submodel backend @@ -43,40 +44,39 @@ */ public class SubmodelInMemoryBackend implements CrudRepository { - private Map inMemoryStore = new LinkedHashMap<>(); + private final ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); @Override - public S save(S entity) { + public @NonNull S save(@NonNull S entity) { inMemoryStore.put(entity.getId(), entity); return entity; } @Override - public Iterable saveAll(Iterable entities) { - for (S entity : entities) - inMemoryStore.put(entity.getId(), entity); + public @NonNull Iterable saveAll(@NonNull Iterable entities) { + entities.forEach(this::save); return entities; } @Override - public Optional findById(String id) { + public @NonNull Optional findById(String id) { return Optional.ofNullable(inMemoryStore.get(id)); } @Override - public boolean existsById(String id) { + public boolean existsById(@NonNull String id) { return inMemoryStore.containsKey(id); } @Override - public Iterable findAll() { + public @NonNull Iterable findAll() { return inMemoryStore.values(); } @Override - public Iterable findAllById(Iterable ids) { + public @NonNull Iterable findAllById(@NonNull Iterable ids) { return StreamSupport.stream(ids.spliterator(), false).map(inMemoryStore::get).filter(Objects::nonNull).collect(Collectors.toList()); } @@ -86,23 +86,23 @@ public long count() { } @Override - public void deleteById(String id) { + public void deleteById(@NonNull String id) { inMemoryStore.remove(id); } @Override - public void delete(Submodel entity) { + public void delete(@NonNull Submodel entity) { inMemoryStore.remove(entity.getId()); } @Override - public void deleteAllById(Iterable ids) { + public void deleteAllById(@NonNull Iterable ids) { for (String id : ids) inMemoryStore.remove(id); } @Override - public void deleteAll(Iterable entities) { + public void deleteAll(@NonNull Iterable entities) { for (Submodel entity : entities) inMemoryStore.remove(entity.getId()); } From af153d98cf87e6278b35ea2789f17b2905ad0414 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:01:08 +0200 Subject: [PATCH 08/10] Bump org.testng:testng from 7.1.0 to 7.10.2 (#380) Bumps [org.testng:testng](https://github.com/testng-team/testng) from 7.1.0 to 7.10.2. - [Release notes](https://github.com/testng-team/testng/releases) - [Changelog](https://github.com/testng-team/testng/blob/master/CHANGES.txt) - [Commits](https://github.com/testng-team/testng/commits/7.10.2) --- updated-dependencies: - dependency-name: org.testng:testng dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- basyx.aasxfileserver/basyx.aasxfileserver-http/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-http/pom.xml b/basyx.aasxfileserver/basyx.aasxfileserver-http/pom.xml index d6c3a5201..e7410d7be 100644 --- a/basyx.aasxfileserver/basyx.aasxfileserver-http/pom.xml +++ b/basyx.aasxfileserver/basyx.aasxfileserver-http/pom.xml @@ -108,7 +108,7 @@ org.testng testng - 7.1.0 + 7.10.2 test From af2318bab452a4dc6cb942bec88afbd1b4434ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sten=20Gr=C3=BCner?= <69786685+StenGruener@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:36:27 +0200 Subject: [PATCH 09/10] Typos in groupId for aasregistry-client-native POM (#354) * Typos in groupId for aasregistry-client-native POM * fixes remarks --------- Co-authored-by: Aaron Zielstorff --- basyx.aasregistry/basyx.aasregistry-client-native/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basyx.aasregistry/basyx.aasregistry-client-native/README.md b/basyx.aasregistry/basyx.aasregistry-client-native/README.md index 6cfdbe598..35d4e5d49 100644 --- a/basyx.aasregistry/basyx.aasregistry-client-native/README.md +++ b/basyx.aasregistry/basyx.aasregistry-client-native/README.md @@ -5,7 +5,7 @@ This is the generated java openAPI client (based on native java with jackson par To use the client in your maven projects define the following dependency: ```xml - org.eclipse.digitaltwin.basyx.aasregistry + org.eclipse.digitaltwin.basyx basyx.aasregistry-client-native ``` @@ -13,7 +13,7 @@ To use the client in your maven projects define the following dependency: If you also want to use the search API we highly recommend that you also include the search path builder class: ```xml - dorg.eclipse.digitaltwin.basyx.aasregistry + org.eclipse.digitaltwin.basyx basyx.aasregistry-paths ``` From b34d232befa2920e214332a2e1d260d21d2a93b9 Mon Sep 17 00:00:00 2001 From: Masud Rana <129751857+masud-svg@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:58:05 +0200 Subject: [PATCH 10/10] MQTT for SubmodelService (#339) * submodelservice-feature-mqtt added Signed-off-by: rana * submodelservice-feature-mqtt read.me file removed Signed-off-by: rana * submodelservice-feature-mqtt restructred Signed-off-by: rana * submodelservice-feature-mqtt changed according to feedback Signed-off-by: rana * submodelservice-feature-mqtt code-format changed Signed-off-by: rana * submodelservice-feature-mqtt pom.xml chnaged Signed-off-by: rana --------- Signed-off-by: rana --- .../pom.xml | 50 +++++ .../feature/mqtt/MqttSubmodelService.java | 192 ++++++++++++++++++ .../MqttSubmodelServiceConfiguration.java | 68 +++++++ .../mqtt/MqttSubmodelServiceFactory.java | 54 +++++ .../mqtt/MqttSubmodelServiceFeature.java | 81 ++++++++ .../mqtt/MqttSubmodelServiceTopicFactory.java | 83 ++++++++ .../feature/mqtt/MqttTestListener.java | 97 +++++++++ .../mqtt/TestMqttSubmodelObserver.java | 191 +++++++++++++++++ .../src/test/resources/config/moquette.conf | 6 + basyx.submodelservice/pom.xml | 1 + 10 files changed, 823 insertions(+) create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/pom.xml create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelService.java create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceConfiguration.java create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFactory.java create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFeature.java create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceTopicFactory.java create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttTestListener.java create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java create mode 100644 basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/resources/config/moquette.conf diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/pom.xml b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/pom.xml new file mode 100644 index 000000000..aa75f6c5d --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/pom.xml @@ -0,0 +1,50 @@ + + 4.0.0 + + org.eclipse.digitaltwin.basyx + basyx.submodelservice + ${revision} + + basyx.submodelservice-feature-mqtt + BaSyx submodelservice-feature-mqtt + BaSyx submodelservice-feature-mqtt + + + + org.eclipse.digitaltwin.basyx + basyx.submodelservice-core + + + org.eclipse.digitaltwin.basyx + basyx.mqttcore + + + org.eclipse.digitaltwin.basyx + basyx.submodelservice-core + tests + test + + + org.eclipse.digitaltwin.basyx + basyx.submodelservice-backend-inmemory + test + + + org.springframework.boot + spring-boot-starter + + + io.moquette + moquette-broker + test + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + org.eclipse.digitaltwin.basyx + basyx.submodelservice-backend-inmemory + + + \ No newline at end of file diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelService.java b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelService.java new file mode 100644 index 000000000..69e41f74c --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelService.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (C) 2024 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.submodelservice.feature.mqtt; + +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.common.mqttcore.serializer.SubmodelElementSerializer; +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.pagination.CursorResult; +import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService; +import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelElementValue; +import org.eclipse.paho.client.mqttv3.IMqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.MqttPersistenceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Service decorator for the MQTT eventing on the submodel level. + * + * @author rana + */ +public class MqttSubmodelService implements SubmodelService { + + private static Logger logger = LoggerFactory.getLogger(MqttSubmodelService.class); + private MqttSubmodelServiceTopicFactory topicFactory; + private SubmodelService decorated; + private IMqttClient mqttClient; + + public MqttSubmodelService(SubmodelService decorated, IMqttClient mqttClient, MqttSubmodelServiceTopicFactory topicFactory) { + this.topicFactory = topicFactory; + this.decorated = decorated; + this.mqttClient = mqttClient; + } + + @Override + public Submodel getSubmodel() { + return decorated.getSubmodel(); + } + + @Override + public CursorResult> getSubmodelElements(PaginationInfo pInfo) { + return decorated.getSubmodelElements(pInfo); + } + + @Override + public SubmodelElement getSubmodelElement(String idShortPath) throws ElementDoesNotExistException { + return decorated.getSubmodelElement(idShortPath); + } + + @Override + public SubmodelElementValue getSubmodelElementValue(String idShortPath) throws ElementDoesNotExistException { + return decorated.getSubmodelElementValue(idShortPath); + } + + @Override + public void setSubmodelElementValue(String idShortPath, SubmodelElementValue value) throws ElementDoesNotExistException { + decorated.setSubmodelElementValue(idShortPath, value); + SubmodelElement submodelElement = decorated.getSubmodelElement(idShortPath); + submodelElementUpdated(submodelElement, idShortPath); + } + + @Override + public void createSubmodelElement(SubmodelElement submodelElement) { + decorated.createSubmodelElement(submodelElement); + SubmodelElement smElement = decorated.getSubmodelElement(submodelElement.getIdShort()); + submodelElementCreated(submodelElement, smElement.getIdShort()); + } + + @Override + public void createSubmodelElement(String idShortPath, SubmodelElement submodelElement) throws ElementDoesNotExistException { + + decorated.createSubmodelElement(idShortPath, submodelElement); + + SubmodelElement smElement = decorated.getSubmodelElement(submodelElement.getIdShort()); + submodelElementCreated(smElement, idShortPath); + } + + @Override + public void updateSubmodelElement(String idShortPath, SubmodelElement submodelElement) throws ElementDoesNotExistException { + + decorated.updateSubmodelElement(idShortPath, submodelElement); + SubmodelElement smElement = decorated.getSubmodelElement(submodelElement.getIdShort()); + submodelElementUpdated(smElement, submodelElement.getIdShort()); + } + + @Override + public void deleteSubmodelElement(String idShortPath) throws ElementDoesNotExistException { + + SubmodelElement smElement = decorated.getSubmodelElement(idShortPath); + decorated.deleteSubmodelElement(idShortPath); + submodelElementDeleted(smElement, idShortPath); + } + + @Override + public void patchSubmodelElements(List submodelElementList) { + decorated.patchSubmodelElements(submodelElementList); + } + + @Override + public OperationVariable[] invokeOperation(String idShortPath, OperationVariable[] input) throws ElementDoesNotExistException { + return decorated.invokeOperation(idShortPath, input); + } + + @Override + public File getFileByPath(String idShortPath) throws ElementDoesNotExistException, ElementNotAFileException, FileDoesNotExistException { + return decorated.getFileByPath(idShortPath); + } + + @Override + public void setFileValue(String idShortPath, String fileName, InputStream inputStream) throws ElementDoesNotExistException, ElementNotAFileException { + decorated.setFileValue(idShortPath, fileName, inputStream); + } + + @Override + public void deleteFileValue(String idShortPath) throws ElementDoesNotExistException, ElementNotAFileException, FileDoesNotExistException { + decorated.deleteFileValue(idShortPath); + } + + private void submodelElementCreated(SubmodelElement submodelElement, String idShort) { + sendMqttMessage(topicFactory.createCreateSubmodelElementTopic(idShort), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); + } + + private void submodelElementUpdated(SubmodelElement submodelElement, String idShortPath) { + sendMqttMessage(topicFactory.createUpdateSubmodelElementTopic(idShortPath), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); + } + + private void submodelElementDeleted(SubmodelElement submodelElement, String idShort) { + sendMqttMessage(topicFactory.createDeleteSubmodelElementTopic(idShort), SubmodelElementSerializer.serializeSubmodelElement(submodelElement)); + } + + /** + * Sends MQTT message to connected broker + * + * @param topic + * in which the message will be published + * @param payload + * the actual message + */ + private void sendMqttMessage(String topic, String payload) { + MqttMessage msg = createMqttMessage(payload); + + try { + logger.debug("Send MQTT message to " + topic + ": " + payload); + mqttClient.publish(topic, msg); + } catch (MqttPersistenceException e) { + logger.error("Could not persist mqtt message", e); + } catch (MqttException e) { + logger.error("Could not send mqtt message", e); + } + } + + private MqttMessage createMqttMessage(String payload) { + if (payload == null) { + return new MqttMessage(); + } else { + return new MqttMessage(payload.getBytes()); + } + } +} diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceConfiguration.java b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceConfiguration.java new file mode 100644 index 000000000..1984dfb94 --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceConfiguration.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (C) 2024 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.submodelservice.feature.mqtt; + +import org.eclipse.paho.client.mqttv3.IMqttClient; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * MQTT configuration to allow for the automatic enable of the feature using the + * config file. + * + * @author rana + */ +@ConditionalOnExpression("#{${" + MqttSubmodelServiceFeature.FEATURENAME + ".enabled:false} or ${basyx.feature.mqtt.enabled:false}}") +@Configuration +public class MqttSubmodelServiceConfiguration { + + @ConditionalOnMissingBean + @Bean + public IMqttClient mqttClient(@Value("${mqtt.clientId}") String clientId, @Value("${mqtt.hostname}") String hostname, @Value("${mqtt.port}") int port) throws MqttException { + IMqttClient mqttClient = new MqttClient("tcp://" + hostname + ":" + port, clientId, new MemoryPersistence()); + + mqttClient.connect(mqttConnectOptions()); + + return mqttClient; + } + + @ConditionalOnMissingBean + @Bean + @ConfigurationProperties(prefix = "mqtt") + public MqttConnectOptions mqttConnectOptions() { + MqttConnectOptions mqttConceptOptions = new MqttConnectOptions(); + mqttConceptOptions.setAutomaticReconnect(true); + return mqttConceptOptions; + } +} diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFactory.java b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFactory.java new file mode 100644 index 000000000..9e3a0f1ca --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFactory.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (C) 2024 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.submodelservice.feature.mqtt; + +import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceFactory; +import org.eclipse.paho.client.mqttv3.IMqttClient; + +/** + * Service factory for the MQTT eventing on the submodel level. + * + * @author rana + */ +public class MqttSubmodelServiceFactory implements SubmodelServiceFactory { + + private SubmodelServiceFactory decorated; + private IMqttClient client; + private MqttSubmodelServiceTopicFactory topicFactory; + + public MqttSubmodelServiceFactory(SubmodelServiceFactory decorated, IMqttClient client, MqttSubmodelServiceTopicFactory topicFactory) { + this.decorated = decorated; + this.client = client; + this.topicFactory = topicFactory; + } + + @Override + public SubmodelService create(Submodel submodel) { + return new MqttSubmodelService(decorated.create(submodel), client, topicFactory); + } +} diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFeature.java b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFeature.java new file mode 100644 index 000000000..7e056450b --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceFeature.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (C) 2024 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.submodelservice.feature.mqtt; + +import org.eclipse.digitaltwin.basyx.common.mqttcore.encoding.Base64URLEncoder; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceFactory; +import org.eclipse.digitaltwin.basyx.submodelservice.feature.SubmodelServiceFeature; +import org.eclipse.paho.client.mqttv3.IMqttClient; +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; + +/** + * Service feature for the MQTT eventing on the submodel level. + * + * @author rana + */ +@ConditionalOnExpression("#{${" + MqttSubmodelServiceFeature.FEATURENAME + ".enabled:false} or ${basyx.feature.mqtt.enabled:false}}") +@Component +public class MqttSubmodelServiceFeature implements SubmodelServiceFeature { + + public final static String FEATURENAME = "basyx.submodelservice.feature.mqtt"; + + @Value("#{${" + FEATURENAME + ".enabled:false} or ${basyx.feature.mqtt.enabled:false}}") + private boolean enabled; + + private IMqttClient mqttClient; + + @Autowired + public MqttSubmodelServiceFeature(IMqttClient mqttClient) { + this.mqttClient = mqttClient; + } + + @Override + public SubmodelServiceFactory decorate(SubmodelServiceFactory component) { + return new MqttSubmodelServiceFactory(component, mqttClient, new MqttSubmodelServiceTopicFactory(new Base64URLEncoder())); + } + + @Override + public void initialize() { + } + + @Override + public void cleanUp() { + + } + + @Override + public String getName() { + return "SubmodelService MQTT"; + } + + @Override + public boolean isEnabled() { + return enabled; + } +} diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceTopicFactory.java b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceTopicFactory.java new file mode 100644 index 000000000..31296f4d0 --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/feature/mqtt/MqttSubmodelServiceTopicFactory.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (C) 2024 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.submodelservice.feature.mqtt; + +import java.util.StringJoiner; + +import org.eclipse.digitaltwin.basyx.common.mqttcore.AbstractMqttTopicFactory; +import org.eclipse.digitaltwin.basyx.common.mqttcore.encoding.Encoder; + +/** + * MQTT topic factory for the eventing on the submodel level. + * + * @author rana + */ +public class MqttSubmodelServiceTopicFactory extends AbstractMqttTopicFactory { + + private static final String SUBMODEL_SERVICE = "sm-service"; + private static final String SUBMODELS = "submodels"; + private static final String CREATED = "created"; + private static final String UPDATED = "updated"; + private static final String DELETED = "deleted"; + private static final String SUBMODEL_ELEMENTS = "submodelElements"; + + /** + * Used for encoding the idShort + * + * @param encoder + */ + public MqttSubmodelServiceTopicFactory(Encoder encoder) { + super(encoder); + } + + /** + * Creates the hierarchical topic for the create event of submodelElements + * + * @param idShort + */ + public String createCreateSubmodelElementTopic(String idShort) { + return new StringJoiner("/", "", "").add(SUBMODEL_SERVICE).add(SUBMODELS).add(SUBMODEL_ELEMENTS).add(idShort).add(CREATED).toString(); + } + + /** + * Creates the hierarchical topic for the update event of submodelElements + * + * @param idShort + */ + public String createUpdateSubmodelElementTopic(String idShort) { + + return new StringJoiner("/", "", "").add(SUBMODEL_SERVICE).add(SUBMODELS).add(SUBMODEL_ELEMENTS).add(idShort).add(UPDATED).toString(); + } + + /** + * Creates the hierarchical topic for the delete event of submodelElements + * + * @param idShort + */ + public String createDeleteSubmodelElementTopic(String idShort) { + return new StringJoiner("/", "", "").add(SUBMODEL_SERVICE).add(SUBMODELS).add(SUBMODEL_ELEMENTS).add(idShort).add(DELETED).toString(); + } +} diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttTestListener.java b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttTestListener.java new file mode 100644 index 000000000..c7cc88b3b --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttTestListener.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (C) 2024 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.mqtt; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +import io.moquette.interception.InterceptHandler; +import io.moquette.interception.messages.InterceptAcknowledgedMessage; +import io.moquette.interception.messages.InterceptConnectMessage; +import io.moquette.interception.messages.InterceptConnectionLostMessage; +import io.moquette.interception.messages.InterceptDisconnectMessage; +import io.moquette.interception.messages.InterceptPublishMessage; +import io.moquette.interception.messages.InterceptSubscribeMessage; +import io.moquette.interception.messages.InterceptUnsubscribeMessage; + +/** + * Very simple MQTT broker listener for testing API events. Stores the last + * received event and makes its topic and payload available for reading. + * + * @author espen + * + */ +public class MqttTestListener implements InterceptHandler { + // Topic and payload of the most recent event + public String lastTopic; + public String lastPayload; + private ArrayList topics = new ArrayList<>(); + + @Override + public String getID() { + return null; + } + + @Override + public Class[] getInterceptedMessageTypes() { + return null; + } + + @Override + public void onConnect(InterceptConnectMessage arg0) { + } + + @Override + public void onConnectionLost(InterceptConnectionLostMessage arg0) { + } + + @Override + public void onDisconnect(InterceptDisconnectMessage arg0) { + } + + @Override + public void onMessageAcknowledged(InterceptAcknowledgedMessage arg0) { + } + + @Override + public synchronized void onPublish(InterceptPublishMessage msg) { + topics.add(msg.getTopicName()); + lastTopic = msg.getTopicName(); + lastPayload = msg.getPayload().toString(StandardCharsets.UTF_8); + } + + @Override + public void onSubscribe(InterceptSubscribeMessage arg0) { + } + + @Override + public void onUnsubscribe(InterceptUnsubscribeMessage arg0) { + } + + public ArrayList getTopics() { + return topics; + } +} diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java new file mode 100644 index 000000000..75eab2b75 --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/TestMqttSubmodelObserver.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (C) 2024 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.mqtt; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException; +import org.eclipse.digitaltwin.aas4j.v3.dataformat.json.JsonDeserializer; +import org.eclipse.digitaltwin.aas4j.v3.model.Property; +import org.eclipse.digitaltwin.aas4j.v3.model.Qualifier; +import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultProperty; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultQualifier; +import org.eclipse.digitaltwin.basyx.common.mqttcore.encoding.Base64URLEncoder; +import org.eclipse.digitaltwin.basyx.common.mqttcore.serializer.SubmodelElementSerializer; +import org.eclipse.digitaltwin.basyx.core.filerepository.InMemoryFileRepository; +import org.eclipse.digitaltwin.basyx.submodelservice.DummySubmodelFactory; +import org.eclipse.digitaltwin.basyx.submodelservice.InMemorySubmodelServiceFactory; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService; +import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceFactory; +import org.eclipse.digitaltwin.basyx.submodelservice.feature.mqtt.MqttSubmodelServiceFactory; +import org.eclipse.digitaltwin.basyx.submodelservice.feature.mqtt.MqttSubmodelServiceTopicFactory; +import org.eclipse.digitaltwin.basyx.submodelservice.value.PropertyValue; +import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelElementValue; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import io.moquette.broker.Server; +import io.moquette.broker.config.ClasspathResourceLoader; +import io.moquette.broker.config.IConfig; +import io.moquette.broker.config.IResourceLoader; +import io.moquette.broker.config.ResourceLoaderConfig; + +/** + * Tests events for submodelElements in SM Service + * + * @author rana + */ +public class TestMqttSubmodelObserver { + + private static Server mqttBroker; + private static MqttClient mqttClient; + private static MqttTestListener listener; + private static MqttSubmodelServiceTopicFactory topicFactory = new MqttSubmodelServiceTopicFactory(new Base64URLEncoder()); + private static SubmodelService submodelService; + + @BeforeClass + public static void setUpClass() throws MqttException, IOException { + mqttBroker = startBroker(); + + listener = configureInterceptListener(mqttBroker); + + mqttClient = createAndConnectClient(); + + submodelService = createMqttSubmodelService(mqttClient); + } + + @AfterClass + public static void tearDownClass() { + mqttBroker.removeInterceptHandler(listener); + mqttBroker.stopServer(); + } + + @Test + public void createSubmodelElementEvent() throws DeserializationException { + + SubmodelElement submodelElement = createSubmodelElementDummy("createSubmodelElementEventId"); + submodelService.createSubmodelElement(submodelElement); + + assertEquals(topicFactory.createCreateSubmodelElementTopic(submodelElement.getIdShort()), listener.lastTopic); + assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); + } + + @Test + public void updateSubmodelElementEvent() throws DeserializationException { + + SubmodelElement submodelElement = createSubmodelElementDummy("updateSubmodelElementEventId"); + submodelService.createSubmodelElement(submodelElement); + + SubmodelElementValue value = new PropertyValue("updatedValue"); + submodelService.setSubmodelElementValue(submodelElement.getIdShort(), value); + + assertEquals(topicFactory.createUpdateSubmodelElementTopic(submodelElement.getIdShort()), listener.lastTopic); + assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); + } + + @Test + public void deleteSubmodelElementEvent() throws DeserializationException { + + SubmodelElement submodelElement = createSubmodelElementDummy("deleteSubmodelElementEventId"); + submodelService.createSubmodelElement(submodelElement); + submodelService.deleteSubmodelElement(submodelElement.getIdShort()); + + assertEquals(topicFactory.createDeleteSubmodelElementTopic(submodelElement.getIdShort()), listener.lastTopic); + assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); + } + + @Test + public void createSubmodelElementWithoutValueEvent() throws DeserializationException { + + SubmodelElement submodelElement = createSubmodelElementDummy("noValueSubmodelElementEventId"); + List qualifierList = createNoValueQualifierList(); + submodelElement.setQualifiers(qualifierList); + submodelService.createSubmodelElement(submodelElement); + + assertEquals(topicFactory.createCreateSubmodelElementTopic(submodelElement.getIdShort()), listener.lastTopic); + assertNotEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); + + ((Property) submodelElement).setValue(null); + assertEquals(submodelElement, deserializeSubmodelElementPayload(listener.lastPayload)); + } + + private List createNoValueQualifierList() { + + Qualifier emptyValueQualifier = new DefaultQualifier.Builder().type(SubmodelElementSerializer.EMPTYVALUEUPDATE_TYPE).value("true").build(); + return Arrays.asList(emptyValueQualifier); + } + + private static SubmodelElement deserializeSubmodelElementPayload(String payload) throws DeserializationException { + + return new JsonDeserializer().read(payload, SubmodelElement.class); + } + + private SubmodelElement createSubmodelElementDummy(String submodelElementId) { + return new DefaultProperty.Builder().idShort(submodelElementId).value("defaultValue").build(); + } + + private static SubmodelService createMqttSubmodelService(MqttClient client) { + + SubmodelServiceFactory repoFactory = new InMemorySubmodelServiceFactory(new InMemoryFileRepository()); + return new MqttSubmodelServiceFactory(repoFactory, client, new MqttSubmodelServiceTopicFactory(new Base64URLEncoder())).create(DummySubmodelFactory.createSubmodelWithAllSubmodelElements()); + } + + private static MqttTestListener configureInterceptListener(Server broker) { + + MqttTestListener testListener = new MqttTestListener(); + broker.addInterceptHandler(testListener); + + return testListener; + } + + private static MqttClient createAndConnectClient() throws MqttException, MqttSecurityException { + + MqttClient client = new MqttClient("tcp://localhost:1884", "testClient"); + client.connect(); + return client; + } + + private static Server startBroker() throws IOException { + + Server broker = new Server(); + IResourceLoader classpathLoader = new ClasspathResourceLoader(); + + IConfig classPathConfig = new ResourceLoaderConfig(classpathLoader); + broker.startServer(classPathConfig); + + return broker; + } +} diff --git a/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/resources/config/moquette.conf b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/resources/config/moquette.conf new file mode 100644 index 000000000..8511afcd1 --- /dev/null +++ b/basyx.submodelservice/basyx.submodelservice-feature-mqtt/src/test/resources/config/moquette.conf @@ -0,0 +1,6 @@ +# Moquette Java Broker configuration file for testing + +# Do not use the default 1883 port +port 1884 +host 0.0.0.0 +allow_anonymous true \ No newline at end of file diff --git a/basyx.submodelservice/pom.xml b/basyx.submodelservice/pom.xml index dc199230c..f5916f017 100644 --- a/basyx.submodelservice/pom.xml +++ b/basyx.submodelservice/pom.xml @@ -18,6 +18,7 @@ basyx.submodelservice-core basyx.submodelservice-http basyx.submodelservice-backend-inmemory + basyx.submodelservice-feature-mqtt basyx.submodelservice.example basyx.submodelservice-client