• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IQSS / dataverse / #22693

03 Jul 2024 01:09PM CUT coverage: 20.626% (-0.09%) from 20.716%
#22693

push

github

web-flow
Merge pull request #10664 from IQSS/develop

merge develop into master for 6.3

195 of 1852 new or added lines in 82 files covered. (10.53%)

72 existing lines in 33 files now uncovered.

17335 of 84043 relevant lines covered (20.63%)

0.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/edu/harvard/iq/dataverse/DatasetVersionFilesServiceBean.java
1
package edu.harvard.iq.dataverse;
2

3
import edu.harvard.iq.dataverse.FileSearchCriteria.FileAccessStatus;
4
import jakarta.ejb.Stateless;
5
import jakarta.inject.Named;
6
import jakarta.persistence.EntityManager;
7
import jakarta.persistence.PersistenceContext;
8
import jakarta.persistence.Tuple;
9
import jakarta.persistence.TypedQuery;
10
import jakarta.persistence.criteria.*;
11

12
import java.io.Serializable;
13
import java.sql.Timestamp;
14
import java.util.*;
15

16
import static edu.harvard.iq.dataverse.DataFileTag.TagLabelToTypes;
17

18
@Stateless
19
@Named
20
public class DatasetVersionFilesServiceBean implements Serializable {
×
21

22
    @PersistenceContext(unitName = "VDCNet-ejbPU")
23
    private EntityManager em;
24

25
    /**
26
     * Different criteria to sort the results of FileMetadata queries used in {@link DatasetVersionFilesServiceBean#getFileMetadatas}
27
     */
28
    public enum FileOrderCriteria {
×
29
        NameAZ, NameZA, Newest, Oldest, Size, Type
×
30
    }
31

32
    /**
33
     * Mode to base the search in {@link DatasetVersionFilesServiceBean#getFilesDownloadSize(DatasetVersion, FileSearchCriteria, FileDownloadSizeMode)}
34
     * <p>
35
     * All: Includes both archival and original sizes for tabular files
36
     * Archival: Includes only the archival size for tabular files
37
     * Original: Includes only the original size for tabular files
38
     * <p>
39
     * All the modes include archival sizes for non-tabular files
40
     */
41
    public enum FileDownloadSizeMode {
×
42
        All, Original, Archival
×
43
    }
44

45
    /**
46
     * Given a DatasetVersion, returns its total file metadata count
47
     *
48
     * @param datasetVersion the DatasetVersion to access
49
     * @return long value of total file metadata count
50
     */
51
    public long getFileMetadataCount(DatasetVersion datasetVersion) {
NEW
52
        return getFileMetadataCount(datasetVersion, new FileSearchCriteria(null, null, null, null, null));
×
53
    }
54

55
    /**
56
     * Given a DatasetVersion, returns its total file metadata count
57
     *
58
     * @param datasetVersion the DatasetVersion to access
59
     * @param searchCriteria for counting only files matching this criteria
60
     * @return long value of total file metadata count
61
     */
62
    public long getFileMetadataCount(DatasetVersion datasetVersion, FileSearchCriteria searchCriteria) {
63
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
64
        CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
×
65
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
66
        criteriaQuery
×
67
                .select(criteriaBuilder.count(fileMetadataRoot))
×
68
                .where(createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot));
×
69
        return em.createQuery(criteriaQuery).getSingleResult();
×
70
    }
71

72
    /**
73
     * Given a DatasetVersion, returns its file metadata count per content type
74
     *
75
     * @param datasetVersion the DatasetVersion to access
76
     * @param searchCriteria for counting only files matching this criteria
77
     * @return Map<String, Long> of file metadata counts per content type
78
     */
79
    public Map<String, Long> getFileMetadataCountPerContentType(DatasetVersion datasetVersion, FileSearchCriteria searchCriteria) {
80
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
81
        CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
×
82
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
83
        Path<String> contentType = fileMetadataRoot.get("dataFile").get("contentType");
×
84
        criteriaQuery
×
85
                .multiselect(contentType, criteriaBuilder.count(contentType))
×
86
                .where(createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot))
×
87
                .groupBy(contentType);
×
88
        return getStringLongMapResultFromQuery(criteriaQuery);
×
89
    }
90

91
    /**
92
     * Given a DatasetVersion, returns its file metadata count per category name
93
     *
94
     * @param datasetVersion the DatasetVersion to access
95
     * @param searchCriteria for counting only files matching this criteria
96
     * @return Map<String, Long> of file metadata counts per category name
97
     */
