1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.datamodel.metadata;
20
21 import static org.mycore.access.MCRAccessManager.PERMISSION_DELETE;
22 import static org.mycore.access.MCRAccessManager.PERMISSION_WRITE;
23
24 import java.io.IOException;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27 import java.nio.file.Paths;
28 import java.util.Collection;
29 import java.util.Date;
30 import java.util.List;
31 import java.util.Optional;
32 import java.util.concurrent.TimeUnit;
33 import java.util.function.BiConsumer;
34 import java.util.stream.Collectors;
35
36 import org.apache.logging.log4j.LogManager;
37 import org.apache.logging.log4j.Logger;
38 import org.jdom2.Document;
39 import org.jdom2.JDOMException;
40 import org.mycore.access.MCRAccessException;
41 import org.mycore.access.MCRAccessManager;
42 import org.mycore.common.MCRCache;
43 import org.mycore.common.MCRCache.ModifiedHandle;
44 import org.mycore.common.MCRException;
45 import org.mycore.common.MCRPersistenceException;
46 import org.mycore.common.events.MCREvent;
47 import org.mycore.common.events.MCREventManager;
48 import org.mycore.datamodel.common.MCRActiveLinkException;
49 import org.mycore.datamodel.common.MCRLinkTableManager;
50 import org.mycore.datamodel.common.MCRMarkManager;
51 import org.mycore.datamodel.common.MCRMarkManager.Operation;
52 import org.mycore.datamodel.common.MCRXMLMetadataManager;
53 import org.mycore.datamodel.metadata.share.MCRMetadataShareAgent;
54 import org.mycore.datamodel.metadata.share.MCRMetadataShareAgentFactory;
55 import org.mycore.datamodel.niofs.MCRPath;
56 import org.mycore.datamodel.niofs.utils.MCRRecursiveDeleter;
57 import org.mycore.datamodel.niofs.utils.MCRTreeCopier;
58 import org.xml.sax.SAXException;
59
60 import jakarta.persistence.PersistenceException;
61
62
63
64
65
66
67
68 public final class MCRMetadataManager {
69
70 private static final Logger LOGGER = LogManager.getLogger();
71
72 private static final MCRCache<MCRObjectID, MCRObjectID> DERIVATE_OBJECT_MAP = new MCRCache<>(10000,
73 "derivate objectid cache");
74
75 private static final MCRCache<MCRObjectID, List<MCRObjectID>> OBJECT_DERIVATE_MAP = new MCRCache<>(10000,
76 "derivate objectid cache");
77
78 private static final MCRXMLMetadataManager XML_MANAGER = MCRXMLMetadataManager.instance();
79
80 private MCRMetadataManager() {
81
82 }
83
84
85
86
87
88
89
90
91
92
93
94 public static MCRObjectID getObjectId(final MCRObjectID derivateID, final long expire, TimeUnit unit) {
95 ModifiedHandle modifiedHandle = XML_MANAGER.getLastModifiedHandle(derivateID, expire, unit);
96 MCRObjectID mcrObjectID = null;
97 try {
98 mcrObjectID = DERIVATE_OBJECT_MAP.getIfUpToDate(derivateID, modifiedHandle);
99 } catch (IOException e) {
100 LOGGER.warn("Could not determine last modified timestamp of derivate {}", derivateID);
101 }
102 if (mcrObjectID != null) {
103 return mcrObjectID;
104 }
105
106 Collection<String> list = MCRLinkTableManager.instance().getSourceOf(derivateID,
107 MCRLinkTableManager.ENTRY_TYPE_DERIVATE);
108 if (!(list == null || list.isEmpty())) {
109 mcrObjectID = MCRObjectID.getInstance(list.iterator().next());
110 } else {
111
112 if (MCRMetadataManager.exists(derivateID)) {
113 mcrObjectID = MCRMetadataManager.retrieveMCRDerivate(derivateID).getOwnerID();
114 }
115 }
116 if (mcrObjectID == null) {
117 return null;
118 }
119 DERIVATE_OBJECT_MAP.put(derivateID, mcrObjectID);
120 return mcrObjectID;
121 }
122
123
124
125
126
127
128
129
130
131
132
133 public static List<MCRObjectID> getDerivateIds(final MCRObjectID objectId, final long expire, final TimeUnit unit) {
134 ModifiedHandle modifiedHandle = XML_MANAGER.getLastModifiedHandle(objectId, expire, unit);
135 List<MCRObjectID> derivateIds = null;
136 try {
137 derivateIds = OBJECT_DERIVATE_MAP.getIfUpToDate(objectId, modifiedHandle);
138 } catch (IOException e) {
139 LOGGER.warn("Could not determine last modified timestamp of derivate {}", objectId);
140 }
141 if (derivateIds != null) {
142 return derivateIds;
143 }
144 derivateIds = MCRObjectUtils.getDerivates(objectId);
145 if (!derivateIds.isEmpty()) {
146 return derivateIds;
147 } else {
148 if (MCRMetadataManager.exists(objectId)) {
149 MCRObject mcrObject = MCRMetadataManager.retrieveMCRObject(objectId);
150 List<MCRMetaEnrichedLinkID> derivates = mcrObject.getStructure().getDerivates();
151 for (MCRMetaEnrichedLinkID der : derivates) {
152 derivateIds.add(der.getXLinkHrefID());
153 }
154 }
155 }
156 return derivateIds;
157 }
158
159
160
161
162
163
164
165
166
167
168
169 public static void create(final MCRDerivate mcrDerivate) throws MCRPersistenceException, MCRAccessException {
170
171 MCRObjectID derivateId = mcrDerivate.getId();
172
173 if (MCRMetadataManager.exists(derivateId)) {
174 throw new MCRPersistenceException("The derivate " + derivateId + " already exists, nothing done.");
175 }
176
177
178 if (derivateId.getNumberAsInteger() == 0) {
179 derivateId = MCRObjectID.getNextFreeId(derivateId.getBase());
180 mcrDerivate.setId(derivateId);
181 LOGGER.info("Assigned new derivate id {}", derivateId);
182 }
183
184 try {
185 mcrDerivate.validate();
186 } catch (MCRException exc) {
187 throw new MCRPersistenceException("The derivate " + derivateId + " is not valid.", exc);
188 }
189
190 final MCRObjectID objectId = mcrDerivate.getDerivate().getMetaLink().getXLinkHrefID();
191 if (!MCRAccessManager.checkPermission(objectId, PERMISSION_WRITE)) {
192 throw MCRAccessException.missingPermission("Add derivate " + derivateId + " to object.",
193 objectId.toString(),
194 PERMISSION_WRITE);
195 }
196
197 byte[] objectBackup;
198 try {
199 objectBackup = MCRXMLMetadataManager.instance().retrieveBLOB(objectId);
200 } catch (IOException ioExc) {
201 throw new MCRPersistenceException("Unable to retrieve xml blob of " + objectId);
202 }
203 if (objectBackup == null) {
204 throw new MCRPersistenceException(
205 "Cannot find " + objectId + " to attach derivate " + derivateId + " to it.");
206 }
207
208
209 if (mcrDerivate.getService().getDate("createdate") == null || !mcrDerivate.isImportMode()) {
210 mcrDerivate.getService().setDate("createdate");
211 }
212 if (mcrDerivate.getService().getDate("modifydate") == null || !mcrDerivate.isImportMode()) {
213 mcrDerivate.getService().setDate("modifydate");
214 }
215
216
217 fireEvent(mcrDerivate, null, MCREvent.EventType.CREATE);
218
219
220 if (mcrDerivate.getDerivate().getInternals() != null) {
221 MCRPath rootPath = MCRPath.getPath(derivateId.toString(), "/");
222 if (mcrDerivate.getDerivate().getInternals().getSourcePath() == null) {
223 try {
224 rootPath.getFileSystem().createRoot(rootPath.getOwner());
225 } catch (IOException ioExc) {
226 throw new MCRPersistenceException(
227 "Cannot create root of '" + rootPath.getOwner() + "'.", ioExc);
228 }
229 } else {
230 final String sourcepath = mcrDerivate.getDerivate().getInternals().getSourcePath();
231 final Path f = Paths.get(sourcepath);
232 if (Files.exists(f)) {
233 try {
234 if (LOGGER.isDebugEnabled()) {
235 LOGGER.debug("Starting File-Import");
236 }
237 importDerivate(derivateId.toString(), f);
238 } catch (final Exception e) {
239 if (Files.exists(rootPath)) {
240 deleteDerivate(derivateId.toString());
241 }
242 MCRMetadataManager.restore(mcrDerivate, objectId, objectBackup);
243 throw new MCRPersistenceException("Can't add derivate to the IFS", e);
244 }
245 } else {
246 LOGGER.warn("Empty derivate, the File or Directory -->{}<-- was not found.", sourcepath);
247 }
248 }
249 }
250
251
252 final MCRMetaEnrichedLinkID der = MCRMetaEnrichedLinkIDFactory.getInstance().getDerivateLink(mcrDerivate);
253
254 try {
255 if (LOGGER.isDebugEnabled()) {
256 LOGGER.debug("adding Derivate in data store");
257 }
258 MCRMetadataManager.addOrUpdateDerivateToObject(objectId, der);
259 } catch (final Exception e) {
260 MCRMetadataManager.restore(mcrDerivate, objectId, objectBackup);
261
262 throw new MCRPersistenceException("Error while creating link to MCRObject " + objectId + ".", e);
263 }
264 }
265
266 private static void deleteDerivate(String derivateID) throws MCRPersistenceException {
267 try {
268 MCRPath rootPath = MCRPath.getPath(derivateID, "/");
269 if (!Files.exists(rootPath)) {
270 LOGGER.info("Derivate does not exist: {}", derivateID);
271 return;
272 }
273 Files.walkFileTree(rootPath, MCRRecursiveDeleter.instance());
274 rootPath.getFileSystem().removeRoot(derivateID);
275 } catch (Exception exc) {
276 throw new MCRPersistenceException("Unable to delete derivate " + derivateID, exc);
277 }
278 }
279
280 private static void importDerivate(String derivateID, Path sourceDir) throws MCRPersistenceException {
281 try {
282 MCRPath rootPath = MCRPath.getPath(derivateID, "/");
283 if (Files.exists(rootPath)) {
284 LOGGER.info("Derivate does already exist: {}", derivateID);
285 }
286 rootPath.getFileSystem().createRoot(derivateID);
287 Files.walkFileTree(sourceDir, new MCRTreeCopier(sourceDir, rootPath));
288 } catch (Exception exc) {
289 throw new MCRPersistenceException(
290 "Unable to import derivate " + derivateID + " from source " + sourceDir.toAbsolutePath(),
291 exc);
292 }
293 }
294
295
296
297
298
299
300
301
302
303
304 public static void create(final MCRObject mcrObject) throws MCRPersistenceException, MCRAccessException {
305
306 MCRObjectID objectId = mcrObject.getId();
307
308 String createBasePrivilege = "create-" + objectId.getBase();
309 String createTypePrivilege = "create-" + objectId.getTypeId();
310 if (!MCRAccessManager.checkPermission(createBasePrivilege)
311 && !MCRAccessManager.checkPermission(createTypePrivilege)) {
312 throw MCRAccessException.missingPrivilege("Create object with id " + objectId, createBasePrivilege,
313 createTypePrivilege);
314 }
315
316 if (MCRMetadataManager.exists(objectId)) {
317 throw new MCRPersistenceException("The object " + objectId + " allready exists, nothing done.");
318 }
319
320
321 if (objectId.getNumberAsInteger() == 0) {
322 objectId = MCRObjectID.getNextFreeId(objectId.getBase());
323 mcrObject.setId(objectId);
324 LOGGER.info("Assigned new object id {}", objectId);
325 }
326
327
328 if (mcrObject.getService().getDate("createdate") == null) {
329 mcrObject.getService().setDate("createdate");
330 }
331 if (mcrObject.getService().getDate("modifydate") == null) {
332 mcrObject.getService().setDate("modifydate");
333 }
334
335
336 receiveMetadata(mcrObject);
337
338 final MCRObjectID parentId = mcrObject.getStructure().getParentID();
339 MCRObject parent = null;
340 if (parentId != null) {
341 if (LOGGER.isDebugEnabled()) {
342 LOGGER.debug("Parent ID = {}", parentId);
343 }
344 parent = MCRMetadataManager.retrieveMCRObject(parentId);
345 }
346
347
348 fireEvent(mcrObject, null, MCREvent.EventType.CREATE);
349
350
351 if (parentId != null) {
352 parent.getStructure().addChild(new MCRMetaLinkID("child", objectId,
353 mcrObject.getStructure().getParent().getXLinkLabel(), mcrObject.getLabel()));
354 MCRMetadataManager.fireUpdateEvent(parent);
355 }
356 }
357
358
359
360
361
362
363
364
365
366
367
368 public static void delete(final MCRDerivate mcrDerivate) throws MCRPersistenceException, MCRAccessException {
369 MCRObjectID id = mcrDerivate.getId();
370 if (!MCRAccessManager.checkDerivateContentPermission(id, PERMISSION_DELETE)) {
371 throw MCRAccessException.missingPermission("Delete derivate", id.toString(), PERMISSION_DELETE);
372 }
373
374 MCRMarkManager.instance().mark(id, Operation.DELETE);
375
376
377 MCRObjectID metaId = null;
378 try {
379 metaId = mcrDerivate.getDerivate().getMetaLink().getXLinkHrefID();
380 if (MCRMetadataManager.removeDerivateFromObject(metaId, id)) {
381 LOGGER.info("Link in MCRObject {} to MCRDerivate {} is deleted.", metaId, id);
382 } else {
383 LOGGER.warn("Link in MCRObject {} to MCRDerivate {} could not be deleted.", metaId, id);
384 }
385 } catch (final Exception e) {
386 LOGGER.warn("Can't delete link for MCRDerivate {} from MCRObject {}. Error ignored.", id, metaId);
387 }
388
389
390 if (mcrDerivate.getDerivate().getInternals() != null) {
391 try {
392 deleteDerivate(id.toString());
393 LOGGER.info("IFS entries for MCRDerivate {} are deleted.", id);
394 } catch (final Exception e) {
395 throw new MCRPersistenceException("Error while delete MCRDerivate " + id + " in IFS", e);
396 }
397 }
398
399
400 fireEvent(mcrDerivate, null, MCREvent.EventType.DELETE);
401
402
403 MCRMarkManager.instance().remove(id);
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418 public static void delete(final MCRObject mcrObject)
419 throws MCRPersistenceException, MCRActiveLinkException, MCRAccessException {
420 delete(mcrObject, MCRMetadataManager::removeChildObject);
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437 private static void delete(final MCRObject mcrObject, BiConsumer<MCRObject, MCRObjectID> parentOperation)
438 throws MCRPersistenceException, MCRActiveLinkException, MCRAccessException {
439 MCRObjectID id = mcrObject.getId();
440 if (id == null) {
441 throw new MCRPersistenceException("The MCRObjectID is null.");
442 }
443 if (!MCRAccessManager.checkPermission(id, PERMISSION_DELETE)) {
444 throw MCRAccessException.missingPermission("Delete object", mcrObject.getId().toString(),
445 PERMISSION_DELETE);
446 }
447
448
449 final Collection<String> sources = MCRLinkTableManager.instance().getSourceOf(mcrObject.mcrId,
450 MCRLinkTableManager.ENTRY_TYPE_REFERENCE);
451 if (LOGGER.isDebugEnabled()) {
452 LOGGER.debug("Sources size:{}", sources.size());
453 }
454 if (sources.size() > 0) {
455 final MCRActiveLinkException activeLinks = new MCRActiveLinkException("Error while deleting object " + id
456 + ". This object is still referenced by other objects and "
457 + "can not be removed until all links are released.");
458 for (final String curSource : sources) {
459 activeLinks.addLink(curSource, id.toString());
460 }
461 throw activeLinks;
462 }
463
464
465 MCRMarkManager.instance().mark(id, Operation.DELETE);
466
467
468 final MCRObjectID parentId = mcrObject.getStructure().getParentID();
469 if (parentId != null) {
470 parentOperation.accept(mcrObject, parentId);
471 }
472
473
474 for (MCRMetaLinkID child : mcrObject.getStructure().getChildren()) {
475 MCRObjectID childId = child.getXLinkHrefID();
476 if (!MCRMetadataManager.exists(childId)) {
477 LOGGER.warn("Unable to remove not existing object {} of parent {}", childId, id);
478 continue;
479 }
480 MCRMetadataManager.deleteMCRObject(childId, (MCRObject o, MCRObjectID p) -> {
481
482 });
483 }
484
485
486 for (MCRMetaLinkID derivate : mcrObject.getStructure().getDerivates()) {
487 MCRObjectID derivateId = derivate.getXLinkHrefID();
488 if (!MCRMetadataManager.exists(derivateId)) {
489 LOGGER.warn("Unable to remove not existing derivate {} of object {}", derivateId, id);
490 continue;
491 }
492 MCRMetadataManager.deleteMCRDerivate(derivateId);
493 }
494
495
496 fireEvent(mcrObject, null, MCREvent.EventType.DELETE);
497
498
499 MCRMarkManager.instance().remove(id);
500 }
501
502
503
504
505
506
507
508
509
510
511
512
513 private static void removeChildObject(final MCRObject mcrObject, final MCRObjectID parentId)
514 throws PersistenceException {
515 if (LOGGER.isDebugEnabled()) {
516 LOGGER.debug("Parent ID = {}", parentId);
517 }
518 try {
519 if (MCRXMLMetadataManager.instance().exists(parentId)) {
520 final MCRObject parent = MCRMetadataManager.retrieveMCRObject(parentId);
521 parent.getStructure().removeChild(mcrObject.getId());
522 MCRMetadataManager.fireUpdateEvent(parent);
523 } else {
524 LOGGER.warn("Unable to find parent {} of {}", parentId, mcrObject.getId());
525 }
526 } catch (Exception exc) {
527 throw new PersistenceException(
528 "Error while deleting object. Unable to remove child " + mcrObject.getId() + " from parent " + parentId
529 + ".",
530 exc);
531 }
532 }
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548 public static void deleteMCRDerivate(final MCRObjectID id) throws MCRPersistenceException, MCRAccessException {
549 final MCRDerivate derivate = MCRMetadataManager.retrieveMCRDerivate(id);
550 MCRMetadataManager.delete(derivate);
551 }
552
553
554
555
556
557
558
559
560
561
562 public static void deleteMCRObject(final MCRObjectID id)
563 throws MCRPersistenceException, MCRActiveLinkException, MCRAccessException {
564 deleteMCRObject(id, MCRMetadataManager::removeChildObject);
565 }
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580 private static void deleteMCRObject(final MCRObjectID id, BiConsumer<MCRObject, MCRObjectID> parentOperation)
581 throws MCRPersistenceException, MCRActiveLinkException, MCRAccessException {
582 final MCRObject object = retrieveMCRObject(id);
583 MCRMetadataManager.delete(object, parentOperation);
584 }
585
586
587
588
589
590
591
592
593
594 public static boolean exists(final MCRObjectID id) throws MCRPersistenceException {
595 return MCRXMLMetadataManager.instance().exists(id);
596 }
597
598
599
600
601
602 public static void fireRepairEvent(final MCRDerivate mcrDerivate) throws MCRPersistenceException {
603
604 fireEvent(mcrDerivate, null, MCREvent.EventType.REPAIR);
605 }
606
607
608
609
610
611 public static void fireRepairEvent(final MCRBase mcrBaseObj) throws MCRPersistenceException {
612 if (mcrBaseObj instanceof MCRDerivate) {
613 MCRMetadataManager.fireRepairEvent((MCRDerivate) mcrBaseObj);
614 } else if (mcrBaseObj instanceof MCRObject) {
615 MCRMetadataManager.fireRepairEvent((MCRObject) mcrBaseObj);
616 }
617 }
618
619
620
621
622
623 public static void fireRepairEvent(final MCRObject mcrObject) throws MCRPersistenceException {
624
625 for (MCRMetaLinkID derivate : mcrObject.getStructure().getDerivates()) {
626 if (!MCRMetadataManager.exists(derivate.getXLinkHrefID())) {
627 LOGGER.error("Can't find MCRDerivate {}", derivate.getXLinkHrefID());
628 }
629 }
630
631 fireEvent(mcrObject, null, MCREvent.EventType.REPAIR);
632 }
633
634
635
636
637
638
639
640
641 public static void fireUpdateEvent(final MCRObject mcrObject) throws MCRPersistenceException {
642 if (!mcrObject.isImportMode() || mcrObject.getService().getDate("modifydate") == null) {
643 mcrObject.getService().setDate("modifydate");
644 }
645
646 mcrObject.getService().getRules().clear();
647
648 fireEvent(mcrObject, retrieveMCRObject(mcrObject.getId()), MCREvent.EventType.UPDATE);
649 }
650
651
652
653
654
655
656
657
658
659 public static MCRDerivate retrieveMCRDerivate(final MCRObjectID id) throws MCRPersistenceException {
660 try {
661 Document xml = MCRXMLMetadataManager.instance().retrieveXML(id);
662 if (xml == null) {
663 throw new MCRPersistenceException("Could not retrieve xml of derivate: " + id);
664 }
665 return new MCRDerivate(xml);
666 } catch (IOException | JDOMException | SAXException e) {
667 throw new MCRPersistenceException("Could not retrieve xml of derivate: " + id, e);
668 }
669 }
670
671
672
673
674
675
676
677
678
679 public static MCRObject retrieveMCRObject(final MCRObjectID id) throws MCRPersistenceException {
680 try {
681 Document xml = MCRXMLMetadataManager.instance().retrieveXML(id);
682 if (xml == null) {
683 throw new MCRPersistenceException("Could not retrieve xml of object: " + id);
684 }
685 return new MCRObject(xml);
686 } catch (IOException | JDOMException | SAXException e) {
687 throw new MCRPersistenceException("Could not retrieve xml of object: " + id, e);
688 }
689 }
690
691
692
693
694
695
696
697
698
699 public static MCRBase retrieve(final MCRObjectID id) throws MCRPersistenceException {
700 if (id.getTypeId().equals("derivate")) {
701 return retrieveMCRDerivate(id);
702 }
703 return retrieveMCRObject(id);
704 }
705
706
707
708
709
710
711
712
713
714
715
716 public static void update(final MCRBase base)
717 throws MCRPersistenceException, MCRAccessException {
718 if (base instanceof MCRObject) {
719 MCRMetadataManager.update((MCRObject) base);
720 } else if (base instanceof MCRDerivate) {
721 MCRMetadataManager.update((MCRDerivate) base);
722 } else {
723 throw new IllegalArgumentException("Type is unsupported " + base.getId());
724 }
725 }
726
727
728
729
730
731
732
733
734
735 public static void update(final MCRDerivate mcrDerivate)
736 throws MCRPersistenceException, MCRAccessException {
737 MCRObjectID derivateId = mcrDerivate.getId();
738
739 if (MCRMarkManager.instance().isMarkedForDeletion(derivateId)) {
740 return;
741 }
742 if (!MCRMetadataManager.exists(derivateId)) {
743 MCRMetadataManager.create(mcrDerivate);
744 return;
745 }
746 if (!MCRAccessManager.checkDerivateMetadataPermission(derivateId, PERMISSION_WRITE)) {
747 throw MCRAccessException.missingPermission("Update derivate", derivateId.toString(), PERMISSION_WRITE);
748 }
749 Path fileSourceDirectory = null;
750 MCRMetaIFS internals = mcrDerivate.getDerivate().getInternals();
751 if (internals != null && internals.getSourcePath() != null) {
752 fileSourceDirectory = Paths.get(internals.getSourcePath());
753
754 if (!Files.exists(fileSourceDirectory)) {
755 LOGGER.warn("{}: the directory {} was not found.", derivateId, fileSourceDirectory);
756 fileSourceDirectory = null;
757 }
758
759 internals.setSourcePath(null);
760
761 }
762
763 MCRDerivate old = MCRMetadataManager.retrieveMCRDerivate(derivateId);
764
765
766 MCRMetaLinkID oldLink = old.getDerivate().getMetaLink();
767 MCRMetaLinkID newLink = mcrDerivate.getDerivate().getMetaLink();
768 MCRObjectID oldMetadataObjectID = oldLink.getXLinkHrefID();
769 MCRObjectID newMetadataObjectID = newLink.getXLinkHrefID();
770 if (!oldMetadataObjectID.equals(newLink.getXLinkHrefID())) {
771 try {
772 MCRMetadataManager.removeDerivateFromObject(oldMetadataObjectID, derivateId);
773 } catch (final MCRException e) {
774 LOGGER.warn(e.getMessage(), e);
775 }
776 }
777
778
779 mcrDerivate.getService().setDate("createdate", old.getService().getDate("createdate"));
780 if (!mcrDerivate.getService().isFlagTypeSet(MCRObjectService.FLAG_TYPE_CREATEDBY)) {
781 for (String flagCreatedBy : old.getService().getFlags(MCRObjectService.FLAG_TYPE_CREATEDBY)) {
782 mcrDerivate.getService().addFlag(MCRObjectService.FLAG_TYPE_CREATEDBY, flagCreatedBy);
783 }
784 }
785
786 MCRMetadataManager.updateMCRDerivateXML(mcrDerivate);
787
788
789 if (fileSourceDirectory != null) {
790 MCRPath targetPath = MCRPath.getPath(derivateId.toString(), "/");
791 try {
792 Files.walkFileTree(fileSourceDirectory, new MCRTreeCopier(fileSourceDirectory, targetPath));
793 } catch (Exception exc) {
794 throw new MCRPersistenceException(
795 "Unable to update IFS. Copy failed from " + fileSourceDirectory.toAbsolutePath()
796 + " to target " + targetPath.toAbsolutePath(),
797 exc);
798 }
799 }
800
801
802 final MCRMetaEnrichedLinkID derivateLink = MCRMetaEnrichedLinkIDFactory.getInstance()
803 .getDerivateLink(mcrDerivate);
804 addOrUpdateDerivateToObject(newMetadataObjectID, derivateLink);
805 }
806
807
808
809
810
811
812
813
814
815 public static void update(final MCRObject mcrObject)
816 throws MCRPersistenceException, MCRAccessException {
817 MCRObjectID id = mcrObject.getId();
818
819 if (MCRMarkManager.instance().isMarkedForDeletion(id)) {
820 return;
821 }
822 if (!MCRMetadataManager.exists(id)) {
823 MCRMetadataManager.create(mcrObject);
824 return;
825 }
826 if (!MCRAccessManager.checkPermission(id, PERMISSION_WRITE)) {
827 throw MCRAccessException.missingPermission("Update object.", id.toString(), PERMISSION_WRITE);
828 }
829 MCRObject old = MCRMetadataManager.retrieveMCRObject(id);
830 Date diskModifyDate = old.getService().getDate(MCRObjectService.DATE_TYPE_MODIFYDATE);
831 Date updateModifyDate = mcrObject.getService().getDate(MCRObjectService.DATE_TYPE_MODIFYDATE);
832 if (diskModifyDate != null && updateModifyDate != null && updateModifyDate.before(diskModifyDate)) {
833 throw new MCRPersistenceException("The object " + mcrObject.getId() + " was modified(" + diskModifyDate
834 + ") during the time it was opened in the editor.");
835 }
836
837
838 final List<String> childOrder = mcrObject.getStructure()
839 .getChildren()
840 .stream()
841 .map(MCRMetaLinkID::getXLinkHref)
842 .collect(Collectors.toList());
843 mcrObject.getStructure().clearChildren();
844
845 final List<MCRMetaEnrichedLinkID> derivateLinks = mcrObject.getStructure().getDerivates();
846 derivateLinks.clear();
847 old.getStructure().getDerivates()
848 .forEach(mcrObject.getStructure()::addDerivate);
849
850
851 MCRObjectID oldParentID = old.getStructure().getParentID();
852 MCRObjectID newParentID = mcrObject.getStructure().getParentID();
853
854 if (oldParentID != null && exists(oldParentID) && (!oldParentID.equals(newParentID))) {
855
856 if (LOGGER.isDebugEnabled()) {
857 LOGGER.debug("Parent ID = {}", oldParentID);
858 }
859 final MCRObject parent = MCRMetadataManager.retrieveMCRObject(oldParentID);
860 parent.getStructure().removeChild(id);
861 MCRMetadataManager.fireUpdateEvent(parent);
862 }
863
864
865 List<MCRMetaLinkID> children = old.getStructure().getChildren();
866 children.sort((link1, link2) -> {
867 int i1 = childOrder.indexOf(link1.getXLinkHref());
868 int i2 = childOrder.indexOf(link2.getXLinkHref());
869 return Integer.compare(i1, i2);
870 });
871 mcrObject.getStructure().getChildren().addAll(children);
872
873
874 receiveMetadata(mcrObject);
875
876
877 if (!mcrObject.isImportMode() || mcrObject.getService().getDate("createdate") == null) {
878 mcrObject.getService().setDate("createdate", old.getService().getDate("createdate"));
879 }
880 if (!mcrObject.isImportMode() && !mcrObject.getService().isFlagTypeSet(MCRObjectService.FLAG_TYPE_CREATEDBY)) {
881 for (String flagCreatedBy : old.getService().getFlags(MCRObjectService.FLAG_TYPE_CREATEDBY)) {
882 mcrObject.getService().addFlag(MCRObjectService.FLAG_TYPE_CREATEDBY, flagCreatedBy);
883 }
884 }
885
886
887 MCRMetadataManager.fireUpdateEvent(mcrObject);
888
889
890 if (newParentID != null && !newParentID.equals(oldParentID)) {
891 MCRObject newParent = retrieveMCRObject(newParentID);
892 newParent.getStructure().addChild(new MCRMetaLinkID("child", id, null, mcrObject.getLabel()));
893 MCRMetadataManager.fireUpdateEvent(newParent);
894 }
895
896
897 if (shareableMetadataChanged(mcrObject, old)) {
898 MCRMetadataShareAgent metadataShareAgent = MCRMetadataShareAgentFactory.getAgent(id);
899 metadataShareAgent.distributeMetadata(mcrObject);
900 }
901 }
902
903 private static boolean shareableMetadataChanged(final MCRObject mcrObject, MCRObject old) {
904 MCRMetadataShareAgent metadataShareAgent = MCRMetadataShareAgentFactory.getAgent(mcrObject.getId());
905 return metadataShareAgent.shareableMetadataChanged(old, mcrObject);
906 }
907
908 private static void receiveMetadata(final MCRObject recipient) {
909 MCRMetadataShareAgent metadataShareAgent = MCRMetadataShareAgentFactory.getAgent(recipient.getId());
910 metadataShareAgent.receiveMetadata(recipient);
911 }
912
913
914
915
916
917
918
919 private static void updateMCRDerivateXML(final MCRDerivate mcrDerivate) throws MCRPersistenceException {
920 if (!mcrDerivate.isImportMode() || mcrDerivate.getService().getDate("modifydate") == null) {
921 mcrDerivate.getService().setDate("modifydate");
922 }
923 fireEvent(mcrDerivate, retrieveMCRDerivate(mcrDerivate.getId()), MCREvent.EventType.UPDATE);
924 }
925
926
927
928
929
930
931
932
933
934
935
936
937
938 public static boolean addOrUpdateDerivateToObject(final MCRObjectID id, final MCRMetaEnrichedLinkID link)
939 throws MCRPersistenceException {
940 final MCRObject object = MCRMetadataManager.retrieveMCRObject(id);
941 if (!object.getStructure().addOrUpdateDerivate(link)) {
942 return false;
943 }
944 if (!object.isImportMode()) {
945 object.getService().setDate("modifydate");
946 }
947 MCRMetadataManager.fireUpdateEvent(object);
948 return true;
949 }
950
951 public static boolean removeDerivateFromObject(final MCRObjectID objectID, final MCRObjectID derivateID)
952 throws MCRPersistenceException {
953 final MCRObject object = MCRMetadataManager.retrieveMCRObject(objectID);
954 if (object.getStructure().removeDerivate(derivateID)) {
955 object.getService().setDate("modifydate");
956 MCRMetadataManager.fireUpdateEvent(object);
957 return true;
958 }
959 return false;
960 }
961
962 private static void restore(final MCRDerivate mcrDerivate, final MCRObjectID mcrObjectId, final byte[] backup) {
963 try {
964 final MCRObject obj = new MCRObject(backup, false);
965
966
967
968
969 MCRXMLMetadataManager.instance().update(mcrObjectId, obj.createXML(), new Date());
970
971
972 MCRMetadataManager.update(obj);
973 } catch (final Exception e1) {
974 LOGGER.warn("Error while restoring {}", mcrObjectId, e1);
975 } finally {
976
977 fireEvent(mcrDerivate, null, MCREvent.EventType.DELETE);
978 }
979 }
980
981 private static void fireEvent(MCRBase base, MCRBase oldBase, MCREvent.EventType eventType) {
982 boolean objectEvent = base instanceof MCRObject;
983 MCREvent.ObjectType type = objectEvent ? MCREvent.ObjectType.OBJECT : MCREvent.ObjectType.DERIVATE;
984 final MCREvent evt = new MCREvent(type, eventType);
985 if (objectEvent) {
986 evt.put(MCREvent.OBJECT_KEY, base);
987 } else {
988 evt.put(MCREvent.DERIVATE_KEY, base);
989 }
990 Optional.ofNullable(oldBase)
991 .ifPresent(b -> evt.put(objectEvent ? MCREvent.OBJECT_OLD_KEY : MCREvent.DERIVATE_OLD_KEY, b));
992 if (MCREvent.EventType.DELETE == eventType) {
993 MCREventManager.instance().handleEvent(evt, MCREventManager.BACKWARD);
994 } else {
995 MCREventManager.instance().handleEvent(evt);
996 }
997 }
998 }