Skip to content

Commit b1b3d20

Browse files
committed
Adds Pagination on Backend (AAS Repo)
1 parent 54c5e56 commit b1b3d20

4 files changed

Lines changed: 119 additions & 30 deletions

File tree

  • basyx.aasservice
    • basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend
    • basyx.aasservice-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend
    • basyx.aasservice-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend
  • basyx.submodelservice/basyx.submodelservice-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/backend

basyx.aasservice/basyx.aasservice-backend-inmemory/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/InMemoryAasBackend.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.TreeMap;
4141
import java.util.function.Function;
4242
import java.util.stream.Collectors;
43+
import java.util.stream.StreamSupport;
4344

4445
/**
4546
* Implements the AasService as in-memory variant
@@ -55,6 +56,18 @@ public InMemoryAasBackend() {
5556
super(AssetAdministrationShell::getId);
5657
}
5758

59+
@Override
60+
public CursorResult<List<AssetAdministrationShell>> getShells(List<SpecificAssetId> assetIds, String idShort, PaginationInfo pInfo) {
61+
Iterable<AssetAdministrationShell> iterable = getAllAas(assetIds, idShort);
62+
List<AssetAdministrationShell> allAas = StreamSupport.stream(iterable.spliterator(), false).toList();
63+
64+
TreeMap<String, AssetAdministrationShell> aasMap = allAas.stream().collect(Collectors.toMap(AssetAdministrationShell::getId, aas -> aas, (a, b) -> a, TreeMap::new));
65+
66+
PaginationSupport<AssetAdministrationShell> paginationSupport = new PaginationSupport<>(aasMap, AssetAdministrationShell::getId);
67+
68+
return paginationSupport.getPaged(pInfo);
69+
}
70+
5871
@Override
5972
public CursorResult<List<Reference>> getSubmodelReferences(String aasId, PaginationInfo pInfo) {
6073
List<Reference> submodelReferences = getAas(aasId).getSubmodels();

basyx.aasservice/basyx.aasservice-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/MongoDBAasOperations.java

Lines changed: 88 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.eclipse.digitaltwin.basyx.core.exceptions.ElementDoesNotExistException;
3535
import org.eclipse.digitaltwin.basyx.core.pagination.CursorResult;
3636
import org.eclipse.digitaltwin.basyx.core.pagination.PaginationInfo;
37+
import org.springframework.data.domain.Sort;
3738
import org.springframework.data.mongodb.core.MongoOperations;
3839
import org.springframework.data.mongodb.core.aggregation.Aggregation;
3940
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
@@ -67,6 +68,42 @@ public MongoDBAasOperations(MongoOperations mongoOperations) {
6768
collectionName = mongoOperations.getCollectionName(AssetAdministrationShell.class);
6869
}
6970

71+
@Override
72+
public CursorResult<List<AssetAdministrationShell>> getShells(List<SpecificAssetId> assetIds, String idShort, PaginationInfo pInfo) {
73+
List<AggregationOperation> ops = new ArrayList<>();
74+
75+
List<Criteria> criteriaList = buildAasFilterCriteria(assetIds, idShort);
76+
if (!criteriaList.isEmpty()) {
77+
ops.add(Aggregation.match(new Criteria().andOperator(criteriaList.toArray(new Criteria[0]))));
78+
}
79+
80+
// Apply cursor (_id > cursor)
81+
if (hasCursor(pInfo)) {
82+
ops.add(Aggregation.match(Criteria.where("_id").gt(pInfo.getCursor())));
83+
}
84+
85+
// Sort for stable pagination
86+
ops.add(Aggregation.sort(Sort.by(Sort.Direction.ASC, "_id")));
87+
88+
// Apply limit
89+
if (hasLimit(pInfo)) {
90+
ops.add(Aggregation.limit(pInfo.getLimit()));
91+
}
92+
93+
// Run aggregation
94+
Aggregation aggregation = Aggregation.newAggregation(ops);
95+
AggregationResults<AssetAdministrationShell> results =
96+
mongoOperations.aggregate(aggregation, collectionName, AssetAdministrationShell.class);
97+
98+
List<AssetAdministrationShell> shells = results.getMappedResults();
99+
100+
String nextCursor = shells.isEmpty()
101+
? null
102+
: shells.get(shells.size() - 1).getId();
103+
104+
return new CursorResult<>(nextCursor, shells);
105+
}
106+
70107

71108
@Override
72109
public CursorResult<List<Reference>> getSubmodelReferences(@NonNull String aasId, @NonNull PaginationInfo pInfo) throws ElementDoesNotExistException {
@@ -174,29 +211,10 @@ public AssetInformation getAssetInformation(@NonNull String aasId) {
174211
@Override
175212
public Iterable<AssetAdministrationShell> getAllAas(List<SpecificAssetId> assetIds, String idShort) {
176213
Query query = new Query();
177-
Criteria criteria = new Criteria();
178-
179-
String globalAssetId = null;
180-
try {
181-
globalAssetId = assetIds.stream().filter(assetId -> assetId.getName().equals("globalAssetId")).findFirst().get().getValue();
182-
assetIds = assetIds.stream().filter(assetId -> !assetId.getName().equals("globalAssetId")).collect(Collectors.toList());
183-
} catch (Exception ignored) {}
214+
List<Criteria> criteriaList = buildAasFilterCriteria(assetIds, idShort);
184215

185-
if (assetIds != null && !assetIds.isEmpty()) {
186-
List<Criteria> assetIdCriteria = new ArrayList<>();
187-
for (SpecificAssetId assetId : assetIds) {
188-
assetIdCriteria.add(Criteria.where("assetInformation.specificAssetIds.name").is(assetId.getName()));
189-
assetIdCriteria.add(Criteria.where("assetInformation.specificAssetIds.value").is(assetId.getValue()));
190-
}
191-
criteria.andOperator(assetIdCriteria);
192-
}
193-
if (idShort != null && !idShort.isEmpty()) {
194-
criteria.and("idShort").is(idShort);
195-
}
196-
query.addCriteria(criteria);
197-
198-
if (globalAssetId != null && !globalAssetId.isEmpty()) {
199-
query.addCriteria(Criteria.where("assetInformation.globalAssetId").is(globalAssetId));
216+
if (!criteriaList.isEmpty()) {
217+
query.addCriteria(new Criteria().andOperator(criteriaList.toArray(new Criteria[0])));
200218
}
201219

202220
return mongoOperations.find(query, AssetAdministrationShell.class, collectionName);
@@ -217,4 +235,52 @@ private static String extractSubmodelId(Reference reference) {
217235

218236
return "";
219237
}
238+
239+
private List<Criteria> buildAasFilterCriteria(List<SpecificAssetId> assetIds, String idShort) {
240+
List<Criteria> criteriaList = new ArrayList<>();
241+
242+
// Extract globalAssetId from assetIds
243+
String globalAssetId = null;
244+
try {
245+
globalAssetId = assetIds.stream()
246+
.filter(assetId -> "globalAssetId".equals(assetId.getName()))
247+
.findFirst()
248+
.map(SpecificAssetId::getValue)
249+
.orElse(null);
250+
251+
assetIds = assetIds.stream()
252+
.filter(assetId -> !"globalAssetId".equals(assetId.getName()))
253+
.collect(Collectors.toList());
254+
} catch (Exception ignored) {}
255+
256+
// Match specific assetIds (name + value pair inside array)
257+
if (assetIds != null && !assetIds.isEmpty()) {
258+
for (SpecificAssetId assetId : assetIds) {
259+
criteriaList.add(Criteria.where("assetInformation.specificAssetIds")
260+
.elemMatch(Criteria.where("name").is(assetId.getName())
261+
.and("value").is(assetId.getValue())));
262+
}
263+
}
264+
265+
// Match idShort if present
266+
if (idShort != null && !idShort.isEmpty()) {
267+
criteriaList.add(Criteria.where("idShort").is(idShort));
268+
}
269+
270+
// Match globalAssetId if present
271+
if (globalAssetId != null && !globalAssetId.isEmpty()) {
272+
criteriaList.add(Criteria.where("assetInformation.globalAssetId").is(globalAssetId));
273+
}
274+
275+
return criteriaList;
276+
}
277+
278+
private static boolean hasLimit(PaginationInfo pInfo) {
279+
return pInfo.getLimit() != null && pInfo.getLimit() > 0;
280+
}
281+
282+
private static boolean hasCursor(PaginationInfo pInfo) {
283+
return pInfo.getCursor() != null && !pInfo.getCursor().isEmpty();
284+
}
285+
220286
}

basyx.aasservice/basyx.aasservice-backend/src/main/java/org/eclipse/digitaltwin/basyx/aasservice/backend/AasOperations.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
*/
4545
public interface AasOperations {
4646

47+
/**
48+
* Retrieves all Asset Administration Shells
49+
*
50+
* @param assetIds List of specific asset IDs to filter AASs
51+
* @param idShort idShort to filter AASs
52+
* @param pInfo the pagination information
53+
* @return a {@code CursorResult} containing a list of Asset Administration Shells
54+
*/
55+
CursorResult<List<AssetAdministrationShell>> getShells(List<SpecificAssetId> assetIds, String idShort, PaginationInfo pInfo);
56+
4757
/**
4858
* Retrieves all Submodel References for the given AAS.
4959
*

basyx.submodelservice/basyx.submodelservice-backend-mongodb/src/main/java/org/eclipse/digitaltwin/basyx/submodelservice/backend/MongoDbSubmodelOperations.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,6 @@ public CursorResult<List<SubmodelElement>> getSubmodelElements(String submodelId
146146
return new CursorResult<>(nextCursor, elements);
147147
}
148148

149-
private static boolean hasLimit(PaginationInfo pInfo) {
150-
return pInfo.getLimit() != null && pInfo.getLimit() > 0;
151-
}
152-
153-
private static boolean hasCursor(PaginationInfo pInfo) {
154-
return pInfo.getCursor() != null && !pInfo.getCursor().isEmpty();
155-
}
156-
157149
@Override
158150
public SubmodelElement getSubmodelElement(String submodelId, String idShortPath) throws ElementDoesNotExistException {
159151
List<AggregationOperation> ops = MongoFilterBuilder.buildAggregationOperations(submodelId, idShortPath);
@@ -334,4 +326,12 @@ private boolean existsSubmodelElement(String submodelId, String idShortPath){
334326
}
335327
}
336328

329+
private static boolean hasLimit(PaginationInfo pInfo) {
330+
return pInfo.getLimit() != null && pInfo.getLimit() > 0;
331+
}
332+
333+
private static boolean hasCursor(PaginationInfo pInfo) {
334+
return pInfo.getCursor() != null && !pInfo.getCursor().isEmpty();
335+
}
336+
337337
}

0 commit comments

Comments
 (0)