Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements filter mechanism and improves filter at backend side for AAS Repository #516

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
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.eclipse.digitaltwin.basyx.core.BaSyxCrudRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;

/**
Expand All @@ -42,10 +42,10 @@
@Component
public class AasDiscoveryInMemoryBackendProvider implements AasDiscoveryBackendProvider {

private CrudRepository<AasDiscoveryDocument, String> repository = new InMemoryCrudRepository<AasDiscoveryDocument>(AasDiscoveryDocument::getShellIdentifier);
private BaSyxCrudRepository<AasDiscoveryDocument> repository = new InMemoryCrudRepository<AasDiscoveryDocument>(AasDiscoveryDocument::getShellIdentifier);

@Override
public CrudRepository<AasDiscoveryDocument, String> getCrudRepository() {
public BaSyxCrudRepository<AasDiscoveryDocument> getCrudRepository() {
return repository;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@
import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.backend.AasDiscoveryBackendProvider;
import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.backend.AasDiscoveryDocument;
import org.eclipse.digitaltwin.basyx.common.mongocore.BasyxMongoMappingContext;
import org.eclipse.digitaltwin.basyx.common.mongocore.MongoDBCrudRepository;
import org.eclipse.digitaltwin.basyx.core.BaSyxCrudRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.repository.support.MappingMongoEntityInformation;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;

/**
Expand Down Expand Up @@ -65,11 +64,12 @@ public AasDiscoveryMongoDBBackendProvider(BasyxMongoMappingContext mappingContex
}

@Override
public CrudRepository<AasDiscoveryDocument, String> getCrudRepository() {
public BaSyxCrudRepository<AasDiscoveryDocument> getCrudRepository() {
@SuppressWarnings("unchecked")
MongoPersistentEntity<AasDiscoveryDocument> entity = (MongoPersistentEntity<AasDiscoveryDocument>) mappingContext
.getPersistentEntity(AasDiscoveryDocument.class);
return new SimpleMongoRepository<>(new MappingMongoEntityInformation<>(entity), template);

return new MongoDBCrudRepository<AasDiscoveryDocument>(new MappingMongoEntityInformation<>(entity), template, AasDiscoveryDocument.class);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
******************************************************************************/
package org.eclipse.digitaltwin.basyx.aasdiscoveryservice.backend;

import org.springframework.data.repository.CrudRepository;
import org.eclipse.digitaltwin.basyx.core.BaSyxCrudRepository;

/**
* Backend provider for the AAS Discovery
Expand All @@ -38,5 +38,5 @@ public interface AasDiscoveryBackendProvider {
*
* @return The CRUD repository
*/
public CrudRepository<AasDiscoveryDocument, String> getCrudRepository();
public BaSyxCrudRepository<AasDiscoveryDocument> getCrudRepository();
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.eclipse.digitaltwin.aas4j.v3.model.SpecificAssetId;
import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.AasDiscoveryService;
import org.eclipse.digitaltwin.basyx.aasdiscoveryservice.core.model.AssetLink;
import org.eclipse.digitaltwin.basyx.core.BaSyxCrudRepository;
import org.eclipse.digitaltwin.basyx.core.exceptions.AssetLinkDoesNotExistException;
import org.eclipse.digitaltwin.basyx.core.exceptions.CollidingAssetLinkException;
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.core.pagination.PaginationUtilities;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.repository.CrudRepository;

