2 * Copyright (C) 2015 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
9 package eu
.etaxonomy
.cdm
.persistence
.hibernate
;
11 import java
.util
.HashSet
;
14 import java
.util
.concurrent
.ConcurrentHashMap
;
16 import org
.apache
.logging
.log4j
.LogManager
;
17 import org
.apache
.logging
.log4j
.Logger
;
18 import org
.hibernate
.Hibernate
;
19 import org
.hibernate
.HibernateException
;
20 import org
.hibernate
.Session
;
21 import org
.hibernate
.event
.spi
.EventSource
;
22 import org
.hibernate
.event
.spi
.MergeEvent
;
23 import org
.hibernate
.event
.spi
.MergeEventListener
;
25 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
26 import eu
.etaxonomy
.cdm
.model
.common
.ITreeNode
;
27 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
33 public class PostMergeEntityListener
implements MergeEventListener
{
35 private static final long serialVersionUID
= 1565797119368313987L;
36 @SuppressWarnings("unused")
37 private static final Logger logger
= LogManager
.getLogger(PostMergeEntityListener
.class);
39 private static Map
<Session
, Set
<CdmBase
>> newEntitiesMap
= new ConcurrentHashMap
<>();
41 public static void addSession(Session session
) {
42 newEntitiesMap
.put(session
, new HashSet
<>());
45 public static void removeSession(Session session
) {
46 newEntitiesMap
.remove(session
);
49 public static Set
<CdmBase
> getNewEntities(Session session
) {
50 return newEntitiesMap
.get(session
);
54 public void onMerge(MergeEvent event
) throws HibernateException
{
55 //Note AM: TODO is there a reason wyh we neglect onMerge in this case?
56 // Shouldn't we do something like "onMerge(event, new HashMap<>());"
57 // Object entity = event.getEntity();
61 public void onMerge(MergeEvent event
, Map copiedAlready
) throws HibernateException
{
62 // any new entities are added to a map which is retrieved at the end of the
63 // CdmEntityDaoBase.merge(T transientObject, boolean returnTransientEntity) call
64 if(event
.getOriginal() != null && CdmBase
.class.isAssignableFrom(event
.getOriginal().getClass()) &&
65 event
.getResult() != null && CdmBase
.class.isAssignableFrom(event
.getResult().getClass())) {
66 CdmBase original
= (CdmBase
) event
.getOriginal();
67 CdmBase result
= (CdmBase
) event
.getResult();
68 handleTreeNodes(result
, original
, event
, copiedAlready
);
69 if(original
!= null && Hibernate
.isInitialized(original
) && original
.getId() == 0 &&
70 result
!= null && Hibernate
.isInitialized(result
) && result
.getId() > 0) {
71 //AM (2022-07-28): why do we set the id here to the original
72 original
.setId(result
.getId());
73 Set
<CdmBase
> newEntities
= newEntitiesMap
.get(event
.getSession());
74 if(newEntities
!= null) {
75 newEntities
.add(result
);
81 private static void handleTreeNodes(CdmBase result
, CdmBase original
, MergeEvent event
, Map copiedAlready
) {
82 EventSource session
= event
.getSession();
83 if (original
!= null){
84 Class
<?
> entityClazz
= original
.getClass();
86 if (ITreeNode
.class.isAssignableFrom(entityClazz
)){ //TaxonNode or TermNode
88 } else if (PolytomousKeyNode
.class.isAssignableFrom(entityClazz
)){
89 // #10101 the following code tried to handle orphanRemoval for key nodes that were
90 // really removed from the graph. Generally the removal worked but it was not possible at this
91 // place to guarantee that the node which was removed from the parent was not used elsewhere
92 // (has a new parent). For this one needs to retrieve the new state of the node (or of its new parent).
93 // But this is not difficult or impossible at this point as the node is not part of the graph to
94 // to be merged or if it is because its new parent is part of the graph also, it is not guaranteed
95 // that it has already treated so far.
96 // Maybe it can better be handled by another type of listener therefore I keep this code here.
97 // See #10101 for further information on this issue and how it was solved.
98 // The implementation was partly copied from https://stackoverflow.com/questions/812364/how-to-determine-collection-changes-in-a-hibernate-postupdateeventlistener
100 // PolytomousKeyNode resultPkn = (PolytomousKeyNode)result;
101 // //copied from https://stackoverflow.com/questions/812364/how-to-determine-collection-changes-in-a-hibernate-postupdateeventlistener
102 // PersistenceContext pc = session.getPersistenceContext();
103 // CollectionEntry childrenEntry = pc.getCollectionEntry((PersistentCollection)resultPkn.getChildren());
104 // List<PolytomousKeyNode> childrenEntrySnapshot = (List<PolytomousKeyNode>)childrenEntry.getSnapshot();
105 // if (childrenEntrySnapshot != null) {
106 // for (PolytomousKeyNode snapshotChild: childrenEntrySnapshot){
107 // if (!resultPkn.getChildren().contains(snapshotChild)) {
108 // EntityEntry currentChild = pc.getEntry(snapshotChild);
109 // Object parent = currentChild == null ? null :
110 // currentChild.getLoadedValue("parent");
111 // if (parent == null || parent == resultPkn) {
112 // session.delete(snapshotChild);