diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/pom.xml b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/pom.xml index 7d7849257..62201b56d 100644 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/pom.xml +++ b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/pom.xml @@ -19,8 +19,11 @@ org.eclipse.digitaltwin.basyx basyx.aasdiscoveryservice-backend - - + + + org.eclipse.digitaltwin.basyx + basyx.backend.inmemory.core + org.eclipse.digitaltwin.basyx basyx.aasdiscoveryservice-core diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryBackendProvider.java b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryBackendProvider.java index 46971ba9c..21720e822 100644 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryBackendProvider.java +++ b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryBackendProvider.java @@ -27,6 +27,7 @@ import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.backend.AasDiscoveryBackendProvider; import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.backend.AasDiscoveryDocument; +import org.eclipse.digitaltwin.basyx.common.backend.inmemory.core.InMemoryCrudRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; @@ -41,7 +42,7 @@ @Component public class AasDiscoveryInMemoryBackendProvider implements AasDiscoveryBackendProvider { - private AasDiscoveryInMemoryCrudRepository repository = new AasDiscoveryInMemoryCrudRepository(); + private CrudRepository repository = new InMemoryCrudRepository(AasDiscoveryDocument::getShellIdentifier); @Override public CrudRepository getCrudRepository() { diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryCrudRepository.java b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryCrudRepository.java deleted file mode 100644 index 7fdf732c7..000000000 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/backend/inmemory/AasDiscoveryInMemoryCrudRepository.java +++ /dev/null @@ -1,138 +0,0 @@ -/******************************************************************************* - * 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.aasdiscoveryservice.backend.inmemory; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.stream.StreamSupport; - -import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId; -import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.backend.AasDiscoveryDocument; -import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.model.AssetLink; -import org.springframework.data.repository.CrudRepository; -import org.springframework.lang.NonNull; - -/** - * In-memory implementation of the {@link CrudRepository} for the AAS Discovery - * - * @author zielstor, fried, mateusmolina - */ -public class AasDiscoveryInMemoryCrudRepository implements CrudRepository { - - private final ConcurrentMap> assetLinks = new ConcurrentHashMap<>(); - private final ConcurrentMap> assetIds = new ConcurrentHashMap<>(); - - @Override - public synchronized @NonNull S save(@NonNull S entity) { - String shellId = entity.getShellIdentifier(); - - this.assetLinks.put(shellId, entity.getAssetLinks()); - this.assetIds.put(shellId, entity.getSpecificAssetIds()); - - return entity; - } - - @Override - public @NonNull Iterable saveAll(@NonNull Iterable entities) { - entities.forEach(this::save); - return entities; - } - - @Override - public @NonNull Optional findById(@NonNull String id) { - return Optional.ofNullable(buildAasDiscoveryDocument(id)); - } - - @Override - public boolean existsById(@NonNull String id) { - return this.assetLinks.containsKey(id); - } - - @Override - public @NonNull Iterable findAll() { - return assetLinks.keySet().stream().map(this::buildAasDiscoveryDocument).toList(); - } - - @Override - public @NonNull Iterable findAllById(@NonNull Iterable ids) { - return StreamSupport.stream(ids.spliterator(), false).map(this::buildAasDiscoveryDocument).toList(); - } - - @Override - public long count() { - return this.assetLinks.size(); - } - - @Override - public synchronized void deleteById(@NonNull String id) { - this.assetLinks.remove(id); - this.assetIds.remove(id); - } - - @Override - public void delete(@NonNull AasDiscoveryDocument entity) { - this.deleteById(entity.getShellIdentifier()); - } - - @Override - public void deleteAllById(@NonNull Iterable ids) { - for (String id : ids) { - this.deleteById(id); - } - } - - @Override - public void deleteAll(@NonNull Iterable entities) { - for (AasDiscoveryDocument entity : entities) { - this.deleteById(entity.getShellIdentifier()); - } - } - - @Override - public synchronized void deleteAll() { - this.assetLinks.clear(); - this.assetIds.clear(); - } - - private synchronized AasDiscoveryDocument buildAasDiscoveryDocument(String shellId) { - Set assetLinksSet = assetLinks.get(shellId); - List assetIdsList = assetIds.get(shellId); - - if (assetIdsList == null) - assetIdsList = new ArrayList<>(); - - if (assetLinksSet == null) - assetLinksSet = new HashSet<>(); - - return new AasDiscoveryDocument(shellId, assetLinksSet, assetIdsList); - } - -} diff --git a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/core/AasDiscoveryServiceSuite.java b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/core/AasDiscoveryServiceSuite.java index 536f21d7d..7e552bdea 100644 --- a/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/core/AasDiscoveryServiceSuite.java +++ b/basyx.aasdiscoveryservice/basyx.aasdiscoveryservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasdiscoveryservice/core/AasDiscoveryServiceSuite.java @@ -55,8 +55,6 @@ public abstract class AasDiscoveryServiceSuite { protected abstract AasDiscoveryService getAasDiscoveryService(); - private final PaginationInfo noLimitPaginationInfo = new PaginationInfo(0, ""); - @Test public void getAllAssetAdministrationShellIdsByAssetLink() { AasDiscoveryService discoveryService = getAasDiscoveryService(); @@ -74,7 +72,7 @@ public void getAllAssetAdministrationShellIdsByAssetLink() { new AssetLink("DummyAssetName2", "DummyAsset_2_Value") )); - List actualResult = discoveryService.getAllAssetAdministrationShellIdsByAssetLink(noLimitPaginationInfo, assetIds) + List actualResult = discoveryService.getAllAssetAdministrationShellIdsByAssetLink(PaginationInfo.NO_LIMIT, assetIds) .getResult(); assertEquals(expectedResult.size(), actualResult.size()); diff --git a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java index 391bf22cd..c3fd3001b 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java +++ b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/AasEnvironmentLoaderTest.java @@ -69,8 +69,6 @@ public class AasEnvironmentLoaderTest { protected static final String TEST_ENVIRONMENT_SHELLS_ONLY_JSON = "/org/eclipse/digitaltwin/basyx/aasenvironment/environment_with_shells_only.json"; protected static final String TEST_ENVIRONMENT_SUBMODELS_ONLY_JSON = "/org/eclipse/digitaltwin/basyx/aasenvironment/environment_with_submodels_only.json"; - protected static final PaginationInfo ALL = new PaginationInfo(0, null); - protected AasRepository aasRepository; protected SubmodelRepository submodelRepository; protected ConceptDescriptionRepository conceptDescriptionRepository; @@ -96,9 +94,9 @@ protected void loadRepositories(List pathsToLoad) throws IOException, De public void testWithResourceFile_AllElementsAreDeployed() throws InvalidFormatException, IOException, DeserializationException { loadRepositories(List.of(TEST_ENVIRONMENT_JSON)); - Assert.assertEquals(2, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(2, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); } @Test @@ -112,9 +110,9 @@ public void testDeployedTwiceNoVersion_AllDeployedButNotOverriden() throws Inval Mockito.verify(submodelRepository, Mockito.times(2)).createSubmodel(Mockito.any()); Mockito.verify(submodelRepository, Mockito.times(0)).updateSubmodel(Mockito.anyString(), Mockito.any()); - Assert.assertEquals(2, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(2, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); } @Test @@ -128,9 +126,9 @@ public void testDeployedTwiceWithSameVersion_AllDeployedButNotOverriden() throws Mockito.verify(submodelRepository, Mockito.times(2)).createSubmodel(Mockito.any()); Mockito.verify(submodelRepository, Mockito.times(0)).updateSubmodel(Mockito.anyString(), Mockito.any()); - Assert.assertEquals(2, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(2, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); } @Test @@ -144,9 +142,9 @@ public void testDeployedTwiceNewRevision_ElementsAreOverriden() throws InvalidFo Mockito.verify(submodelRepository, Mockito.times(2)).createSubmodel(Mockito.any()); Mockito.verify(submodelRepository, Mockito.times(1)).updateSubmodel(Mockito.anyString(), Mockito.any()); - Assert.assertEquals(2, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(2, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); } @Test @@ -168,17 +166,17 @@ public void testWithResourceFile_NoExceptionsWhenReuploadAfterElementsAreRemoved loadRepositoriesWithEnvironment(List.of(TEST_ENVIRONMENT_JSON), envLoader); - Assert.assertEquals(2, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(2, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); deleteElementsFromRepos(); loadRepositoriesWithEnvironment(List.of(TEST_ENVIRONMENT_JSON), envLoader); - Assert.assertEquals(2, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(2, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); } @Test @@ -187,9 +185,9 @@ public void testWithResourceFile_ExceptionIsThrownWhenReuploadWithExistingElemen loadRepositoriesWithEnvironment(List.of(TEST_ENVIRONMENT_JSON), envLoader); - Assert.assertEquals(2, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(2, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); String expectedMsg = new CollidingIdentifierException("aas1").getMessage(); Assert.assertThrows(expectedMsg, CollidingIdentifierException.class, () -> loadRepositoriesWithEnvironment(List.of(TEST_ENVIRONMENT_JSON), envLoader)); @@ -204,13 +202,13 @@ private void loadRepositoriesWithEnvironment(List pathsToLoad, AasEnviro } private void deleteElementsFromRepos() { - aasRepository.getAllAas(ALL).getResult().stream().forEach(aas -> aasRepository.deleteAas(aas.getId())); - submodelRepository.getAllSubmodels(ALL).getResult().stream().forEach(sm -> submodelRepository.deleteSubmodel(sm.getId())); - conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().stream().forEach(cd -> conceptDescriptionRepository.deleteConceptDescription(cd.getId())); + aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().stream().forEach(aas -> aasRepository.deleteAas(aas.getId())); + submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().stream().forEach(sm -> submodelRepository.deleteSubmodel(sm.getId())); + conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().stream().forEach(cd -> conceptDescriptionRepository.deleteConceptDescription(cd.getId())); - Assert.assertEquals(0, aasRepository.getAllAas(ALL).getResult().size()); - Assert.assertEquals(0, submodelRepository.getAllSubmodels(ALL).getResult().size()); - Assert.assertEquals(0, conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().size()); + Assert.assertEquals(0, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(0, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size()); + Assert.assertEquals(0, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size()); } } \ No newline at end of file diff --git a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/PreconfigurationLoaderTextualResourceTest.java b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/PreconfigurationLoaderTextualResourceTest.java index 29a8774c4..7cd689cc3 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/PreconfigurationLoaderTextualResourceTest.java +++ b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/PreconfigurationLoaderTextualResourceTest.java @@ -31,6 +31,7 @@ import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException; import org.eclipse.digitaltwin.basyx.aasenvironment.base.DefaultAASEnvironment; import org.eclipse.digitaltwin.basyx.aasenvironment.preconfiguration.AasEnvironmentPreconfigurationLoader; +import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -52,9 +53,9 @@ protected void loadRepositories(List pathsToLoad) throws IOException, In @Test public void testWithEmptyResource_NoElementsAreDeployed() throws InvalidFormatException, IOException, DeserializationException { loadRepositories(List.of()); - Assert.assertTrue(aasRepository.getAllAas(ALL).getResult().isEmpty()); - Assert.assertTrue(submodelRepository.getAllSubmodels(ALL).getResult().isEmpty()); - Assert.assertTrue(conceptDescriptionRepository.getAllConceptDescriptions(ALL).getResult().isEmpty()); + Assert.assertTrue(aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().isEmpty()); + Assert.assertTrue(submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().isEmpty()); + Assert.assertTrue(conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().isEmpty()); Mockito.verify(aasRepository, Mockito.never()).createAas(Mockito.any()); Mockito.verify(aasRepository, Mockito.never()).updateAas(Mockito.anyString(), Mockito.any()); diff --git a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java index 3734e36ea..0564b0d4a 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java +++ b/basyx.aasenvironment/basyx.aasenvironment-core/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/TestAASEnvironmentSerialization.java @@ -74,7 +74,6 @@ public class TestAASEnvironmentSerialization { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, ""); public static final String AAS_TECHNICAL_DATA_ID = "shell001"; public static final String AAS_OPERATIONAL_DATA_ID = "shell002"; public static final String SUBMODEL_TECHNICAL_DATA_ID = "7A7104BDAB57E184"; @@ -266,9 +265,9 @@ private static List retrieveConceptDescriptionIds(Environment aasEnviron } private void validateRepositoriesState() { - assertTrue(aasRepository.getAllAas(NO_LIMIT_PAGINATION_INFO).getResult().containsAll(createDummyShells())); - assertTrue(submodelRepository.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult().containsAll(createDummySubmodels())); - assertTrue(conceptDescriptionRepository.getAllConceptDescriptions(NO_LIMIT_PAGINATION_INFO).getResult().containsAll(createDummyConceptDescriptions())); + assertTrue(aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().containsAll(createDummyShells())); + assertTrue(submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().containsAll(createDummySubmodels())); + assertTrue(conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().containsAll(createDummyConceptDescriptions())); } } diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java index 8f056bd58..7676800a3 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java +++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentSerialization.java @@ -70,7 +70,6 @@ */ public class TestAuthorizedAasEnvironmentSerialization { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static String authenticaltionServerTokenEndpoint = "http://localhost:9096/realms/BaSyx/protocol/openid-connect/token"; private static String clientId = "basyx-client-api"; private static AccessTokenProvider tokenProvider; @@ -101,9 +100,9 @@ public static void tearDown() { public void reset() throws FileNotFoundException, IOException { configureSecurityContext(); - Collection assetAdministrationShells = aasRepo.getAllAas(NO_LIMIT_PAGINATION_INFO).getResult(); - Collection submodels = submodelRepo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult(); - Collection conceptDescriptions = conceptDescriptionRepo.getAllConceptDescriptions(NO_LIMIT_PAGINATION_INFO).getResult(); + Collection assetAdministrationShells = aasRepo.getAllAas(PaginationInfo.NO_LIMIT).getResult(); + Collection submodels = submodelRepo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult(); + Collection conceptDescriptions = conceptDescriptionRepo.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult(); assetAdministrationShells.stream().forEach(aas -> aasRepo.deleteAas(aas.getId())); submodels.stream().forEach(sm -> submodelRepo.deleteSubmodel(sm.getId())); diff --git a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java index 785ae35ad..3b39566dd 100644 --- a/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java +++ b/basyx.aasenvironment/basyx.aasenvironment-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasenvironment/feature/authorization/TestAuthorizedAasEnvironmentUpload.java @@ -67,7 +67,6 @@ */ public class TestAuthorizedAasEnvironmentUpload { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static String authenticaltionServerTokenEndpoint = "http://localhost:9096/realms/BaSyx/protocol/openid-connect/token"; private static String clientId = "basyx-client-api"; private static AccessTokenProvider tokenProvider; @@ -94,9 +93,9 @@ public void reset() throws FileNotFoundException, IOException { configureSecurityContext(); - Collection assetAdministrationShells = aasRepo.getAllAas(NO_LIMIT_PAGINATION_INFO).getResult(); - Collection submodels = submodelRepo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult(); - Collection conceptDescriptions = conceptDescriptionRepo.getAllConceptDescriptions(NO_LIMIT_PAGINATION_INFO).getResult(); + Collection assetAdministrationShells = aasRepo.getAllAas(PaginationInfo.NO_LIMIT).getResult(); + Collection submodels = submodelRepo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult(); + Collection conceptDescriptions = conceptDescriptionRepo.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult(); assetAdministrationShells.stream().forEach(aas -> aasRepo.deleteAas(aas.getId())); submodels.stream().forEach(sm -> submodelRepo.deleteSubmodel(sm.getId())); diff --git a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java index c78e3831e..e233ab306 100644 --- a/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java +++ b/basyx.aasregistry/basyx.aasregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/regression/feature/authorization/TestAuthorizedAasRegistry.java @@ -66,7 +66,6 @@ public class TestAuthorizedAasRegistry { private static final String AAS_REGISTRY_PATH = "shell-descriptors"; - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static final String AAS_DESCRIPTOR_SIMPLE_2_JSON = "authorization/AasDescriptorSimple_2.json"; private static final String AAS_DESCRIPTOR_SIMPLE_1_JSON = "authorization/AasDescriptorSimple_1.json"; private static final String SPECIFIC_SHELL_ID_2 = "specificAasId-2"; @@ -108,7 +107,7 @@ public void initializeRepositories() throws FileNotFoundException, IOException { public void reset() throws FileNotFoundException, IOException { configureSecurityContext(); - Collection descriptors = storage.getAllAasDescriptors(NO_LIMIT_PAGINATION_INFO, new DescriptorFilter(AssetKind.TYPE, "TestAsset")).getResult(); + Collection descriptors = storage.getAllAasDescriptors(PaginationInfo.NO_LIMIT, new DescriptorFilter(AssetKind.TYPE, "TestAsset")).getResult(); descriptors.forEach(descriptor -> storage.removeAasDescriptor(descriptor.getId())); diff --git a/basyx.aasregistry/basyx.aasregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/service/tests/BaseInterfaceTest.java b/basyx.aasregistry/basyx.aasregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/service/tests/BaseInterfaceTest.java index 0ade65fce..8e85e1d00 100644 --- a/basyx.aasregistry/basyx.aasregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/service/tests/BaseInterfaceTest.java +++ b/basyx.aasregistry/basyx.aasregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/service/tests/BaseInterfaceTest.java @@ -134,12 +134,12 @@ protected void verifyNoEventSent() { } protected List getAllAasDescriptors() { - return storage.getAllAasDescriptors(new PaginationInfo(null, null), new DescriptorFilter(null, null)).getResult(); + return storage.getAllAasDescriptors(PaginationInfo.NO_LIMIT, new DescriptorFilter(null, null)).getResult(); } protected List getAllAasDescriptorsFiltered(AssetKind kind, String type) { - return storage.getAllAasDescriptors(new PaginationInfo(null, null), new DescriptorFilter(kind, type)).getResult(); + return storage.getAllAasDescriptors(PaginationInfo.NO_LIMIT, new DescriptorFilter(kind, type)).getResult(); } protected CursorResult> getAllAasDescriptorsWithPagination(int limit, String cursor) { @@ -147,7 +147,7 @@ protected CursorResult> getAllAasDescri } protected List getAllSubmodels(String id) { - return storage.getAllSubmodels(id, new PaginationInfo(null, null)).getResult(); + return storage.getAllSubmodels(id, PaginationInfo.NO_LIMIT).getResult(); } protected CursorResult> getAllSubmodelsWithPagination(String aasId, int limit, String cursor) { diff --git a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml index 3f6b3a9b8..45c8dc476 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml +++ b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/pom.xml @@ -22,6 +22,10 @@ org.eclipse.digitaltwin.basyx basyx.aasrepository-backend + + org.eclipse.digitaltwin.basyx + basyx.backend.inmemory.core + org.eclipse.digitaltwin.basyx basyx.aasrepository-core diff --git a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackend.java b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackend.java deleted file mode 100644 index aeb02fd99..000000000 --- a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackend.java +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2023 the Eclipse BaSyx Authors - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * SPDX-License-Identifier: MIT - ******************************************************************************/ - -package org.eclipse.digitaltwin.basyx.aasrepository.backend.inmemory; - -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; -import org.springframework.data.repository.CrudRepository; -import org.springframework.lang.NonNull; - -/** - * InMemory implementation for the AAS backend - * - * @author mateusmolina - * - */ -public class AasInMemoryBackend implements CrudRepository { - - private final ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); - - @Override - public @NonNull S save(@NonNull S entity) { - inMemoryStore.put(entity.getId(), entity); - - return entity; - } - - @Override - public @NonNull Iterable saveAll(@NonNull Iterable entities) { - entities.forEach(this::save); - - return entities; - } - - @Override - public @NonNull Optional findById(@NonNull String id) { - return Optional.ofNullable(inMemoryStore.get(id)); - } - - @Override - public boolean existsById(@NonNull String id) { - return inMemoryStore.containsKey(id); - } - - @Override - public @NonNull Iterable findAll() { - return inMemoryStore.values(); - } - - @Override - public @NonNull Iterable findAllById(@NonNull Iterable ids) { - return StreamSupport.stream(ids.spliterator(), false).map(inMemoryStore::get).filter(Objects::nonNull).collect(Collectors.toList()); - } - - @Override - public long count() { - return inMemoryStore.size(); - } - - @Override - public void deleteById(@NonNull String id) { - inMemoryStore.remove(id); - } - - @Override - public void delete(@NonNull AssetAdministrationShell entity) { - inMemoryStore.remove(entity.getId()); - } - - @Override - public void deleteAllById(@NonNull Iterable ids) { - for (String id : ids) - inMemoryStore.remove(id); - } - - @Override - public void deleteAll(@NonNull Iterable entities) { - for (AssetAdministrationShell entity : entities) - inMemoryStore.remove(entity.getId()); - } - - @Override - public void deleteAll() { - inMemoryStore.clear(); - } - - -} - diff --git a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackendProvider.java b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackendProvider.java index 0a8a4e788..44860711d 100644 --- a/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackendProvider.java +++ b/basyx.aasrepository/basyx.aasrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasrepository/backend/inmemory/AasInMemoryBackendProvider.java @@ -27,6 +27,7 @@ import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell; import org.eclipse.digitaltwin.basyx.aasrepository.backend.AasBackendProvider; +import org.eclipse.digitaltwin.basyx.common.backend.inmemory.core.InMemoryCrudRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; @@ -35,7 +36,7 @@ * * InMemory backend provider for the AAS * - * @author mateusmolina + * @author mateusmolina, danish */ @ConditionalOnExpression("'${basyx.backend}'.equals('InMemory')") @Component @@ -43,7 +44,7 @@ public class AasInMemoryBackendProvider implements AasBackendProvider { @Override public CrudRepository getCrudRepository() { - return new AasInMemoryBackend(); + return new InMemoryCrudRepository(AssetAdministrationShell::getId); } } diff --git a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java index 0020d6ba3..6e50cf903 100644 --- a/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java +++ b/basyx.aasrepository/basyx.aasrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/AasRepositorySuite.java @@ -51,7 +51,6 @@ * */ public abstract class AasRepositorySuite extends AasServiceSuite { - private final PaginationInfo noLimitPaginationInfo = new PaginationInfo(0, ""); private static final String AAS_EMPTY_ID = " "; private static final String AAS_NULL_ID = null; @@ -132,7 +131,7 @@ public void deleteNonExistingAas() { @Test(expected = ElementDoesNotExistException.class) public void getSubmodelReferencesOfNonExistingAas() { AasRepository aasRepo = getAasRepository(); - aasRepo.getSubmodelReferences("doesNotMatter", noLimitPaginationInfo).getResult(); + aasRepo.getSubmodelReferences("doesNotMatter", PaginationInfo.NO_LIMIT).getResult(); } @Test(expected = ElementDoesNotExistException.class) diff --git a/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/TestAasRepositoryHTTP.java b/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/TestAasRepositoryHTTP.java index 9591f4566..5e5edea39 100644 --- a/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/TestAasRepositoryHTTP.java +++ b/basyx.aasrepository/basyx.aasrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/aasrepository/http/TestAasRepositoryHTTP.java @@ -41,7 +41,6 @@ * */ public class TestAasRepositoryHTTP extends AasRepositoryHTTPSuite { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static ConfigurableApplicationContext appContext; @BeforeClass @@ -52,7 +51,7 @@ public static void startAasRepo() throws Exception { @Override public void resetRepository() { AasRepository repo = appContext.getBean(AasRepository.class); - repo.getAllAas(NO_LIMIT_PAGINATION_INFO) + repo.getAllAas(PaginationInfo.NO_LIMIT) .getResult() .stream() .map(a -> a.getId()) diff --git a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java index 0c7e4cbf0..be42e8490 100644 --- a/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java +++ b/basyx.aasservice/basyx.aasservice-core/src/test/java/org/eclipse/digitaltwin/basyx/aasservice/AasServiceSuite.java @@ -64,8 +64,6 @@ */ public abstract class AasServiceSuite { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); - protected abstract AasService getAasService(AssetAdministrationShell shell); protected abstract AasService getAasServiceWithThumbnail() throws IOException; @@ -82,7 +80,7 @@ public void getSubmodelReference() { DummyAssetAdministrationShellFactory.addDummySubmodelReference(expected); AasService aasService = getAasService(expected); - List submodelReferences = aasService.getSubmodelReferences(NO_LIMIT_PAGINATION_INFO).getResult(); + List submodelReferences = aasService.getSubmodelReferences(PaginationInfo.NO_LIMIT).getResult(); Reference submodelReference = getFirstSubmodelReference(submodelReferences); assertEquals(DummyAssetAdministrationShellFactory.submodelReference, submodelReference); } @@ -100,7 +98,7 @@ public void addSubmodelReference() { aasService.addSubmodelReference(ref); - List submodelReferences = aasService.getSubmodelReferences(NO_LIMIT_PAGINATION_INFO).getResult(); + List submodelReferences = aasService.getSubmodelReferences(PaginationInfo.NO_LIMIT).getResult(); Reference submodelReference = getFirstSubmodelReference(submodelReferences); @@ -113,9 +111,9 @@ public void removeSubmodelReference() { DummyAssetAdministrationShellFactory.addDummySubmodelReference(expected); AasService aasService = getAasService(expected); - List submodelReferences = aasService.getSubmodelReferences(NO_LIMIT_PAGINATION_INFO).getResult(); + List submodelReferences = aasService.getSubmodelReferences(PaginationInfo.NO_LIMIT).getResult(); aasService.removeSubmodelReference(DummyAssetAdministrationShellFactory.SUBMODEL_ID); - submodelReferences = aasService.getSubmodelReferences(NO_LIMIT_PAGINATION_INFO).getResult(); + submodelReferences = aasService.getSubmodelReferences(PaginationInfo.NO_LIMIT).getResult(); assertEquals(0, submodelReferences.size()); } diff --git a/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java b/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java index 17dcdd0e3..cc8909ff3 100644 --- a/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java +++ b/basyx.aasservice/basyx.aasservice-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/feature/mqtt/MqttAasService.java @@ -54,7 +54,6 @@ * */ public class MqttAasService implements AasService { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static Logger logger = LoggerFactory.getLogger(MqttAasService.class); private MqttAasServiceTopicFactory topicFactory; @@ -154,7 +153,7 @@ public void removeSubmodelReference(String submodelId) { } private Reference extractSubmodelReferenceById(String submodelId) { - List submodelsReferences = getSubmodelReferences(NO_LIMIT_PAGINATION_INFO).getResult(); + List submodelsReferences = getSubmodelReferences(PaginationInfo.NO_LIMIT).getResult(); return submodelsReferences.stream() .filter(reference -> containsSubmodelId(reference, submodelId)) diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/pom.xml b/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/pom.xml index 79e8704d8..f601be551 100644 --- a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/pom.xml +++ b/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/pom.xml @@ -17,6 +17,10 @@ org.eclipse.digitaltwin.basyx basyx.aasxfileserver-core + + org.eclipse.digitaltwin.basyx + basyx.backend.inmemory.core + org.eclipse.digitaltwin.basyx basyx.aasxfileserver-core diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryBackendProvider.java b/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryBackendProvider.java index 68a050e98..b80b64198 100644 --- a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryBackendProvider.java +++ b/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryBackendProvider.java @@ -27,6 +27,7 @@ import org.eclipse.digitaltwin.basyx.aasxfileserver.backend.AASXFileServerBackendProvider; import org.eclipse.digitaltwin.basyx.aasxfileserver.model.Package; +import org.eclipse.digitaltwin.basyx.common.backend.inmemory.core.InMemoryCrudRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; @@ -36,7 +37,7 @@ @Component public class AASXFileServerInMemoryBackendProvider implements AASXFileServerBackendProvider { - private AASXFileServerInMemoryCrudRepository repository = new AASXFileServerInMemoryCrudRepository(); + private CrudRepository repository = new InMemoryCrudRepository(Package::getPackageId); @Override public CrudRepository getCrudRepository() { diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryCrudRepository.java b/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryCrudRepository.java deleted file mode 100644 index f1c61802a..000000000 --- a/basyx.aasxfileserver/basyx.aasxfileserver-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/AASXFileServerInMemoryCrudRepository.java +++ /dev/null @@ -1,110 +0,0 @@ -/******************************************************************************* -* 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.aasxfileserver; - -import java.util.List; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import org.eclipse.digitaltwin.basyx.aasxfileserver.model.Package; -import org.springframework.data.repository.CrudRepository; -import org.springframework.lang.NonNull; - -public class AASXFileServerInMemoryCrudRepository implements CrudRepository { - - private final ConcurrentMap packageMap = new ConcurrentHashMap<>(); - - @Override - public @NonNull S save(@NonNull S entity) { - packageMap.put(entity.getPackageId(), entity); - - return entity; - } - - @Override - public @NonNull Iterable saveAll(@NonNull Iterable entities) { - entities.forEach(this::save); - - return entities; - } - - @Override - public @NonNull Optional findById(@NonNull String id) { - return Optional.ofNullable(packageMap.get(id)); - } - - @Override - public boolean existsById(@NonNull String id) { - return packageMap.containsKey(id); - } - - @Override - public @NonNull Iterable findAll() { - return packageMap.values(); - } - - @Override - public @NonNull Iterable findAllById(@NonNull Iterable ids) { - List idList = StreamSupport.stream(ids.spliterator(), false).collect(Collectors.toList()); - return packageMap.entrySet().stream().filter(entry -> idList.contains(entry.getKey())).map(Entry::getValue).collect(Collectors.toList()); - } - - @Override - public long count() { - return packageMap.size(); - } - - @Override - public void deleteById(@NonNull String id) { - packageMap.remove(id); - } - - @Override - public void delete(@NonNull Package entity) { - packageMap.remove(entity.getPackageId()); - } - - @Override - public void deleteAllById(@NonNull Iterable ids) { - List idList = StreamSupport.stream(ids.spliterator(), false).collect(Collectors.toList()); - packageMap.keySet().removeAll(idList); - } - - @Override - public void deleteAll(@NonNull Iterable entities) { - List idList = StreamSupport.stream(entities.spliterator(), false).map(Package::getPackageId).collect(Collectors.toList()); - packageMap.keySet().removeAll(idList); - } - - @Override - public void deleteAll() { - packageMap.clear(); - } -} diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/backend/CrudAASXFileServer.java b/basyx.aasxfileserver/basyx.aasxfileserver-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/backend/CrudAASXFileServer.java index 599a28c7b..ce5211c52 100644 --- a/basyx.aasxfileserver/basyx.aasxfileserver-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/backend/CrudAASXFileServer.java +++ b/basyx.aasxfileserver/basyx.aasxfileserver-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasxfileserver/backend/CrudAASXFileServer.java @@ -25,7 +25,6 @@ package org.eclipse.digitaltwin.basyx.aasxfileserver.backend; import java.io.InputStream; -import java.util.Collection; import java.util.List; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicInteger; @@ -33,7 +32,6 @@ import java.util.stream.StreamSupport; import org.eclipse.digitaltwin.aas4j.v3.model.PackageDescription; -import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultPackageDescription; import org.eclipse.digitaltwin.basyx.aasxfileserver.AASXFileServer; import org.eclipse.digitaltwin.basyx.aasxfileserver.model.Package; diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-core/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/core/AASXFileServerSuite.java b/basyx.aasxfileserver/basyx.aasxfileserver-core/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/core/AASXFileServerSuite.java index e93d552a4..2d0fc77b0 100644 --- a/basyx.aasxfileserver/basyx.aasxfileserver-core/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/core/AASXFileServerSuite.java +++ b/basyx.aasxfileserver/basyx.aasxfileserver-core/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/core/AASXFileServerSuite.java @@ -53,7 +53,6 @@ public abstract class AASXFileServerSuite { protected abstract AASXFileServer getAASXFileServer(); - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0,""); @Test public void getAllAASXPackageIds() { @@ -65,7 +64,7 @@ public void getAllAASXPackageIds() { List expectedPackageDescriptions = Arrays.asList(expectedDescription1, expectedDescription2); - CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds("",NO_LIMIT_PAGINATION_INFO); + CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds("", PaginationInfo.NO_LIMIT); List actualPackageDescriptions = pagedPackageDescriptions.getResult(); @@ -82,7 +81,7 @@ public void getAllAASXPackageIdsByShellId() { List expectedPackageDescriptions = Arrays.asList(expectedDescription); - CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds("AAS_ID_3",NO_LIMIT_PAGINATION_INFO); + CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds("AAS_ID_3", PaginationInfo.NO_LIMIT); List actualPackageDescriptions = pagedPackageDescriptions.getResult(); assertGetAllAASXPackageIds(expectedPackageDescriptions, actualPackageDescriptions); } @@ -103,7 +102,7 @@ public void getAllAASXPackageIdsEmpty() { String shellId = "testShellId"; AASXFileServer server = getAASXFileServer(); - CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds(shellId,NO_LIMIT_PAGINATION_INFO); + CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds(shellId, PaginationInfo.NO_LIMIT); List packageDescriptions = pagedPackageDescriptions.getResult(); assertTrue(packageDescriptions.isEmpty()); } @@ -128,7 +127,7 @@ public void updateExistingAASXByPackageId() throws IOException { expectedPackageDescription.setPackageId("1"); expectedPackageDescription.setItems(DummyAASXFileServerFactory.SECOND_SHELL_IDS); - CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds("",NO_LIMIT_PAGINATION_INFO); + CursorResult> pagedPackageDescriptions = server.getAllAASXPackageIds("", PaginationInfo.NO_LIMIT); List actualPackageDescription = pagedPackageDescriptions.getResult(); assertUpdatedAASXPackageId(expectedPackageDescription, actualPackageDescription, server); } diff --git a/basyx.aasxfileserver/basyx.aasxfileserver-http/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/http/TestAASXFileServerHTTP.java b/basyx.aasxfileserver/basyx.aasxfileserver-http/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/http/TestAASXFileServerHTTP.java index 8fb388f8c..33de1702d 100644 --- a/basyx.aasxfileserver/basyx.aasxfileserver-http/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/http/TestAASXFileServerHTTP.java +++ b/basyx.aasxfileserver/basyx.aasxfileserver-http/src/test/java/org/eclipse/digitaltwin/basyx/aasxfileserver/http/TestAASXFileServerHTTP.java @@ -74,7 +74,7 @@ public void setup() { @AfterMethod public void cleanUp() { try { - this.aasxFileServer.getAllAASXPackageIds("", new PaginationInfo(0, "")).getResult().stream().forEach(p -> this.aasxFileServer.deleteAASXByPackageId(p.getPackageId())); + this.aasxFileServer.getAllAASXPackageIds("", PaginationInfo.NO_LIMIT).getResult().stream().forEach(p -> this.aasxFileServer.deleteAASXByPackageId(p.getPackageId())); } catch (Exception ignored) { } @@ -193,11 +193,11 @@ public void testGetAllPackages() throws Exception { } private boolean isPackageNotPresent(String aasId) { - return this.aasxFileServer.getAllAASXPackageIds(aasId, new PaginationInfo(0, "")).getResult().size() == 0; + return this.aasxFileServer.getAllAASXPackageIds(aasId, PaginationInfo.NO_LIMIT).getResult().size() == 0; } private boolean isPackagePresentOneTime(String aasId) { - return this.aasxFileServer.getAllAASXPackageIds(aasId, new PaginationInfo(0, "")).getResult().size() == 1; + return this.aasxFileServer.getAllAASXPackageIds(aasId, PaginationInfo.NO_LIMIT).getResult().size() == 1; } private PackageDescription createAASXPackageOnServer() throws Exception { diff --git a/basyx.common/basyx.authorization.rules.rbac.backend.submodel/src/main/java/org/eclipse/digitaltwin/basyx/authorization/rules/rbac/backend/submodel/SubmodelAuthorizationRbacStorage.java b/basyx.common/basyx.authorization.rules.rbac.backend.submodel/src/main/java/org/eclipse/digitaltwin/basyx/authorization/rules/rbac/backend/submodel/SubmodelAuthorizationRbacStorage.java index fed4005aa..2c8ea1652 100644 --- a/basyx.common/basyx.authorization.rules.rbac.backend.submodel/src/main/java/org/eclipse/digitaltwin/basyx/authorization/rules/rbac/backend/submodel/SubmodelAuthorizationRbacStorage.java +++ b/basyx.common/basyx.authorization.rules.rbac.backend.submodel/src/main/java/org/eclipse/digitaltwin/basyx/authorization/rules/rbac/backend/submodel/SubmodelAuthorizationRbacStorage.java @@ -91,7 +91,7 @@ public boolean exist(String key) { @Override public Map getRbacRules() { - return smService.getSubmodelElements(new PaginationInfo(0, "")).getResult().stream().map(SubmodelElementCollection.class::cast).map(ruleAdapter::adapt).collect(Collectors.toMap(rbacRule -> createKey(rbacRule), rbacRule -> rbacRule)); + return smService.getSubmodelElements(PaginationInfo.NO_LIMIT).getResult().stream().map(SubmodelElementCollection.class::cast).map(ruleAdapter::adapt).collect(Collectors.toMap(rbacRule -> createKey(rbacRule), rbacRule -> rbacRule)); } private String createKey(RbacRule rbacRule) { diff --git a/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java b/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java index f39dff335..46a235644 100644 --- a/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java +++ b/basyx.common/basyx.authorization/src/test/java/org/eclipse/digitaltwin/basyx/authorization/TestKeycloakRoleProvider.java @@ -185,4 +185,4 @@ public void getRoles_whenClaimNotPresent() { assertTrue(roles.isEmpty()); } -} \ No newline at end of file +} diff --git a/basyx.common/basyx.backend.inmemory.core/pom.xml b/basyx.common/basyx.backend.inmemory.core/pom.xml new file mode 100644 index 000000000..579e9c321 --- /dev/null +++ b/basyx.common/basyx.backend.inmemory.core/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + + org.eclipse.digitaltwin.basyx + basyx.common + ${revision} + + basyx.backend.inmemory.core + BaSyx InMemory Backend core + BaSyx InMemory Backend core + + + + org.eclipse.digitaltwin.basyx + basyx.core + + + org.springframework.data + spring-data-commons + + + org.eclipse.digitaltwin.aas4j + aas4j-dataformat-json + + + \ No newline at end of file diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackend.java b/basyx.common/basyx.backend.inmemory.core/src/main/java/org/eclipse/digitaltwin/basyx/common/backend/inmemory/core/InMemoryCrudRepository.java similarity index 69% rename from basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackend.java rename to basyx.common/basyx.backend.inmemory.core/src/main/java/org/eclipse/digitaltwin/basyx/common/backend/inmemory/core/InMemoryCrudRepository.java index 91afca35d..8c5267266 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackend.java +++ b/basyx.common/basyx.backend.inmemory.core/src/main/java/org/eclipse/digitaltwin/basyx/common/backend/inmemory/core/InMemoryCrudRepository.java @@ -23,45 +23,51 @@ * SPDX-License-Identifier: MIT ******************************************************************************/ -package org.eclipse.digitaltwin.basyx.submodelrepository; +package org.eclipse.digitaltwin.basyx.common.backend.inmemory.core; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.StreamSupport; -import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; import org.springframework.data.repository.CrudRepository; import org.springframework.lang.NonNull; /** - * InMemory implementation for the Submodel backend - * - * @author mateusmolina, danish + * CrudRepository implementation for InMemory backends * + * @author danish */ -public class SubmodelInMemoryBackend implements CrudRepository { - - private final ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); +public class InMemoryCrudRepository implements CrudRepository { + + private final ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); + private Function idGetter; + public InMemoryCrudRepository(Function idGetter) { + this.idGetter = idGetter; + } + @Override - public @NonNull S save(@NonNull S entity) { - inMemoryStore.put(entity.getId(), entity); + public @NonNull S save(@NonNull S entity) { + String id = idGetter.apply(entity); + + inMemoryStore.put(id, entity); return entity; } @Override - public @NonNull Iterable saveAll(@NonNull Iterable entities) { + public @NonNull Iterable saveAll(@NonNull Iterable entities) { entities.forEach(this::save); return entities; } @Override - public @NonNull Optional findById(String id) { + public @NonNull Optional findById(@NonNull String id) { return Optional.ofNullable(inMemoryStore.get(id)); } @@ -71,12 +77,12 @@ public boolean existsById(@NonNull String id) { } @Override - public @NonNull Iterable findAll() { + public @NonNull Iterable findAll() { return inMemoryStore.values(); } @Override - public @NonNull Iterable findAllById(@NonNull Iterable ids) { + public @NonNull Iterable findAllById(@NonNull Iterable ids) { return StreamSupport.stream(ids.spliterator(), false).map(inMemoryStore::get).filter(Objects::nonNull).collect(Collectors.toList()); } @@ -91,8 +97,10 @@ public void deleteById(@NonNull String id) { } @Override - public void delete(@NonNull Submodel entity) { - inMemoryStore.remove(entity.getId()); + public void delete(@NonNull T entity) { + String id = idGetter.apply(entity); + + inMemoryStore.remove(id); } @Override @@ -102,9 +110,10 @@ public void deleteAllById(@NonNull Iterable ids) { } @Override - public void deleteAll(@NonNull Iterable entities) { - for (Submodel entity : entities) - inMemoryStore.remove(entity.getId()); + public void deleteAll(@NonNull Iterable entities) { + + for (T entity : entities) + inMemoryStore.remove(idGetter.apply(entity)); } @Override @@ -112,5 +121,5 @@ public void deleteAll() { inMemoryStore.clear(); } -} +} diff --git a/basyx.common/basyx.client/pom.xml b/basyx.common/basyx.client/pom.xml index b751f6a23..04245d5fd 100644 --- a/basyx.common/basyx.client/pom.xml +++ b/basyx.common/basyx.client/pom.xml @@ -63,7 +63,7 @@ com.nimbusds oauth2-oidc-sdk - 11.12 + 11.20.1 diff --git a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationInfo.java b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationInfo.java index 1b65cce4d..f23939e08 100644 --- a/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationInfo.java +++ b/basyx.common/basyx.core/src/main/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationInfo.java @@ -27,7 +27,7 @@ package org.eclipse.digitaltwin.basyx.core.pagination; public class PaginationInfo { - public static final PaginationInfo NO_LIMIT = new PaginationInfo(0, null); + public static final PaginationInfo NO_LIMIT = new PaginationInfo(null, null); private Integer limit; private String cursor; diff --git a/basyx.common/basyx.core/src/test/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationSupportTest.java b/basyx.common/basyx.core/src/test/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationSupportTest.java index 8d1464cde..a3a15bc81 100644 --- a/basyx.common/basyx.core/src/test/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationSupportTest.java +++ b/basyx.common/basyx.core/src/test/java/org/eclipse/digitaltwin/basyx/core/pagination/PaginationSupportTest.java @@ -39,7 +39,7 @@ public void testPaginationNoLimit() { @Test public void testNoLimit() { PaginationSupport support = getPaginationSupport(); - CursorResult> cursorResult = support.getPaged(new PaginationInfo(null, null)); + CursorResult> cursorResult = support.getPaged(PaginationInfo.NO_LIMIT); Assert.assertEquals(null, cursorResult.getCursor()); Assert.assertArrayEquals(new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, cursorResult.getResult().toArray(String[]::new)); } diff --git a/basyx.common/pom.xml b/basyx.common/pom.xml index 9ac32b4b3..fe6807eaa 100644 --- a/basyx.common/pom.xml +++ b/basyx.common/pom.xml @@ -20,6 +20,7 @@ basyx.mongocore basyx.authorization basyx.client + basyx.backend.inmemory.core basyx.filerepository-backend basyx.filerepository-backend-inmemory basyx.filerepository-backend-mongodb diff --git a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/pom.xml b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/pom.xml index 3d9e795dd..12471a489 100644 --- a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/pom.xml +++ b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/pom.xml @@ -20,6 +20,10 @@ org.eclipse.digitaltwin.basyx basyx.conceptdescriptionrepository-backend + + + org.eclipse.digitaltwin.basyx + basyx.backend.inmemory.core org.eclipse.digitaltwin.basyx diff --git a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackend.java b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackend.java deleted file mode 100644 index 38d8afa27..000000000 --- a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackend.java +++ /dev/null @@ -1,116 +0,0 @@ -/******************************************************************************* - * 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.conceptdescriptionrepository; - -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import org.eclipse.digitaltwin.aas4j.v3.model.ConceptDescription; -import org.springframework.data.repository.CrudRepository; -import org.springframework.lang.NonNull; - -/** - * InMemory implementation for the {@link ConceptDescription} backend - * - * @author danish, mateusmolina - * - */ -public class ConceptDescriptionInMemoryBackend implements CrudRepository { - - private final ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); - - @Override - public @NonNull S save(@NonNull S entity) { - inMemoryStore.put(entity.getId(), entity); - - return entity; - } - - @Override - public @NonNull Iterable saveAll(@NonNull Iterable entities) { - entities.forEach(this::save); - - return entities; - } - - @Override - public @NonNull Optional findById(@NonNull String id) { - return Optional.ofNullable(inMemoryStore.get(id)); - } - - @Override - public boolean existsById(@NonNull String id) { - return inMemoryStore.containsKey(id); - } - - @Override - public @NonNull Iterable findAll() { - return inMemoryStore.values(); - } - - @Override - public @NonNull Iterable findAllById(@NonNull Iterable ids) { - return StreamSupport.stream(ids.spliterator(), false).map(inMemoryStore::get).filter(Objects::nonNull).collect(Collectors.toList()); - } - - @Override - public long count() { - return inMemoryStore.size(); - } - - @Override - public void deleteById(@NonNull String id) { - inMemoryStore.remove(id); - } - - @Override - public void delete(@NonNull ConceptDescription entity) { - inMemoryStore.remove(entity.getId()); - } - - @Override - public void deleteAllById(@NonNull Iterable ids) { - for (String id : ids) - inMemoryStore.remove(id); - } - - @Override - public void deleteAll(@NonNull Iterable entities) { - for (ConceptDescription entity : entities) - inMemoryStore.remove(entity.getId()); - } - - @Override - public void deleteAll() { - inMemoryStore.clear(); - } - -} - diff --git a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackendProvider.java b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackendProvider.java index b2dae7e65..e5775d9e7 100644 --- a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackendProvider.java +++ b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/ConceptDescriptionInMemoryBackendProvider.java @@ -27,6 +27,7 @@ import org.eclipse.digitaltwin.aas4j.v3.model.ConceptDescription; import org.eclipse.digitaltwin.basyx.aasrepository.backend.ConceptDescriptionBackendProvider; +import org.eclipse.digitaltwin.basyx.common.backend.inmemory.core.InMemoryCrudRepository; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Component; @@ -42,7 +43,7 @@ public class ConceptDescriptionInMemoryBackendProvider implements ConceptDescrip @Override public CrudRepository getCrudRepository() { - return new ConceptDescriptionInMemoryBackend(); + return new InMemoryCrudRepository(ConceptDescription::getId); } } diff --git a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/core/ConceptDescriptionRepositorySuite.java b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/core/ConceptDescriptionRepositorySuite.java index 1ebf9fe72..3fda24520 100644 --- a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/core/ConceptDescriptionRepositorySuite.java +++ b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/core/ConceptDescriptionRepositorySuite.java @@ -61,8 +61,6 @@ public abstract class ConceptDescriptionRepositorySuite { protected abstract ConceptDescriptionRepository getConceptDescriptionRepository(Collection conceptDescriptions); - private final PaginationInfo noLimitPaginationInfo = new PaginationInfo(0, ""); - private static final String EMPTY_ID = " "; private static final String NULL_ID = null; @@ -71,7 +69,7 @@ public void getAllConceptDescriptionsPreconfigured() { Collection expectedConceptDescriptions = DummyConceptDescriptionFactory.getConceptDescriptions(); ConceptDescriptionRepository repo = getConceptDescriptionRepository(expectedConceptDescriptions); - Collection actualConceptDescriptions = repo.getAllConceptDescriptions(noLimitPaginationInfo) + Collection actualConceptDescriptions = repo.getAllConceptDescriptions(PaginationInfo.NO_LIMIT) .getResult(); assertEquals(4, actualConceptDescriptions.size()); @@ -84,7 +82,7 @@ public void getAllConceptDescriptionsWithIdShortPreconfigured() { Collection expectedDescriptions = Arrays.asList(DummyConceptDescriptionFactory.createBasicConceptDescription()); ConceptDescriptionRepository repo = getConceptDescriptionRepository(allConceptDescriptions); - Collection actualConceptDescriptions = repo.getAllConceptDescriptionsByIdShort("BasicConceptDescription", noLimitPaginationInfo) + Collection actualConceptDescriptions = repo.getAllConceptDescriptionsByIdShort("BasicConceptDescription", PaginationInfo.NO_LIMIT) .getResult(); assertEquals(1, actualConceptDescriptions.size()); @@ -103,7 +101,7 @@ public void getAllConceptDescriptionsWithIsCaseOfPreconfigured() { Collection expectedDescriptions = Arrays.asList(DummyConceptDescriptionFactory.createConceptDescription(), DummyConceptDescriptionFactory.createBasicConceptDescriptionWithDataSpecification()); ConceptDescriptionRepository repo = getConceptDescriptionRepository(allConceptDescriptions); - Collection actualConceptDescriptions = repo.getAllConceptDescriptionsByIsCaseOf(reference, noLimitPaginationInfo) + Collection actualConceptDescriptions = repo.getAllConceptDescriptionsByIsCaseOf(reference, PaginationInfo.NO_LIMIT) .getResult(); assertEquals(2, actualConceptDescriptions.size()); @@ -122,7 +120,7 @@ public void getAllConceptDescriptionsWithDataSpecPreconfigured() { Collection expectedDescriptions = Arrays.asList(DummyConceptDescriptionFactory.createBasicConceptDescriptionWithDataSpecification()); ConceptDescriptionRepository repo = getConceptDescriptionRepository(allConceptDescriptions); - Collection actualConceptDescriptions = repo.getAllConceptDescriptionsByDataSpecificationReference(reference, noLimitPaginationInfo) + Collection actualConceptDescriptions = repo.getAllConceptDescriptionsByDataSpecificationReference(reference, PaginationInfo.NO_LIMIT) .getResult(); assertEquals(1, actualConceptDescriptions.size()); @@ -132,7 +130,7 @@ public void getAllConceptDescriptionsWithDataSpecPreconfigured() { @Test public void getAllConceptDescriptionsEmpty() { ConceptDescriptionRepository repo = getConceptDescriptionRepository(); - Collection conceptDescriptions = repo.getAllConceptDescriptions(noLimitPaginationInfo) + Collection conceptDescriptions = repo.getAllConceptDescriptions(PaginationInfo.NO_LIMIT) .getResult(); assertIsEmpty(conceptDescriptions); diff --git a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/http/TestConceptDescriptionRepositoryHTTP.java b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/http/TestConceptDescriptionRepositoryHTTP.java index 3517c3349..c7289d7b9 100644 --- a/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/http/TestConceptDescriptionRepositoryHTTP.java +++ b/basyx.conceptdescriptionrepository/basyx.conceptdescriptionrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/conceptdescriptionrepository/http/TestConceptDescriptionRepositoryHTTP.java @@ -45,7 +45,6 @@ * */ public class TestConceptDescriptionRepositoryHTTP extends ConceptDescriptionRepositoryHTTPSuite { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static ConfigurableApplicationContext appContext; @BeforeClass @@ -61,7 +60,7 @@ public void resetRepository() { } private void resetRepoToDefaultConceptDescriptions(ConceptDescriptionRepository repo, Collection conceptDescriptions) { - repo.getAllConceptDescriptions(NO_LIMIT_PAGINATION_INFO) + repo.getAllConceptDescriptions(PaginationInfo.NO_LIMIT) .getResult() .stream() .map(s -> s.getId()) diff --git a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/regression/feature/authorization/TestAuthorizedSubmodelRegistry.java b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/regression/feature/authorization/TestAuthorizedSubmodelRegistry.java index 37f359a32..af8568883 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/regression/feature/authorization/TestAuthorizedSubmodelRegistry.java +++ b/basyx.submodelregistry/basyx.submodelregistry-feature-authorization/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/regression/feature/authorization/TestAuthorizedSubmodelRegistry.java @@ -66,7 +66,6 @@ */ public class TestAuthorizedSubmodelRegistry { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static final String SUBMODEL_DESCRIPTOR_SIMPLE_2_JSON = "authorization/SubmodelDescriptorSimple_2.json"; private static final String SUBMODEL_DESCRIPTOR_SIMPLE_1_JSON = "authorization/SubmodelDescriptorSimple_1.json"; private static final String SPECIFIC_SUBMODEL_ID_2 = "specificSubmodelId-2"; @@ -107,7 +106,7 @@ public void initializeRepositories() throws IOException { public void reset() throws IOException { configureSecurityContext(); - Collection descriptors = storage.getAllSubmodelDescriptors(NO_LIMIT_PAGINATION_INFO).getResult(); + Collection descriptors = storage.getAllSubmodelDescriptors(PaginationInfo.NO_LIMIT).getResult(); descriptors.forEach(descriptor -> storage.removeSubmodelDescriptor(descriptor.getId())); diff --git a/basyx.submodelregistry/basyx.submodelregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/service/tests/BaseInterfaceTest.java b/basyx.submodelregistry/basyx.submodelregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/service/tests/BaseInterfaceTest.java index 4bb7ce5d3..e9d999838 100644 --- a/basyx.submodelregistry/basyx.submodelregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/service/tests/BaseInterfaceTest.java +++ b/basyx.submodelregistry/basyx.submodelregistry-service-basetests/src/main/java/org/eclipse/digitaltwin/basyx/submodelregistry/service/tests/BaseInterfaceTest.java @@ -107,7 +107,7 @@ protected void verifyNoEventSent() { } protected List getAllSubmodels() { - return storage.getAllSubmodelDescriptors(new PaginationInfo(null, null)).getResult(); + return storage.getAllSubmodelDescriptors(PaginationInfo.NO_LIMIT).getResult(); } protected CursorResult> getAllSubmodelsWithPagination(int limit, String cursor) { diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/pom.xml b/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/pom.xml index 11d97c975..1edfa7be2 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/pom.xml +++ b/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/pom.xml @@ -24,6 +24,10 @@ org.eclipse.digitaltwin.basyx basyx.submodelservice-core + + + org.eclipse.digitaltwin.basyx + basyx.backend.inmemory.core org.eclipse.digitaltwin.basyx diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackendProvider.java b/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackendProvider.java index 79b69eb2a..bf65b85dc 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackendProvider.java +++ b/basyx.submodelrepository/basyx.submodelrepository-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelInMemoryBackendProvider.java @@ -26,6 +26,7 @@ package org.eclipse.digitaltwin.basyx.submodelrepository; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; +import org.eclipse.digitaltwin.basyx.common.backend.inmemory.core.InMemoryCrudRepository; import org.eclipse.digitaltwin.basyx.submodelrepository.backend.SubmodelBackendProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.data.repository.CrudRepository; @@ -43,7 +44,7 @@ public class SubmodelInMemoryBackendProvider implements SubmodelBackendProvider @Override public CrudRepository getCrudRepository() { - return new SubmodelInMemoryBackend(); + return new InMemoryCrudRepository(Submodel::getId); } } diff --git a/basyx.submodelrepository/basyx.submodelrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/backend/CrudSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/backend/CrudSubmodelRepository.java index b1f80f289..6fc3bbfe3 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/backend/CrudSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-backend/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/backend/CrudSubmodelRepository.java @@ -26,6 +26,7 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.backend; import java.io.InputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -39,8 +40,10 @@ import org.eclipse.digitaltwin.aas4j.v3.dataformat.json.JsonDeserializer; import org.eclipse.digitaltwin.aas4j.v3.dataformat.json.JsonSerializer; import org.eclipse.digitaltwin.aas4j.v3.model.OperationVariable; +import org.eclipse.digitaltwin.aas4j.v3.model.Reference; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; import org.eclipse.digitaltwin.aas4j.v3.model.SubmodelElement; +import org.eclipse.digitaltwin.basyx.client.internal.ApiException; import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException; import org.eclipse.digitaltwin.basyx.core.exceptions.ElementNotAFileException; @@ -50,6 +53,7 @@ import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationSupport; +import org.eclipse.digitaltwin.basyx.http.Base64UrlEncoder; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository; import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelService; import org.eclipse.digitaltwin.basyx.submodelservice.SubmodelServiceFactory; @@ -58,6 +62,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.repository.CrudRepository; +import org.springframework.http.HttpStatus; /** * Default Implementation for the {@link SubmodelRepository} based on Spring @@ -69,7 +74,6 @@ public class CrudSubmodelRepository implements SubmodelRepository { private Logger logger = LoggerFactory.getLogger(CrudSubmodelRepository.class); - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private CrudRepository submodelBackend; private SubmodelServiceFactory submodelServiceFactory; @@ -120,6 +124,27 @@ public CursorResult> getAllSubmodels(PaginationInfo pInfo) { return paginationSupport.getPaged(pInfo); } + @Override + public CursorResult> getAllSubmodels(String semanticId, PaginationInfo pInfo) { + Iterable iterable = submodelBackend.findAll(); + List submodels = StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList()); + + List filteredSubmodels = submodels.stream() + .filter((submodel) -> { + return submodel.getSemanticId() != null && + submodel.getSemanticId().getKeys().stream().filter((key) -> { + return key.getValue().equals(semanticId); + }).findAny().isPresent(); + }) + .collect(Collectors.toList()); + + TreeMap submodelMap = filteredSubmodels.stream().collect(Collectors.toMap(Submodel::getId, submodel -> submodel, (a, b) -> a, TreeMap::new)); + + PaginationSupport paginationSupport = new PaginationSupport<>(submodelMap, Submodel::getId); + + return paginationSupport.getPaged(pInfo); + } + @Override public Submodel getSubmodel(String submodelId) throws ElementDoesNotExistException { return submodelBackend.findById(submodelId).orElseThrow(() -> new ElementDoesNotExistException(submodelId)); @@ -222,7 +247,7 @@ public OperationVariable[] invokeOperation(String submodelId, String idShortPath @Override public SubmodelValueOnly getSubmodelByIdValueOnly(String submodelId) throws ElementDoesNotExistException { - return new SubmodelValueOnly(getSubmodelElements(submodelId, NO_LIMIT_PAGINATION_INFO).getResult()); + return new SubmodelValueOnly(getSubmodelElements(submodelId, PaginationInfo.NO_LIMIT).getResult()); } @Override diff --git a/basyx.submodelrepository/basyx.submodelrepository-client/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/ConnectedSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-client/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/ConnectedSubmodelRepository.java index 0fc9c551b..397767fa6 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-client/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/ConnectedSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-client/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/ConnectedSubmodelRepository.java @@ -155,6 +155,21 @@ public CursorResult> getAllSubmodels(PaginationInfo pInfo) { } + @Override + public CursorResult> getAllSubmodels(String semanticId, PaginationInfo pInfo) { + try { + String encodedCursor = pInfo.getCursor() == null ? null : Base64UrlEncoder.encode(pInfo.getCursor()); + String encodedSemanticId = Base64UrlEncoder.encode(semanticId); + return repoApi.getAllSubmodels(encodedSemanticId, null, pInfo.getLimit(), encodedCursor, null, null); + } catch (ApiException e) { + if (e.getCode() == HttpStatus.INTERNAL_SERVER_ERROR.value()) { + return new CursorResult<>("", new ArrayList<>()); + } else { + throw e; + } + } + } + @Override public void updateSubmodelElement(String submodelId, String idShortPath, SubmodelElement submodelElement) throws ElementDoesNotExistException { getConnectedSubmodelService(submodelId).updateSubmodelElement(idShortPath, submodelElement); diff --git a/basyx.submodelrepository/basyx.submodelrepository-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/TestConnectedSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/TestConnectedSubmodelRepository.java index 9946f1c8e..8809b86f9 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/TestConnectedSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/client/TestConnectedSubmodelRepository.java @@ -51,7 +51,6 @@ */ public class TestConnectedSubmodelRepository extends SubmodelRepositorySuite { private static ConfigurableApplicationContext appContext; - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); @BeforeClass public static void startAASRepo() throws Exception { @@ -61,7 +60,7 @@ public static void startAASRepo() throws Exception { @After public void removeSubmodelFromRepo() { SubmodelRepository repo = appContext.getBean(SubmodelRepository.class); - repo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); + repo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); } @AfterClass diff --git a/basyx.submodelrepository/basyx.submodelrepository-core/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-core/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelRepository.java index d34139fa9..0a5df3ec7 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-core/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-core/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/SubmodelRepository.java @@ -38,6 +38,7 @@ import org.eclipse.digitaltwin.basyx.core.exceptions.MissingIdentifierException; import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult; import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; +import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelElementValue; import org.eclipse.digitaltwin.basyx.submodelservice.value.SubmodelValueOnly; @@ -55,7 +56,14 @@ public interface SubmodelRepository { * @return a list of all found Submodels */ public CursorResult> getAllSubmodels(PaginationInfo pInfo); - + + /** + * Retrieves all Submodels from the repository filtered by the Semantic ID + * + * @return a list of all found Submodels with common Semantic ID + */ + public CursorResult> getAllSubmodels(String semanticId, PaginationInfo pInfo); + /** * Retrieves the Submodel with the specific id * diff --git a/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java b/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java index 77b7a99d3..ce9c3aa04 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java +++ b/basyx.submodelrepository/basyx.submodelrepository-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/core/SubmodelRepositorySuite.java @@ -26,7 +26,6 @@ package org.eclipse.digitaltwin.basyx.submodelrepository.core; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -34,7 +33,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; import org.eclipse.digitaltwin.aas4j.v3.model.DataTypeDefXsd; import org.eclipse.digitaltwin.aas4j.v3.model.OperationVariable; @@ -69,7 +67,6 @@ * */ public abstract class SubmodelRepositorySuite extends SubmodelServiceSuite { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(null, null); private static final String EMPTY_ID = " "; private static final String NULL_ID = null; private static final String ID = "testId"; @@ -87,20 +84,30 @@ public void getAllSubmodelsPreconfigured() { Collection expectedSubmodels = DummySubmodelFactory.getSubmodels(); SubmodelRepository repo = getSubmodelRepository(expectedSubmodels); - Collection submodels = repo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult(); + Collection submodels = repo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult(); + + assertSubmodelsAreContained(expectedSubmodels, submodels); + } + + @Test + public void getAllSubmodelsBySemanticIDPreconfigured() { + Collection expectedSubmodels = DummySubmodelFactory.getSubmodelsBySemanticid(DummySubmodelFactory.SUBMODEL_TECHNICAL_DATA_SEMANTIC_ID); + + SubmodelRepository repo = getSubmodelRepository(expectedSubmodels); + Collection submodels = repo.getAllSubmodels(DummySubmodelFactory.SUBMODEL_TECHNICAL_DATA_SEMANTIC_ID, PaginationInfo.NO_LIMIT).getResult(); assertSubmodelsAreContained(expectedSubmodels, submodels); } private void assertSubmodelsAreContained(Collection expectedSubmodels, Collection submodels) { - assertEquals(3, submodels.size()); + assertEquals(expectedSubmodels.size(), submodels.size()); assertTrue(submodels.containsAll(expectedSubmodels)); } @Test public void getAllSubmodelsEmpty() { SubmodelRepository repo = getSubmodelRepository(); - Collection submodels = repo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult(); + Collection submodels = repo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult(); assertIsEmpty(submodels); } @@ -214,7 +221,7 @@ public void deleteNonExistingSubmodel() { @Test(expected = ElementDoesNotExistException.class) public void getSubmodelElementsOfNonExistingSubmodel() { SubmodelRepository repo = getSubmodelRepositoryWithDummySubmodels(); - repo.getSubmodelElements("notExisting", NO_LIMIT_PAGINATION_INFO).getResult(); + repo.getSubmodelElements("notExisting", PaginationInfo.NO_LIMIT).getResult(); } @Test(expected = ElementDoesNotExistException.class) diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/authorization/AuthorizedSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/authorization/AuthorizedSubmodelRepository.java index e75bc4a2b..2b94ecaac 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/authorization/AuthorizedSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-authorization/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/authorization/AuthorizedSubmodelRepository.java @@ -72,6 +72,15 @@ public CursorResult> getAllSubmodels(PaginationInfo pInfo) { return decorated.getAllSubmodels(pInfo); } + + @Override + public CursorResult> getAllSubmodels(String semanticId, PaginationInfo pInfo) { + boolean isAuthorized = permissionResolver.hasPermission(Action.READ, new SubmodelTargetInformation(getIdAsList(ALL_ALLOWED_WILDCARD), getIdAsList(ALL_ALLOWED_WILDCARD))); + + throwExceptionIfInsufficientPermission(isAuthorized); + + return decorated.getAllSubmodels(semanticId, pInfo); + } @Override public Submodel getSubmodel(String submodelId) throws ElementDoesNotExistException { diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java index c5b0a5f8f..86d11bc29 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-mqtt/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/mqtt/MqttSubmodelRepository.java @@ -45,6 +45,11 @@ public MqttSubmodelRepository(SubmodelRepository decorated, IMqttClient mqttClie public CursorResult> getAllSubmodels(PaginationInfo pInfo) { return decorated.getAllSubmodels(pInfo); } + + @Override + public CursorResult> getAllSubmodels(String semanticId, PaginationInfo pInfo) { + return decorated.getAllSubmodels(semanticId, pInfo); + } @Override public Submodel getSubmodel(String submodelId) throws ElementDoesNotExistException { diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/OperationDelegationSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/OperationDelegationSubmodelRepository.java index 6404475cb..457fa6c19 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/OperationDelegationSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/OperationDelegationSubmodelRepository.java @@ -65,6 +65,11 @@ public OperationDelegationSubmodelRepository(SubmodelRepository decorated, Opera public CursorResult> getAllSubmodels(PaginationInfo pInfo) { return decorated.getAllSubmodels(pInfo); } + + @Override + public CursorResult> getAllSubmodels(String semanticId, PaginationInfo pInfo) { + return decorated.getAllSubmodels(semanticId, pInfo); + } @Override public Submodel getSubmodel(String submodelId) throws ElementDoesNotExistException { diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/TestOperationDelegationFeature.java b/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/TestOperationDelegationFeature.java index 1aa094112..cd10be43b 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/TestOperationDelegationFeature.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-operation-delegation/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/operation/delegation/TestOperationDelegationFeature.java @@ -75,7 +75,6 @@ */ public class TestOperationDelegationFeature { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static SubmodelRepository submodelRepository; private static HTTPMockServer httpMockServer = new HTTPMockServer(2020); private static WebClient webClient; @@ -104,7 +103,7 @@ public void reset() { if (submodelRepository == null) return; - submodelRepository.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult().stream().forEach(sm -> submodelRepository.deleteSubmodel(sm.getId())); + submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().stream().forEach(sm -> submodelRepository.deleteSubmodel(sm.getId())); } @Test diff --git a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepository.java b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepository.java index 071c0e8e1..57760d07c 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepository.java +++ b/basyx.submodelrepository/basyx.submodelrepository-feature-registry-integration/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/feature/registry/integration/RegistryIntegrationSubmodelRepository.java @@ -73,6 +73,11 @@ public RegistryIntegrationSubmodelRepository(SubmodelRepository decorated, Submo public CursorResult> getAllSubmodels(PaginationInfo paginationInfo) { return decorated.getAllSubmodels(paginationInfo); } + + @Override + public CursorResult> getAllSubmodels(String semanticId, PaginationInfo paginationInfo) { + return decorated.getAllSubmodels(semanticId, paginationInfo); + } @Override public Submodel getSubmodel(String submodelId) throws ElementDoesNotExistException { diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java index 2fb171111..645486669 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositoryApiHTTPController.java @@ -44,6 +44,7 @@ import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifierSize; +import org.eclipse.digitaltwin.basyx.http.Base64UrlEncoder; import org.eclipse.digitaltwin.basyx.http.pagination.Base64UrlEncodedCursor; import org.eclipse.digitaltwin.basyx.http.pagination.PagedResult; import org.eclipse.digitaltwin.basyx.http.pagination.PagedResultPagingMetadata; @@ -116,7 +117,12 @@ public ResponseEntity getAllSubmodels(@Base64UrlEncodedIdentifierSi PaginationInfo pInfo = new PaginationInfo(limit, decodedCursor); - CursorResult> cursorResult = repository.getAllSubmodels(pInfo); + CursorResult> cursorResult; + if (semanticId != null) { + cursorResult = repository.getAllSubmodels(semanticId.getIdentifier(), pInfo); + } else { + cursorResult = repository.getAllSubmodels(pInfo); + } GetSubmodelsResult paginatedSubmodel = new GetSubmodelsResult(); diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java index 019f099a8..a00b76091 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/SubmodelRepositorySubmodelHTTPTestSuite.java @@ -97,6 +97,18 @@ public void getAllSubmodelsPreconfigured() throws IOException, ParseException { BaSyxHttpTestUtils.assertSameJSONContent(expectedSubmodelsJSON,getJSONWithoutCursorInfo(submodelsJSON)); } + + @Test + public void getAllSubmodelsBySemanticIDPreconfigured() throws IOException, ParseException { + String semanticId = Base64UrlEncodedIdentifier.encodeIdentifier(DummySubmodelFactory.SUBMODEL_TECHNICAL_DATA_SEMANTIC_ID); + String url = getURL() + "?semanticId=" + semanticId; + + String submodelsJSON = BaSyxSubmodelHttpTestUtils.requestAllSubmodels(url); + + String expectedSubmodelsJSON = getJSONValueAsString("MultipleSubmodelsWithSameSemanticId.json"); + + BaSyxHttpTestUtils.assertSameJSONContent(expectedSubmodelsJSON,getJSONWithoutCursorInfo(submodelsJSON)); + } @Test public void getSpecificSubmodel() throws ParseException, IOException { diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelElementsHTTP.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelElementsHTTP.java index 9fff6f6de..ce18a4a70 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelElementsHTTP.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelElementsHTTP.java @@ -43,7 +43,6 @@ * */ public class TestSubmodelRepositorySubmodelElementsHTTP extends SubmodelServiceSubmodelElementsTestSuiteHTTP { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static ConfigurableApplicationContext appContext; @BeforeClass @@ -60,7 +59,7 @@ public void createSubmodelOnRepo() { @After public void removeSubmodelFromRepo() { SubmodelRepository repo = appContext.getBean(SubmodelRepository.class); - repo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); + repo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); } @AfterClass diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelHTTP.java b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelHTTP.java index 57132baec..f050e82de 100644 --- a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelHTTP.java +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/java/org/eclipse/digitaltwin/basyx/submodelrepository/http/TestSubmodelRepositorySubmodelHTTP.java @@ -42,7 +42,6 @@ * */ public class TestSubmodelRepositorySubmodelHTTP extends SubmodelRepositorySubmodelHTTPTestSuite { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private static ConfigurableApplicationContext appContext; @BeforeClass @@ -53,7 +52,7 @@ public static void startAASRepo() throws Exception { @Override public void resetRepository() { SubmodelRepository repo = appContext.getBean(SubmodelRepository.class); - repo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); + repo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); } @Override diff --git a/basyx.submodelrepository/basyx.submodelrepository-http/src/test/resources/MultipleSubmodelsWithSameSemanticId.json b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/resources/MultipleSubmodelsWithSameSemanticId.json new file mode 100644 index 000000000..e41361c39 --- /dev/null +++ b/basyx.submodelrepository/basyx.submodelrepository-http/src/test/resources/MultipleSubmodelsWithSameSemanticId.json @@ -0,0 +1,454 @@ +{ + "paging_metadata": {}, + "result": [ + { + "modelType": "Submodel", + "id": "7A7104BDAB57E184", + "kind":"Instance", + "idShort": "TechnicalData", + "submodelElements": [ + { + "modelType": "Property", + "value": "5000", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "MaxRotationSpeed", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Range", + "max": "300", + "min": "200", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "RotationSpeedRange", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "MultiLanguageProperty", + "category": "PARAM", + "idShort": "MultiLanguage", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + }, + "value": [ + { + "language": "en", + "text": "Hello" + }, + { + "language": "de", + "text": "Hallo" + } + ] + }, + { + "modelType": "File", + "contentType": "application/json", + "value": "testFile.json", + "category": "PARAMETER", + "idShort": "FileData", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Entity", + "entityType": "CoManagedEntity", + "specificAssetIds": [ + { + "name": "specificAssetIdName", + "value": "specificValue" + } + ], + "statements": [ + { + "modelType": "Property", + "value": "5000", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "MaxRotationSpeed", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Range", + "max": "300", + "min": "200", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "RotationSpeedRange", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + } + ], + "category": "Entity", + "idShort": "EntityData", + "globalAssetId": "globalAssetID", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "ReferenceElement", + "category": "PARAMETER", + "idShort": "ReferenceElement", + "value": { + "keys": [ + { + "type": "DataElement", + "value": "DataElement" + } + ], + "type": "ModelReference" + }, + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "RelationshipElement", + "category": "PARAMETER", + "idShort": "RelationshipElement", + "first": { + "keys": [ + { + "type": "DataElement", + "value": "DataElement" + } + ], + "type": "ModelReference" + }, + "second": { + "keys": [ + { + "type": "BasicEventElement", + "value": "BasicEventElement" + } + ], + "type": "ExternalReference" + }, + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "AnnotatedRelationshipElement", + "category": "PARAMETER", + "idShort": "AnnotatedRelationshipElement", + "first": { + "keys": [ + { + "type": "DataElement", + "value": "DataElement" + } + ], + "type": "ModelReference" + }, + "second": { + "keys": [ + { + "type": "BasicEventElement", + "value": "BasicEventElement" + } + ], + "type": "ExternalReference" + }, + "annotations": [ + { + "modelType": "Property", + "value": "5000", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "MaxRotationSpeed", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Range", + "max": "300", + "min": "200", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "RotationSpeedRange", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + } + ], + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Blob", + "contentType": "application/xml", + "value": "VGVzdCBjb250ZW50IG9mIFhNTCBmaWxl", + "category": "PARAMETER", + "idShort": "BlobData", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "SubmodelElementCollection", + "category": "PARAMETER", + "idShort": "SubmodelElementCollection", + "value": [ + { + "modelType": "File", + "contentType": "application/json", + "value": "testFile.json", + "category": "PARAMETER", + "idShort": "FileData", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Property", + "value": "5000", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "MaxRotationSpeed", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + } + ], + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "SubmodelElementList", + "category": "PARAMETER", + "idShort": "SubmodelElementList", + "orderRelevant": true, + "value": [ + { + "modelType": "Range", + "max": "300", + "min": "200", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "RotationSpeedRange", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Property", + "value": "5000", + "valueType": "xs:integer", + "category": "PARAMETER", + "idShort": "MaxRotationSpeed", + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + } + ], + "semanticId": { + "keys": [ + { + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + } + }, + { + "modelType": "Operation", + "idShort": "square", + "inputVariables": [ + { + "value": { + "modelType": "Property", + "valueType": "xs:int", + "idShort": "input" + } + } + ], + "outputVariables": [ + { + "value": { + "modelType": "Property", + "valueType": "xs:int", + "idShort": "result" + } + } + ] + } + ], + "semanticId": { + "keys": [ + { + "type": "GlobalReference", + "value": "0173-1#01-AFZ615#016" + } + ], + "type": "ExternalReference" + } + }, + { + "id": "8A6344BDAB57E184", + "idShort": "FileTests", + "modelType": "Submodel", + "kind":"Instance", + "semanticId": { + "keys": [{ + "type": "GlobalReference", + "value": "0173-1#01-AFZ615#016" + } + ], + "type": "ExternalReference" + }, + "submodelElements": [{ + "category": "PARAMETER", + "contentType": "application/json", + "idShort": "FileData", + "modelType": "File", + "semanticId": { + "keys": [{ + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + }, + "value": "BaSyx-Logo.png" + }, { + "category": "PARAMETER", + "idShort": "NonFileParameter", + "modelType": "Property", + "semanticId": { + "keys": [{ + "type": "ConceptDescription", + "value": "0173-1#02-BAA120#008" + } + ], + "type": "ExternalReference" + }, + "value": "5000", + "valueType": "xs:integer" + } + ] + } + ] +} \ No newline at end of file diff --git a/basyx.submodelservice/basyx.submodelservice-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/client/TestConnectedSubmodelService.java b/basyx.submodelservice/basyx.submodelservice-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/client/TestConnectedSubmodelService.java index a6cda20f4..a285c0e54 100644 --- a/basyx.submodelservice/basyx.submodelservice-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/client/TestConnectedSubmodelService.java +++ b/basyx.submodelservice/basyx.submodelservice-client/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/client/TestConnectedSubmodelService.java @@ -27,6 +27,7 @@ package org.eclipse.digitaltwin.basyx.submodelservice.client; import org.eclipse.digitaltwin.aas4j.v3.model.Submodel; +import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo; import org.eclipse.digitaltwin.basyx.http.Base64UrlEncodedIdentifier; import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository; import org.eclipse.digitaltwin.basyx.submodelrepository.http.DummySubmodelRepositoryComponent; @@ -63,7 +64,7 @@ public static void shutdownSubmodelService() { @After public void removeSubmodelFromRepo() { SubmodelRepository repo = appContext.getBean(SubmodelRepository.class); - repo.getAllSubmodels(NO_LIMIT_PAGINATION_INFO).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); + repo.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().stream().map(s -> s.getId()).forEach(repo::deleteSubmodel); } @Override diff --git a/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/DummySubmodelFactory.java b/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/DummySubmodelFactory.java index f8696fc9f..a6086000d 100644 --- a/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/DummySubmodelFactory.java +++ b/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/DummySubmodelFactory.java @@ -110,6 +110,19 @@ public class DummySubmodelFactory { public static Collection getSubmodels() { return Lists.newArrayList(createTechnicalDataSubmodel(), createOperationalDataSubmodel(), createSimpleDataSubmodel()); } + + public static Collection getSubmodelsBySemanticid(String semanticId) { + Collection submodels = Lists.newArrayList(createTechnicalDataSubmodel(), createOperationalDataSubmodel(), createSimpleDataSubmodel()); + + return submodels.stream() + .filter((submodel) -> { + return submodel.getSemanticId() != null && + submodel.getSemanticId().getKeys().stream().filter((key) -> { + return key.getValue().equals(semanticId); + }).findAny().isPresent(); + }) + .collect(Collectors.toList()); + } public static Submodel createSubmodelWithAllSubmodelElements() { List submodelElements = getAllSubmodelElementsList(); diff --git a/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java b/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java index e3f1e43b6..94820e893 100644 --- a/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java +++ b/basyx.submodelservice/basyx.submodelservice-core/src/test/java/org/eclipse/digitaltwin/basyx/submodelservice/SubmodelServiceSuite.java @@ -78,8 +78,6 @@ * */ public abstract class SubmodelServiceSuite { - protected static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(null, null); - protected abstract SubmodelService getSubmodelService(Submodel submodel); /** @@ -107,7 +105,7 @@ public void getSubmodelElements() { Submodel technicalData = DummySubmodelFactory.createTechnicalDataSubmodel(); SubmodelService smService = getSubmodelService(technicalData); - assertTrue(technicalData.getSubmodelElements().containsAll(smService.getSubmodelElements(NO_LIMIT_PAGINATION_INFO).getResult())); + assertTrue(technicalData.getSubmodelElements().containsAll(smService.getSubmodelElements(PaginationInfo.NO_LIMIT).getResult())); } @Test diff --git a/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java b/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java index 7248c6904..6c755e332 100644 --- a/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java +++ b/basyx.submodelservice/basyx.submodelservice-http/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/http/SubmodelServiceHTTPApiController.java @@ -70,7 +70,6 @@ @RestController public class SubmodelServiceHTTPApiController implements SubmodelServiceHTTPApi { - private static final PaginationInfo NO_LIMIT_PAGINATION_INFO = new PaginationInfo(0, null); private SubmodelService service; @Autowired @@ -177,7 +176,7 @@ public ResponseEntity getSubmodelValueOnly( @Parameter(in = ParameterIn.QUERY, description = "Determines to which extent the resource is being serialized", schema = @Schema(allowableValues = { "withBlobValue", "withoutBlobValue" }, defaultValue = "withoutBlobValue")) @Valid @RequestParam(value = "extent", required = false, defaultValue = "withoutBlobValue") String extent) { - SubmodelValueOnly result = new SubmodelValueOnly(service.getSubmodelElements(NO_LIMIT_PAGINATION_INFO).getResult()); + SubmodelValueOnly result = new SubmodelValueOnly(service.getSubmodelElements(PaginationInfo.NO_LIMIT).getResult()); return new ResponseEntity(result, HttpStatus.OK); } diff --git a/examples/BaSyxClient/basyx-client/Dockerfile b/examples/BaSyxClient/basyx-client/Dockerfile index f3d9eb42e..d1c6edeb9 100644 --- a/examples/BaSyxClient/basyx-client/Dockerfile +++ b/examples/BaSyxClient/basyx-client/Dockerfile @@ -1,12 +1,10 @@ FROM maven:3.8.1-openjdk-17 AS build WORKDIR /app COPY pom.xml . -RUN mvn dependency:go-offline COPY src src RUN mvn clean package -DskipTests FROM openjdk:17 WORKDIR /app -COPY --from=build /app/target/*.jar app.jar -EXPOSE 8080 +COPY --from=build /app/target/*-jar-with-dependencies.jar app.jar ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/examples/BaSyxClient/basyx-client/pom.xml b/examples/BaSyxClient/basyx-client/pom.xml index 4cb2981a4..ffbc422fe 100644 --- a/examples/BaSyxClient/basyx-client/pom.xml +++ b/examples/BaSyxClient/basyx-client/pom.xml @@ -3,48 +3,16 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.2.4 - - org.eclipse.digitaltwin.basyx example-basyx-client 0.0.1-SNAPSHOT examples.basyxclient BaSyx Client Example - 17 - 1.0.2 + 17 + 17 - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - org.eclipse.digitaltwin.aas4j - aas4j-model - ${aas4j-version} - - - org.slf4j - slf4j-simple - - - org.eclipse.digitaltwin.basyx @@ -62,10 +30,28 @@ - org.springframework.boot - spring-boot-maven-plugin + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + + + + org.eclipse.digitaltwin.basyx.examples.basyxclient.Application + + + - - + + \ No newline at end of file diff --git a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/Application.java b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/Application.java index df7433b75..0d3f06281 100644 --- a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/Application.java +++ b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/Application.java @@ -25,16 +25,12 @@ package org.eclipse.digitaltwin.basyx.examples.basyxclient; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; -import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; - -@SpringBootApplication(exclude = { MongoAutoConfiguration.class, MongoDataAutoConfiguration.class }) +import java.nio.file.Path; public class Application { + static final Path DIR_TO_WATCH = Path.of("/ingest"); public static void main(String[] args) { - SpringApplication.run(Application.class, args); + new Thread(DirectoryWatcherFactory.build(DIR_TO_WATCH)).start(); } } diff --git a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/DirectoryWatcherFactory.java b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/DirectoryWatcherFactory.java new file mode 100644 index 000000000..618449bb3 --- /dev/null +++ b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/DirectoryWatcherFactory.java @@ -0,0 +1,45 @@ +package org.eclipse.digitaltwin.basyx.examples.basyxclient; + +import java.nio.file.Path; +import java.util.List; + +import org.eclipse.digitaltwin.basyx.aasenvironment.client.ConnectedAasManager; +import org.eclipse.digitaltwin.basyx.examples.basyxclient.configuration.BasyxSettings; +import org.eclipse.digitaltwin.basyx.examples.basyxclient.processing.BaSyxSyncService; +import org.eclipse.digitaltwin.basyx.examples.basyxclient.processing.BaSyxWarehouseService; +import org.eclipse.digitaltwin.basyx.examples.basyxclient.processing.DirectoryWatcher; +import org.eclipse.digitaltwin.basyx.examples.basyxclient.processing.EntryProcessor; + +public final class DirectoryWatcherFactory { + + private DirectoryWatcherFactory() { + } + + public static DirectoryWatcher build(Path pathToWatch) { + BasyxSettings settings = buildBasyxSettingsFromEnv(); + ConnectedAasManager connectedAasManager = buildConnectedAasManager(settings); + List entryProcessors = buildEntryProcessors(connectedAasManager); + + return new DirectoryWatcher(entryProcessors, pathToWatch); + } + + static BasyxSettings buildBasyxSettingsFromEnv() { + String aasRegistryBaseUrl = System.getenv("AAS_REGISTRY_BASE_URL"); + String aasRepositoryBaseUrl = System.getenv("AAS_REPOSITORY_BASE_URL"); + String submodelRegistryBaseUrl = System.getenv("SUBMODEL_REGISTRY_BASE_URL"); + String submodelRepositoryBaseUrl = System.getenv("SUBMODEL_REPOSITORY_BASE_URL"); + + return new BasyxSettings(aasRepositoryBaseUrl, submodelRepositoryBaseUrl, aasRegistryBaseUrl, submodelRegistryBaseUrl); + } + + static ConnectedAasManager buildConnectedAasManager(BasyxSettings settings) { + return new ConnectedAasManager(settings.aasRegistryBaseUrl(), settings.aasRepositoryBaseUrl(), settings.submodelRegistryBaseUrl(), settings.submodelRepositoryBaseUrl()); + } + + static List buildEntryProcessors(ConnectedAasManager connectedAasManager) { + BaSyxSyncService syncService = new BaSyxSyncService(connectedAasManager); + BaSyxWarehouseService warehouseService = new BaSyxWarehouseService(connectedAasManager); + + return List.of(syncService, warehouseService); + } +} diff --git a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/configuration/BasyxConfiguration.java b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/configuration/BasyxConfiguration.java deleted file mode 100644 index 56964f6dc..000000000 --- a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/configuration/BasyxConfiguration.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * 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.examples.basyxclient.configuration; - -import org.eclipse.digitaltwin.basyx.aasenvironment.client.ConnectedAasManager; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableConfigurationProperties({ BasyxSettings.class }) -public class BasyxConfiguration { - @Bean - public ConnectedAasManager getConnectedAasManager(BasyxSettings settings) { - return new ConnectedAasManager(settings.aasRegistryBaseUrl(), settings.aasRepositoryBaseUrl(), settings.submodelRegistryBaseUrl(), settings.submodelRepositoryBaseUrl()); - } -} diff --git a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/configuration/BasyxSettings.java b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/configuration/BasyxSettings.java index 42cdc09d0..ba4f26cb3 100644 --- a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/configuration/BasyxSettings.java +++ b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/configuration/BasyxSettings.java @@ -25,8 +25,5 @@ package org.eclipse.digitaltwin.basyx.examples.basyxclient.configuration; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "basyx") public record BasyxSettings(String aasRepositoryBaseUrl, String submodelRepositoryBaseUrl, String aasRegistryBaseUrl, String submodelRegistryBaseUrl) { } \ No newline at end of file diff --git a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxSyncService.java b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxSyncService.java index 696dc346e..b4b4b58f1 100644 --- a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxSyncService.java +++ b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxSyncService.java @@ -35,9 +35,7 @@ import org.eclipse.digitaltwin.basyx.submodelservice.client.ConnectedSubmodelService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -@Service public class BaSyxSyncService implements EntryProcessor { private final Logger logger = LoggerFactory.getLogger(BaSyxSyncService.class); diff --git a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxWarehouseService.java b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxWarehouseService.java index b14bf528d..9baad52c0 100644 --- a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxWarehouseService.java +++ b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/BaSyxWarehouseService.java @@ -44,9 +44,7 @@ import org.eclipse.digitaltwin.basyx.submodelservice.client.ConnectedSubmodelService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -@Service public class BaSyxWarehouseService implements EntryProcessor { private final Logger logger = LoggerFactory.getLogger(BaSyxWarehouseService.class); diff --git a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/DirectoryWatcher.java b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/DirectoryWatcher.java index a3ebb6b2a..dd98695e4 100644 --- a/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/DirectoryWatcher.java +++ b/examples/BaSyxClient/basyx-client/src/main/java/org/eclipse/digitaltwin/basyx/examples/basyxclient/processing/DirectoryWatcher.java @@ -39,14 +39,10 @@ import org.eclipse.digitaltwin.basyx.examples.basyxclient.model.MotorEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Component; import com.opencsv.bean.CsvToBeanBuilder; -@Component -public class DirectoryWatcher implements CommandLineRunner { +public class DirectoryWatcher implements Runnable { private final Logger logger = LoggerFactory.getLogger(DirectoryWatcher.class); @@ -54,14 +50,19 @@ public class DirectoryWatcher implements CommandLineRunner { private final Path dirToWatch; - public DirectoryWatcher(List entryProcessors, @Value("${erp.internal.watchpath:/ingest}") Path dirToWatch) { + public DirectoryWatcher(List entryProcessors, Path dirToWatch) { this.entryProcessors = entryProcessors; this.dirToWatch = dirToWatch; } @Override - public void run(String... args) throws Exception { - watchDirectory(dirToWatch); + public void run() { + try { + watchDirectory(dirToWatch); + } catch (IOException | InterruptedException e) { + logger.error("Error watching directory", e); + Thread.currentThread().interrupt(); + } } public void watchDirectory(Path dirToWatch) throws IOException, InterruptedException { @@ -113,4 +114,5 @@ private void processAllEntries(List entries) { } } + } diff --git a/examples/BaSyxClient/config/basyx-client.env b/examples/BaSyxClient/config/basyx-client.env new file mode 100644 index 000000000..1225b9b38 --- /dev/null +++ b/examples/BaSyxClient/config/basyx-client.env @@ -0,0 +1,4 @@ +AAS_REGISTRY_BASE_URL=http://localhost:8082 +SUBMODEL_REGISTRY_BASE_URL=http://localhost:8083 +AAS_REPOSITORY_BASE_URL=http://localhost:8081 +SUBMODEL_REPOSITORY_BASE_URL=http://localhost:8081 \ No newline at end of file diff --git a/examples/BaSyxClient/config/basyx-client.properties b/examples/BaSyxClient/config/basyx-client.properties deleted file mode 100644 index 0baa55814..000000000 --- a/examples/BaSyxClient/config/basyx-client.properties +++ /dev/null @@ -1,4 +0,0 @@ -basyx.aasRegistryBaseUrl=http://localhost:8082 -basyx.submodelRegistryBaseUrl=http://localhost:8083 -basyx.aasRepositoryBaseUrl=http://localhost:8081 -basyx.submodelRepositoryBaseUrl=http://localhost:8081 \ No newline at end of file diff --git a/examples/BaSyxClient/docker-compose.yml b/examples/BaSyxClient/docker-compose.yml index 86f744f24..f44017df9 100644 --- a/examples/BaSyxClient/docker-compose.yml +++ b/examples/BaSyxClient/docker-compose.yml @@ -49,11 +49,9 @@ services: context: ./basyx-client dockerfile: Dockerfile container_name: basyx-client + env_file: ./config/basyx-client.env volumes: - - ./config/basyx-client.properties:/app/application.properties - ./ingest:/ingest - ports: - - '8087:8087' network_mode: host depends_on: aas-env: diff --git a/examples/BaSyxDatabridge/README.md b/examples/BaSyxDatabridge/README.md new file mode 100644 index 000000000..b73db0236 --- /dev/null +++ b/examples/BaSyxDatabridge/README.md @@ -0,0 +1,42 @@ +# BaSyx Databridge Example Setup + +This example showcases the usage of the BaSyx Databridge. The BaSyx Databridge is a service that allows the exchange of data between assets and the AAS. +Here, an example MQTT client for an environmental sensor is used to send data via the BaSyx Databridge to an AAS located in the BaSyx AAS Environment. + +## How to run the BaSyx Databridge Example + +1. Open a terminal in this folder +2. Run the following command to start the BaSyx containers: + +```bash +docker-compose up -d +``` + +> To run the example containers, you need to have Docker installed on your device. + +## View the working Example + +To see the working example, open the [BaSyx AAS Web UI](http://localhost:3000) and navigate to the `SensorExampleAAS`. You can see the data coming from the MQTT client in the `SensorData` submodel. +To see updates in real-time, active the `Auto-Sync` feature in the AAS Web UI (see top right corner of the UI). + +## Where to find the configuration + +### BaSyx Databridge + +The configuration for the BaSyx Databridge can be found in the `databridge` folder. There you can find the `routes.config` file, which defines the routes from the assets data source to the AAS data sink. +The data source configuration can be found in the `mqttconsumer.json` file, and the data sink configuration can be found in the `aasserver.json` file. +There are also data transformers defined for extracting the data from the MQTT message. +For more details on how to configure the BaSyx Databridge, please refer to the [BaSyx Databridge documentation](https://wiki.basyx.org/en/latest/content/user_documentation/basyx_components/databridge/index.html). + +### MQTT Client + +The configuration for the MQTT client can be found in the `mqtt-publisher` folder. It is a small Python script that publishes data to the MQTT broker. + +### MQTT Broker + +The MQTT brokers configuration can be found in the `mosquitto` folder. The configuration is defined in the `config/mosquitto.conf` file. + +### BaSyx Components + +The configuration for the BaSyx components can be found in the `basyx` folder. +The AAS used in this example is located in the `aas` folder. diff --git a/examples/BaSyxDatabridge/aas/SensorExampleComplete.aasx b/examples/BaSyxDatabridge/aas/SensorExampleComplete.aasx new file mode 100644 index 000000000..33e68fe50 Binary files /dev/null and b/examples/BaSyxDatabridge/aas/SensorExampleComplete.aasx differ diff --git a/examples/BaSyxDatabridge/basyx/aas-env.properties b/examples/BaSyxDatabridge/basyx/aas-env.properties new file mode 100644 index 000000000..3d3d08d9d --- /dev/null +++ b/examples/BaSyxDatabridge/basyx/aas-env.properties @@ -0,0 +1,8 @@ +server.port=8081 +basyx.backend=InMemory +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.submodelrepository.feature.registryintegration=http://sm-registry:8080 +basyx.externalurl=http://localhost:8081 diff --git a/examples/BaSyxDatabridge/basyx/aas-registry.yml b/examples/BaSyxDatabridge/basyx/aas-registry.yml new file mode 100644 index 000000000..4fac8db3a --- /dev/null +++ b/examples/BaSyxDatabridge/basyx/aas-registry.yml @@ -0,0 +1,4 @@ +basyx: + cors: + allowed-origins: '*' + allowed-methods: GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD diff --git a/examples/BaSyxDatabridge/basyx/sm-registry.yml b/examples/BaSyxDatabridge/basyx/sm-registry.yml new file mode 100644 index 000000000..4fac8db3a --- /dev/null +++ b/examples/BaSyxDatabridge/basyx/sm-registry.yml @@ -0,0 +1,4 @@ +basyx: + cors: + allowed-origins: '*' + allowed-methods: GET,POST,PATCH,DELETE,PUT,OPTIONS,HEAD diff --git a/examples/BaSyxDatabridge/databridge/AirQualityTransformer.jsonata b/examples/BaSyxDatabridge/databridge/AirQualityTransformer.jsonata new file mode 100644 index 000000000..af93b795f --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/AirQualityTransformer.jsonata @@ -0,0 +1 @@ +airQuality \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/HumidityTransformer.jsonata b/examples/BaSyxDatabridge/databridge/HumidityTransformer.jsonata new file mode 100644 index 000000000..6506bbd58 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/HumidityTransformer.jsonata @@ -0,0 +1 @@ +humidity \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/TemperatureTransformer.jsonata b/examples/BaSyxDatabridge/databridge/TemperatureTransformer.jsonata new file mode 100644 index 000000000..4d81bb0f8 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/TemperatureTransformer.jsonata @@ -0,0 +1 @@ +temperature \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/aasserver.json b/examples/BaSyxDatabridge/databridge/aasserver.json new file mode 100644 index 000000000..2d6509135 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/aasserver.json @@ -0,0 +1,20 @@ +[ + { + "uniqueId": "TemperatureAAS", + "submodelEndpoint": "http://host.docker.internal:8081/submodels/YjdlNTA2NzgtZGY3Mi00ODAxLWI3YzAtNzI2NTNkMmU0NzI0", + "idShortPath": "TemperatureValue", + "api": "DotAAS-V3" + }, + { + "uniqueId": "HumidityAAS", + "submodelEndpoint": "http://host.docker.internal:8081/submodels/YjdlNTA2NzgtZGY3Mi00ODAxLWI3YzAtNzI2NTNkMmU0NzI0", + "idShortPath": "HumidityValue", + "api": "DotAAS-V3" + }, + { + "uniqueId": "AirQualityAAS", + "submodelEndpoint": "http://host.docker.internal:8081/submodels/YjdlNTA2NzgtZGY3Mi00ODAxLWI3YzAtNzI2NTNkMmU0NzI0", + "idShortPath": "AirQualityValue", + "api": "DotAAS-V3" + } +] diff --git a/examples/BaSyxDatabridge/databridge/jsonatatransformer.json b/examples/BaSyxDatabridge/databridge/jsonatatransformer.json new file mode 100644 index 000000000..691253839 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/jsonatatransformer.json @@ -0,0 +1,20 @@ +[ + { + "uniqueId": "TemperatureTransformer", + "queryPath": "TemperatureTransformer.jsonata", + "inputType": "JsonString", + "outputType": "JsonString" + }, + { + "uniqueId": "HumidityTransformer", + "queryPath": "HumidityTransformer.jsonata", + "inputType": "JsonString", + "outputType": "JsonString" + }, + { + "uniqueId": "AirQualityTransformer", + "queryPath": "AirQualityTransformer.jsonata", + "inputType": "JsonString", + "outputType": "JsonString" + } +] \ No newline at end of file diff --git a/examples/BaSyxDatabridge/databridge/mqttconsumer.json b/examples/BaSyxDatabridge/databridge/mqttconsumer.json new file mode 100644 index 000000000..5a6f7c890 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/mqttconsumer.json @@ -0,0 +1,8 @@ +[ + { + "uniqueId": "EnvironmentalSensorMQTT", + "serverUrl": "mosquitto", + "serverPort": 1883, + "topic": "EnvironmentalSensor/CombinedData" + } +] diff --git a/examples/BaSyxDatabridge/databridge/routes.json b/examples/BaSyxDatabridge/databridge/routes.json new file mode 100644 index 000000000..887c84db5 --- /dev/null +++ b/examples/BaSyxDatabridge/databridge/routes.json @@ -0,0 +1,22 @@ +[ + { + "datasource": "EnvironmentalSensorMQTT", + "transformers": [ + "TemperatureTransformer", + "HumidityTransformer", + "AirQualityTransformer" + ], + "datasinks": [ + "TemperatureAAS", + "HumidityAAS", + "AirQualityAAS" + ], + "datasinkMappingConfiguration": + { + "TemperatureAAS": ["TemperatureTransformer"], + "HumidityAAS": ["HumidityTransformer"], + "AirQualityAAS": ["AirQualityTransformer"] + }, + "trigger": "event" + } +] diff --git a/examples/BaSyxDatabridge/docker-compose.yml b/examples/BaSyxDatabridge/docker-compose.yml new file mode 100644 index 000000000..01a180222 --- /dev/null +++ b/examples/BaSyxDatabridge/docker-compose.yml @@ -0,0 +1,89 @@ +services: + # AAS Environment + aas-env: + image: eclipsebasyx/aas-environment:2.0.0-SNAPSHOT + container_name: aas-env + volumes: + - ./aas:/application/aas + - ./basyx/aas-env.properties:/application/application.properties + ports: + - '8081:8081' + restart: always + depends_on: + aas-registry: + condition: service_healthy + sm-registry: + condition: service_healthy + + # AAS Registry + aas-registry: + image: eclipsebasyx/aas-registry-log-mem:2.0.0-SNAPSHOT + container_name: aas-registry + ports: + - '8082:8080' + volumes: + - ./basyx/aas-registry.yml:/workspace/config/application.yml + restart: always + + # Submodel Registry + sm-registry: + image: eclipsebasyx/submodel-registry-log-mem:2.0.0-SNAPSHOT + container_name: sm-registry + ports: + - '8083:8080' + volumes: + - ./basyx/sm-registry.yml:/workspace/config/application.yml + restart: always + + # AAS Web UI + aas-web-ui: + image: eclipsebasyx/aas-gui:v2-241006 + container_name: aas-ui + ports: + - '3000:3000' + environment: + AAS_REGISTRY_PATH: http://localhost:8082/shell-descriptors + SUBMODEL_REGISTRY_PATH: http://localhost:8083/submodel-descriptors + AAS_REPO_PATH: http://localhost:8081/shells + SUBMODEL_REPO_PATH: http://localhost:8081/submodels + CD_REPO_PATH: http://localhost:8081/concept-descriptions + restart: always + depends_on: + aas-env: + condition: service_healthy + + # MQTT Broker + mosquitto: + image: eclipse-mosquitto:2.0.15 + container_name: mosquitto + ports: + - 1883:1883 + volumes: + - ./mosquitto:/mosquitto + healthcheck: + test: ["CMD-SHELL", mosquitto_sub -p 1883 -t 'topic' -C 1 -E -i probe -W 3] + interval: 5s + retries: 3 + start_period: 1s + timeout: 10s + restart: always + + # MQTT Publisher (for testing) + mqtt-publisher: + build: ./mqtt-publisher + container_name: mqtt-publisher + depends_on: + - mosquitto + restart: always + + # DataBridge + databridge: + image: eclipsebasyx/databridge:1.0.0-SNAPSHOT + container_name: databridge + volumes: + - "./databridge:/usr/share/config" + depends_on: + - mosquitto + - aas-env + restart: always + diff --git a/examples/BaSyxDatabridge/mosquitto/config/mosquitto.conf b/examples/BaSyxDatabridge/mosquitto/config/mosquitto.conf new file mode 100644 index 000000000..d05bdebdb --- /dev/null +++ b/examples/BaSyxDatabridge/mosquitto/config/mosquitto.conf @@ -0,0 +1,23 @@ +# Default listener port for unencrypted connections (usually 1883) +listener 1883 0.0.0.0 + +# Path to the directory where persistence information is stored. +# Remove or comment out to disable persistence. +persistence true +persistence_location /mosquitto/data/ + +# Log settings +log_dest file /mosquitto/log/mosquitto.log +log_type all + +# Connection settings +# Setting for maximum concurrent connections. -1 means unlimited. +max_connections -1 + +# Security settings +# Uncomment and set these for enabling username-password authentication. +#allow_anonymous false +#password_file /mosquitto/config/mosquitto_passwd + +# Other settings like SSL/TLS, ACLs, etc., can also be configured as needed. +allow_anonymous true diff --git a/examples/BaSyxDatabridge/mqtt-publisher/Dockerfile b/examples/BaSyxDatabridge/mqtt-publisher/Dockerfile new file mode 100644 index 000000000..9883c13ca --- /dev/null +++ b/examples/BaSyxDatabridge/mqtt-publisher/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.8-slim + +RUN pip install paho-mqtt + +COPY publisher.py /publisher.py + +CMD ["python", "/publisher.py"] \ No newline at end of file diff --git a/examples/BaSyxDatabridge/mqtt-publisher/publisher.py b/examples/BaSyxDatabridge/mqtt-publisher/publisher.py new file mode 100644 index 000000000..9a56afbd5 --- /dev/null +++ b/examples/BaSyxDatabridge/mqtt-publisher/publisher.py @@ -0,0 +1,47 @@ +import time +import random +import json +import paho.mqtt.client as mqtt + +# MQTT settings +broker_address = "mosquitto" +port = 1883 +base_topic = "EnvironmentalSensor/" + +# Connect to MQTT Broker +client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, "Client") +client.connect(broker_address, port) + +# Start the network loop in a separate thread +client.loop_start() + +try: + + while True: + # Generate different types of dynamic data + temperatureValue = random.uniform(0, 30) + humidityValue = random.uniform(0.0, 100.0) + airQualityValue = random.uniform(0.0, 1000.0) + + # Create a dictionary with all values + data = { + "temperature": temperatureValue, + "humidity": humidityValue, + "airQuality": airQualityValue + } + + # Convert the dictionary to a JSON string + json_data = json.dumps(data) + + # Publish dynamic data to respective subtopics + client.publish(base_topic + "Temperature", temperatureValue) + client.publish(base_topic + "Humidity", humidityValue) + client.publish(base_topic + "AirQuality", airQualityValue) + client.publish(base_topic + "CombinedData", json_data) + + # Wait for a short period before publishing the next set of values + time.sleep(1) +except KeyboardInterrupt: + # Stop the network loop if the script is interrupted + client.loop_stop() + client.disconnect() diff --git a/examples/README.md b/examples/README.md index fbd8a6274..a9d44aa1b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,4 +14,7 @@ See the separate [Time Series example](https://github.com/eclipse-basyx/basyx-ap See the separate [Operation Delegation Example](BaSyxOperationDelegation) for a comprehensive setup leveraging Operation Delegation. ## BaSyx Secure Setup Example -See the separate [Secure Setup Example](BaSyxSecured) for a comprehensive setup leveraging Keycloak. \ No newline at end of file +See the separate [Secure Setup Example](BaSyxSecured) for a comprehensive setup leveraging Keycloak. + +## BaSyx Client Example +See the separate [Client Example](BaSyxClient) for a comprehensive setup leveraging the BaSyx Java Client library. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 079e995d4..7ece3f8bb 100644 --- a/pom.xml +++ b/pom.xml @@ -448,6 +448,11 @@ basyx.filerepository-backend-mongodb ${revision} + + org.eclipse.digitaltwin.basyx + basyx.backend.inmemory.core + ${revision} + org.eclipse.digitaltwin.basyx