diff --git a/.github/workflows/basyx_test.yml b/.github/workflows/basyx_test.yml index 787113194..792b1bc54 100644 --- a/.github/workflows/basyx_test.yml +++ b/.github/workflows/basyx_test.yml @@ -39,6 +39,9 @@ jobs: - 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" @@ -91,6 +94,9 @@ jobs: - 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" @@ -156,6 +162,9 @@ jobs: - 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" @@ -221,6 +230,9 @@ jobs: - 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" @@ -285,7 +297,10 @@ jobs: - 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" @@ -340,7 +355,10 @@ jobs: - 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" @@ -405,7 +423,10 @@ jobs: - 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" @@ -460,7 +481,10 @@ jobs: - 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" @@ -525,7 +549,10 @@ jobs: - 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" @@ -591,6 +618,9 @@ jobs: - 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" @@ -656,6 +686,9 @@ jobs: - 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" 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.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/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..675454294 --- /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,191 @@ +/******************************************************************************* + * 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.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; +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); + } + + @Override + public void updateAas(String shellId, AssetAdministrationShell shell) { + updateAssetLinks(shellId, 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 { + updateAssetLinks(shellId, wrapAssetInformationInShell(shellId, shellInfo)); + 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 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 new file mode 100644 index 000000000..06a014693 --- /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,98 @@ +/******************************************************************************* + * 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.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.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; + +/** + * 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.aasrepository.feature.discoveryintegration.authorization.enabled:false}") + private boolean isAuthorizationEnabledOnDiscovery; + + @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 (!isAuthorizationEnabledOnDiscovery) + return new ConnectedAasDiscoveryService(discoveryBasePath); + + TokenManager tokenManager = new TokenManager(authenticationServerTokenEndpoint, createAccessTokenProvider()); + + return new AuthorizedConnectedAasDiscoveryService(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/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..a6f40e4a1 --- /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,68 @@ +/******************************************************************************* + * 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.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(DummyAasRepositoryDiscoveryIntegrationComponent.class); + } + + @AfterClass + public static void tearDown() { + appContext.close(); + } + + @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..7cafb1b6f --- /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,252 @@ +/******************************************************************************* + * 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.*; +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(); + + // -------------------- CREATE TESTS -------------------- + + @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); + } + + // -------------------- UPDATE TESTS -------------------- + + @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 + public void updateAAS() throws IOException { + AssetAdministrationShell aas = getDemoAAS(true, true); + postAAS(aas); + + addAssetIdToAAS(aas); + updateAAS(aas); + + assertNewAssetLinksAreSet(aas); + } + + @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(getAASURL(aas)); + getDiscoveryService().getAllAssetLinksById(aas.getId()); + } + + // -------------------- 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 = (globalAssetId ? 1 : 0) + (specificAssetId ? 1 : 0); + try { + postAAS(aas); + 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 = (globalAssetId ? 1 : 0) + (specificAssetId ? 1 : 0); + try { + String aasJSON = new ObjectMapper().writeValueAsString(aas); + 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()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + 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()); + } + } + + 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()); + } + return new DefaultAssetAdministrationShell.Builder() + .id("test-aas-id") + .idShort("taas") + .assetInformation(assetInfoBuilder.build()) + .build(); + } +} 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..1ac6c192c --- /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,71 @@ +/******************************************************************************* + * 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.*; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; + +import static org.junit.Assert.assertThrows; + +public class AuthorizedAasRepositoryDiscoveryIntegrationTest extends AasRepositoryDiscoveryIntegrationTestSuite { + private static ConfigurableApplicationContext appContext; + + @BeforeClass + public static void setUp() { + SpringApplication application = new SpringApplication(DummyAasRepositoryDiscoveryIntegrationComponent.class); + application.setAdditionalProfiles("authdiscovery"); + + appContext = application.run(new String[] {}); + } + + @AfterClass + public static void tearDown() { + appContext.close(); + } + + @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/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..585d60b0d --- /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,45 @@ +/******************************************************************************* + * 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 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(); + } +} diff --git a/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryDiscoveryIntegrationComponent.java b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryDiscoveryIntegrationComponent.java new file mode 100644 index 000000000..c02ffabf5 --- /dev/null +++ b/basyx.aasrepository/basyx.aasrepository-feature-discovery-integration/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/feature/discoveryintegration/DummyAasRepositoryDiscoveryIntegrationComponent.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 DummyAasRepositoryDiscoveryIntegrationComponent { + + public static void main(String[] args) { + SpringApplication.run(DummyAasRepositoryDiscoveryIntegrationComponent.class, args); + } +} 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/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/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/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 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/ci/docker-compose.yml b/ci/docker-compose.yml index cd3868e5b..787be6921 100644 --- a/ci/docker-compose.yml +++ b/ci/docker-compose.yml @@ -84,7 +84,34 @@ 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-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": "*" + } + ] + } + } +] 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/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 diff --git a/pom.xml b/pom.xml index 66896683b..913e63e8d 100644 --- a/pom.xml +++ b/pom.xml @@ -654,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 @@ -1101,6 +1106,12 @@ ${revision} tests + + org.eclipse.digitaltwin.basyx + basyx.aasrepository-feature-discovery-integration + ${revision} + tests + org.eclipse.digitaltwin.basyx basyx.aasrepository-feature-authorization