Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1130547
test: extract test suite from aasmanagermultithreading test
MateusMolina Dec 3, 2024
5faa294
test: add failing test for aasenv multithreading mongoDB
MateusMolina Dec 4, 2024
485639f
refactor: experimental change of the design of the AasBackend + CrudA…
MateusMolina Dec 5, 2024
36fadb7
refactor: replace AasService dep in AasRespository through Repository…
MateusMolina Dec 10, 2024
26b7c3f
feat: implement SmRef methods of the MongoDB AasServiceBackend
MateusMolina Jan 23, 2025
f714b12
style: add license header
MateusMolina Jan 23, 2025
a552039
refactor: introduce method to inject a generic fragment -- indep. of …
MateusMolina Jan 24, 2025
68dc94b
feat: implement InMemoryAasBackend based on AasService
MateusMolina Jan 24, 2025
40246d1
refactor: rename AasServiceBackend to AasServiceOperations
MateusMolina Jan 24, 2025
40c7a5b
refactor: rename AasBackend to AasRepositoryBackend
MateusMolina Jan 24, 2025
0aff443
test: fix failing tests due to InMemoryAasBackend change
MateusMolina Jan 27, 2025
bf0abca
refactor: improve name consistency
MateusMolina Jan 27, 2025
0a80805
refactor: rename SimpleAasRepositoryFactory to CrudAasRepositoryFactory
MateusMolina Jan 27, 2025
6f85db7
refactor: modify CrudAasRepositoryFactory constructor
MateusMolina Jan 27, 2025
33dd27c
feat: implement remaining methods from MongoDBAasServiceOperations
MateusMolina Jan 30, 2025
bd335b2
fix: fix exception handling in MongoDbAasServiceOperations
MateusMolina Jan 30, 2025
c367a8d
fix: remaining tests affected by the arch refactor
MateusMolina Jan 30, 2025
2f6dbd3
fix: add configuration to registryintegration test
MateusMolina Jan 30, 2025
b659e26
test: limit configuration to registryintegration tests
MateusMolina Jan 30, 2025
dc45f5b
refactor: move AasServiceOperation to aasservice
MateusMolina Jan 31, 2025
8a8bc96
feat: add repository fragment configuration postProcessor
MateusMolina Jan 31, 2025
a9fe1a8
refactor: remove qualifier from aasServiceOperations bean
MateusMolina Jan 31, 2025
5539859
fix: fix InMemory backend not working
MateusMolina Jan 31, 2025
02a662e
refactor: move MongoDBAasServiceOperations to aasservice-backend-mongodb
MateusMolina Jan 31, 2025
4fdfa20
docs: improve brief of AasRepositoryFragmentConfig
MateusMolina Feb 3, 2025
1bc6099
refactor: extract filehandling logic from service to util
MateusMolina Feb 3, 2025
2597dff
optimize: reduce number of queries when using aasServiceOperations by…
MateusMolina Feb 3, 2025
4b8e343
refactor: simplify MongoDBAasServiceOps collectionName injection
MateusMolina Feb 3, 2025
95e31b6
docs: bump license header year; add missing license headers
MateusMolina Feb 3, 2025
0711f95
Merge branch 'main' of github.com:mateusmolina-iese/basyx-java-server…
MateusMolina Feb 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*******************************************************************************
* Copyright (C) 2025 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.aasenvironment.client;

import static org.junit.Assert.*;

import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.IntStream;

import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.Key;
import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.junit.Test;

