Skip to content

Commit 7efd157

Browse files
committed
Fixes test failures and adds legacy support to aas registry
1 parent ab7cfe6 commit 7efd157

3 files changed

Lines changed: 121 additions & 16 deletions

File tree

basyx.aasregistry/basyx.aasregistry-service-mongodb-storage/src/main/java/org/eclipse/digitaltwin/basyx/aasregistry/service/storage/mongodb/MongoDbAasRegistryStorage.java

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.stream.Collectors;
3737
import lombok.NonNull;
3838
import lombok.RequiredArgsConstructor;
39+
import org.bson.Document;
3940
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetAdministrationShellDescriptor;
4041
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetKind;
4142
import org.eclipse.digitaltwin.basyx.aasregistry.model.ShellDescriptorQuery;
@@ -80,6 +81,8 @@ public class MongoDbAasRegistryStorage implements AasRegistryStorage {
8081
private static final String SUBMODEL_DESCRIPTORS_ID = "submodelDescriptors._id";
8182
private static final String ASSET_TYPE = "assetType";
8283
private static final String ASSET_KIND = "assetKind";
84+
private static final String SUPPLEMENTAL_SEMANTIC_ID = "supplementalSemanticId";
85+
private static final String SUPPLEMENTAL_SEMANTIC_IDS = "supplementalSemanticIds";
8386

8487
private final MongoTemplate template;
8588

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

149152
@Override
150153
public AssetAdministrationShellDescriptor getAasDescriptor(@NonNull String aasDescriptorId) throws AasDescriptorNotFoundException {
151-
AssetAdministrationShellDescriptor descriptor = template.findById(aasDescriptorId, AssetAdministrationShellDescriptor.class, collectionName);
154+
Document descriptor = template.findById(aasDescriptorId, Document.class, collectionName);
152155
if (descriptor == null) {
153156
throw new AasDescriptorNotFoundException(aasDescriptorId);
154157
}
155-
return descriptor;
158+
return toAasDescriptor(descriptor);
156159
}
157160

158161
@Override
@@ -212,8 +215,8 @@ public CursorResult<List<SubmodelDescriptor>> getAllSubmodels(@NonNull String aa
212215
allAggregations.add(Aggregation.replaceRoot(SUBMODEL_DESCRIPTORS));
213216
this.applySorting(allAggregations);
214217
this.applyPagination(pRequest, allAggregations);
215-
AggregationResults<SubmodelDescriptor> results = template.aggregate(Aggregation.newAggregation(allAggregations), collectionName, SubmodelDescriptor.class);
216-
List<SubmodelDescriptor> submodels = results.getMappedResults();
218+
AggregationResults<Document> results = template.aggregate(Aggregation.newAggregation(allAggregations), collectionName, Document.class);
219+
List<SubmodelDescriptor> submodels = results.getMappedResults().stream().map(this::toSubmodelDescriptor).collect(Collectors.toList());
217220
String cursor = resolveCursor(pRequest, submodels, SubmodelDescriptor::getId);
218221
return new CursorResult<>(cursor, submodels);
219222
}
@@ -224,16 +227,21 @@ public SubmodelDescriptor getSubmodel(@NonNull String aasDescriptorId, @NonNull
224227
all.add(Aggregation.match(Criteria.where(ID).is(aasDescriptorId)));
225228
ArrayOperators.Filter filter = ArrayOperators.arrayOf(SUBMODEL_DESCRIPTORS).filter().as(SUBMODEL_DESCRIPTORS).by(ComparisonOperators.valueOf(SUBMODEL_DESCRIPTORS_ID).equalToValue(submodelId));
226229
all.add(Aggregation.project().and(filter).as(SUBMODEL_DESCRIPTORS));
227-
AggregationResults<AssetAdministrationShellDescriptor> results = template.aggregate(Aggregation.newAggregation(all), collectionName, AssetAdministrationShellDescriptor.class);
228-
List<AssetAdministrationShellDescriptor> aasDescriptors = results.getMappedResults();
230+
AggregationResults<Document> results = template.aggregate(Aggregation.newAggregation(all), collectionName, Document.class);
231+
List<Document> aasDescriptors = results.getMappedResults();
229232
if (aasDescriptors.isEmpty()) {
230233
throw new AasDescriptorNotFoundException(aasDescriptorId);
231234
}
232-
List<SubmodelDescriptor> descriptors = aasDescriptors.get(0).getSubmodelDescriptors();
233-
if (descriptors == null || descriptors.isEmpty()) {
235+
Document compatibleAasDescriptor = ensureLegacyAasDescriptorCompatibility(aasDescriptors.get(0));
236+
Object descriptorsObject = compatibleAasDescriptor.get(SUBMODEL_DESCRIPTORS);
237+
if (!(descriptorsObject instanceof List<?> descriptors) || descriptors.isEmpty()) {
234238
throw new SubmodelNotFoundException(aasDescriptorId, submodelId);
235239
}
236-
return descriptors.get(0);
240+
Object firstDescriptor = descriptors.get(0);
241+
if (!(firstDescriptor instanceof Document descriptorDocument)) {
242+
throw new SubmodelNotFoundException(aasDescriptorId, submodelId);
243+
}
244+
return toSubmodelDescriptor(descriptorDocument);
237245
}
238246

239247
@Override
@@ -321,9 +329,52 @@ public ShellDescriptorSearchResponse searchAasDescriptors(@NonNull ShellDescript
321329
qBuilder.withProjection(grouped.getQueriesInsideSubmodel(), aggregationOps);
322330

323331
Aggregation aggregation = Aggregation.newAggregation(aggregationOps);
324-
AggregationResults<AssetAdministrationShellDescriptor> results = template.aggregate(aggregation, collectionName, AssetAdministrationShellDescriptor.class);
332+
AggregationResults<Document> results = template.aggregate(aggregation, collectionName, Document.class);
325333

326-
List<AssetAdministrationShellDescriptor> descriptors = results.getMappedResults();
334+
List<AssetAdministrationShellDescriptor> descriptors = results.getMappedResults().stream().map(this::toAasDescriptor).collect(Collectors.toList());
327335
return new ShellDescriptorSearchResponse(total, descriptors);
328336
}
337+
338+
private AssetAdministrationShellDescriptor toAasDescriptor(Document descriptorDocument) {
339+
Document compatibleDocument = ensureLegacyAasDescriptorCompatibility(descriptorDocument);
340+
return template.getConverter().read(AssetAdministrationShellDescriptor.class, compatibleDocument);
341+
}
342+
343+
private SubmodelDescriptor toSubmodelDescriptor(Document descriptorDocument) {
344+
Document compatibleDocument = ensureLegacySubmodelDescriptorCompatibility(descriptorDocument);
345+
return template.getConverter().read(SubmodelDescriptor.class, compatibleDocument);
346+
}
347+
348+
private Document ensureLegacyAasDescriptorCompatibility(Document descriptorDocument) {
349+
Object submodelDescriptorsObject = descriptorDocument.get(SUBMODEL_DESCRIPTORS);
350+
if (!(submodelDescriptorsObject instanceof List<?> submodelDescriptors)) {
351+
return descriptorDocument;
352+
}
353+
boolean changed = false;
354+
List<Object> compatibleSubmodels = new ArrayList<>(submodelDescriptors.size());
355+
for (Object eachSubmodel : submodelDescriptors) {
356+
if (eachSubmodel instanceof Document submodelDocument) {
357+
Document compatibleSubmodel = ensureLegacySubmodelDescriptorCompatibility(submodelDocument);
358+
compatibleSubmodels.add(compatibleSubmodel);
359+
changed |= compatibleSubmodel != submodelDocument;
360+
} else {
361+
compatibleSubmodels.add(eachSubmodel);
362+
}
363+
}
364+
if (!changed) {
365+
return descriptorDocument;
366+
}
367+
Document compatibleDescriptor = new Document(descriptorDocument);
368+
compatibleDescriptor.put(SUBMODEL_DESCRIPTORS, compatibleSubmodels);
369+
return compatibleDescriptor;
370+
}
371+
372+
private Document ensureLegacySubmodelDescriptorCompatibility(Document descriptorDocument) {
373+
if (descriptorDocument.containsKey(SUPPLEMENTAL_SEMANTIC_IDS) || !descriptorDocument.containsKey(SUPPLEMENTAL_SEMANTIC_ID)) {
374+
return descriptorDocument;
375+
}
376+
Document compatibleDocument = new Document(descriptorDocument);
377+
compatibleDocument.put(SUPPLEMENTAL_SEMANTIC_IDS, descriptorDocument.get(SUPPLEMENTAL_SEMANTIC_ID));
378+
return compatibleDocument;
379+
}
329380
}

basyx.aasregistry/basyx.aasregistry-service-mongodb-storage/src/test/java/org/eclipse/digitaltwin/basyx/aasregistry/service/tests/MongoDbAasRegistryStorageTest.java

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,24 @@
2626

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

29+
import java.util.Arrays;
30+
import java.util.List;
2931
import java.util.Optional;
3032

3133
import org.bson.Document;
34+
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetAdministrationShellDescriptor;
3235
import org.eclipse.digitaltwin.basyx.aasregistry.model.AssetKind;
3336
import org.eclipse.digitaltwin.basyx.aasregistry.model.ShellDescriptorQuery;
3437
import org.eclipse.digitaltwin.basyx.aasregistry.model.ShellDescriptorQuery.QueryTypeEnum;
38+
import org.eclipse.digitaltwin.basyx.aasregistry.model.SubmodelDescriptor;
3539
import org.eclipse.digitaltwin.basyx.aasregistry.paths.AasRegistryPaths;
3640
import org.eclipse.digitaltwin.basyx.aasregistry.service.configuration.MongoDbConfiguration;
3741
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.DescriptorFilter;
3842
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.ShellDescriptorSearchRequests;
3943
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.mongodb.MongoDbAasRegistryStorage;
4044
import org.eclipse.digitaltwin.basyx.aasregistry.service.storage.mongodb.SearchQueryBuilder;
45+
import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult;
46+
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
4147
import org.junit.Test;
4248
import org.springframework.beans.factory.annotation.Autowired;
4349
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -51,7 +57,7 @@
5157
import com.mongodb.client.MongoCollection;
5258

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

120+
@Test
121+
public void givenLegacySupplementalSemanticIdInSubmodel_whenGetAasById_thenSubmodelContainsSupplementalSemanticField() {
122+
template.remove(new Query(), "aasdescriptors");
123+
template.save(createLegacyAasDocument("legacy-aas-1", "legacy-submodel-1"), "aasdescriptors");
124+
125+
AssetAdministrationShellDescriptor descriptor = storage.getAasDescriptor("legacy-aas-1");
126+
SubmodelDescriptor submodelDescriptor = descriptor.getSubmodelDescriptors().get(0);
127+
128+
Document writtenSubmodelDescriptor = new Document();
129+
template.getConverter().write(submodelDescriptor, writtenSubmodelDescriptor);
130+
131+
assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isNotNull();
132+
assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isInstanceOf(List.class);
133+
assertThat((List<?>) extractSupplementalSemanticField(writtenSubmodelDescriptor)).hasSize(1);
134+
}
135+
136+
@Test
137+
public void givenLegacySupplementalSemanticIdInSubmodel_whenGetAllSubmodels_thenSubmodelContainsSupplementalSemanticField() {
138+
template.remove(new Query(), "aasdescriptors");
139+
template.save(createLegacyAasDocument("legacy-aas-2", "legacy-submodel-2"), "aasdescriptors");
140+
141+
CursorResult<List<SubmodelDescriptor>> result = storage.getAllSubmodels("legacy-aas-2", PaginationInfo.NO_LIMIT);
142+
SubmodelDescriptor submodelDescriptor = result.getResult().stream().filter(x -> "legacy-submodel-2".equals(x.getId())).findFirst().orElse(null);
143+
assertThat(submodelDescriptor).isNotNull();
144+
145+
Document writtenSubmodelDescriptor = new Document();
146+
template.getConverter().write(submodelDescriptor, writtenSubmodelDescriptor);
147+
148+
assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isNotNull();
149+
assertThat(extractSupplementalSemanticField(writtenSubmodelDescriptor)).isInstanceOf(List.class);
150+
assertThat((List<?>) extractSupplementalSemanticField(writtenSubmodelDescriptor)).hasSize(1);
151+
}
152+
114153
private void testIndexFilter(AssetKind kind, String type) {
115154
MongoDbAasRegistryStorage storage = new MongoDbAasRegistryStorage(template, "aasdescriptors");
116155
Optional<Criteria> criteriaOpt = storage.createFilterCriteria(new DescriptorFilter(kind, type));
@@ -124,4 +163,19 @@ private void testIndexFilter(Criteria criteria) {
124163
Document doc = collection.find(Query.query(criteria).getQueryObject()).explain(ExplainVerbosity.QUERY_PLANNER);
125164
assertThat(doc.toJson()).doesNotContain("\"COLLSCAN\"");
126165
}
166+
167+
private Object extractSupplementalSemanticField(Document descriptorDocument) {
168+
if (descriptorDocument.containsKey("supplementalSemanticIds")) {
169+
return descriptorDocument.get("supplementalSemanticIds");
170+
}
171+
return descriptorDocument.get("supplementalSemanticId");
172+
}
173+
174+
private Document createLegacyAasDocument(String aasId, String submodelId) {
175+
Document key = new Document("type", "FILE").append("value", "urn:test:" + submodelId);
176+
Document reference = new Document("type", "EXTERNALREFERENCE").append("keys", Arrays.asList(key));
177+
Document submodelDescriptor = new Document("_id", submodelId).append("idShort", "short-" + submodelId).append("endpoints", Arrays.asList())
178+
.append("supplementalSemanticId", Arrays.asList(reference));
179+
return new Document("_id", aasId).append("idShort", "short-" + aasId).append("endpoints", Arrays.asList()).append("submodelDescriptors", Arrays.asList(submodelDescriptor));
180+
}
127181
}

basyx.submodelregistry/basyx.submodelregistry-service-mongodb-storage/src/test/java/org/eclipse/digitaltwin/basyx/submodelregistry/service/tests/MongoDbSubmodelRegistryStorageTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ private Object extractSupplementalSemanticField(Document descriptorDocument) {
108108
}
109109

110110
private Document createLegacyDocument(String id) {
111-
Document key = new Document("type", "GlobalReference").append("value", "urn:test:" + id);
112-
Document reference = new Document("type", "ExternalReference").append("keys", Arrays.asList(key));
111+
Document key = new Document("type", "FILE").append("value", "urn:test:" + id);
112+
Document reference = new Document("type", "EXTERNALREFERENCE").append("keys", Arrays.asList(key));
113113
return new Document("_id", id).append("idShort", "short-" + id).append("endpoints", Arrays.asList()).append("supplementalSemanticId", Arrays.asList(reference));
114114
}
115115
}

0 commit comments

Comments
 (0)