98
    public Map<String, Long> getFileMetadataCountPerCategoryName(DatasetVersion datasetVersion, FileSearchCriteria searchCriteria) {
99
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
100
        CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
×
101
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
102
        Root<DataFileCategory> dataFileCategoryRoot = criteriaQuery.from(DataFileCategory.class);
×
103
        Path<String> categoryName = dataFileCategoryRoot.get("name");
×
104
        criteriaQuery
×
105
                .multiselect(categoryName, criteriaBuilder.count(fileMetadataRoot))
×
106
                .where(criteriaBuilder.and(
×
107
                        createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot),
×
108
                        dataFileCategoryRoot.in(fileMetadataRoot.get("fileCategories"))))
×
109
                .groupBy(categoryName);
×
110
        return getStringLongMapResultFromQuery(criteriaQuery);
×
111
    }
112

113
    /**
114
     * Given a DatasetVersion, returns its file metadata count per DataFileTag.TagType
115
     *
116
     * @param datasetVersion the DatasetVersion to access
117
     * @param searchCriteria for counting only files matching this criteria
118
     * @return Map<DataFileTag.TagType, Long> of file metadata counts per DataFileTag.TagType
119
     */
120
    public Map<DataFileTag.TagType, Long> getFileMetadataCountPerTabularTagName(DatasetVersion datasetVersion, FileSearchCriteria searchCriteria) {
121
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
122
        CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
×
123
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
124
        Root<DataFileTag> dataFileTagRoot = criteriaQuery.from(DataFileTag.class);
×
125
        Path<DataFileTag.TagType> dataFileTagType = dataFileTagRoot.get("type");
×
126
        criteriaQuery
×
127
                .multiselect(dataFileTagType, criteriaBuilder.count(fileMetadataRoot))
×
128
                .where(criteriaBuilder.and(
×
129
                        createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot),
×
130
                        dataFileTagRoot.in(fileMetadataRoot.get("dataFile").get("dataFileTags"))))
×
131
                .groupBy(dataFileTagType);
×
132
        List<Tuple> tagNameOccurrences = em.createQuery(criteriaQuery).getResultList();
×
133
        Map<DataFileTag.TagType, Long> result = new HashMap<>();
×
134
        for (Tuple occurrence : tagNameOccurrences) {
×
135
            result.put(occurrence.get(0, DataFileTag.TagType.class), occurrence.get(1, Long.class));
×
136
        }
×
137
        return result;
×
138
    }
139

140
    /**
141
     * Given a DatasetVersion, returns its file metadata count per FileAccessStatus
142
     *
143
     * @param datasetVersion the DatasetVersion to access
144
     * @param searchCriteria for counting only files matching this criteria
145
     * @return Map<FileAccessStatus, Long> of file metadata counts per FileAccessStatus
146
     */
147
    public Map<FileAccessStatus, Long> getFileMetadataCountPerAccessStatus(DatasetVersion datasetVersion, FileSearchCriteria searchCriteria) {
148
        Map<FileAccessStatus, Long> allCounts = new HashMap<>();
×
149
        addAccessStatusCountToTotal(datasetVersion, allCounts, FileAccessStatus.Public, searchCriteria);
×
150
        addAccessStatusCountToTotal(datasetVersion, allCounts, FileAccessStatus.Restricted, searchCriteria);
×
151
        addAccessStatusCountToTotal(datasetVersion, allCounts, FileAccessStatus.EmbargoedThenPublic, searchCriteria);
×
152
        addAccessStatusCountToTotal(datasetVersion, allCounts, FileAccessStatus.EmbargoedThenRestricted, searchCriteria);
×
153
        return allCounts;
×
154
    }
155

156
    /**
157
     * Returns a FileMetadata list of files in the specified DatasetVersion
158
     *
159
     * @param datasetVersion the DatasetVersion to access
160
     * @param limit          for pagination, can be null
161
     * @param offset         for pagination, can be null
162
     * @param searchCriteria for retrieving only files matching this criteria
163
     * @param orderCriteria  a FileOrderCriteria to order the results
164
     * @return a FileMetadata list from the specified DatasetVersion
165
     */