public abstract class ConnectedAasManagerMultithreadingTestSuite {
static final int N_THREADS = 20;

protected abstract AasRepository getAasRepository();

protected abstract ConnectedAasManager getConnectedAasManager();

@Test
public void testParallelSubmodelCreation() throws ExecutionException, InterruptedException {
AssetAdministrationShell shell = createShell();

ExecutorService executorService = Executors.newFixedThreadPool(N_THREADS);
ConcurrentLinkedDeque<String> createdSubmodelIds = new ConcurrentLinkedDeque<>();

List<Future<Boolean>> futures = IntStream.range(0, N_THREADS).mapToObj(i -> executorService.submit(() -> createdSubmodelIds.add(createSubmodel(shell.getId(), i)))).toList();

try {
for (int i = 0; i < N_THREADS; i++) {
futures.get(i).get();
}
} finally {
executorService.shutdown();
}

createdSubmodelIds.forEach(submodelId -> assertSubmodelWasCreatedAndRegistered(shell.getId(), submodelId));
}

void assertSubmodelWasCreatedAndRegistered(String shellId, String submodelId) {
assertEquals("No submodel with id " + submodelId + " found by the client", submodelId, getConnectedAasManager().getSubmodelService(submodelId).getSubmodel().getId());
assertTrue("SubmodelRef " + submodelId + " not found in shell " + shellId,
getAasRepository().getSubmodelReferences(shellId, PaginationInfo.NO_LIMIT).getResult().stream().map(Reference::getKeys).flatMap(Collection::stream).map(Key::getValue).anyMatch(submodelId::equals));
}

private AssetAdministrationShell createShell() {
String id = UUID.randomUUID().toString();
DefaultAssetAdministrationShell shell = new DefaultAssetAdministrationShell.Builder().id(id).build();
getConnectedAasManager().createAas(shell);
return getConnectedAasManager().getAasService(id).getAAS();
}

private String createSubmodel(String aasId, int threadId) {
try {
String id = aasId + "-thread" + threadId;
DefaultSubmodel submodel = new DefaultSubmodel.Builder().id(id).build();
getConnectedAasManager().createSubmodelInAas(aasId, submodel);
return id;
} catch (Exception e) {
throw new RuntimeException("Failed at thread " + threadId, e);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2024 the Eclipse BaSyx Authors
* Copyright (C) 2025 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
Expand All @@ -25,60 +25,33 @@

package org.eclipse.digitaltwin.basyx.aasenvironment.client;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.IntStream;

import org.eclipse.digitaltwin.aas4j.v3.model.AssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.Key;
import org.eclipse.digitaltwin.aas4j.v3.model.Reference;
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultAssetAdministrationShell;
import org.eclipse.digitaltwin.aas4j.v3.model.impl.DefaultSubmodel;
import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.client.ConnectedAasRepository;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi;
import org.eclipse.digitaltwin.basyx.submodelrepository.SubmodelRepository;
import org.eclipse.digitaltwin.basyx.submodelrepository.client.ConnectedSubmodelRepository;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;

public class TestConnectedAasManagerMultithreading {
public class TestConnectedAasManagerMultithreadingInMemory extends ConnectedAasManagerMultithreadingTestSuite {
static final String AAS_REPOSITORY_BASE_PATH = "http://localhost:8081";
static final String SM_REPOSITORY_BASE_PATH = "http://localhost:8081";
static final String AAS_REGISTRY_BASE_PATH = "http://localhost:8050";
static final String SM_REGISTRY_BASE_PATH = "http://localhost:8060";
static final int N_THREADS = 20;

static ConfigurableApplicationContext appContext;
static AasRepository aasRepository;
static SubmodelRepository smRepository;

static ConnectedAasManager aasManager;
static ConnectedAasRepository connectedAasRepository;
static ConnectedSubmodelRepository connectedSmRepository;
static RegistryAndDiscoveryInterfaceApi aasRegistryApi;
static SubmodelRegistryApi smRegistryApi;

static ConnectedAasManager aasManager;
static ConfigurableApplicationContext appContext;

@BeforeClass
public static void setupRepositories() {
appContext = new SpringApplication(DummyAasEnvironmentComponent.class).run(new String[] {});

connectedAasRepository = new ConnectedAasRepository(AAS_REPOSITORY_BASE_PATH);
connectedSmRepository = new ConnectedSubmodelRepository(SM_REPOSITORY_BASE_PATH);
aasRegistryApi = new RegistryAndDiscoveryInterfaceApi(AAS_REGISTRY_BASE_PATH);
Expand All @@ -98,32 +71,6 @@ public static void stopContext() {
appContext.close();
}

@Test
public void testParallelSubmodelCreation() throws ExecutionException, InterruptedException {
AssetAdministrationShell shell = createShell();

ExecutorService executorService = Executors.newFixedThreadPool(N_THREADS);
ConcurrentLinkedDeque<String> createdSubmodelIds = new ConcurrentLinkedDeque<>();

List<Future<Boolean>> futures = IntStream.range(0, N_THREADS).mapToObj(i -> executorService.submit(() -> createdSubmodelIds.add(createSubmodel(shell.getId(), i)))).toList();

try {
for (int i = 0; i < N_THREADS; i++) {
futures.get(i).get();
}
} finally {
executorService.shutdown();
}

createdSubmodelIds.forEach(submodelId -> assertSubmodelWasCreatedAndRegistered(shell.getId(), submodelId));
}

static void assertSubmodelWasCreatedAndRegistered(String shellId, String submodelId) {
assertEquals(submodelId, aasManager.getSubmodelService(submodelId).getSubmodel().getId());
assertTrue(connectedAasRepository.getSubmodelReferences(shellId, PaginationInfo.NO_LIMIT).getResult().stream().map(Reference::getKeys).flatMap(Collection::stream).map(Key::getValue).anyMatch(submodelId::equals));
}


private static void cleanUpRegistries() {
try {
aasRegistryApi.deleteAllShellDescriptors();
Expand All @@ -137,22 +84,13 @@ private static void cleanUpRegistries() {
}
}

private static AssetAdministrationShell createShell() {
String id = UUID.randomUUID().toString();
DefaultAssetAdministrationShell shell = new DefaultAssetAdministrationShell.Builder().id(id).build();
aasManager.createAas(shell);
return aasManager.getAasService(id).getAAS();
@Override
public AasRepository getAasRepository() {
return connectedAasRepository;
}

private static String createSubmodel(String aasId, int threadId) {
try {
String id = aasId + "-thread" + threadId;
DefaultSubmodel submodel = new DefaultSubmodel.Builder().id(id).build();
aasManager.createSubmodelInAas(aasId, submodel);
return id;
} catch (Exception e) {
throw new RuntimeException("Failed at thread " + threadId, e);
}
@Override
public ConnectedAasManager getConnectedAasManager() {
return aasManager;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*******************************************************************************
* Copyright (C) 2025 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
******************************************************************************/

package org.eclipse.digitaltwin.basyx.aasenvironment.client;

import org.eclipse.digitaltwin.basyx.aasregistry.client.api.RegistryAndDiscoveryInterfaceApi;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.client.ConnectedAasRepository;
import org.eclipse.digitaltwin.basyx.submodelregistry.client.api.SubmodelRegistryApi;
import org.eclipse.digitaltwin.basyx.submodelrepository.client.ConnectedSubmodelRepository;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;

public class TestConnectedAasManagerMultithreadingMongoDb extends ConnectedAasManagerMultithreadingTestSuite {
static final String AAS_REPOSITORY_BASE_PATH = "http://localhost:8081";
static final String SM_REPOSITORY_BASE_PATH = "http://localhost:8081";
static final String AAS_REGISTRY_BASE_PATH = "http://localhost:8050";
static final String SM_REGISTRY_BASE_PATH = "http://localhost:8060";

static ConnectedAasManager aasManager;
static ConnectedAasRepository connectedAasRepository;
static ConnectedSubmodelRepository connectedSmRepository;
static RegistryAndDiscoveryInterfaceApi aasRegistryApi;
static SubmodelRegistryApi smRegistryApi;
static ConfigurableApplicationContext appContext;

@BeforeClass
public static void setupRepositories() {
appContext = new SpringApplicationBuilder(DummyAasEnvironmentComponent.class).profiles("mongodb").run(new String[] {});
connectedAasRepository = new ConnectedAasRepository(AAS_REPOSITORY_BASE_PATH);
connectedSmRepository = new ConnectedSubmodelRepository(SM_REPOSITORY_BASE_PATH);
aasRegistryApi = new RegistryAndDiscoveryInterfaceApi(AAS_REGISTRY_BASE_PATH);
smRegistryApi = new SubmodelRegistryApi(SM_REGISTRY_BASE_PATH);
aasManager = new ConnectedAasManager(AAS_REGISTRY_BASE_PATH, AAS_REPOSITORY_BASE_PATH, SM_REGISTRY_BASE_PATH, SM_REPOSITORY_BASE_PATH);

cleanUpRegistries();
}

@After
public void cleanUpComponents() {
cleanUpRegistries();
}

@AfterClass
public static void stopContext() {
appContext.close();
}

private static void cleanUpRegistries() {
try {
aasRegistryApi.deleteAllShellDescriptors();
} catch (Exception e) {
System.out.println(e.getMessage());
}
try {
smRegistryApi.deleteAllSubmodelDescriptors();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}

@Override
public AasRepository getAasRepository() {
return connectedAasRepository;
}

@Override
public ConnectedAasManager getConnectedAasManager() {
return aasManager;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
basyx.backend = MongoDB

spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017
spring.data.mongodb.database=aas-env
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.username=mongoAdmin
spring.data.mongodb.password=mongoPassword
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (C) 2024 the Eclipse BaSyx Authors
* Copyright (C) 2025 the Eclipse BaSyx Authors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
Expand Down Expand Up @@ -36,8 +36,7 @@
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.backend.CrudAasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.backend.CrudConceptDescriptionRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.backend.inmemory.AasInMemoryBackendProvider;
import org.eclipse.digitaltwin.basyx.aasservice.backend.InMemoryAasServiceFactory;
import org.eclipse.digitaltwin.basyx.aasrepository.backend.inmemory.InMemoryAasRepositoryBackend;
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionInMemoryBackendProvider;
import org.eclipse.digitaltwin.basyx.conceptdescriptionrepository.ConceptDescriptionRepository;
import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingIdentifierException;
Expand Down Expand Up @@ -77,7 +76,7 @@ public class AasEnvironmentLoaderTest {
@Before
public void setUp() {
submodelRepository = Mockito.spy(new CrudSubmodelRepository(new SubmodelInMemoryBackendProvider(), new InMemorySubmodelServiceFactory(new InMemoryFileRepository())));
aasRepository = Mockito.spy(new CrudAasRepository(new AasInMemoryBackendProvider(), new InMemoryAasServiceFactory(new InMemoryFileRepository())));
aasRepository = Mockito.spy(new CrudAasRepository(InMemoryAasRepositoryBackend.buildDefault(), "aas-repo"));
conceptDescriptionRepository = Mockito.spy(new CrudConceptDescriptionRepository(new ConceptDescriptionInMemoryBackendProvider()));
}

Expand Down
Loading