Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -32,7 +32,7 @@
"idShort": "specificAasIdShort-2-SM",
"id": "specificAasId-2-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-SM",
"id": "dummyShellId_3-1-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-Update-SM",
"id": "dummyShellId_3-1-Update-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ public void whenSendFullObjectStructure_ItemIsProcessedProperly() throws ApiExce
EmbeddedDataSpecification edSpec = new EmbeddedDataSpecification().dataSpecification(reference).dataSpecificationContent(new DataSpecificationContent(dsContent));

AdministrativeInformation aInfo = new AdministrativeInformation().addEmbeddedDataSpecificationsItem(edSpec);
SubmodelDescriptor sm = new SubmodelDescriptor().id("sm").id("short").addDescriptionItem(dType).addDisplayNameItem(nType).addEndpointsItem(ep).addExtensionsItem(ext).addSupplementalSemanticIdItem(reference);
SubmodelDescriptor sm = new SubmodelDescriptor().id("sm").id("short").addDescriptionItem(dType).addDisplayNameItem(nType).addEndpointsItem(ep).addExtensionsItem(ext).addSupplementalSemanticIdsItem(reference);
AssetAdministrationShellDescriptor descriptor = new AssetAdministrationShellDescriptor().id("id1").id("short").addDescriptionItem(dType).addDisplayNameItem(nType).addEndpointsItem(ep).addExtensionsItem(ext)
.addSpecificAssetIdsItem(saId).administration(aInfo).assetKind(AssetKind.TYPE).assetType("tp1").globalAssetId("global1").addSubmodelDescriptorsItem(sm);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.stream.Collectors;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.bson.Document;
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetAdministrationShellDescriptor;
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetKind;
import org.eclipse.digitaltwin.basyx.aasregistry.model.ShellDescriptorQuery;
Expand Down Expand Up @@ -80,6 +81,8 @@ public class MongoDbAasRegistryStorage implements AasRegistryStorage {
private static final String SUBMODEL_DESCRIPTORS_ID = "submodelDescriptors._id";
private static final String ASSET_TYPE = "assetType";
private static final String ASSET_KIND = "assetKind";
private static final String SUPPLEMENTAL_SEMANTIC_ID = "supplementalSemanticId";
private static final String SUPPLEMENTAL_SEMANTIC_IDS = "supplementalSemanticIds";

private final MongoTemplate template;

Expand All @@ -91,8 +94,8 @@ public CursorResult<List<AssetAdministrationShellDescriptor>> getAllAasDescripto
applyFilter(filter, allAggregations);
applySorting(allAggregations);
applyPagination(pRequest, allAggregations);
AggregationResults<AssetAdministrationShellDescriptor> results = template.aggregate(Aggregation.newAggregation(allAggregations), collectionName, AssetAdministrationShellDescriptor.class);
List<AssetAdministrationShellDescriptor> foundDescriptors = results.getMappedResults();
AggregationResults<Document> results = template.aggregate(Aggregation.newAggregation(allAggregations), collectionName, Document.class);
List<AssetAdministrationShellDescriptor> foundDescriptors = results.getMappedResults().stream().map(this::toAasDescriptor).collect(Collectors.toList());
String cursor = resolveCursor(pRequest, foundDescriptors, AssetAdministrationShellDescriptor::getId);
return new CursorResult<>(cursor, foundDescriptors);
}
Expand Down Expand Up @@ -148,11 +151,11 @@ public Optional<Criteria> createFilterCriteria(DescriptorFilter filter) {

@Override
public AssetAdministrationShellDescriptor getAasDescriptor(@NonNull String aasDescriptorId) throws AasDescriptorNotFoundException {
AssetAdministrationShellDescriptor descriptor = template.findById(aasDescriptorId, AssetAdministrationShellDescriptor.class, collectionName);
Document descriptor = template.findById(aasDescriptorId, Document.class, collectionName);
if (descriptor == null) {
throw new AasDescriptorNotFoundException(aasDescriptorId);
}
return descriptor;
return toAasDescriptor(descriptor);
}

@Override
Expand Down Expand Up @@ -212,8 +215,8 @@ public CursorResult<List<SubmodelDescriptor>> getAllSubmodels(@NonNull String aa
allAggregations.add(Aggregation.replaceRoot(SUBMODEL_DESCRIPTORS));
this.applySorting(allAggregations);
this.applyPagination(pRequest, allAggregations);
AggregationResults<SubmodelDescriptor> results = template.aggregate(Aggregation.newAggregation(allAggregations), collectionName, SubmodelDescriptor.class);
List<SubmodelDescriptor> submodels = results.getMappedResults();
AggregationResults<Document> results = template.aggregate(Aggregation.newAggregation(allAggregations), collectionName, Document.class);
List<SubmodelDescriptor> submodels = results.getMappedResults().stream().map(this::toSubmodelDescriptor).collect(Collectors.toList());
String cursor = resolveCursor(pRequest, submodels, SubmodelDescriptor::getId);
return new CursorResult<>(cursor, submodels);
}
Expand All @@ -224,16 +227,21 @@ public SubmodelDescriptor getSubmodel(@NonNull String aasDescriptorId, @NonNull
all.add(Aggregation.match(Criteria.where(ID).is(aasDescriptorId)));
ArrayOperators.Filter filter = ArrayOperators.arrayOf(SUBMODEL_DESCRIPTORS).filter().as(SUBMODEL_DESCRIPTORS).by(ComparisonOperators.valueOf(SUBMODEL_DESCRIPTORS_ID).equalToValue(submodelId));
all.add(Aggregation.project().and(filter).as(SUBMODEL_DESCRIPTORS));
AggregationResults<AssetAdministrationShellDescriptor> results = template.aggregate(Aggregation.newAggregation(all), collectionName, AssetAdministrationShellDescriptor.class);
List<AssetAdministrationShellDescriptor> aasDescriptors = results.getMappedResults();
AggregationResults<Document> results = template.aggregate(Aggregation.newAggregation(all), collectionName, Document.class);
List<Document> aasDescriptors = results.getMappedResults();
if (aasDescriptors.isEmpty()) {
throw new AasDescriptorNotFoundException(aasDescriptorId);
}
List<SubmodelDescriptor> descriptors = aasDescriptors.get(0).getSubmodelDescriptors();
if (descriptors == null || descriptors.isEmpty()) {
Document compatibleAasDescriptor = ensureLegacyAasDescriptorCompatibility(aasDescriptors.get(0));
Object descriptorsObject = compatibleAasDescriptor.get(SUBMODEL_DESCRIPTORS);
if (!(descriptorsObject instanceof List<?> descriptors) || descriptors.isEmpty()) {
throw new SubmodelNotFoundException(aasDescriptorId, submodelId);
}
return descriptors.get(0);
Object firstDescriptor = descriptors.get(0);
if (!(firstDescriptor instanceof Document descriptorDocument)) {
throw new SubmodelNotFoundException(aasDescriptorId, submodelId);
}
return toSubmodelDescriptor(descriptorDocument);
}

@Override
Expand Down Expand Up @@ -321,9 +329,52 @@ public ShellDescriptorSearchResponse searchAasDescriptors(@NonNull ShellDescript
qBuilder.withProjection(grouped.getQueriesInsideSubmodel(), aggregationOps);

Aggregation aggregation = Aggregation.newAggregation(aggregationOps);
AggregationResults<AssetAdministrationShellDescriptor> results = template.aggregate(aggregation, collectionName, AssetAdministrationShellDescriptor.class);
AggregationResults<Document> results = template.aggregate(aggregation, collectionName, Document.class);

List<AssetAdministrationShellDescriptor> descriptors = results.getMappedResults();
List<AssetAdministrationShellDescriptor> descriptors = results.getMappedResults().stream().map(this::toAasDescriptor).collect(Collectors.toList());
return new ShellDescriptorSearchResponse(total, descriptors);
}

private AssetAdministrationShellDescriptor toAasDescriptor(Document descriptorDocument) {
Document compatibleDocument = ensureLegacyAasDescriptorCompatibility(descriptorDocument);
return template.getConverter().read(AssetAdministrationShellDescriptor.class, compatibleDocument);
}

private SubmodelDescriptor toSubmodelDescriptor(Document descriptorDocument) {
Document compatibleDocument = ensureLegacySubmodelDescriptorCompatibility(descriptorDocument);
return template.getConverter().read(SubmodelDescriptor.class, compatibleDocument);
}

private Document ensureLegacyAasDescriptorCompatibility(Document descriptorDocument) {
Object submodelDescriptorsObject = descriptorDocument.get(SUBMODEL_DESCRIPTORS);
if (!(submodelDescriptorsObject instanceof List<?> submodelDescriptors)) {
return descriptorDocument;
}
boolean changed = false;
List<Object> compatibleSubmodels = new ArrayList<>(submodelDescriptors.size());
for (Object eachSubmodel : submodelDescriptors) {
if (eachSubmodel instanceof Document submodelDocument) {
Document compatibleSubmodel = ensureLegacySubmodelDescriptorCompatibility(submodelDocument);
compatibleSubmodels.add(compatibleSubmodel);
changed |= compatibleSubmodel != submodelDocument;
} else {
compatibleSubmodels.add(eachSubmodel);
}
}
if (!changed) {
return descriptorDocument;
}
Document compatibleDescriptor = new Document(descriptorDocument);
compatibleDescriptor.put(SUBMODEL_DESCRIPTORS, compatibleSubmodels);
return compatibleDescriptor;
}

private Document ensureLegacySubmodelDescriptorCompatibility(Document descriptorDocument) {
if (descriptorDocument.containsKey(SUPPLEMENTAL_SEMANTIC_IDS) || !descriptorDocument.containsKey(SUPPLEMENTAL_SEMANTIC_ID)) {
return descriptorDocument;
}
Document compatibleDocument = new Document(descriptorDocument);
compatibleDocument.put(SUPPLEMENTAL_SEMANTIC_IDS, descriptorDocument.get(SUPPLEMENTAL_SEMANTIC_ID));
return compatibleDocument;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,24 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.bson.Document;
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetAdministrationShellDescriptor;
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetKind;
import org.eclipse.digitaltwin.basyx.aasregistry.model.ShellDescriptorQuery;
import org.eclipse.digitaltwin.basyx.aasregistry.model.ShellDescriptorQuery.QueryTypeEnum;
import org.eclipse.digitaltwin.basyx.aasregistry.model.SubmodelDescriptor;
import org.eclipse.digitaltwin.basyx.aasregistry.paths.AasRegistryPaths;
import org.eclipse.digitaltwin.basyx.aasregistry.service.configuration.MongoDbConfiguration;
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.DescriptorFilter;
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.ShellDescriptorSearchRequests;
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.mongodb.MongoDbAasRegistryStorage;
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.mongodb.SearchQueryBuilder;
import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult;
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
Expand All @@ -51,7 +57,7 @@
import com.mongodb.client.MongoCollection;

@TestPropertySource(properties = { "registry.type=mongodb", "spring.data.mongodb.database=aasregistry"
, "spring.data.mongodb.uri=mongodb://mongoAdmin:mongoPassword@localhost:27017" })
, "spring.data.mongodb.uri=mongodb://mongoAdmin:mongoPassword@localhost:27017", "basyx.aasregistry.mongodb.collectionName=aasdescriptors" })
@ContextConfiguration(classes = { MongoDbConfiguration.class })
@EnableAutoConfiguration
public class MongoDbAasRegistryStorageTest extends AasRegistryStorageTest {
Expand Down Expand Up @@ -111,6 +117,39 @@ public void whenGetByAasID_NotAllDocumentsScannedButIndexUsed() {
assertThat(doc.toJson()).doesNotContain("\"COLLSCAN\"");
}

@Test
public void givenLegacySupplementalSemanticIdInSubmodel_whenGetAasById_thenSubmodelContainsSupplementalSemanticField() {
template.remove(new Query(), "aasdescriptors");
template.save(createLegacyAasDocument("legacy-aas-1", "legacy-submodel-1"), "aasdescriptors");

AssetAdministrationShellDescriptor descriptor = storage.getAasDescriptor("legacy-aas-1");
SubmodelDescriptor submodelDescriptor = descriptor.getSubmodelDescriptors().get(0);

Document writtenSubmodelDescriptor = new Document();
template.getConverter().write(submodelDescriptor, writtenSubmodelDescriptor);

assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isNotNull();
assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isInstanceOf(List.class);
assertThat((List<?>) extractSupplementalSemanticField(writtenSubmodelDescriptor)).hasSize(1);
}

@Test
public void givenLegacySupplementalSemanticIdInSubmodel_whenGetAllSubmodels_thenSubmodelContainsSupplementalSemanticField() {
template.remove(new Query(), "aasdescriptors");
template.save(createLegacyAasDocument("legacy-aas-2", "legacy-submodel-2"), "aasdescriptors");

CursorResult<List<SubmodelDescriptor>> result = storage.getAllSubmodels("legacy-aas-2", PaginationInfo.NO_LIMIT);
SubmodelDescriptor submodelDescriptor = result.getResult().stream().filter(x -> "legacy-submodel-2".equals(x.getId())).findFirst().orElse(null);
assertThat(submodelDescriptor).isNotNull();

Document writtenSubmodelDescriptor = new Document();
template.getConverter().write(submodelDescriptor, writtenSubmodelDescriptor);

assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isNotNull();
assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isInstanceOf(List.class);
assertThat((List<?>) extractSupplementalSemanticField(writtenSubmodelDescriptor)).hasSize(1);
}

private void testIndexFilter(AssetKind kind, String type) {
MongoDbAasRegistryStorage storage = new MongoDbAasRegistryStorage(template, "aasdescriptors");
Optional<Criteria> criteriaOpt = storage.createFilterCriteria(new DescriptorFilter(kind, type));
Expand All @@ -124,4 +163,19 @@ private void testIndexFilter(Criteria criteria) {
Document doc = collection.find(Query.query(criteria).getQueryObject()).explain(ExplainVerbosity.QUERY_PLANNER);
assertThat(doc.toJson()).doesNotContain("\"COLLSCAN\"");
}

private Object extractSupplementalSemanticField(Document descriptorDocument) {
if (descriptorDocument.containsKey("supplementalSemanticIds")) {
return descriptorDocument.get("supplementalSemanticIds");
}
return descriptorDocument.get("supplementalSemanticId");
}

private Document createLegacyAasDocument(String aasId, String submodelId) {
Document key = new Document("type", "FILE").append("value", "urn:test:" + submodelId);
Document reference = new Document("type", "EXTERNALREFERENCE").append("keys", Arrays.asList(key));
Document submodelDescriptor = new Document("_id", submodelId).append("idShort", "short-" + submodelId).append("endpoints", Arrays.asList())
.append("supplementalSemanticId", Arrays.asList(reference));
return new Document("_id", aasId).append("idShort", "short-" + aasId).append("endpoints", Arrays.asList()).append("submodelDescriptors", Arrays.asList(submodelDescriptor));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"idShort": "specificAasIdShort-2-SM",
"id": "specificAasId-2-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-SM",
"id": "dummyShellId_3-1-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-Update-SM",
"id": "dummyShellId_3-1-Update-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"idShort": "specificAasIdShort-2-SM",
"id": "specificAasId-2-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-SM",
"id": "dummyShellId_3-1-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-Update-SM",
"id": "dummyShellId_3-1-Update-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"idShort": "specificAasIdShort-2-SM",
"id": "specificAasId-2-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-SM",
"id": "dummyShellId_3-1-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-Update-SM",
"id": "dummyShellId_3-1-Update-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"idShort": "specificAasIdShort-2-SM",
"id": "specificAasId-2-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-SM",
"id": "dummyShellId_3-1-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"idShort": "dummyShellIdShort_3-1-Update-SM",
"id": "dummyShellId_3-1-Update-SM",
"semanticId": null,
"supplementalSemanticId": null,
"supplementalSemanticIds": null,
"endpoints": [
{
"interface": "AAS-3.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ components:
type: string
semanticId:
$ref: '#/components/schemas/Reference'
supplementalSemanticId:
supplementalSemanticIds:
minItems: 1
type: array
items:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,7 @@ components:
type: string
semanticId:
$ref: '#/components/schemas/Reference'
supplementalSemanticId:
supplementalSemanticIds:
minItems: 1
type: array
items:
Expand Down
Loading