166
    public List<FileMetadata> getFileMetadatas(DatasetVersion datasetVersion, Integer limit, Integer offset, FileSearchCriteria searchCriteria, FileOrderCriteria orderCriteria) {
167
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
168
        CriteriaQuery<FileMetadata> criteriaQuery = criteriaBuilder.createQuery(FileMetadata.class);
×
169
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
170
        criteriaQuery
×
171
                .select(fileMetadataRoot)
×
172
                .where(createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot))
×
173
                .orderBy(createGetFileMetadatasOrder(criteriaBuilder, orderCriteria, fileMetadataRoot));
×
174
        TypedQuery<FileMetadata> typedQuery = em.createQuery(criteriaQuery);
×
175
        if (limit != null) {
×
176
            typedQuery.setMaxResults(limit);
×
177
        }
178
        if (offset != null) {
×
179
            typedQuery.setFirstResult(offset);
×
180
        }
181
        return typedQuery.getResultList();
×
182
    }
183

184
    /**
185
     * Returns the total download size of all files for a particular DatasetVersion
186
     *
187
     * @param datasetVersion the DatasetVersion to access
188
     * @param searchCriteria for retrieving only files matching this criteria
189
     * @param mode           a FileDownloadSizeMode to base the search on
190
     * @return long value of total file download size
191
     */
192
    public long getFilesDownloadSize(DatasetVersion datasetVersion, FileSearchCriteria searchCriteria, FileDownloadSizeMode mode) {
193
        return switch (mode) {
×
194
            case All ->
195
                    Long.sum(getOriginalTabularFilesSize(datasetVersion, searchCriteria), getArchivalFilesSize(datasetVersion, false, searchCriteria));
×
196
            case Original ->
197
                    Long.sum(getOriginalTabularFilesSize(datasetVersion, searchCriteria), getArchivalFilesSize(datasetVersion, true, searchCriteria));
×
198
            case Archival -> getArchivalFilesSize(datasetVersion, false, searchCriteria);
×
199
        };
200
    }
201

202
    /**
203
     * Determines whether or not a DataFile is present in a DatasetVersion
204
     *
205
     * @param datasetVersion the DatasetVersion to check
206
     * @param dataFile the DataFile to check
207
     * @return boolean value
208
     */
209
    public boolean isDataFilePresentInDatasetVersion(DatasetVersion datasetVersion, DataFile dataFile) {
NEW
210
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
NEW
211
        CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
×
NEW
212
        Root<DataFile> dataFileRoot = criteriaQuery.from(DataFile.class);
×
NEW
213
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
NEW
214
        Root<DatasetVersion> datasetVersionRoot = criteriaQuery.from(DatasetVersion.class);
×
NEW
215
        criteriaQuery
×
NEW
216
                .select(criteriaBuilder.count(dataFileRoot))
×
NEW
217
                .where(criteriaBuilder.and(
×
NEW
218
                        criteriaBuilder.equal(dataFileRoot.get("id"), dataFile.getId()),
×
NEW
219
                        criteriaBuilder.equal(datasetVersionRoot.get("id"), datasetVersion.getId()),
×
NEW
220
                        fileMetadataRoot.in(dataFileRoot.get("fileMetadatas")),
×
NEW
221
                        fileMetadataRoot.in(datasetVersionRoot.get("fileMetadatas"))
×
222
                        )
223
                );
NEW
224
        Long count = em.createQuery(criteriaQuery).getSingleResult();
×
NEW
225
        return count != null && count > 0;
×
226
    }
227

228
    private void addAccessStatusCountToTotal(DatasetVersion datasetVersion, Map<FileAccessStatus, Long> totalCounts, FileAccessStatus dataFileAccessStatus, FileSearchCriteria searchCriteria) {
229
        long fileMetadataCount = getFileMetadataCountByAccessStatus(datasetVersion, dataFileAccessStatus, searchCriteria);
×
230
        if (fileMetadataCount > 0) {
×
231
            totalCounts.put(dataFileAccessStatus, fileMetadataCount);
×
232
        }
233
    }
×
234

235
    private long getFileMetadataCountByAccessStatus(DatasetVersion datasetVersion, FileAccessStatus accessStatus, FileSearchCriteria searchCriteria) {
236
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
237
        CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
×
238
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
239
        criteriaQuery
×
240
                .select(criteriaBuilder.count(fileMetadataRoot))
×
241
                .where(criteriaBuilder.and(
×
242
                        createSearchCriteriaAccessStatusPredicate(accessStatus, criteriaBuilder, fileMetadataRoot),
×
243
                        createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot)));
