From 512b39cb7abe1277b7bb587e98cdc84f2fb6a6c0 Mon Sep 17 00:00:00 2001 From: FriedJannik Date: Wed, 30 Apr 2025 15:54:30 +0200 Subject: [PATCH 01/10] Adds Feature Discovery-Integration - TODO: Test --- .../pom.xml | 72 ++++++++ .../DiscoveryIntegrationAasRepository.java | 174 ++++++++++++++++++ ...IntegrationAasRepositoryConfiguration.java | 101 ++++++++++ ...coveryIntegrationAasRepositoryFactory.java | 52 ++++++ ...coveryIntegrationAasRepositoryFeature.java | 82 +++++++++ basyx.aasrepository/pom.xml | 1 + .../RepositoryDiscoveryLinkException.java | 37 ++++ .../RepositoryDiscoveryUnlinkException.java | 37 ++++ pom.xml | 12 ++ 9 files changed, 568 insertions(+) create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/pom.xml create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFactory.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFeature.java create mode 100644 basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryLinkException.java create mode 100644 basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryUnlinkException.java diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/pom.xml b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/pom.xml new file mode 100644 index 000000000..705b7468b --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + org.eclipse.digitaltwin.basyx + basyx.aasrepository + ${revision} + + + basyx.aasrepository-feature-discovery-integration + BaSyx AAS Repository feature-discovery-integration + + + + org.eclipse.digitaltwin.basyx + basyx.aasdiscoveryservice-client + + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-core + + + org.eclipse.digitaltwin.basyx + basyx.http + test + tests + + + org.eclipse.digitaltwin.basyx + basyx.http + + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-http + tests + test + + + org.eclipse.digitaltwin.basyx + basyx.filerepository-backend-inmemory + test + + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-http + test + + + org.eclipse.digitaltwin.basyx + basyx.aasservice-backend-inmemory + test + + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-backend-inmemory + test + + + org.apache.httpcomponents.client5 + httpclient5 + test + + + org.mockito + mockito-core + test + + + + \ No newline at end of file diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java new file mode 100644 index 000000000..f89fa9333 --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; +import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; +import org.eclipse.digitaltwin.aas4j.v3.model.Reference; +import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSpecificAssetId; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; +import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException; +import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; +import org.eclipse.digitaltwin.basyx.core.exceptions.RepositoryDiscoveryLinkException; +import org.eclipse.digitaltwin.basyx.core.exceptions.RepositoryDiscoveryUnlinkException; +import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; +import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * Decorator for linking {@link AasRepository} with Discovery + * + * @author fried + * + */ +public class DiscoveryIntegrationAasRepository implements AasRepository { + private static Logger logger = LoggerFactory.getLogger(DiscoveryIntegrationAasRepository.class); + + private AasRepository decorated; + + private final AasDiscoveryService discoveryApi; + + public DiscoveryIntegrationAasRepository(AasRepository decorated, AasDiscoveryService discoveryApi) { + this.decorated = decorated; + this.discoveryApi = discoveryApi; + } + + @Override + public CursorResult> getAllAas(PaginationInfo pInfo) { + return decorated.getAllAas(pInfo); + } + + @Override + public AssetAdministrationShell getAas(String shellId) throws ElementDoesNotExistException { + return decorated.getAas(shellId); + } + + @Override + public void createAas(AssetAdministrationShell shell) throws CollidingIdentifierException { + decorated.createAas(shell); + + createAssetLinksOnDiscoveryServiceIfNecessary(shell); + } + + private void createAssetLinksOnDiscoveryServiceIfNecessary(AssetAdministrationShell shell) { + List linksToAdd = new ArrayList<>(shell.getAssetInformation().getSpecificAssetIds()); + if(!shell.getAssetInformation().getGlobalAssetId().isEmpty()){ + linksToAdd.add(getGlobalAssetIdAsSpecificAssetId(shell)); + } + if(!linksToAdd.isEmpty()){ + try { + discoveryApi.createAllAssetLinksById(shell.getId(), linksToAdd); + } catch (Exception e) { + decorated.deleteAas(shell.getId()); + throw new RepositoryDiscoveryLinkException(shell.getId(), e); + } + } + } + + @Override + public void updateAas(String shellId, AssetAdministrationShell shell) { + AssetAdministrationShell oldShell = getAas(shellId); + if(oldShell.getAssetInformation().getGlobalAssetId().equals(shell.getAssetInformation().getGlobalAssetId()) && oldShell.getAssetInformation().getSpecificAssetIds().equals(shell.getAssetInformation().getSpecificAssetIds())){ + logger.info("No changes in asset links, skipping update on discovery service"); + } else { + try { + discoveryApi.deleteAllAssetLinksById(shellId); + } catch (Exception e){ + throw new RepositoryDiscoveryUnlinkException(shellId, e); + } + createAssetLinksOnDiscoveryServiceIfNecessary(shell); + } + decorated.updateAas(shellId, shell); + } + + @Override + public void deleteAas(String shellId) { + decorated.deleteAas(shellId); + + try { + discoveryApi.deleteAllAssetLinksById(shellId); + } catch (Exception e){ + throw new RepositoryDiscoveryUnlinkException(shellId, e); + } + } + + @Override + public String getName() { + return decorated.getName(); + } + + @Override + public CursorResult> getSubmodelReferences(String shellId, PaginationInfo paginationInfo) { + return decorated.getSubmodelReferences(shellId, paginationInfo); + } + + @Override + public void addSubmodelReference(String shellId, Reference submodelReference) { + decorated.addSubmodelReference(shellId, submodelReference); + } + + @Override + public void removeSubmodelReference(String shellId, String submodelId) { + decorated.removeSubmodelReference(shellId, submodelId); + } + + @Override + public void setAssetInformation(String shellId, AssetInformation shellInfo) throws ElementDoesNotExistException { + decorated.setAssetInformation(shellId, shellInfo); + } + + @Override + public AssetInformation getAssetInformation(String shellId) throws ElementDoesNotExistException { + return decorated.getAssetInformation(shellId); + } + + @Override + public File getThumbnail(String aasId) { + return decorated.getThumbnail(aasId); + } + + @Override + public void setThumbnail(String aasId, String fileName, String contentType, InputStream inputStream) { + decorated.setThumbnail(aasId, fileName, contentType, inputStream); + } + + @Override + public void deleteThumbnail(String aasId) { + decorated.deleteThumbnail(aasId); + } + + private static DefaultSpecificAssetId getGlobalAssetIdAsSpecificAssetId(AssetAdministrationShell shell) { + return new DefaultSpecificAssetId.Builder().name("globalAssetId").value(shell.getAssetInformation().getGlobalAssetId()).build(); + } + +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java new file mode 100644 index 000000000..3aa2aafae --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.ConnectedAasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; +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; +import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.GrantType; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Collection; +import java.util.List; + +/** + * Configuration for integrating {@link AasRepository} with Discovery + * + * @author fried + */ +@Configuration +@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${basyx.aasrepository.feature.discoveryintegration:}')") +public class DiscoveryIntegrationAasRepositoryConfiguration { + + @Value("${basyx.aasrepository.feature.discoveryintegration:#{null}}") + private String discoveryBasePath; + + @Value("#{'${basyx.externalurl}'.split(',')}") + private List aasRepositoryBaseURLs; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.enabled:false}") + private boolean isAuthorizationEnabledOnRegistry; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.token-endpoint:#{null}}") + private String authenticationServerTokenEndpoint; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.grant-type:#{null}}") + private String grantType; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.client-id:#{null}}") + private String clientId; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.client-secret:#{null}}") + private String clientSecret; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.username:#{null}}") + private String username; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.password:#{null}}") + private String password; + + @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.scopes:#{null}}") + private Collection scopes; + + @Bean + public AasDiscoveryService getConnectedAasDiscoveryService() { + if (!isAuthorizationEnabledOnRegistry) + return new ConnectedAasDiscoveryService(discoveryBasePath); + + TokenManager tokenManager = new TokenManager(authenticationServerTokenEndpoint, createAccessTokenProvider()); + + return new ConnectedAasDiscoveryService(discoveryBasePath, tokenManager); + } + + private AccessTokenProvider createAccessTokenProvider() { + + AccessTokenProviderFactory factory = new AccessTokenProviderFactory(GrantType.valueOf(grantType), scopes); + factory.setClientCredentials(clientId, clientSecret); + factory.setPasswordCredentials(username, password); + + return factory.create(); + } + +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFactory.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFactory.java new file mode 100644 index 000000000..eb4968a85 --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFactory.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepositoryFactory; + +/** + * Factory for creating {@link DiscoveryIntegrationAasRepository} + * + * @author fried + */ +public class DiscoveryIntegrationAasRepositoryFactory implements AasRepositoryFactory { + + private AasRepositoryFactory decorated; + private final AasDiscoveryService discoveryApi; + + public DiscoveryIntegrationAasRepositoryFactory(AasRepositoryFactory decorated, AasDiscoveryService discoveryApi) { + this.decorated = decorated; + this.discoveryApi = discoveryApi; + } + + @Override + public AasRepository create() { + return new DiscoveryIntegrationAasRepository(decorated.create(), discoveryApi); + } + +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFeature.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFeature.java new file mode 100644 index 000000000..6570caf6e --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryFeature.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepositoryFactory; +import org.eclipse.digitaltwin.basyx.aasrepository.feature.AasRepositoryFeature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Component; + +/** + * Feature for integrating Discovery with {@link AasRepository} + * + * @author fried + */ +@Component +@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${basyx.aasrepository.feature.discoveryintegration:}')") +public class DiscoveryIntegrationAasRepositoryFeature implements AasRepositoryFeature { + public final static String FEATURENAME = "basyx.aasrepository.feature.discoveryintegration"; + + + @Value("${" + FEATURENAME + ":}") + private String discoveryBaseURL; + + private final AasDiscoveryService discoveryApi; + + @Autowired + public DiscoveryIntegrationAasRepositoryFeature(AasDiscoveryService discoveryApi) { + this.discoveryApi = discoveryApi; + } + + @Override + public AasRepositoryFactory decorate(AasRepositoryFactory aasRepositoryFactory) { + return new DiscoveryIntegrationAasRepositoryFactory(aasRepositoryFactory, discoveryApi); + } + + @Override + public void initialize() { + } + + @Override + public void cleanUp() { + + } + + @Override + public String getName() { + return "AasRepository Discovery Integration"; + } + + @Override + public boolean isEnabled() { + return !discoveryBaseURL.isBlank(); + } +} diff --git a/basyx.aasrepository/pom.xml b/basyx.aasrepository/pom.xml index ae8f067e6..1b20fd9bb 100644 --- a/basyx.aasrepository/pom.xml +++ b/basyx.aasrepository/pom.xml @@ -22,6 +22,7 @@ basyx.aasrepository-feature-mqtt basyx.aasrepository-feature-kafka basyx.aasrepository-feature-registry-integration + basyx.aasrepository-feature-discovery-integration basyx.aasrepository-feature-authorization basyx.aasrepository-tck basyx.aasrepository.component diff --git a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryLinkException.java b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryLinkException.java new file mode 100644 index 000000000..b49037a3b --- /dev/null +++ b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryLinkException.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (C) 2025 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 RepositoryDiscoveryLinkException extends RuntimeException { + + public RepositoryDiscoveryLinkException(String id, Throwable th) { + super(getMessage(id), th); + } + + private static String getMessage(String id) { + return "Unable to link the element with id '" + id + "' with the Discovery Service."; + } +} diff --git a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryUnlinkException.java b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryUnlinkException.java new file mode 100644 index 000000000..dc2245e7e --- /dev/null +++ b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/exceptions/RepositoryDiscoveryUnlinkException.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (C) 2025 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 RepositoryDiscoveryUnlinkException extends RuntimeException { + + public RepositoryDiscoveryUnlinkException(String id, Throwable th) { + super(getMessage(id), th); + } + + private static String getMessage(String id) { + return "Unable to unlink the element with id '" + id + "' with the Discovery Service."; + } +} diff --git a/pom.xml b/pom.xml index ccd7a14e0..6046f26e6 100644 --- a/pom.xml +++ b/pom.xml @@ -566,6 +566,12 @@ basyx.submodelrepository-feature-registry-integration ${revision} + + org.eclipse.digitaltwin.basyx + + basyx.submodelrepository-feature-discovery-integration + ${revision} + org.eclipse.digitaltwin.basyx basyx.submodelrepository-feature-authorization @@ -1101,6 +1107,12 @@ ${revision} tests + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-feature-discovery-integration + ${revision} + tests + org.eclipse.digitaltwin.basyx basyx.aasrepository-feature-authorization From d9298c268faa8cb6389332578432603e5987ae28 Mon Sep 17 00:00:00 2001 From: fried Date: Fri, 2 May 2025 10:34:09 +0200 Subject: [PATCH 02/10] Adds Tests for AAS Repository Discovery Integration --- .../client/ConnectedAasDiscoveryService.java | 8 +- .../DiscoveryIntegrationAasRepository.java | 15 +- ...IntegrationAasRepositoryConfiguration.java | 3 - ...AasRepositoryDiscoveryIntegrationTest.java | 70 +++++++ ...positoryDiscoveryIntegrationTestSuite.java | 174 ++++++++++++++++++ ...DiscoveryIntegrationTestConfiguration.java | 43 +++++ ...ummyAasRepositoryIntegrationComponent.java | 44 +++++ .../src/test/resources/application.properties | 9 + ci/docker-compose.yml | 10 +- 9 files changed, 364 insertions(+), 12 deletions(-) create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryIntegrationComponent.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application.properties diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java index 0e61e629a..312d5d7ac 100644 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java +++ b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java @@ -61,7 +61,7 @@ public CursorResult> getAllAssetAdministrationShellIdsByAssetLink(P return discoveryApi.getAllAssetAdministrationShellIdsByAssetLink(assetIds, pInfo.getLimit(), pInfo.getCursor()); } catch (ApiException e) { if(e.getCode() == HttpStatus.NOT_FOUND.value()){ - throw new AssetLinkDoesNotExistException("No matching element for given assetIds"); + throw new AssetLinkDoesNotExistException(); } else { throw new RuntimeException("Error while getting all Asset Administration Shell IDs by Asset Link", e); } @@ -74,7 +74,7 @@ public List getAllAssetLinksById(String shellIdentifier) { return discoveryApi.getAllAssetLinksById(shellIdentifier); } catch (ApiException e) { if(e.getCode() == HttpStatus.NOT_FOUND.value()){ - throw new AssetLinkDoesNotExistException("Element with id "+shellIdentifier+" does not exist"); + throw new AssetLinkDoesNotExistException(shellIdentifier); } else { throw new RuntimeException("Error while getting all Asset Links by ID", e); } @@ -87,7 +87,7 @@ public List createAllAssetLinksById(String shellIdentifier, Lis return discoveryApi.postAllAssetLinksById(shellIdentifier, assetIds); } catch (ApiException e) { if(e.getCode() == HttpStatus.CONFLICT.value()){ - throw new CollidingAssetLinkException("Asset Links for shell "+shellIdentifier+" already exists"); + throw new CollidingAssetLinkException(shellIdentifier); } else { throw new RuntimeException("Error while creating all Asset Links by ID", e); } @@ -100,7 +100,7 @@ public void deleteAllAssetLinksById(String shellIdentifier) { discoveryApi.deleteAllAssetLinksById(shellIdentifier); } catch (ApiException e) { if(e.getCode() == HttpStatus.NOT_FOUND.value()){ - throw new AssetLinkDoesNotExistException("Element with id "+shellIdentifier+" does not exist"); + throw new AssetLinkDoesNotExistException(shellIdentifier); } else { throw new RuntimeException("Error while deleting all Asset Links by ID", e); } diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java index f89fa9333..9b723e58c 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java @@ -82,7 +82,7 @@ public void createAas(AssetAdministrationShell shell) throws CollidingIdentifier private void createAssetLinksOnDiscoveryServiceIfNecessary(AssetAdministrationShell shell) { List linksToAdd = new ArrayList<>(shell.getAssetInformation().getSpecificAssetIds()); - if(!shell.getAssetInformation().getGlobalAssetId().isEmpty()){ + if(shell.getAssetInformation().getGlobalAssetId() != null){ linksToAdd.add(getGlobalAssetIdAsSpecificAssetId(shell)); } if(!linksToAdd.isEmpty()){ @@ -98,19 +98,26 @@ private void createAssetLinksOnDiscoveryServiceIfNecessary(AssetAdministrationSh @Override public void updateAas(String shellId, AssetAdministrationShell shell) { AssetAdministrationShell oldShell = getAas(shellId); - if(oldShell.getAssetInformation().getGlobalAssetId().equals(shell.getAssetInformation().getGlobalAssetId()) && oldShell.getAssetInformation().getSpecificAssetIds().equals(shell.getAssetInformation().getSpecificAssetIds())){ + if(!isGlobalAssetIdUpdated(shell, oldShell) && !specificAssetIdsUpdated(shell, oldShell)){ logger.info("No changes in asset links, skipping update on discovery service"); } else { try { discoveryApi.deleteAllAssetLinksById(shellId); - } catch (Exception e){ - throw new RepositoryDiscoveryUnlinkException(shellId, e); + } catch (Exception ignored){ } createAssetLinksOnDiscoveryServiceIfNecessary(shell); } decorated.updateAas(shellId, shell); } + private static boolean specificAssetIdsUpdated(AssetAdministrationShell shell, AssetAdministrationShell oldShell) { + return !(oldShell.getAssetInformation().getSpecificAssetIds() != null && oldShell.getAssetInformation().getSpecificAssetIds().equals(shell.getAssetInformation().getSpecificAssetIds())); + } + + private static boolean isGlobalAssetIdUpdated(AssetAdministrationShell shell, AssetAdministrationShell oldShell) { + return !(oldShell.getAssetInformation().getGlobalAssetId() != null && oldShell.getAssetInformation().getGlobalAssetId().equals(shell.getAssetInformation().getGlobalAssetId())); + } + @Override public void deleteAas(String shellId) { decorated.deleteAas(shellId); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java index 3aa2aafae..1ea834583 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java @@ -52,9 +52,6 @@ public class DiscoveryIntegrationAasRepositoryConfiguration { @Value("${basyx.aasrepository.feature.discoveryintegration:#{null}}") private String discoveryBasePath; - @Value("#{'${basyx.externalurl}'.split(',')}") - private List aasRepositoryBaseURLs; - @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.enabled:false}") private boolean isAuthorizationEnabledOnRegistry; diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java new file mode 100644 index 000000000..82aceb05a --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.ConnectedAasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; + +public class AasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscoveryIntegrationTestSuite{ + private static ConfigurableApplicationContext appContext; + + @BeforeClass + public static void setUp() { + appContext = SpringApplication.run(DummyAasRepositoryIntegrationComponent.class); + } + + @AfterClass + public static void tearDown() { + appContext.close(); + } + + @Before + @After + public void resetRepository() { + AssetAdministrationShell shell = getDemoAAS(false, false); + try { + appContext.getBean(AasRepository.class).deleteAas(shell.getId()); + } catch (Exception e) {} + } + + @Override + protected AasDiscoveryService getDiscoveryService() { + return new ConnectedAasDiscoveryService("http://localhost:8049"); + } + + @Override + protected String getAASRepositoryURL() { + return "http://localhost:4753/shells"; + } +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java new file mode 100644 index 000000000..0e6dd47f8 --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; +import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId; +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.DefaultSpecificAssetId; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; +import org.eclipse.digitaltwin.basyx.core.exceptions.AssetLinkDoesNotExistException; +import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; +import org.eclipse.digitaltwin.basyx.http.serialization.BaSyxHttpTestUtils; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * Test suite to test the AAS Repository Integration with the AAS Discovery Service + * Extend this Class to test your implementation + * + * @author fried + */ +public abstract class AasRepositoryDiscoveryIntegrationTestSuite { + + protected abstract AasDiscoveryService getDiscoveryService(); + + protected abstract String getAASRepositoryURL(); + + @Test + public void createAASWithGlobalAssetId(){ + executeCreateTestWithProperties(true, false); + } + + @Test + public void createAASWithSpecificAssetId(){ + executeCreateTestWithProperties(false, true); + } + + @Test + public void createAASWithGlobalAssetIdAndSpecificAssetId(){ + executeCreateTestWithProperties(true, true); + } + + @Test(expected = AssetLinkDoesNotExistException.class) + public void createAASWithoutGlobalAndSpecificAssetId_expectNoDiscoveryLink(){ + executeCreateTestWithProperties(false, false); + } + + @Test + public void updateAAS_withGlobalAssetId() throws IOException { + try{ + executeCreateTestWithProperties(false, false); + fail(); + }catch(AssetLinkDoesNotExistException e){ + executeUpdateTestWithProperties(true, false); + } + } + + @Test + public void updateAAS_withSpecificAssetId(){ + try{ + executeCreateTestWithProperties(false, false); + fail(); + }catch(AssetLinkDoesNotExistException e){ + executeUpdateTestWithProperties(false, true); + } + } + + @Test(expected = AssetLinkDoesNotExistException.class) + public void updateAAS_withoutGlobalAndSpecificAssetId_expectNoDiscoveryLink(){ + executeCreateTestWithProperties(true, false); + executeUpdateTestWithProperties(false, false); + } + + @Test + public void updateAAS_withGlobalAndSpecificAssetId(){ + try{ + executeCreateTestWithProperties(false, false); + fail(); + }catch(AssetLinkDoesNotExistException e){ + executeUpdateTestWithProperties(true, true); + } + } + + @Test(expected = AssetLinkDoesNotExistException.class) + public void deleteAAS_expectDiscoveryLinkRemoved() throws IOException { + executeCreateTestWithProperties(true, true); + AssetAdministrationShell aas = getDemoAAS(false, false); + BaSyxHttpTestUtils.executeDeleteOnURL(getAASRepositoryURL()+"/"+new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier()); + List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); + } + + private void executeCreateTestWithProperties(boolean globalAssetId, boolean specificAssetId) { + AssetAdministrationShell aas = getDemoAAS(globalAssetId, specificAssetId); + int expectedCount = 0; + expectedCount = globalAssetId ? expectedCount + 1 : expectedCount; + expectedCount = specificAssetId ? expectedCount + 1 : expectedCount; + try { + String aasJSON = new ObjectMapper().writeValueAsString(aas); + CloseableHttpResponse postResponse = BaSyxHttpTestUtils.executePostOnURL(getAASRepositoryURL(),aasJSON); + if(postResponse.getCode()/100 != 2){ + throw new RuntimeException("POST request to AAS Repository failed with status code: " + postResponse.getCode()); + } + postResponse.close(); + List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); + assertEquals(expectedCount,assetIds.size()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void executeUpdateTestWithProperties(boolean globalAssetId, boolean specificAssetId) { + AssetAdministrationShell aas = getDemoAAS(globalAssetId, specificAssetId); + int expectedCount = 0; + expectedCount = globalAssetId ? expectedCount + 1 : expectedCount; + expectedCount = specificAssetId ? expectedCount + 1 : expectedCount; + try { + String aasJSON = new ObjectMapper().writeValueAsString(aas); + CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL(getAASRepositoryURL()+"/"+new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier(),aasJSON); + if(putResponse.getCode()/100 != 2){ + System.out.println(getAASRepositoryURL()+"/"+new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier()); + throw new RuntimeException("PUT request to AAS Repository failed with status code: " + putResponse.getCode()); + } + putResponse.close(); + List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); + assertEquals(expectedCount,assetIds.size()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected AssetAdministrationShell getDemoAAS(boolean hasGlobalAssetId, boolean hasSpecificAssetId){ + DefaultAssetAdministrationShell.Builder builder = new DefaultAssetAdministrationShell.Builder().id("test-aas-id").idShort("taas"); + DefaultAssetInformation.Builder assetInformation = new DefaultAssetInformation.Builder(); + if(hasGlobalAssetId){ + assetInformation.globalAssetId("test-global-asset-id"); + } + if(hasSpecificAssetId){ + assetInformation.specificAssetIds(new DefaultSpecificAssetId.Builder().name("test-specific-asset-id").value("test-specific-asset-id-value").build()); + } + builder.assetInformation(assetInformation.build()); + return builder.build(); + } +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java new file mode 100644 index 000000000..3f69c284b --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +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.DecoratedAasRepositoryFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Configuration +public class DiscoveryIntegrationTestConfiguration { + @Bean + AasRepository getAasRepository(AasRepositoryFactory aasRepositoryFactory, List features) { + return new DecoratedAasRepositoryFactory(aasRepositoryFactory, features).create(); + } +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryIntegrationComponent.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryIntegrationComponent.java new file mode 100644 index 000000000..bbd527372 --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryIntegrationComponent.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * 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.aasrepository.feature.discoveryintegration; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Spring application configured for tests. + * + * @author danish + * + */ + +@SpringBootApplication(scanBasePackages = "org.eclipse.digitaltwin.basyx") +public class DummyAasRepositoryIntegrationComponent { + + public static void main(String[] args) { + SpringApplication.run(DummyAasRepositoryIntegrationComponent.class, args); + } +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application.properties b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application.properties new file mode 100644 index 000000000..002a7ebd5 --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application.properties @@ -0,0 +1,9 @@ +server.port=4753 +server.error.path=/error + +spring.application.name=AAS Repository +basyx.aasrepo.name=aas-repo + +basyx.backend = InMemory + +basyx.aasrepository.feature.discoveryintegration=http://localhost:8049 \ No newline at end of file diff --git a/ci/docker-compose.yml b/ci/docker-compose.yml index cd3868e5b..b37e1ee12 100644 --- a/ci/docker-compose.yml +++ b/ci/docker-compose.yml @@ -84,7 +84,15 @@ services: networks: - basyx-java-server-sdk - + aas-discovery: + image: eclipsebasyx/aas-discovery:$BASYX_VERSION + container_name: aas-discovery + ports: + - "8049:8081" + restart: always + networks: + - basyx-java-server-sdk + aas-registry-log-mem: image: eclipsebasyx/aas-registry-log-mem:$BASYX_VERSION container_name: aas-registry-log-mem From c78b8940fc3e2cb424def4439685fc3f79a80f6f Mon Sep 17 00:00:00 2001 From: fried Date: Fri, 2 May 2025 10:56:30 +0200 Subject: [PATCH 03/10] Adds Test for Authorized AAS Discovery Integration --- ...AasRepositoryDiscoveryIntegrationTest.java | 82 +++++++++++++++++++ .../application-authdiscovery.properties | 14 ++++ ci/docker-compose.yml | 19 +++++ .../rules/rbac_rules-aas-discovery.json | 43 ++++++++++ 4 files changed, 158 insertions(+) create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java create mode 100644 basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application-authdiscovery.properties create mode 100644 ci/keycloak/rules/rbac_rules-aas-discovery.json diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java new file mode 100644 index 000000000..957e1dc90 --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (C) 2025 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.discoveryintegration; + +import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.AuthorizedConnectedAasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.ConnectedAasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; +import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; +import org.eclipse.digitaltwin.basyx.client.internal.ApiException; +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; +import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.GrantType; +import org.junit.*; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.http.HttpStatus; + +import java.io.IOException; +import java.util.List; + +import static org.junit.Assert.assertThrows; + +public class AuthorizedAasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscoveryIntegrationTestSuite{ + private static ConfigurableApplicationContext appContext; + + @BeforeClass + public static void setUp() { + SpringApplication application = new SpringApplication(DummyAasRepositoryIntegrationComponent.class); + application.setAdditionalProfiles("authdiscovery"); + + appContext = application.run(new String[] {}); + } + + @AfterClass + public static void tearDown() { + appContext.close(); + } + + @Before + @After + public void resetRepository() { + AssetAdministrationShell shell = getDemoAAS(false, false); + try { + appContext.getBean(AasRepository.class).deleteAas(shell.getId()); + } catch (Exception e) {} + } + + @Override + protected AasDiscoveryService getDiscoveryService() { + return new ConnectedAasDiscoveryService("http://localhost:8049"); + } + + @Override + protected String getAASRepositoryURL() { + return "http://localhost:4753/shells"; + } +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application-authdiscovery.properties b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application-authdiscovery.properties new file mode 100644 index 000000000..a42e7ceeb --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/resources/application-authdiscovery.properties @@ -0,0 +1,14 @@ +server.port=4753 +server.error.path=/error + +spring.application.name=AAS Repository +basyx.aasrepo.name=aas-repo + +basyx.backend = InMemory + +basyx.aasrepository.feature.discoveryintegration=http://localhost:8049 +basyx.aasrepository.feature.discoveryintegration.authorization.enabled=true +basyx.aasrepository.feature.discoveryintegration.authorization.token-endpoint=http://localhost/realms/BaSyx/protocol/openid-connect/token +basyx.aasrepository.feature.discoveryintegration.authorization.grant-type = CLIENT_CREDENTIALS +basyx.aasrepository.feature.discoveryintegration.authorization.client-id=workstation-1 +basyx.aasrepository.feature.discoveryintegration.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom \ No newline at end of file diff --git a/ci/docker-compose.yml b/ci/docker-compose.yml index b37e1ee12..787be6921 100644 --- a/ci/docker-compose.yml +++ b/ci/docker-compose.yml @@ -93,6 +93,25 @@ services: networks: - basyx-java-server-sdk + aas-discovery-secured: + image: eclipsebasyx/aas-discovery:$BASYX_VERSION + container_name: aas-discovery-secured + environment: + BASYX_CORS_ALLOWED_ORIGINS: '*' + BASYX_CORS_ALLOWED_METHODS: GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD + BASYX_FEATURE_AUTHORIZATION_ENABLED: true + BASYX_FEATURE_AUTHORIZATION_TYPE: rbac + BASYX_FEATURE_AUTHORIZATION_JWTBEARERTOKENPROVIDER: keycloak + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: http://keycloak.basyx.localhost/realms/BaSyx + BASYX_FEATURE_AUTHORIZATION_RBAC_FILE: file:/rbac/rbac_rules.json + ports: + - "8048:8081" + volumes: + - ./keycloak/rules/rbac_rules-aas-discovery.json:/rbac/rbac_rules.json:ro + restart: always + networks: + - basyx-java-server-sdk + aas-registry-log-mem: image: eclipsebasyx/aas-registry-log-mem:$BASYX_VERSION container_name: aas-registry-log-mem diff --git a/ci/keycloak/rules/rbac_rules-aas-discovery.json b/ci/keycloak/rules/rbac_rules-aas-discovery.json new file mode 100644 index 000000000..23eb2d992 --- /dev/null +++ b/ci/keycloak/rules/rbac_rules-aas-discovery.json @@ -0,0 +1,43 @@ +[ + { + "role": "basyx-assetid-creator", + "action": "CREATE", + "targetInformation": { + "@type": "aas-discovery-service", + "aasIds": "*", + "assetIds": [] + } + }, + { + "role": "basyx-assetid-discoverer", + "action": "READ", + "targetInformation": { + "@type": "aas-discovery-service", + "aasIds": "*", + "assetIds": [] + } + }, + { + "role": "basyx-assetid-deleter", + "action": "DELETE", + "targetInformation": { + "@type": "aas-discovery-service", + "aasIds": "*", + "assetIds": [] + } + }, + { + "role": "basyx-aas-discoverer", + "action": "READ", + "targetInformation": { + "@type": "aas-discovery-service", + "aasIds": null, + "assetIds": [ + { + "name": "*", + "value": "*" + } + ] + } + } +] From 6349c584b955799ebc1e8750e9bed0593e4ea81b Mon Sep 17 00:00:00 2001 From: fried Date: Fri, 2 May 2025 13:59:27 +0200 Subject: [PATCH 04/10] Refactoring and adds missing Tests --- .github/workflows/basyx_test.yml | 119 ++++++++++++++---- .../client/ConnectedAasDiscoveryService.java | 4 - .../src/main/resources/application.properties | 23 +++- .../DiscoveryIntegrationAasRepository.java | 76 ++++++----- ...IntegrationAasRepositoryConfiguration.java | 8 +- ...AasRepositoryDiscoveryIntegrationTest.java | 3 +- ...positoryDiscoveryIntegrationTestSuite.java | 44 ++++++- ...AasRepositoryDiscoveryIntegrationTest.java | 3 +- .../src/main/resources/application.properties | 26 +++- 9 files changed, 230 insertions(+), 76 deletions(-) diff --git a/.github/workflows/basyx_test.yml b/.github/workflows/basyx_test.yml index 86e3281cb..e2c107ddb 100644 --- a/.github/workflows/basyx_test.yml +++ b/.github/workflows/basyx_test.yml @@ -35,6 +35,12 @@ jobs: java-version: '17' distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -57,9 +63,6 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} - - name: Test BaSyx Common run: mvn test -f "basyx.common/pom.xml" @@ -87,6 +90,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -108,8 +118,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test AASX FileServer run: mvn test -f "basyx.aasxfileserver/pom.xml" -DskipITs @@ -148,6 +158,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -169,8 +186,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test AAS Environment run: mvn test -f "basyx.aasenvironment/pom.xml" -DskipITs @@ -209,6 +226,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -230,8 +254,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test AAS Repository run: mvn test -f "basyx.aasrepository/pom.xml" -DskipITs @@ -270,6 +294,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -291,8 +322,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test AAS Service run: mvn test -f "basyx.aasservice/pom.xml" @@ -321,6 +352,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -342,8 +380,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test Submodel Repository run: mvn test -f "basyx.submodelrepository/pom.xml" -DskipITs @@ -382,6 +420,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -403,8 +448,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test Submodel Service run: mvn test -f "basyx.submodelservice/pom.xml" @@ -433,6 +478,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -454,8 +506,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test Concept Description Repository run: mvn test -f "basyx.conceptdescriptionrepository/pom.xml" -DskipITs @@ -494,6 +546,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -515,8 +574,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test Submodel Registry run: mvn test -f "basyx.submodelregistry/pom.xml" -DskipITs @@ -555,6 +614,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -576,8 +642,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test AAS Registry run: mvn test -f "basyx.aasregistry/pom.xml" -DskipITs @@ -616,6 +682,13 @@ jobs: distribution: 'adopt' cache: maven + + - name: Build BaSyx + run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + + - name: Build Discovery Service + run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.aasdiscoveryservice.component" + - name: Build Submodel Repository run: mvn package -DskipTests -Ddocker.namespace=eclipsebasyx --pl "org.eclipse.digitaltwin.basyx:basyx.submodelrepository.component" @@ -637,8 +710,8 @@ jobs: - name: Start environment run: docker compose --project-directory ./ci up -d --wait - - name: Build BaSyx - run: mvn clean install ${MVN_ARGS_BUILD_BASYX} + - name: Test BaSyx Common + run: mvn test -f "basyx.common/pom.xml" - name: Test AAS Discovery Service run: mvn test -f "basyx.aasdiscoveryservice/pom.xml" -DskipITs diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java index 312d5d7ac..ef8d1e39b 100644 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java +++ b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java @@ -51,10 +51,6 @@ public ConnectedAasDiscoveryService(String baseURL){ this.discoveryApi = new AssetAdministrationShellDiscoveryApi(baseURL); } - public ConnectedAasDiscoveryService(String baseURL, TokenManager tokenManager){ - this.discoveryApi = new AssetAdministrationShellDiscoveryApi(baseURL, tokenManager); - } - @Override public CursorResult> getAllAssetAdministrationShellIdsByAssetLink(PaginationInfo pInfo, List assetIds) { try{ diff --git a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties index bada859f2..254b3729f 100644 --- a/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties +++ b/basyx.aasenvironment/basyx.aasenvironment.component/src/main/resources/application.properties @@ -73,4 +73,25 @@ basyx.backend = InMemory #################################################################################### # To define the total request size for a multipart/form-data (default 10 MB) -# spring.servlet.multipart.max-request-size=128KB \ No newline at end of file +# spring.servlet.multipart.max-request-size=128KB + +#################################################################################### +# Feature: Registry Integration +#################################################################################### +#basyx.aasrepository.feature.registryintegration=http://localhost:8050 +#basyx.externalurl=http://localhost:8081 +#basyx.aasrepository.feature.registryintegration.authorization.enabled=true +#basyx.aasrepository.feature.registryintegration.authorization.token-endpoint=http://localhost/realms/BaSyx/protocol/openid-connect/token +#basyx.aasrepository.feature.registryintegration.authorization.grant-type = CLIENT_CREDENTIALS +#basyx.aasrepository.feature.registryintegration.authorization.client-id=workstation-1 +#basyx.aasrepository.feature.registryintegration.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom + +#################################################################################### +# Feature: Discovery Integration +#################################################################################### +#basyx.aasrepository.feature.discoveryintegration=http://localhost:8084 +#basyx.aasrepository.feature.discoveryintegration.authorization.enabled=true +#basyx.aasrepository.feature.discoveryintegration.authorization.token-endpoint=http://localhost/realms/BaSyx/protocol/openid-connect/token +#basyx.aasrepository.feature.discoveryintegration.authorization.grant-type = CLIENT_CREDENTIALS +#basyx.aasrepository.feature.discoveryintegration.authorization.client-id=workstation-1 +#basyx.aasrepository.feature.discoveryintegration.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom \ No newline at end of file diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java index 9b723e58c..675454294 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepository.java @@ -28,6 +28,7 @@ import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; import org.eclipse.digitaltwin.aas4j.v3.model.Reference; import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId; +import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSpecificAssetId; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; @@ -80,44 +81,12 @@ public void createAas(AssetAdministrationShell shell) throws CollidingIdentifier createAssetLinksOnDiscoveryServiceIfNecessary(shell); } - private void createAssetLinksOnDiscoveryServiceIfNecessary(AssetAdministrationShell shell) { - List linksToAdd = new ArrayList<>(shell.getAssetInformation().getSpecificAssetIds()); - if(shell.getAssetInformation().getGlobalAssetId() != null){ - linksToAdd.add(getGlobalAssetIdAsSpecificAssetId(shell)); - } - if(!linksToAdd.isEmpty()){ - try { - discoveryApi.createAllAssetLinksById(shell.getId(), linksToAdd); - } catch (Exception e) { - decorated.deleteAas(shell.getId()); - throw new RepositoryDiscoveryLinkException(shell.getId(), e); - } - } - } - @Override public void updateAas(String shellId, AssetAdministrationShell shell) { - AssetAdministrationShell oldShell = getAas(shellId); - if(!isGlobalAssetIdUpdated(shell, oldShell) && !specificAssetIdsUpdated(shell, oldShell)){ - logger.info("No changes in asset links, skipping update on discovery service"); - } else { - try { - discoveryApi.deleteAllAssetLinksById(shellId); - } catch (Exception ignored){ - } - createAssetLinksOnDiscoveryServiceIfNecessary(shell); - } + updateAssetLinks(shellId, shell); decorated.updateAas(shellId, shell); } - private static boolean specificAssetIdsUpdated(AssetAdministrationShell shell, AssetAdministrationShell oldShell) { - return !(oldShell.getAssetInformation().getSpecificAssetIds() != null && oldShell.getAssetInformation().getSpecificAssetIds().equals(shell.getAssetInformation().getSpecificAssetIds())); - } - - private static boolean isGlobalAssetIdUpdated(AssetAdministrationShell shell, AssetAdministrationShell oldShell) { - return !(oldShell.getAssetInformation().getGlobalAssetId() != null && oldShell.getAssetInformation().getGlobalAssetId().equals(shell.getAssetInformation().getGlobalAssetId())); - } - @Override public void deleteAas(String shellId) { decorated.deleteAas(shellId); @@ -151,6 +120,7 @@ public void removeSubmodelReference(String shellId, String submodelId) { @Override public void setAssetInformation(String shellId, AssetInformation shellInfo) throws ElementDoesNotExistException { + updateAssetLinks(shellId, wrapAssetInformationInShell(shellId, shellInfo)); decorated.setAssetInformation(shellId, shellInfo); } @@ -174,8 +144,48 @@ public void deleteThumbnail(String aasId) { decorated.deleteThumbnail(aasId); } + private static DefaultAssetAdministrationShell wrapAssetInformationInShell(String shellId, AssetInformation shellInfo) { + return new DefaultAssetAdministrationShell.Builder().assetInformation(shellInfo).id(shellId).build(); + } + + private void updateAssetLinks(String shellId, AssetAdministrationShell shell) { + AssetAdministrationShell oldShell = getAas(shellId); + if(!isGlobalAssetIdUpdated(shell, oldShell) && !specificAssetIdsUpdated(shell, oldShell)){ + logger.info("No changes in asset links, skipping update on discovery service"); + } else { + try { + discoveryApi.deleteAllAssetLinksById(shellId); + } catch (Exception ignored){ + } + createAssetLinksOnDiscoveryServiceIfNecessary(shell); + } + } + private static DefaultSpecificAssetId getGlobalAssetIdAsSpecificAssetId(AssetAdministrationShell shell) { return new DefaultSpecificAssetId.Builder().name("globalAssetId").value(shell.getAssetInformation().getGlobalAssetId()).build(); } + private void createAssetLinksOnDiscoveryServiceIfNecessary(AssetAdministrationShell shell) { + List linksToAdd = new ArrayList<>(shell.getAssetInformation().getSpecificAssetIds()); + if(shell.getAssetInformation().getGlobalAssetId() != null){ + linksToAdd.add(getGlobalAssetIdAsSpecificAssetId(shell)); + } + if(!linksToAdd.isEmpty()){ + try { + discoveryApi.createAllAssetLinksById(shell.getId(), linksToAdd); + } catch (Exception e) { + decorated.deleteAas(shell.getId()); + throw new RepositoryDiscoveryLinkException(shell.getId(), e); + } + } + } + + private static boolean specificAssetIdsUpdated(AssetAdministrationShell shell, AssetAdministrationShell oldShell) { + return !(oldShell.getAssetInformation().getSpecificAssetIds() != null && oldShell.getAssetInformation().getSpecificAssetIds().equals(shell.getAssetInformation().getSpecificAssetIds())); + } + + private static boolean isGlobalAssetIdUpdated(AssetAdministrationShell shell, AssetAdministrationShell oldShell) { + return !(oldShell.getAssetInformation().getGlobalAssetId() != null && oldShell.getAssetInformation().getGlobalAssetId().equals(shell.getAssetInformation().getGlobalAssetId())); + } + } diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java index 1ea834583..06a014693 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationAasRepositoryConfiguration.java @@ -25,6 +25,7 @@ package org.eclipse.digitaltwin.basyx.aasrepository.feature.discoveryintegration; +import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.AuthorizedConnectedAasDiscoveryService; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.ConnectedAasDiscoveryService; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; @@ -38,7 +39,6 @@ import org.springframework.context.annotation.Configuration; import java.util.Collection; -import java.util.List; /** * Configuration for integrating {@link AasRepository} with Discovery @@ -53,7 +53,7 @@ public class DiscoveryIntegrationAasRepositoryConfiguration { private String discoveryBasePath; @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.enabled:false}") - private boolean isAuthorizationEnabledOnRegistry; + private boolean isAuthorizationEnabledOnDiscovery; @Value("${basyx.aasrepository.feature.discoveryintegration.authorization.token-endpoint:#{null}}") private String authenticationServerTokenEndpoint; @@ -78,12 +78,12 @@ public class DiscoveryIntegrationAasRepositoryConfiguration { @Bean public AasDiscoveryService getConnectedAasDiscoveryService() { - if (!isAuthorizationEnabledOnRegistry) + if (!isAuthorizationEnabledOnDiscovery) return new ConnectedAasDiscoveryService(discoveryBasePath); TokenManager tokenManager = new TokenManager(authenticationServerTokenEndpoint, createAccessTokenProvider()); - return new ConnectedAasDiscoveryService(discoveryBasePath, tokenManager); + return new AuthorizedConnectedAasDiscoveryService(discoveryBasePath, tokenManager); } private AccessTokenProvider createAccessTokenProvider() { diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java index 82aceb05a..a7eae675a 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java @@ -36,7 +36,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; -public class AasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscoveryIntegrationTestSuite{ +public class AasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscoveryIntegrationTestSuite { private static ConfigurableApplicationContext appContext; @BeforeClass @@ -49,7 +49,6 @@ public static void tearDown() { appContext.close(); } - @Before @After public void resetRepository() { AssetAdministrationShell shell = getDemoAAS(false, false); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java index 0e6dd47f8..27a78831e 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java @@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; +import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetInformation; @@ -112,12 +113,48 @@ public void updateAAS_withGlobalAndSpecificAssetId(){ } } + @Test + public void updateAAS() throws IOException { + AssetAdministrationShell aas = getDemoAAS(true, true); + String aasJSON = new ObjectMapper().writeValueAsString(aas); + CloseableHttpResponse postResponse = BaSyxHttpTestUtils.executePostOnURL(getAASRepositoryURL(),aasJSON); + if(postResponse.getCode()/100 != 2){ + throw new RuntimeException("POST request to AAS Repository failed with status code: " + postResponse.getCode()); + } + postResponse.close(); + + addAssetIdToAAS(aas); + + String newAasJSON = new ObjectMapper().writeValueAsString(aas); + CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL(getAASRepositoryURL() + "/" + new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier(),newAasJSON); + if(putResponse.getCode()/100 != 2){ + throw new RuntimeException("PUT request to AAS Repository failed with status code: " + putResponse.getCode()); + } + + List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); + assertEquals(3,assetIds.size()); + assertEquals("test-specific-asset-id",assetIds.get(0).getName()); + assertEquals("test-specific-asset-id-value",assetIds.get(0).getValue()); + assertEquals("test-specific-asset-id-2",assetIds.get(1).getName()); + assertEquals("test-specific-asset-id-value-2",assetIds.get(1).getValue()); + + putResponse.close(); + } + @Test(expected = AssetLinkDoesNotExistException.class) public void deleteAAS_expectDiscoveryLinkRemoved() throws IOException { executeCreateTestWithProperties(true, true); AssetAdministrationShell aas = getDemoAAS(false, false); - BaSyxHttpTestUtils.executeDeleteOnURL(getAASRepositoryURL()+"/"+new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier()); - List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); + BaSyxHttpTestUtils.executeDeleteOnURL(getAASRepositoryURL() + "/" + new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier()); + getDiscoveryService().getAllAssetLinksById(aas.getId()); + } + + private static void addAssetIdToAAS(AssetAdministrationShell aas) { + AssetInformation aasAssetInformation = aas.getAssetInformation(); + List assetIds = aasAssetInformation.getSpecificAssetIds(); + assetIds.add(new DefaultSpecificAssetId.Builder().name("test-specific-asset-id-2").value("test-specific-asset-id-value-2").build()); + aasAssetInformation.setSpecificAssetIds(assetIds); + aas.setAssetInformation(aasAssetInformation); } private void executeCreateTestWithProperties(boolean globalAssetId, boolean specificAssetId) { @@ -146,9 +183,8 @@ private void executeUpdateTestWithProperties(boolean globalAssetId, boolean spec expectedCount = specificAssetId ? expectedCount + 1 : expectedCount; try { String aasJSON = new ObjectMapper().writeValueAsString(aas); - CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL(getAASRepositoryURL()+"/"+new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier(),aasJSON); + CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL(getAASRepositoryURL() + "/" + new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier(),aasJSON); if(putResponse.getCode()/100 != 2){ - System.out.println(getAASRepositoryURL()+"/"+new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier()); throw new RuntimeException("PUT request to AAS Repository failed with status code: " + putResponse.getCode()); } putResponse.close(); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java index 957e1dc90..2af9b0c5e 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java @@ -45,7 +45,7 @@ import static org.junit.Assert.assertThrows; -public class AuthorizedAasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscoveryIntegrationTestSuite{ +public class AuthorizedAasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscoveryIntegrationTestSuite { private static ConfigurableApplicationContext appContext; @BeforeClass @@ -61,7 +61,6 @@ public static void tearDown() { appContext.close(); } - @Before @After public void resetRepository() { AssetAdministrationShell shell = getDemoAAS(false, false); diff --git a/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties b/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties index 6fb440a75..d9650a5eb 100644 --- a/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties +++ b/basyx.aasrepository/basyx.aasrepository.component/src/main/resources/application.properties @@ -6,8 +6,7 @@ basyx.aasrepo.name=aas-repo basyx.backend = InMemory -# basyx.aasrepository.feature.registryintegration=http://localhost:8050 -# basyx.externalurl=http://localhost:8081 + #basyx.backend = MongoDB #spring.data.mongodb.host=127.0.0.1 @@ -40,4 +39,25 @@ basyx.backend = InMemory #basyx.feature.authorization.rules.backend.submodel.authorization.token-endpoint=http://localhost:9097/realms/BaSyx/protocol/openid-connect/token #basyx.feature.authorization.rules.backend.submodel.authorization.grant-type = CLIENT_CREDENTIALS #basyx.feature.authorization.rules.backend.submodel.authorization.client-id=workstation-1 -#basyx.feature.authorization.rules.backend.submodel.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom \ No newline at end of file +#basyx.feature.authorization.rules.backend.submodel.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom + +#################################################################################### +# Feature: Registry Integration +#################################################################################### +#basyx.aasrepository.feature.registryintegration=http://localhost:8050 +#basyx.externalurl=http://localhost:8081 +#basyx.aasrepository.feature.registryintegration.authorization.enabled=true +#basyx.aasrepository.feature.registryintegration.authorization.token-endpoint=http://localhost/realms/BaSyx/protocol/openid-connect/token +#basyx.aasrepository.feature.registryintegration.authorization.grant-type = CLIENT_CREDENTIALS +#basyx.aasrepository.feature.registryintegration.authorization.client-id=workstation-1 +#basyx.aasrepository.feature.registryintegration.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom + +#################################################################################### +# Feature: Discovery Integration +#################################################################################### +#basyx.aasrepository.feature.discoveryintegration=http://localhost:8084 +#basyx.aasrepository.feature.discoveryintegration.authorization.enabled=true +#basyx.aasrepository.feature.discoveryintegration.authorization.token-endpoint=http://localhost/realms/BaSyx/protocol/openid-connect/token +#basyx.aasrepository.feature.discoveryintegration.authorization.grant-type = CLIENT_CREDENTIALS +#basyx.aasrepository.feature.discoveryintegration.authorization.client-id=workstation-1 +#basyx.aasrepository.feature.discoveryintegration.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom \ No newline at end of file From 6c58e71338352ec5df8e7f85944958719f4f02e4 Mon Sep 17 00:00:00 2001 From: fried Date: Mon, 5 May 2025 08:27:57 +0200 Subject: [PATCH 05/10] Refactoring and adds missing Tests --- .../client/ConnectedAasDiscoveryService.java | 4 + ...positoryDiscoveryIntegrationTestSuite.java | 182 +++++++++++------- 2 files changed, 116 insertions(+), 70 deletions(-) diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java index ef8d1e39b..312d5d7ac 100644 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java +++ b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-client/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/client/ConnectedAasDiscoveryService.java @@ -51,6 +51,10 @@ public ConnectedAasDiscoveryService(String baseURL){ this.discoveryApi = new AssetAdministrationShellDiscoveryApi(baseURL); } + public ConnectedAasDiscoveryService(String baseURL, TokenManager tokenManager){ + this.discoveryApi = new AssetAdministrationShellDiscoveryApi(baseURL, tokenManager); + } + @Override public CursorResult> getAllAssetAdministrationShellIdsByAssetLink(PaginationInfo pInfo, List assetIds) { try{ diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java index 27a78831e..7cafb1b6f 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTestSuite.java @@ -27,9 +27,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; -import org.eclipse.digitaltwin.aas4j.v3.model.AssetInformation; -import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId; +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.DefaultSpecificAssetId; @@ -46,69 +44,72 @@ import static org.junit.Assert.fail; /** - * Test suite to test the AAS Repository Integration with the AAS Discovery Service - * Extend this Class to test your implementation + * Test suite to test the AAS Repository Integration with the AAS Discovery Service. + * Extend this Class to test your implementation. * * @author fried */ public abstract class AasRepositoryDiscoveryIntegrationTestSuite { protected abstract AasDiscoveryService getDiscoveryService(); - protected abstract String getAASRepositoryURL(); + // -------------------- CREATE TESTS -------------------- + @Test - public void createAASWithGlobalAssetId(){ + public void createAASWithGlobalAssetId() { executeCreateTestWithProperties(true, false); } @Test - public void createAASWithSpecificAssetId(){ + public void createAASWithSpecificAssetId() { executeCreateTestWithProperties(false, true); } @Test - public void createAASWithGlobalAssetIdAndSpecificAssetId(){ + public void createAASWithGlobalAssetIdAndSpecificAssetId() { executeCreateTestWithProperties(true, true); } @Test(expected = AssetLinkDoesNotExistException.class) - public void createAASWithoutGlobalAndSpecificAssetId_expectNoDiscoveryLink(){ + public void createAASWithoutGlobalAndSpecificAssetId_expectNoDiscoveryLink() { executeCreateTestWithProperties(false, false); } + // -------------------- UPDATE TESTS -------------------- + @Test public void updateAAS_withGlobalAssetId() throws IOException { - try{ + try { executeCreateTestWithProperties(false, false); fail(); - }catch(AssetLinkDoesNotExistException e){ + } catch (AssetLinkDoesNotExistException e) { executeUpdateTestWithProperties(true, false); } } @Test - public void updateAAS_withSpecificAssetId(){ - try{ + public void updateAAS_withSpecificAssetId() { + try { executeCreateTestWithProperties(false, false); fail(); - }catch(AssetLinkDoesNotExistException e){ + } catch (AssetLinkDoesNotExistException e) { executeUpdateTestWithProperties(false, true); } } @Test(expected = AssetLinkDoesNotExistException.class) - public void updateAAS_withoutGlobalAndSpecificAssetId_expectNoDiscoveryLink(){ + public void updateAAS_withoutGlobalAndSpecificAssetId_expectNoDiscoveryLink() { executeCreateTestWithProperties(true, false); executeUpdateTestWithProperties(false, false); } @Test - public void updateAAS_withGlobalAndSpecificAssetId(){ - try{ + public void updateAAS_withGlobalAndSpecificAssetId() { + try { executeCreateTestWithProperties(false, false); fail(); - }catch(AssetLinkDoesNotExistException e){ + } catch (AssetLinkDoesNotExistException e) { executeUpdateTestWithProperties(true, true); } } @@ -116,61 +117,57 @@ public void updateAAS_withGlobalAndSpecificAssetId(){ @Test public void updateAAS() throws IOException { AssetAdministrationShell aas = getDemoAAS(true, true); - String aasJSON = new ObjectMapper().writeValueAsString(aas); - CloseableHttpResponse postResponse = BaSyxHttpTestUtils.executePostOnURL(getAASRepositoryURL(),aasJSON); - if(postResponse.getCode()/100 != 2){ - throw new RuntimeException("POST request to AAS Repository failed with status code: " + postResponse.getCode()); - } - postResponse.close(); + postAAS(aas); addAssetIdToAAS(aas); + updateAAS(aas); - String newAasJSON = new ObjectMapper().writeValueAsString(aas); - CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL(getAASRepositoryURL() + "/" + new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier(),newAasJSON); - if(putResponse.getCode()/100 != 2){ - throw new RuntimeException("PUT request to AAS Repository failed with status code: " + putResponse.getCode()); - } + assertNewAssetLinksAreSet(aas); + } - List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); - assertEquals(3,assetIds.size()); - assertEquals("test-specific-asset-id",assetIds.get(0).getName()); - assertEquals("test-specific-asset-id-value",assetIds.get(0).getValue()); - assertEquals("test-specific-asset-id-2",assetIds.get(1).getName()); - assertEquals("test-specific-asset-id-value-2",assetIds.get(1).getValue()); + @Test + public void updateAAS_AssetInformation() throws IOException { + AssetAdministrationShell aas = getDemoAAS(true, true); + postAAS(aas); + + addAssetIdToAAS(aas); + AssetInformation newInfo = aas.getAssetInformation(); + String assetInfoJSON = new ObjectMapper().writeValueAsString(newInfo); + CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL(getAASAssetInformationURL(aas), assetInfoJSON); + throwErrorIfRequestWasUnsuccessful(putResponse, "PUT request to AAS Repository failed with status code: "); putResponse.close(); + + assertNewAssetLinksAreSet(aas); } + // -------------------- DELETE TEST -------------------- + @Test(expected = AssetLinkDoesNotExistException.class) public void deleteAAS_expectDiscoveryLinkRemoved() throws IOException { executeCreateTestWithProperties(true, true); AssetAdministrationShell aas = getDemoAAS(false, false); - BaSyxHttpTestUtils.executeDeleteOnURL(getAASRepositoryURL() + "/" + new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier()); + BaSyxHttpTestUtils.executeDeleteOnURL(getAASURL(aas)); getDiscoveryService().getAllAssetLinksById(aas.getId()); } - private static void addAssetIdToAAS(AssetAdministrationShell aas) { - AssetInformation aasAssetInformation = aas.getAssetInformation(); - List assetIds = aasAssetInformation.getSpecificAssetIds(); - assetIds.add(new DefaultSpecificAssetId.Builder().name("test-specific-asset-id-2").value("test-specific-asset-id-value-2").build()); - aasAssetInformation.setSpecificAssetIds(assetIds); - aas.setAssetInformation(aasAssetInformation); + // -------------------- HELPER METHODS -------------------- + + private String getAASURL(AssetAdministrationShell aas) { + return getAASRepositoryURL() + "/" + encode(aas.getId()); + } + + private String getAASAssetInformationURL(AssetAdministrationShell aas) { + return getAASRepositoryURL() + "/" + encode(aas.getId()) + "/asset-information"; } private void executeCreateTestWithProperties(boolean globalAssetId, boolean specificAssetId) { AssetAdministrationShell aas = getDemoAAS(globalAssetId, specificAssetId); - int expectedCount = 0; - expectedCount = globalAssetId ? expectedCount + 1 : expectedCount; - expectedCount = specificAssetId ? expectedCount + 1 : expectedCount; + int expectedCount = (globalAssetId ? 1 : 0) + (specificAssetId ? 1 : 0); try { - String aasJSON = new ObjectMapper().writeValueAsString(aas); - CloseableHttpResponse postResponse = BaSyxHttpTestUtils.executePostOnURL(getAASRepositoryURL(),aasJSON); - if(postResponse.getCode()/100 != 2){ - throw new RuntimeException("POST request to AAS Repository failed with status code: " + postResponse.getCode()); - } - postResponse.close(); + postAAS(aas); List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); - assertEquals(expectedCount,assetIds.size()); + assertEquals(expectedCount, assetIds.size()); } catch (IOException e) { throw new RuntimeException(e); } @@ -178,33 +175,78 @@ private void executeCreateTestWithProperties(boolean globalAssetId, boolean spec private void executeUpdateTestWithProperties(boolean globalAssetId, boolean specificAssetId) { AssetAdministrationShell aas = getDemoAAS(globalAssetId, specificAssetId); - int expectedCount = 0; - expectedCount = globalAssetId ? expectedCount + 1 : expectedCount; - expectedCount = specificAssetId ? expectedCount + 1 : expectedCount; + int expectedCount = (globalAssetId ? 1 : 0) + (specificAssetId ? 1 : 0); try { String aasJSON = new ObjectMapper().writeValueAsString(aas); - CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL(getAASRepositoryURL() + "/" + new Base64UrlEncodedIdentifier(aas.getId()).getEncodedIdentifier(),aasJSON); - if(putResponse.getCode()/100 != 2){ - throw new RuntimeException("PUT request to AAS Repository failed with status code: " + putResponse.getCode()); - } + CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL( + getAASURL(aas), aasJSON); + throwErrorIfRequestWasUnsuccessful(putResponse, "PUT request to AAS Repository failed with status code: "); putResponse.close(); List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); - assertEquals(expectedCount,assetIds.size()); + assertEquals(expectedCount, assetIds.size()); } catch (IOException e) { throw new RuntimeException(e); } } - protected AssetAdministrationShell getDemoAAS(boolean hasGlobalAssetId, boolean hasSpecificAssetId){ - DefaultAssetAdministrationShell.Builder builder = new DefaultAssetAdministrationShell.Builder().id("test-aas-id").idShort("taas"); - DefaultAssetInformation.Builder assetInformation = new DefaultAssetInformation.Builder(); - if(hasGlobalAssetId){ - assetInformation.globalAssetId("test-global-asset-id"); + private void postAAS(AssetAdministrationShell aas) throws IOException { + String aasJSON = new ObjectMapper().writeValueAsString(aas); + CloseableHttpResponse postResponse = BaSyxHttpTestUtils.executePostOnURL(getAASRepositoryURL(), aasJSON); + throwErrorIfRequestWasUnsuccessful(postResponse, "POST request to AAS Repository failed with status code: "); + postResponse.close(); + } + + private void updateAAS(AssetAdministrationShell aas) throws IOException { + String newAasJSON = new ObjectMapper().writeValueAsString(aas); + CloseableHttpResponse putResponse = BaSyxHttpTestUtils.executePutOnURL( + getAASURL(aas), newAasJSON); + throwErrorIfRequestWasUnsuccessful(putResponse, "PUT request to AAS Repository failed with status code: "); + putResponse.close(); + } + + private void assertNewAssetLinksAreSet(AssetAdministrationShell aas) { + List assetIds = getDiscoveryService().getAllAssetLinksById(aas.getId()); + assertEquals(3, assetIds.size()); + assertEquals("test-specific-asset-id", assetIds.get(0).getName()); + assertEquals("test-specific-asset-id-value", assetIds.get(0).getValue()); + assertEquals("test-specific-asset-id-2", assetIds.get(1).getName()); + assertEquals("test-specific-asset-id-value-2", assetIds.get(1).getValue()); + } + + private static void addAssetIdToAAS(AssetAdministrationShell aas) { + AssetInformation info = aas.getAssetInformation(); + List assetIds = info.getSpecificAssetIds(); + assetIds.add(new DefaultSpecificAssetId.Builder() + .name("test-specific-asset-id-2") + .value("test-specific-asset-id-value-2") + .build()); + info.setSpecificAssetIds(assetIds); + aas.setAssetInformation(info); + } + + private static void throwErrorIfRequestWasUnsuccessful(CloseableHttpResponse response, String message) { + if (response.getCode() / 100 != 2) { + throw new RuntimeException(message + response.getCode()); } - if(hasSpecificAssetId){ - assetInformation.specificAssetIds(new DefaultSpecificAssetId.Builder().name("test-specific-asset-id").value("test-specific-asset-id-value").build()); + } + + private static String encode(String id) { + return new Base64UrlEncodedIdentifier(id).getEncodedIdentifier(); + } + + protected AssetAdministrationShell getDemoAAS(boolean hasGlobalAssetId, boolean hasSpecificAssetId) { + DefaultAssetInformation.Builder assetInfoBuilder = new DefaultAssetInformation.Builder(); + if (hasGlobalAssetId) assetInfoBuilder.globalAssetId("test-global-asset-id"); + if (hasSpecificAssetId) { + assetInfoBuilder.specificAssetIds(new DefaultSpecificAssetId.Builder() + .name("test-specific-asset-id") + .value("test-specific-asset-id-value") + .build()); } - builder.assetInformation(assetInformation.build()); - return builder.build(); + return new DefaultAssetAdministrationShell.Builder() + .id("test-aas-id") + .idShort("taas") + .assetInformation(assetInfoBuilder.build()) + .build(); } } From 89ebfb6fa79d4941a36973690d6ff11c58760aa9 Mon Sep 17 00:00:00 2001 From: fried Date: Mon, 5 May 2025 09:13:33 +0200 Subject: [PATCH 06/10] Adapts examples and fixes error in parent pom --- .../basyx.aasrepository.component/pom.xml | 10 ++++++++++ examples/BaSyxClient/docker-compose.yml | 1 - examples/BaSyxDynamicRBAC/basyx/aas-env.properties | 10 +++++++++- examples/BaSyxMinimal/aas-env.properties | 1 + examples/BaSyxMinimal/docker-compose-cd-repo.yml | 1 - examples/BaSyxMinimal/docker-compose.yml | 1 - examples/BaSyxNGINX/basyx/aas-env.properties | 1 + examples/BaSyxNGINX/docker-compose.yml | 2 -- examples/BaSyxOperationDelegation/docker-compose.yml | 1 - pom.xml | 11 +++++------ 10 files changed, 26 insertions(+), 13 deletions(-) diff --git a/basyx.aasrepository/basyx.aasrepository.component/pom.xml b/basyx.aasrepository/basyx.aasrepository.component/pom.xml index 6a6b5f10f..822c5b7f6 100644 --- a/basyx.aasrepository/basyx.aasrepository.component/pom.xml +++ b/basyx.aasrepository/basyx.aasrepository.component/pom.xml @@ -79,6 +79,16 @@ tests test + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-feature-discovery-integration + + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-feature-discovery-integration + tests + test + org.eclipse.digitaltwin.basyx basyx.aasrepository-feature-authorization diff --git a/examples/BaSyxClient/docker-compose.yml b/examples/BaSyxClient/docker-compose.yml index 5fcf076c9..2a354a230 100644 --- a/examples/BaSyxClient/docker-compose.yml +++ b/examples/BaSyxClient/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3' services: aas-env: image: eclipsebasyx/aas-environment:2.0.0-milestone-04 diff --git a/examples/BaSyxDynamicRBAC/basyx/aas-env.properties b/examples/BaSyxDynamicRBAC/basyx/aas-env.properties index 86b9654ea..398849c6e 100644 --- a/examples/BaSyxDynamicRBAC/basyx/aas-env.properties +++ b/examples/BaSyxDynamicRBAC/basyx/aas-env.properties @@ -4,6 +4,7 @@ basyx.environment=file:aas basyx.cors.allowed-origins=* basyx.cors.allowed-methods=GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD basyx.aasrepository.feature.registryintegration=http://aas-registry:8080 +basyx.aasrepository.feature.discoveryintegration=http://aas-discovery:8081 basyx.submodelrepository.feature.registryintegration=http://sm-registry:8080 basyx.externalurl=http://localhost:8081 @@ -35,6 +36,13 @@ basyx.aasrepository.feature.registryintegration.authorization.token-endpoint=htt basyx.aasrepository.feature.registryintegration.authorization.grant-type = CLIENT_CREDENTIALS basyx.aasrepository.feature.registryintegration.authorization.client-id = workstation-1 basyx.aasrepository.feature.registryintegration.authorization.client-secret = nY0mjyECF60DGzNmQUjL81XurSl8etom + +basyx.aasrepository.feature.discoveryintegration.authorization.enabled=true +basyx.aasrepository.feature.discoveryintegration.authorization.token-endpoint=http://keycloak-rbac:8080/realms/BaSyx/protocol/openid-connect/token +basyx.aasrepository.feature.discoveryintegration.authorization.grant-type = CLIENT_CREDENTIALS +basyx.aasrepository.feature.discoveryintegration.authorization.client-id = workstation-1 +basyx.aasrepository.feature.discoveryintegration.authorization.client-secret = nY0mjyECF60DGzNmQUjL81XurSl8etom + basyx.submodelrepository.feature.registryintegration.authorization.enabled=true basyx.submodelrepository.feature.registryintegration.authorization.token-endpoint=http://keycloak-rbac:8080/realms/BaSyx/protocol/openid-connect/token basyx.submodelrepository.feature.registryintegration.authorization.grant-type = CLIENT_CREDENTIALS @@ -42,4 +50,4 @@ basyx.submodelrepository.feature.registryintegration.authorization.client-id=wor basyx.submodelrepository.feature.registryintegration.authorization.client-secret=nY0mjyECF60DGzNmQUjL81XurSl8etom #basyx.aasrepository.feature.registryintegration.authorization.username=test #basyx.aasrepository.feature.registryintegration.authorization.password=test -#basyx.aasrepository.feature.registryintegration.authorization.scopes=[] \ No newline at end of file +#basyx.aasrepository.feature.registryintegration.authorization.scopes=[] diff --git a/examples/BaSyxMinimal/aas-env.properties b/examples/BaSyxMinimal/aas-env.properties index 9e1f52f44..403f17018 100644 --- a/examples/BaSyxMinimal/aas-env.properties +++ b/examples/BaSyxMinimal/aas-env.properties @@ -19,5 +19,6 @@ basyx.cors.allowed-origins=* basyx.cors.allowed-methods=GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD basyx.aasrepository.feature.registryintegration = http://aas-registry:8080 +basyx.aasrepository.feature.discoveryintegration = http://aas-discovery:8081 basyx.submodelrepository.feature.registryintegration = http://sm-registry:8080 basyx.externalurl = http://localhost:8081 diff --git a/examples/BaSyxMinimal/docker-compose-cd-repo.yml b/examples/BaSyxMinimal/docker-compose-cd-repo.yml index 93019078d..648e5a211 100644 --- a/examples/BaSyxMinimal/docker-compose-cd-repo.yml +++ b/examples/BaSyxMinimal/docker-compose-cd-repo.yml @@ -1,4 +1,3 @@ -version: "3.9" services: cd-repo: # get the image from dockerhub diff --git a/examples/BaSyxMinimal/docker-compose.yml b/examples/BaSyxMinimal/docker-compose.yml index 1f16d4951..e3f8f7bf4 100644 --- a/examples/BaSyxMinimal/docker-compose.yml +++ b/examples/BaSyxMinimal/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.9" services: mongo: image: mongo:5.0.10 diff --git a/examples/BaSyxNGINX/basyx/aas-env.properties b/examples/BaSyxNGINX/basyx/aas-env.properties index 42a193b98..538cd6f85 100644 --- a/examples/BaSyxNGINX/basyx/aas-env.properties +++ b/examples/BaSyxNGINX/basyx/aas-env.properties @@ -7,6 +7,7 @@ basyx.cors.allowed-origins=* basyx.cors.allowed-methods=GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD basyx.aasrepository.feature.registryintegration = http://aas-registry:8080/aas-registry +basyx.aasrepository.feature.discoveryintegration = http://aas-discovery:8081 basyx.submodelrepository.feature.registryintegration = http://sm-registry:8080/sm-registry # basyx.externalurl with trailing slash basyx.externalurl = http://localhost/aas-env/ diff --git a/examples/BaSyxNGINX/docker-compose.yml b/examples/BaSyxNGINX/docker-compose.yml index 4d79aa591..b20a13eb8 100644 --- a/examples/BaSyxNGINX/docker-compose.yml +++ b/examples/BaSyxNGINX/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3' - services: # nginx nginx: diff --git a/examples/BaSyxOperationDelegation/docker-compose.yml b/examples/BaSyxOperationDelegation/docker-compose.yml index 7c4e33799..8cc9f78de 100644 --- a/examples/BaSyxOperationDelegation/docker-compose.yml +++ b/examples/BaSyxOperationDelegation/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3' services: aas-env: image: eclipsebasyx/aas-environment:2.0.0-milestone-04 diff --git a/pom.xml b/pom.xml index 6046f26e6..4636ec3c6 100644 --- a/pom.xml +++ b/pom.xml @@ -566,12 +566,6 @@ basyx.submodelrepository-feature-registry-integration ${revision} - - org.eclipse.digitaltwin.basyx - - basyx.submodelrepository-feature-discovery-integration - ${revision} - org.eclipse.digitaltwin.basyx basyx.submodelrepository-feature-authorization @@ -660,6 +654,11 @@ basyx.aasrepository-backend-mongodb ${revision} + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-feature-discovery-integration + ${revision} + org.eclipse.digitaltwin.basyx basyx.aasrepository-feature-aasxupload From 3b279b0e6886e296fba4c89e871c79c719b0e3da Mon Sep 17 00:00:00 2001 From: fried Date: Mon, 5 May 2025 09:27:56 +0200 Subject: [PATCH 07/10] Resolves Bean Conflict --- .../AasRepositoryDiscoveryIntegrationTest.java | 3 +-- ...horizedAasRepositoryDiscoveryIntegrationTest.java | 12 +----------- ...yAasRepositoryDiscoveryIntegrationComponent.java} | 4 ++-- 3 files changed, 4 insertions(+), 15 deletions(-) rename basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/{DummyAasRepositoryIntegrationComponent.java => DummyAasRepositoryDiscoveryIntegrationComponent.java} (92%) diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java index a7eae675a..a6f40e4a1 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AasRepositoryDiscoveryIntegrationTest.java @@ -31,7 +31,6 @@ import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; import org.junit.After; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; @@ -41,7 +40,7 @@ public class AasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscover @BeforeClass public static void setUp() { - appContext = SpringApplication.run(DummyAasRepositoryIntegrationComponent.class); + appContext = SpringApplication.run(DummyAasRepositoryDiscoveryIntegrationComponent.class); } @AfterClass diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java index 2af9b0c5e..1ac6c192c 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/AuthorizedAasRepositoryDiscoveryIntegrationTest.java @@ -26,22 +26,12 @@ package org.eclipse.digitaltwin.basyx.aasrepository.feature.discoveryintegration; import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; -import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.AuthorizedConnectedAasDiscoveryService; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.client.ConnectedAasDiscoveryService; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService; import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository; -import org.eclipse.digitaltwin.basyx.client.internal.ApiException; -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; -import org.eclipse.digitaltwin.basyx.client.internal.authorization.grant.GrantType; import org.junit.*; import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.http.HttpStatus; - -import java.io.IOException; -import java.util.List; import static org.junit.Assert.assertThrows; @@ -50,7 +40,7 @@ public class AuthorizedAasRepositoryDiscoveryIntegrationTest extends AasReposito @BeforeClass public static void setUp() { - SpringApplication application = new SpringApplication(DummyAasRepositoryIntegrationComponent.class); + SpringApplication application = new SpringApplication(DummyAasRepositoryDiscoveryIntegrationComponent.class); application.setAdditionalProfiles("authdiscovery"); appContext = application.run(new String[] {}); diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryIntegrationComponent.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryDiscoveryIntegrationComponent.java similarity index 92% rename from basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryIntegrationComponent.java rename to basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryDiscoveryIntegrationComponent.java index bbd527372..c02ffabf5 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryIntegrationComponent.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryDiscoveryIntegrationComponent.java @@ -36,9 +36,9 @@ */ @SpringBootApplication(scanBasePackages = "org.eclipse.digitaltwin.basyx") -public class DummyAasRepositoryIntegrationComponent { +public class DummyAasRepositoryDiscoveryIntegrationComponent { public static void main(String[] args) { - SpringApplication.run(DummyAasRepositoryIntegrationComponent.class, args); + SpringApplication.run(DummyAasRepositoryDiscoveryIntegrationComponent.class, args); } } From 018f38d0f6cc20df6ee411ef159e422f07f1e81d Mon Sep 17 00:00:00 2001 From: fried Date: Mon, 5 May 2025 09:37:05 +0200 Subject: [PATCH 08/10] Resolves Bean Conflict --- .../DiscoveryIntegrationTestConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java index 3f69c284b..be840a603 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java @@ -37,7 +37,7 @@ @Configuration public class DiscoveryIntegrationTestConfiguration { @Bean - AasRepository getAasRepository(AasRepositoryFactory aasRepositoryFactory, List features) { + AasRepository getDiscoveryIntegrationAasRepository(AasRepositoryFactory aasRepositoryFactory, List features) { return new DecoratedAasRepositoryFactory(aasRepositoryFactory, features).create(); } } From 27a3101d7d9b1419297622cd48d7df5661a5410a Mon Sep 17 00:00:00 2001 From: fried Date: Mon, 5 May 2025 10:08:24 +0200 Subject: [PATCH 09/10] Resolves Bean Conflict --- .../DiscoveryIntegrationTestConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java index be840a603..585d60b0d 100644 --- a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DiscoveryIntegrationTestConfiguration.java @@ -31,12 +31,14 @@ import org.eclipse.digitaltwin.basyx.aasrepository.feature.DecoratedAasRepositoryFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import java.util.List; @Configuration public class DiscoveryIntegrationTestConfiguration { @Bean + @Primary AasRepository getDiscoveryIntegrationAasRepository(AasRepositoryFactory aasRepositoryFactory, List features) { return new DecoratedAasRepositoryFactory(aasRepositoryFactory, features).create(); } From 0b99c07a459a3ba18de0385171e947652d17b66e Mon Sep 17 00:00:00 2001 From: fried Date: Mon, 5 May 2025 10:37:00 +0200 Subject: [PATCH 10/10] Adds Discovery Integration to example --- examples/BaSyxSecured/basyx/aas-env.properties | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/BaSyxSecured/basyx/aas-env.properties b/examples/BaSyxSecured/basyx/aas-env.properties index 649b4a47e..d5f80f5bd 100644 --- a/examples/BaSyxSecured/basyx/aas-env.properties +++ b/examples/BaSyxSecured/basyx/aas-env.properties @@ -4,6 +4,7 @@ basyx.environment=file:aas basyx.cors.allowed-origins=* basyx.cors.allowed-methods=GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD basyx.aasrepository.feature.registryintegration=http://aas-registry:8080 +basyx.aasrepository.feature.discoveryintegration=http://aas-discovery:8081 basyx.submodelrepository.feature.registryintegration=http://sm-registry:8080 basyx.externalurl=http://aasenv.basyx.localhost @@ -27,6 +28,13 @@ basyx.aasrepository.feature.registryintegration.authorization.token-endpoint=htt basyx.aasrepository.feature.registryintegration.authorization.grant-type = CLIENT_CREDENTIALS basyx.aasrepository.feature.registryintegration.authorization.client-id = workstation-1 basyx.aasrepository.feature.registryintegration.authorization.client-secret = nY0mjyECF60DGzNmQUjL81XurSl8etom + +basyx.aasrepository.feature.discoveryintegration.authorization.enabled=true +basyx.aasrepository.feature.discoveryintegration.authorization.token-endpoint=http://keycloak.basyx.localhost/realms/BaSyx/protocol/openid-connect/token +basyx.aasrepository.feature.discoveryintegration.authorization.grant-type = CLIENT_CREDENTIALS +basyx.aasrepository.feature.discoveryintegration.authorization.client-id = workstation-1 +basyx.aasrepository.feature.discoveryintegration.authorization.client-secret = nY0mjyECF60DGzNmQUjL81XurSl8etom + basyx.submodelrepository.feature.registryintegration.authorization.enabled=true basyx.submodelrepository.feature.registryintegration.authorization.token-endpoint=http://keycloak.basyx.localhost/realms/BaSyx/protocol/openid-connect/token basyx.submodelrepository.feature.registryintegration.authorization.grant-type = CLIENT_CREDENTIALS