Skip to content

Commit cf0b0c6

Browse files
authored
UFAL/Health report license summary (#1146)
* VSB-TUO/Health report license summary (#1135) * added select get bitstreams based on uuids, improved speed of run * incorrect indentation, removed unused map, checkstyle * VSB-TUO/Fix bitstreamuuid query (#1140) * revent PostgreSQL parameter limit error by batching bitstream UUID queries in findByBitstreamUUIDs * BATCH_SIZE as configurable constant
1 parent d35e377 commit cf0b0c6

5 files changed

Lines changed: 88 additions & 56 deletions

File tree

dspace-api/src/main/java/org/dspace/content/clarin/ClarinLicenseResourceMappingServiceImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ public List<ClarinLicenseResourceMapping> findByBitstreamUUID(Context context, U
181181
return clarinLicenseResourceMappingDAO.findByBitstreamUUID(context, bitstreamID);
182182
}
183183

184+
public List<ClarinLicenseResourceMapping> findByBitstreamUUIDs(Context context, List<UUID> bitstreamIDs)
185+
throws SQLException {
186+
return clarinLicenseResourceMappingDAO.findByBitstreamUUIDs(context, bitstreamIDs);
187+
}
188+
184189
@Override
185190
public ClarinLicense getLicenseToAgree(Context context, UUID userId, UUID resourceID) throws SQLException {
186191
// Load Clarin License for current bitstream.

dspace-api/src/main/java/org/dspace/content/dao/clarin/ClarinLicenseResourceMappingDAO.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@
1818
public interface ClarinLicenseResourceMappingDAO extends GenericDAO<ClarinLicenseResourceMapping> {
1919

2020
List<ClarinLicenseResourceMapping> findByBitstreamUUID(Context context, UUID bitstreamUUID) throws SQLException;
21+
List<ClarinLicenseResourceMapping> findByBitstreamUUIDs(Context context, List<UUID> bitstreamUUIDs)
22+
throws SQLException;
2123
}

dspace-api/src/main/java/org/dspace/content/dao/impl/clarin/ClarinLicenseResourceMappingDAOImpl.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package org.dspace.content.dao.impl.clarin;
99

1010
import java.sql.SQLException;
11+
import java.util.ArrayList;
1112
import java.util.List;
1213
import java.util.UUID;
1314
import javax.persistence.Query;
@@ -23,6 +24,11 @@ protected ClarinLicenseResourceMappingDAOImpl() {
2324
super();
2425
}
2526

27+
/**
28+
* Maximum number of UUIDs to include per query batch.
29+
*/
30+
private static final int BATCH_SIZE = 10_000;
31+
2632
@Override
2733
public List<ClarinLicenseResourceMapping> findByBitstreamUUID(Context context, UUID bitstreamUUID)
2834
throws SQLException {
@@ -36,6 +42,30 @@ public List<ClarinLicenseResourceMapping> findByBitstreamUUID(Context context, U
3642
return list(query);
3743
}
3844

45+
@Override
46+
public List<ClarinLicenseResourceMapping> findByBitstreamUUIDs(Context context, List<UUID> bitstreamUUIDs)
47+
throws SQLException {
48+
if (bitstreamUUIDs == null || bitstreamUUIDs.isEmpty()) {
49+
return List.of();
50+
}
51+
List<ClarinLicenseResourceMapping> results = new ArrayList<>();
52+
53+
for (int i = 0; i < bitstreamUUIDs.size(); i += BATCH_SIZE) {
54+
int end = Math.min(i + BATCH_SIZE, bitstreamUUIDs.size());
55+
List<UUID> batch = bitstreamUUIDs.subList(i, end);
56+
57+
Query query = createQuery(context,
58+
"SELECT clrm FROM ClarinLicenseResourceMapping clrm " +
59+
"WHERE clrm.bitstream.id IN :bitstreamUUIDs");
60+
query.setParameter("bitstreamUUIDs", batch);
61+
query.setHint("org.hibernate.cacheable", Boolean.TRUE);
62+
63+
results.addAll(list(query));
64+
}
65+
66+
return results;
67+
}
68+
3969
@Override
4070
public void delete(Context context, ClarinLicenseResourceMapping clarinLicenseResourceMapping) throws SQLException {
4171
clarinLicenseResourceMapping.setBitstream(null);

dspace-api/src/main/java/org/dspace/content/service/clarin/ClarinLicenseResourceMappingService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,8 @@ void attachLicense(Context context, ClarinLicense clarinLicense, Bitstream bitst
4040

4141
List<ClarinLicenseResourceMapping> findByBitstreamUUID(Context context, UUID bitstreamID) throws SQLException;
4242

43+
List<ClarinLicenseResourceMapping> findByBitstreamUUIDs(Context context, List<UUID> bitstreamIDs)
44+
throws SQLException;
45+
4346
ClarinLicense getLicenseToAgree(Context context, UUID userId, UUID resourceID) throws SQLException;
4447
}

dspace-api/src/main/java/org/dspace/health/LicenseCheck.java

Lines changed: 48 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import java.util.Objects;
1717
import java.util.UUID;
1818

19-
import com.amazonaws.util.CollectionUtils;
2019
import org.dspace.content.Bitstream;
2120
import org.dspace.content.Bundle;
2221
import org.dspace.content.Item;
@@ -38,92 +37,85 @@ public class LicenseCheck extends Check {
3837
private ClarinLicenseResourceMappingService clarinLicenseResourceMappingService =
3938
ClarinServiceFactory.getInstance().getClarinLicenseResourceMappingService();
4039

41-
private Map<String, Integer> licensesCount = new HashMap<>();
42-
private Map<String, List<UUID>> problemItems = new HashMap<>();
4340

4441
@Override
4542
protected String run(ReportInfo ri) {
4643
Context context = new Context();
4744
StringBuilder sb = new StringBuilder();
48-
49-
Iterator<Item> items;
5045
ItemService itemService = ContentServiceFactory.getInstance().getItemService();
46+
Map<String, Integer> licensesCount = new HashMap<>();
47+
Map<String, List<UUID>> problemItems = new HashMap<>();
48+
List<UUID> bitstreamUUIDs = new ArrayList<>();
49+
Iterator<Item> items;
5150
try {
5251
items = itemService.findAll(context);
53-
} catch (SQLException e) {
54-
throw new RuntimeException("Error while fetching items. ", e);
55-
}
56-
57-
for (Iterator<Item> it = items; it.hasNext(); ) {
58-
Item item = it.next();
59-
60-
List<Bundle> bundles = item.getBundles(Constants.DEFAULT_BUNDLE_NAME);
61-
if (bundles.isEmpty()) {
62-
licensesCount.put("no bundle", licensesCount.getOrDefault("no bundle", 0) + 1);
63-
continue;
64-
}
65-
66-
if (item.getBundles(Constants.LICENSE_BUNDLE_NAME).isEmpty()) {
67-
problemItems.computeIfAbsent(
68-
"UUIDs of items without license bundle", k -> new ArrayList<>()).add(item.getID());
52+
while (items.hasNext()) {
53+
Item item = items.next();
54+
List<Bundle> bundles = item.getBundles(Constants.DEFAULT_BUNDLE_NAME);
55+
if (bundles.isEmpty()) {
56+
licensesCount.put("no bundle", licensesCount.getOrDefault("no bundle", 0) + 1);
57+
continue;
58+
}
59+
if (item.getBundles(Constants.LICENSE_BUNDLE_NAME).isEmpty()) {
60+
problemItems.computeIfAbsent(
61+
"UUIDs of items without license bundle", k -> new ArrayList<>()).add(item.getID());
62+
}
63+
List<Bitstream> bitstreams = bundles.get(0).getBitstreams();
64+
if (bitstreams.isEmpty()) {
65+
problemItems.computeIfAbsent(
66+
"UUIDs of items without bitstreams", k -> new ArrayList<>()).add(item.getID());
67+
continue;
68+
}
69+
Bitstream firstBitstream = bitstreams.get(0);
70+
UUID uuid = firstBitstream.getID();
71+
bitstreamUUIDs.add(uuid);
6972
}
70-
71-
List<Bitstream> bitstreams = bundles.get(0).getBitstreams();
72-
if (bitstreams.isEmpty()) {
73-
problemItems.computeIfAbsent(
74-
"UUIDs of items without bitstreams", k -> new ArrayList<>()).add(item.getID());
75-
continue;
73+
// Batch fetch all mappings for the collected UUIDs
74+
List<ClarinLicenseResourceMapping> mappingList =
75+
clarinLicenseResourceMappingService.findByBitstreamUUIDs(context, bitstreamUUIDs);
76+
Map<UUID, ClarinLicenseResourceMapping> mappingByUUID = new HashMap<>();
77+
for (ClarinLicenseResourceMapping mapping : mappingList) {
78+
if (mapping.getBitstream() != null) {
79+
mappingByUUID.put(mapping.getBitstream().getID(), mapping);
80+
}
7681
}
77-
78-
// one bitstream is enough as there is only one license for all bitstreams in item
79-
Bitstream firstBitstream = bitstreams.get(0);
80-
UUID uuid = firstBitstream.getID();
81-
try {
82-
List<ClarinLicenseResourceMapping> clarinLicenseResourceMappingList =
83-
clarinLicenseResourceMappingService.findByBitstreamUUID(context, uuid);
84-
85-
if (CollectionUtils.isNullOrEmpty(clarinLicenseResourceMappingList)) {
86-
log.error("No license mapping found for bitstream with uuid {}", uuid);
82+
// Process results in memory
83+
for (UUID uuid : bitstreamUUIDs) {
84+
ClarinLicenseResourceMapping mapping = mappingByUUID.get(uuid);
85+
if (mapping == null) {
8786
problemItems.computeIfAbsent(
88-
"UUIDs of bitstreams without license mappings", k -> new ArrayList<>()).add(uuid);
87+
"UUIDs of bitstreams without license mappings", k -> new ArrayList<>()).add(uuid);
8988
continue;
9089
}
91-
9290
// Every resource mapping between license and the bitstream has only one record,
9391
// because the bitstream has unique UUID, so get the first record from the List
94-
ClarinLicenseResourceMapping clarinLicenseResourceMapping = clarinLicenseResourceMappingList.get(0);
95-
96-
ClarinLicenseLabel nonExtendedLabel =
97-
clarinLicenseResourceMapping.getLicense().getNonExtendedClarinLicenseLabel();
98-
92+
ClarinLicenseLabel nonExtendedLabel = mapping.getLicense().getNonExtendedClarinLicenseLabel();
9993
if (Objects.isNull(nonExtendedLabel)) {
100-
log.error("Item {} with id {} does not have non extended license label.",
101-
item.getName(), item.getID());
94+
problemItems.computeIfAbsent(
95+
"UUIDs of bitstreams without non-extended license labels",
96+
k -> new ArrayList<>()).add(uuid);
10297
} else {
10398
licensesCount.put(nonExtendedLabel.getLabel(),
10499
licensesCount.getOrDefault(nonExtendedLabel.getLabel(), 0) + 1);
105100
}
106-
} catch (SQLException e) {
107-
throw new RuntimeException("Error while fetching ClarinLicenseResourceMapping by Bitstream UUID: " +
108-
uuid, e);
109101
}
102+
} catch (SQLException e) {
103+
throw new RuntimeException("Error while fetching items or license mappings.", e);
104+
} finally {
105+
context.close();
110106
}
111-
112107
for (Map.Entry<String, Integer> result : licensesCount.entrySet()) {
113108
sb.append(String.format("%-20s: %d\n", result.getKey(), result.getValue()));
114109
}
115-
116110
if (!problemItems.isEmpty()) {
117-
for (Map.Entry<String, List<UUID>> problemItems : problemItems.entrySet()) {
118-
List<UUID> uuids = problemItems.getValue();
119-
sb.append(String.format("\n%s: %d\n", problemItems.getKey(), uuids.size()));
111+
for (Map.Entry<String, List<UUID>> problemEntry : problemItems.entrySet()) {
112+
List<UUID> uuids = problemEntry.getValue();
113+
sb.append(String.format("\n%s: %d\n", problemEntry.getKey(), uuids.size()));
120114
for (UUID uuid : uuids) {
121115
sb.append(String.format(" %s\n", uuid));
122116
}
123117
}
124118
}
125-
126-
context.close();
127119
return sb.toString();
128120
}
129121
}

0 commit comments

Comments
 (0)