×
244
        return em.createQuery(criteriaQuery).getSingleResult();
×
245
    }
246

247
    private Predicate createSearchCriteriaAccessStatusPredicate(FileAccessStatus accessStatus, CriteriaBuilder criteriaBuilder, Root<FileMetadata> fileMetadataRoot) {
248
        Path<Object> dataFile = fileMetadataRoot.get("dataFile");
×
NEW
249
        Path<Object> retention = dataFile.get("retention");
×
NEW
250
        Predicate retentionExpiredPredicate = criteriaBuilder.lessThan(retention.<Date>get("dateUnavailable"), criteriaBuilder.currentDate());
×
251
        Path<Object> embargo = dataFile.get("embargo");
×
252
        Predicate activelyEmbargoedPredicate = criteriaBuilder.greaterThanOrEqualTo(embargo.<Date>get("dateAvailable"), criteriaBuilder.currentDate());
×
253
        Predicate inactivelyEmbargoedPredicate = criteriaBuilder.isNull(embargo);
×
254
        Path<Boolean> isRestricted = dataFile.get("restricted");
×
255
        Predicate isRestrictedPredicate = criteriaBuilder.isTrue(isRestricted);
×
256
        Predicate isUnrestrictedPredicate = criteriaBuilder.isFalse(isRestricted);
×
257
        return switch (accessStatus) {
×
NEW
258
            case RetentionPeriodExpired -> criteriaBuilder.and(retentionExpiredPredicate);
×
259
            case EmbargoedThenRestricted -> criteriaBuilder.and(activelyEmbargoedPredicate, isRestrictedPredicate);
×
260
            case EmbargoedThenPublic -> criteriaBuilder.and(activelyEmbargoedPredicate, isUnrestrictedPredicate);
×
261
            case Restricted -> criteriaBuilder.and(inactivelyEmbargoedPredicate, isRestrictedPredicate);
×
262
            case Public -> criteriaBuilder.and(inactivelyEmbargoedPredicate, isUnrestrictedPredicate);
×
263
        };
264
    }
265

266
    private Predicate createSearchCriteriaPredicate(DatasetVersion datasetVersion,
267
                                                    FileSearchCriteria searchCriteria,
268
                                                    CriteriaBuilder criteriaBuilder,
269
                                                    CriteriaQuery<?> criteriaQuery,
270
                                                    Root<FileMetadata> fileMetadataRoot) {
271
        List<Predicate> predicates = new ArrayList<>();
×
272
        Predicate basePredicate = criteriaBuilder.equal(fileMetadataRoot.get("datasetVersion").<String>get("id"), datasetVersion.getId());
×
273
        predicates.add(basePredicate);
×
274
        String contentType = searchCriteria.getContentType();
×
275
        if (contentType != null) {
×
276
            predicates.add(criteriaBuilder.equal(fileMetadataRoot.get("dataFile").<String>get("contentType"), contentType));
×
277
        }
278
        FileAccessStatus accessStatus = searchCriteria.getAccessStatus();
×
279
        if (accessStatus != null) {
×
280
            predicates.add(createSearchCriteriaAccessStatusPredicate(accessStatus, criteriaBuilder, fileMetadataRoot));
×
281
        }
282
        String categoryName = searchCriteria.getCategoryName();
×
283
        if (categoryName != null) {
×
284
            Root<DataFileCategory> dataFileCategoryRoot = criteriaQuery.from(DataFileCategory.class);
×
285
            predicates.add(criteriaBuilder.equal(dataFileCategoryRoot.get("name"), categoryName));
×
286
            predicates.add(dataFileCategoryRoot.in(fileMetadataRoot.get("fileCategories")));
×
287
        }
288
        String tabularTagName = searchCriteria.getTabularTagName();
×
289
        if (tabularTagName != null) {
×
290
            Root<DataFileTag> dataFileTagRoot = criteriaQuery.from(DataFileTag.class);
×
291
            predicates.add(criteriaBuilder.equal(dataFileTagRoot.get("type"), TagLabelToTypes.get(tabularTagName)));
×
292
            predicates.add(dataFileTagRoot.in(fileMetadataRoot.get("dataFile").get("dataFileTags")));
×
293
        }
294
        String searchText = searchCriteria.getSearchText();
×
295
        if (searchText != null && !searchText.isEmpty()) {
×
296
            searchText = searchText.trim().toLowerCase();
×
297
            predicates.add(criteriaBuilder.like(fileMetadataRoot.get("label"), "%" + searchText + "%"));
×
298
        }
299
        return criteriaBuilder.and(predicates.toArray(new Predicate[]{}));
×
300
    }