Expand All @@ -56,7 +56,7 @@
*/
public class CrudAasDiscovery implements AasDiscoveryService {

private AasDiscoveryBackendProvider provider;
private BaSyxCrudRepository<AasDiscoveryDocument> aasDiscoveryBackend;
private String aasDiscoveryServiceName;

/**
Expand All @@ -66,7 +66,7 @@ public class CrudAasDiscovery implements AasDiscoveryService {
* The backend provider
*/
public CrudAasDiscovery(AasDiscoveryBackendProvider provider) {
this.provider = provider;
this.aasDiscoveryBackend = provider.getCrudRepository();
}

/**
Expand Down Expand Up @@ -95,9 +95,11 @@ public CrudAasDiscovery(AasDiscoveryBackendProvider provider,
*/
@Override
public CursorResult<List<String>> getAllAssetAdministrationShellIdsByAssetLink(PaginationInfo pInfo, List<AssetLink> assetIds) {
Set<String> shellIds = getShellIdsWithAssetLinks(assetIds);
List<String> shellIds = getShellIdsWithAssetLinks(assetIds, pInfo);

return paginateList(pInfo, new ArrayList<>(shellIds));
String cursor = PaginationUtilities.resolveCursor(pInfo, shellIds);

return new CursorResult<>(cursor, shellIds);
}

/**
Expand All @@ -110,11 +112,12 @@ public CursorResult<List<String>> getAllAssetAdministrationShellIdsByAssetLink(P
*/
@Override
public List<SpecificAssetId> getAllAssetLinksById(String shellIdentifier) {
Map<String, List<SpecificAssetId>> assetIds = getAssetIds();

throwIfSpecificAssetIdLinkDoesNotExist(assetIds, shellIdentifier);

return assetIds.get(shellIdentifier);
throwIfSpecificAssetIdLinkDoesNotExist(shellIdentifier);

AasDiscoveryDocument aasDiscoveryDocuments = aasDiscoveryBackend.findById(shellIdentifier).orElseThrow(() -> new AssetLinkDoesNotExistException(shellIdentifier));

return aasDiscoveryDocuments.getSpecificAssetIds();
}

/**
Expand All @@ -129,19 +132,13 @@ public List<SpecificAssetId> getAllAssetLinksById(String shellIdentifier) {
* @return a list of asset identifiers
*/
@Override
public List<SpecificAssetId> createAllAssetLinksById(String shellIdentifier,
List<SpecificAssetId> specificAssetIds) {

Map<String, Set<AssetLink>> assetLinks = getAssetLinks();
public List<SpecificAssetId> createAllAssetLinksById(String shellIdentifier, List<SpecificAssetId> specificAssetIds) {

synchronized (assetLinks) {
throwIfAssetLinkExists(assetLinks, shellIdentifier);
throwIfAssetLinkExists(shellIdentifier);

List<AssetLink> shellAssetLinks = deriveAssetLinksFromSpecificAssetIds(specificAssetIds);
AasDiscoveryDocument aasDiscoveryDocument = new AasDiscoveryDocument(shellIdentifier,
new HashSet<>(shellAssetLinks), specificAssetIds);
provider.getCrudRepository().save(aasDiscoveryDocument);
}
List<AssetLink> shellAssetLinks = deriveAssetLinksFromSpecificAssetIds(specificAssetIds);
AasDiscoveryDocument aasDiscoveryDocument = new AasDiscoveryDocument(shellIdentifier, new HashSet<>(shellAssetLinks), specificAssetIds);
aasDiscoveryBackend.save(aasDiscoveryDocument);

return specificAssetIds;
}
Expand All @@ -155,46 +152,36 @@ public List<SpecificAssetId> createAllAssetLinksById(String shellIdentifier,
*/
@Override
public void deleteAllAssetLinksById(String shellIdentifier) {
Map<String, Set<AssetLink>> assetLinks = getAssetLinks();
synchronized (assetLinks) {
throwIfAssetLinkDoesNotExist(assetLinks, shellIdentifier);

throwIfAssetLinkDoesNotExist(shellIdentifier);

provider.getCrudRepository().deleteById(shellIdentifier);
}
aasDiscoveryBackend.deleteById(shellIdentifier);
}

@Override
public String getName(){
return aasDiscoveryServiceName == null ? AasDiscoveryService.super.getName() : aasDiscoveryServiceName;
}

private void throwIfAssetLinkExists(Map<String, Set<AssetLink>> assetLinks, String shellIdentifier) {
if (assetLinks.containsKey(shellIdentifier))
private void throwIfAssetLinkExists(String shellIdentifier) {
if (aasDiscoveryBackend.existsById(shellIdentifier))
throw new CollidingAssetLinkException(shellIdentifier);
}

private void throwIfAssetLinkDoesNotExist(Map<String, Set<AssetLink>> assetLinks, String shellIdentifier) {
if (!assetLinks.containsKey(shellIdentifier))
private void throwIfAssetLinkDoesNotExist(String shellIdentifier) {

if (!aasDiscoveryBackend.existsById(shellIdentifier))
throw new AssetLinkDoesNotExistException(shellIdentifier);

}

private void throwIfSpecificAssetIdLinkDoesNotExist(Map<String, List<SpecificAssetId>> assetIds,
private void throwIfSpecificAssetIdLinkDoesNotExist(
String shellIdentifier) {
if (!assetIds.containsKey(shellIdentifier))
if (!aasDiscoveryBackend.existsById(shellIdentifier))
throw new AssetLinkDoesNotExistException(shellIdentifier);
}

private Map<String, List<SpecificAssetId>> getAssetIds() {
Iterable<AasDiscoveryDocument> aasDiscoveryDocuments = provider.getCrudRepository().findAll();
List<AasDiscoveryDocument> aasDiscoveryDocumentList = StreamSupport
.stream(aasDiscoveryDocuments.spliterator(), false).collect(Collectors.toList());
Map<String, List<SpecificAssetId>> assetIds = aasDiscoveryDocumentList.stream().collect(
Collectors.toMap(AasDiscoveryDocument::getShellIdentifier, AasDiscoveryDocument::getSpecificAssetIds));
return assetIds;
}

private Map<String, Set<AssetLink>> getAssetLinks() {
Iterable<AasDiscoveryDocument> aasDiscoveryDocuments = provider.getCrudRepository().findAll();
private Map<String, Set<AssetLink>> getAssetLinks(Iterable<AasDiscoveryDocument> aasDiscoveryDocuments) {
List<AasDiscoveryDocument> aasDiscoveryDocumentList = StreamSupport
.stream(aasDiscoveryDocuments.spliterator(), false).collect(Collectors.toList());
Map<String, Set<AssetLink>> assetLinks = aasDiscoveryDocumentList.stream()
Expand All @@ -203,18 +190,16 @@ private Map<String, Set<AssetLink>> getAssetLinks() {
return assetLinks;
}

private Set<String> getShellIdsWithAssetLinks(List<AssetLink> requestedLinks) {
Map<String, Set<AssetLink>> assetLinks = getAssetLinks();
return assetLinks.entrySet().stream().filter(entry -> entry.getValue().containsAll(requestedLinks))
private List<String> getShellIdsWithAssetLinks(List<AssetLink> requestedLinks, PaginationInfo pInfo) {

Iterable<AasDiscoveryDocument> aasDiscoveryDocuments = aasDiscoveryBackend.findAll(pInfo, null);

Map<String, Set<AssetLink>> assetLinks = getAssetLinks(aasDiscoveryDocuments);

Set<String> assetLinksSet = assetLinks.entrySet().stream().filter(entry -> entry.getValue().containsAll(requestedLinks))
.map(Map.Entry::getKey).collect(Collectors.toSet());

return new ArrayList<>(assetLinksSet);
}

private CursorResult<List<String>> paginateList(PaginationInfo pInfo, List<String> shellIdentifiers) {
TreeMap<String, String> shellIdentifierMap = shellIdentifiers.stream()
.collect(Collectors.toMap(Function.identity(), Function.identity(), (a, b) -> a, TreeMap::new));

PaginationSupport<String> paginationSupport = new PaginationSupport<>(shellIdentifierMap, Function.identity());

return paginationSupport.getPaged(pInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class CrudAasDiscoveryTest {

@Test
public void getConfiguredAasDiscoveryName(){
AasDiscoveryService service = new SimpleAasDiscoveryFactory(null, CONFIGURED_AAS_DISCOVERY_NAME).create();
AasDiscoveryService service = new SimpleAasDiscoveryFactory(() -> null, CONFIGURED_AAS_DISCOVERY_NAME).create();

assertEquals(CONFIGURED_AAS_DISCOVERY_NAME,service.getName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.eclipse.digitaltwin.aas4j.v3.dataformat.core.DeserializationException;
import org.eclipse.digitaltwin.basyx.aasenvironment.base.DefaultAASEnvironment;
import org.eclipse.digitaltwin.basyx.aasenvironment.environmentloader.CompleteEnvironment;
import org.eclipse.digitaltwin.basyx.aasrepository.AasFilter;
import org.eclipse.digitaltwin.basyx.aasrepository.AasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.backend.CrudAasRepository;
import org.eclipse.digitaltwin.basyx.aasrepository.backend.CrudConceptDescriptionRepository;
Expand Down Expand Up @@ -94,7 +95,7 @@ protected void loadRepositories(List<String> pathsToLoad) throws IOException, De
public void testWithResourceFile_AllElementsAreDeployed() throws InvalidFormatException, IOException, DeserializationException {
loadRepositories(List.of(TEST_ENVIRONMENT_JSON));

Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().size());
Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size());
}
Expand All @@ -110,7 +111,7 @@ 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(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().size());
Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size());
}
Expand All @@ -126,7 +127,7 @@ 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(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().size());
Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size());
}
Expand All @@ -142,7 +143,7 @@ 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(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().size());
Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size());
}
Expand All @@ -166,15 +167,15 @@ public void testWithResourceFile_NoExceptionsWhenReuploadAfterElementsAreRemoved

loadRepositoriesWithEnvironment(List.of(TEST_ENVIRONMENT_JSON), envLoader);

Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).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(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().size());
Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size());
}
Expand All @@ -185,7 +186,7 @@ public void testWithResourceFile_ExceptionIsThrownWhenReuploadWithExistingElemen

loadRepositoriesWithEnvironment(List.of(TEST_ENVIRONMENT_JSON), envLoader);

Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().size());
Assert.assertEquals(2, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(2, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size());

Expand All @@ -202,11 +203,11 @@ private void loadRepositoriesWithEnvironment(List<String> pathsToLoad, AasEnviro
}

private void deleteElementsFromRepos() {
aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().stream().forEach(aas -> aasRepository.deleteAas(aas.getId()));
aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).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(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(0, aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().size());
Assert.assertEquals(0, submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().size());
Assert.assertEquals(0, conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().size());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.aasrepository.AasFilter;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.junit.Assert;
import org.junit.Test;
Expand All @@ -53,7 +54,7 @@ protected void loadRepositories(List<String> pathsToLoad) throws IOException, In
@Test
public void testWithEmptyResource_NoElementsAreDeployed() throws InvalidFormatException, IOException, DeserializationException {
loadRepositories(List.of());
Assert.assertTrue(aasRepository.getAllAas(PaginationInfo.NO_LIMIT).getResult().isEmpty());
Assert.assertTrue(aasRepository.getAllAas(PaginationInfo.NO_LIMIT, new AasFilter()).getResult().isEmpty());
Assert.assertTrue(submodelRepository.getAllSubmodels(PaginationInfo.NO_LIMIT).getResult().isEmpty());
Assert.assertTrue(conceptDescriptionRepository.getAllConceptDescriptions(PaginationInfo.NO_LIMIT).getResult().isEmpty());

Expand Down
Loading