1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.opencastproject.assetmanager.impl.persistence;
22
23 import static org.opencastproject.db.Queries.namedQuery;
24
25 import org.opencastproject.assetmanager.api.Availability;
26 import org.opencastproject.assetmanager.api.Property;
27 import org.opencastproject.assetmanager.api.PropertyId;
28 import org.opencastproject.assetmanager.api.Snapshot;
29 import org.opencastproject.assetmanager.impl.HttpAssetProvider;
30 import org.opencastproject.assetmanager.impl.PartialMediaPackage;
31 import org.opencastproject.assetmanager.impl.VersionImpl;
32 import org.opencastproject.db.DBSession;
33 import org.opencastproject.db.Queries;
34 import org.opencastproject.mediapackage.MediaPackage;
35 import org.opencastproject.mediapackage.MediaPackageElement;
36
37 import org.apache.commons.lang3.StringUtils;
38 import org.apache.commons.lang3.tuple.Pair;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import java.util.Collection;
43 import java.util.Collections;
44 import java.util.Date;
45 import java.util.List;
46 import java.util.Optional;
47 import java.util.stream.Collectors;
48
49 import javax.annotation.ParametersAreNonnullByDefault;
50 import javax.persistence.NoResultException;
51 import javax.persistence.TypedQuery;
52
53
54
55
56 @ParametersAreNonnullByDefault
57 public class Database {
58 private static final Logger logger = LoggerFactory.getLogger(Database.class);
59
60 private final DBSession db;
61
62 private HttpAssetProvider httpAssetProvider;
63
64 public Database(DBSession db) {
65 this.db = db;
66 }
67
68 public void setHttpAssetProvider(HttpAssetProvider httpAssetProvider) {
69 this.httpAssetProvider = httpAssetProvider;
70 }
71
72
73
74
75 public boolean saveProperty(final Property property) {
76 return db.execTx(em -> {
77 final PropertyId pId = property.getId();
78 final String mpId = pId.getMediaPackageId();
79 final String namespace = pId.getNamespace();
80 final String propertyName = pId.getName();
81
82
83 Long snapshotCount = em.createQuery(
84 "SELECT COUNT(s.id) FROM Snapshot s "
85 + "WHERE s.mediaPackageId = :mediaPackageId", Long.class)
86 .setParameter("mediaPackageId", mpId)
87 .getSingleResult();
88
89 if (snapshotCount == 0) {
90 return false;
91 }
92
93
94 TypedQuery<PropertyDto> query = em.createQuery(
95 "SELECT p FROM Property p "
96 + "WHERE p.mediaPackageId = :mediaPackageId "
97 + "AND p.namespace = :namespace "
98 + "AND p.propertyName = :propertyName",
99 PropertyDto.class);
100 query.setParameter("mediaPackageId", mpId);
101 query.setParameter("namespace", namespace);
102 query.setParameter("propertyName", propertyName);
103
104 PropertyDto existing = null;
105 try {
106 existing = query.getSingleResult();
107 } catch (NoResultException e) {
108
109 }
110
111 PropertyDto updatedOrNew = existing == null
112 ? PropertyDto.mk(property)
113 : existing.update(property.getValue());
114
115 namedQuery.persistOrUpdate(updatedOrNew).apply(em);
116 return true;
117 });
118 }
119
120
121
122
123
124
125 public VersionImpl claimVersion(final String mpId) {
126 return db.execTx(em -> {
127 final Optional<VersionClaimDto> lastOpt = VersionClaimDto.findLastQuery(mpId).apply(em);
128 if (lastOpt.isPresent()) {
129 final VersionImpl claim = VersionImpl.next(lastOpt.get().getLastClaimed());
130 VersionClaimDto.updateQuery(mpId, claim.value()).apply(em);
131 return claim;
132 } else {
133 final VersionImpl first = VersionImpl.FIRST;
134 em.persist(VersionClaimDto.mk(mpId, first.value()));
135 return first;
136 }
137 });
138 }
139
140
141
142
143 public SnapshotDto saveSnapshot(
144 final String orgId,
145 final PartialMediaPackage pmp,
146 final Date archivalDate,
147 final VersionImpl version,
148 final Availability availability,
149 final String storageId,
150 final String owner) {
151 final SnapshotDto snapshotDto = SnapshotDto.mk(
152 pmp.getMediaPackage(),
153 version,
154 orgId,
155 archivalDate,
156 availability,
157 storageId,
158 owner);
159 return db.execTx(em -> {
160
161 em.persist(snapshotDto);
162
163 for (MediaPackageElement e : pmp.getElements()) {
164 final AssetDto a = AssetDto.mk(
165 e.getIdentifier(),
166 snapshotDto,
167 e.getChecksum().toString(),
168 Optional.ofNullable(e.getMimeType()),
169 storageId,
170 e.getSize());
171 em.persist(a);
172 }
173 return snapshotDto;
174 });
175 }
176
177 public void setStorageLocation(Snapshot snapshot, final String storageId) {
178 setStorageLocation(
179 VersionImpl.mk(snapshot.getVersion()),
180 snapshot.getMediaPackage().getIdentifier().toString(),
181 storageId
182 );
183 }
184
185 public void setStorageLocation(final VersionImpl version, final String mpId, final String storageId) {
186 db.execTx(em -> {
187
188 namedQuery.update(
189 "Snapshot.updateStorageIdByVersionAndMpId",
190 Pair.of("storageId", storageId),
191 Pair.of("version", version.value()),
192 Pair.of("mediaPackageId", mpId)
193 );
194
195
196 Optional<SnapshotDtos.Medium> optSnapshot = getSnapshot(version, mpId);
197 if (optSnapshot.isPresent()) {
198
199 namedQuery.update(
200 "Asset.updateStorageIdBySnapshot",
201 Pair.of("storageId", storageId),
202 Pair.of("snapshot", optSnapshot.get().getSnapshotDto())
203 ).apply(em);
204 }
205
206 return null;
207 });
208 }
209
210 public void setAssetStorageLocation(final VersionImpl version, final String mpId, final String mpeId,
211 final String storageId) {
212 db.execTx(em -> {
213 Optional<SnapshotDtos.Medium> optSnapshot = getSnapshot(version, mpId);
214 if (optSnapshot.isPresent()) {
215
216 namedQuery.update(
217 "Asset.updateStorageIdBySnapshotAndMpElementId",
218 Pair.of("storageId", storageId),
219 Pair.of("snapshot", optSnapshot.get().getSnapshotDto()),
220 Pair.of("mediaPackageElementId", mpeId)
221 ).apply(em);
222 }
223
224 return null;
225 });
226 }
227
228 public int setAvailability(final VersionImpl version, final String mpId, final Availability availability) {
229 return db.execTx(em -> {
230 return namedQuery.update(
231 "Snapshot.updateAvailabilityByVersionAndMpId",
232 Pair.of("availability", availability.name()),
233 Pair.of("version", version.value()),
234 Pair.of("mediaPackageId", mpId)
235 ).apply(em);
236 });
237 }
238
239
240
241
242
243
244 public Optional<AssetDtos.Medium> getAsset(final VersionImpl version, final String mpId, final String mpeId) {
245 return db.execTx(em -> {
246 return Queries.namedQuery
247 .findOpt(
248 "Asset.findMediumByMpIdMpeIdAndVersion",
249 Object[].class,
250 Pair.of("mpId", mpId),
251 Pair.of("mpeId", mpeId),
252 Pair.of("version", version.value()))
253 .apply(em)
254 .map(result -> {
255 AssetDto assetDto = (AssetDto) result[0];
256 String availability = (String) result[1];
257 String organizationId = (String) result[2];
258 return new AssetDtos.Medium(assetDto, Availability.valueOf(availability), organizationId);
259 });
260 });
261 }
262
263 public Optional<SnapshotDtos.Medium> getSnapshot(final VersionImpl version, final String mpId) {
264 return db.execTx(em -> {
265 return namedQuery.findOpt(
266 "Snapshot.findByMpIdAndVersionOrderByVersionDesc",
267 SnapshotDto.class,
268 Pair.of("mpId", mpId),
269 Pair.of("version", version.value()))
270 .apply(em)
271 .map(result -> new SnapshotDtos.Medium(
272 result,
273 Availability.valueOf(result.getAvailability()),
274 result.getStorageId(),
275 result.getOrganizationId(),
276 result.getOwner()
277 ));
278 });
279 }
280
281
282
283
284
285
286
287
288
289 public int deleteProperties(final String mediaPackageId) {
290 return db.execTx(PropertyDto.deleteQuery(mediaPackageId));
291 }
292
293
294
295
296
297
298
299
300
301
302 public int deleteProperties(final String mediaPackageId, final String namespace) {
303 if (StringUtils.isBlank(namespace)) {
304 return db.execTx(PropertyDto.deleteQuery(mediaPackageId));
305 }
306 return db.execTx(PropertyDto.deleteQuery(mediaPackageId, namespace));
307 }
308
309
310
311
312
313
314
315
316 public boolean snapshotExists(final String mediaPackageId) {
317 return db.execTx(SnapshotDto.existsQuery(mediaPackageId));
318 }
319
320
321
322
323
324
325
326
327
328
329 public boolean snapshotExists(final String mediaPackageId, final String organization) {
330 return db.exec(SnapshotDto.existsQuery(mediaPackageId, organization));
331 }
332
333
334
335
336
337
338
339
340
341
342 public List<Property> selectProperties(final String mediaPackageId, final String namespace) {
343 return db.exec(PropertyDto.selectQuery(mediaPackageId, namespace));
344 }
345
346
347
348
349
350
351
352
353 public long countEvents(final String organization) {
354 return db.exec(SnapshotDto.countEventsQuery(organization));
355 }
356
357
358
359
360
361
362
363
364 public long countSnapshots(final String organization) {
365 return db.exec(SnapshotDto.countSnapshotsQuery(organization));
366 }
367
368 public long countAssets() {
369 return db.exec(AssetDto.countAssetsQuery());
370 }
371
372 public long countProperties() {
373 return db.exec(PropertyDto.countPropertiesQuery());
374 }
375
376 public Optional<AssetDtos.Full> findAssetByChecksumAndStoreAndOrg(final String checksum, final String storeId,
377 final String orgId) {
378 return db.execTx(em -> {
379 return namedQuery.findOpt(
380 "Asset.findByChecksumStorageIdAndOrganizationId",
381 AssetDto.class,
382 Pair.of("checksum", checksum),
383 Pair.of("storageId", storeId),
384 Pair.of("orgId", orgId))
385 .apply(em)
386 .map(result -> {
387 SnapshotDto snapshot = result.getSnapshot();
388 return new AssetDtos.Full(
389 result,
390 Availability.valueOf(snapshot.getAvailability()),
391 snapshot.getStorageId(),
392 snapshot.getOrganizationId(),
393 snapshot.getOwner(),
394 snapshot.getMediaPackageId(),
395 snapshot.getVersion()
396 );
397 });
398 });
399 }
400
401 public Optional<Snapshot> getLatestSnapshot(String mediaPackageId) {
402 return getLatestSnapshot(mediaPackageId, null);
403 }
404
405 public Optional<Snapshot> getLatestSnapshot(String mediaPackageId, String orgId) {
406 return db.execTx(em -> {
407 Optional<SnapshotDto> snapshotDto = namedQuery.findOpt(
408 "Snapshot.findLatest",
409 SnapshotDto.class,
410 Pair.of("mediaPackageId", mediaPackageId),
411 Pair.of("organizationId", orgId)
412 ).apply(em);
413
414 if (snapshotDto.isEmpty()) {
415 return Optional.empty();
416 }
417
418 Snapshot snapshot = snapshotDto.get().toSnapshot();
419
420 snapshot = httpAssetProvider.prepareForDelivery(snapshot);
421
422 return Optional.of(snapshot);
423 });
424 }
425
426 public Optional<MediaPackage> getMediaPackage(String mediaPackageId) {
427 return getMediaPackage(mediaPackageId, null);
428 }
429 public Optional<MediaPackage> getMediaPackage(String mediaPackageId, String orgId) {
430 return getLatestSnapshot(mediaPackageId, orgId).map(Snapshot::getMediaPackage);
431 }
432
433 public List<Snapshot> getSnapshots(String mediaPackageId) {
434 return getSnapshots(mediaPackageId, null);
435 }
436
437 public List<Snapshot> getSnapshots(String mediaPackageId, String orgId) {
438 return getSnapshots(mediaPackageId, orgId, null);
439 }
440
441 public List<Snapshot> getSnapshots(String mediaPackageId, String orgId, String orderByVersion) {
442 return db.execTx(em -> {
443 String namedQueryName = "ASC".equals(orderByVersion)
444 ? "Snapshot.findOldestVersionFirst" : "Snapshot.findLatestVersionFirst";
445
446 List<SnapshotDto> snapshotDto = namedQuery.findAll(
447 namedQueryName,
448 SnapshotDto.class,
449 Pair.of("mediaPackageId", mediaPackageId),
450 Pair.of("organizationId", orgId)
451 ).apply(em);
452
453 return snapshotDtoToSnapshot(snapshotDto);
454 });
455 }
456
457 public int deleteSnapshots(String mediaPackageId, String orgId) {
458 return db.execTx(em -> {
459 return namedQuery.delete(
460 "Snapshot.delete",
461 Pair.of("mediaPackageId", mediaPackageId),
462 Pair.of("organizationId", orgId)
463 ).apply(em);
464 });
465 }
466
467 public int deleteAllButLatestSnapshot(String mediaPackageId, String orgId) {
468 return db.execTx(em -> {
469 return namedQuery.delete(
470 "Snapshot.deleteAllButLatest",
471 Pair.of("mediaPackageId", mediaPackageId),
472 Pair.of("organizationId", orgId)
473 ).apply(em);
474 });
475 }
476
477 public List<Snapshot> getSnapshotsByMpIdAndVersion(String mediaPackageId, Long version, String orgId) {
478 return db.execTx(em -> {
479 List<SnapshotDto> snapshotDto = namedQuery.findAll(
480 "Snapshot.findByMpIdAndVersion",
481 SnapshotDto.class,
482 Pair.of("mediaPackageId", mediaPackageId),
483 Pair.of("version", version),
484 Pair.of("organizationId", orgId)
485 ).apply(em);
486
487 return snapshotDtoToSnapshot(snapshotDto);
488 });
489 }
490
491 public List<Snapshot> getSnapshotsByDateOrderByMpId(Date start, Date end, String orgId) {
492 return db.execTx(em -> {
493 List<SnapshotDto> snapshotDto = namedQuery.findAll(
494 "Snapshot.findByDateOrderByMpId",
495 SnapshotDto.class,
496 Pair.of("startDate", start),
497 Pair.of("endDate", end),
498 Pair.of("organizationId", orgId)
499 ).apply(em);
500
501 return snapshotDtoToSnapshot(snapshotDto);
502 });
503 }
504
505 public List<Snapshot> getSnapshotsByMpdIdAndDate(String mediaPackageId, Date start, Date end, String orgId) {
506 return getSnapshotsByMpdIdAndDate(mediaPackageId, start, end, orgId, null);
507 }
508
509 public List<Snapshot> getSnapshotsByMpdIdAndDate(String mediaPackageId, Date start, Date end, String orgId,
510 String orderByVersion) {
511 return db.execTx(em -> {
512 String namedQueryName = "Snapshot.findByMpIdAndDate";
513 if ("ASC".equals(orderByVersion)) {
514 namedQueryName = "Snapshot.findByMpIdAndDateOldestVersionFirst";
515 }
516 if ("DESC".equals(orderByVersion)) {
517 namedQueryName = "Snapshot.findByMpIdAndDateLatestVersionFirst";
518 }
519
520 List<SnapshotDto> snapshotDto = namedQuery.findAll(
521 namedQueryName,
522 SnapshotDto.class,
523 Pair.of("mediaPackageId", mediaPackageId),
524 Pair.of("startDate", start),
525 Pair.of("endDate", end),
526 Pair.of("organizationId", orgId)
527 ).apply(em);
528
529 return snapshotDtoToSnapshot(snapshotDto);
530 });
531 }
532
533 public List<Snapshot> getSnapshotsByNotStorageAndDate(String storageId, Date start, Date end, String orgId) {
534 return db.execTx(em -> {
535 List<SnapshotDto> snapshotDto = namedQuery.findAll(
536 "Snapshot.findByNotStorageAndDate",
537 SnapshotDto.class,
538 Pair.of("storageId", storageId),
539 Pair.of("startDate", start),
540 Pair.of("endDate", end),
541 Pair.of("organizationId", orgId)
542 ).apply(em);
543
544 return snapshotDtoToSnapshot(snapshotDto);
545 });
546 }
547
548 public List<Snapshot> getSnapshotsBySeries(String seriesId, String orgId) {
549 return db.execTx(em -> {
550 List<SnapshotDto> snapshotDto = namedQuery.findAll(
551 "Snapshot.findLatestBySeriesId",
552 SnapshotDto.class,
553 Pair.of("seriesId", seriesId),
554 Pair.of("organizationId", orgId)
555 ).apply(em);
556
557 return snapshotDtoToSnapshot(snapshotDto);
558 });
559 }
560
561 public List<Snapshot> getLatestSnapshotsByMediaPackageIds(Collection mediaPackageIds, String orgId) {
562 if (mediaPackageIds.isEmpty()) {
563 return Collections.emptyList();
564 }
565 return db.execTx(em -> {
566 List<SnapshotDto> snapshotDto = namedQuery.findAll(
567 "Snapshot.findLatestByMpIds",
568 SnapshotDto.class,
569 Pair.of("mediaPackageIds", mediaPackageIds),
570 Pair.of("organizationId", orgId)
571 ).apply(em);
572
573 return snapshotDtoToSnapshot(snapshotDto);
574 });
575 }
576
577 public Optional<Snapshot> getSnapshot(String mediaPackageId, String orgId, Long version) {
578 return db.execTx(em -> {
579 Optional<SnapshotDto> snapshotDto = namedQuery.findOpt(
580 "Snapshot.findByMpIdOrgIdAndVersion",
581 SnapshotDto.class,
582 Pair.of("mediaPackageId", mediaPackageId),
583 Pair.of("organizationId", orgId),
584 Pair.of("version", version)
585 ).apply(em);
586
587 if (snapshotDto.isEmpty()) {
588 return Optional.empty();
589 }
590
591 Snapshot snapshot = snapshotDto.get().toSnapshot();
592
593 snapshot = httpAssetProvider.prepareForDelivery(snapshot);
594
595 return Optional.of(snapshot);
596 });
597 }
598
599 public List<Snapshot> getSnapshotsForIndexRebuild(int offset, int limit) {
600 return db.execTx(em -> {
601 List<SnapshotDto> snapshotDto = namedQuery.findSome(
602 "Snapshot.findForIndexRebuild",
603 offset,
604 limit,
605 SnapshotDto.class
606 ).apply(em);
607
608 return snapshotDtoToSnapshot(snapshotDto);
609 });
610 }
611
612 public List<Long> getVersionsByMediaPackage(String mediaPackageId, String orgId) {
613 return db.execTx(em -> {
614 List<Long> versions = namedQuery.findAll(
615 "Snapshot.getSnapshotVersions",
616 Long.class,
617 Pair.of("mediaPackageId", mediaPackageId),
618 Pair.of("organizationId", orgId)
619 ).apply(em);
620
621 return versions;
622 });
623 }
624
625
626
627
628
629 public static <A> A insidePersistenceContextCheck(A a) {
630 if (a != null) {
631 return a;
632 } else {
633 throw new RuntimeException(
634 "Used DTO outside of a persistence context or the DTO has not been assigned an ID yet.");
635 }
636 }
637
638 private List<Snapshot> snapshotDtoToSnapshot(List<SnapshotDto> snapshotDtos) {
639 return snapshotDtos.stream()
640 .map(s -> s.toSnapshot())
641 .map(s -> httpAssetProvider.prepareForDelivery(s))
642 .collect(Collectors.toList());
643 }
644 }