301

302
    private List<Order> createGetFileMetadatasOrder(CriteriaBuilder criteriaBuilder,
303
                                                    FileOrderCriteria orderCriteria,
304
                                                    Root<FileMetadata> fileMetadataRoot) {
305
        Path<Object> label = fileMetadataRoot.get("label");
×
306
        Path<Object> dataFile = fileMetadataRoot.get("dataFile");
×
307
        Path<Timestamp> publicationDate = dataFile.get("publicationDate");
×
308
        Path<Timestamp> createDate = dataFile.get("createDate");
×
309
        Expression<Object> orderByLifetimeExpression = criteriaBuilder.selectCase().when(publicationDate.isNotNull(), publicationDate).otherwise(createDate);
×
310
        List<Order> orderList = new ArrayList<>();
×
311
        switch (orderCriteria) {
×
312
            case NameZA -> orderList.add(criteriaBuilder.desc(label));
×
313
            case Newest -> orderList.add(criteriaBuilder.desc(orderByLifetimeExpression));
×
314
            case Oldest -> orderList.add(criteriaBuilder.asc(orderByLifetimeExpression));
×
315
            case Size -> orderList.add(criteriaBuilder.asc(dataFile.get("filesize")));
×
316
            case Type -> {
317
                orderList.add(criteriaBuilder.asc(dataFile.get("contentType")));
×
318
                orderList.add(criteriaBuilder.asc(label));
×
319
            }
×
320
            default -> orderList.add(criteriaBuilder.asc(label));
×
321
        }
322
        return orderList;
×
323
    }
324

325
    private long getOriginalTabularFilesSize(DatasetVersion datasetVersion, FileSearchCriteria searchCriteria) {
326
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
327
        CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
×
328
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
329
        Root<DataTable> dataTableRoot = criteriaQuery.from(DataTable.class);
×
330
        criteriaQuery
×
331
                .select(criteriaBuilder.sum(dataTableRoot.get("originalFileSize")))
×
332
                .where(criteriaBuilder.and(
×
333
                        criteriaBuilder.equal(dataTableRoot.get("dataFile"), fileMetadataRoot.get("dataFile")),
×
334
                        createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot)));
×
335
        Long result = em.createQuery(criteriaQuery).getSingleResult();
×
336
        return (result == null) ? 0 : result;
×
337
    }
338

339
    private long getArchivalFilesSize(DatasetVersion datasetVersion, boolean ignoreTabular, FileSearchCriteria searchCriteria) {
340
        CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
×
341
        CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
×
342
        Root<FileMetadata> fileMetadataRoot = criteriaQuery.from(FileMetadata.class);
×
343
        Predicate searchCriteriaPredicate = createSearchCriteriaPredicate(datasetVersion, searchCriteria, criteriaBuilder, criteriaQuery, fileMetadataRoot);
×
344
        Predicate wherePredicate;
345
        if (ignoreTabular) {
×
346
            wherePredicate = criteriaBuilder.and(searchCriteriaPredicate, criteriaBuilder.isEmpty(fileMetadataRoot.get("dataFile").get("dataTables")));
×
347
        } else {
348
            wherePredicate = searchCriteriaPredicate;
×
349
        }
350
        criteriaQuery
×
351
                .select(criteriaBuilder.sum(fileMetadataRoot.get("dataFile").get("filesize")))
×
352
                .where(wherePredicate);
×
353
        Long result = em.createQuery(criteriaQuery).getSingleResult();
×
354
        return (result == null) ? 0 : result;
×
355
    }
356

357
    private Map<String, Long> getStringLongMapResultFromQuery(CriteriaQuery<Tuple> criteriaQuery) {
358
        List<Tuple> categoryNameOccurrences = em.createQuery(criteriaQuery).getResultList();
×
359
        Map<String, Long> result = new HashMap<>();
×
360
        for (Tuple occurrence : categoryNameOccurrences) {
×
361
            result.put(occurrence.get(0, String.class), occurrence.get(1, Long.class));
×
362
        }
×
363
        return result;
×
364
    }
365
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc