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
.MergeEvent
;
22 import org
.hibernate
.event
.spi
.MergeEventListener
;
24 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
25 import eu
.etaxonomy
.cdm
.model
.common
.ITreeNode
;
26 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
32 public class PostMergeEntityListener
implements MergeEventListener
{
34 private static final long serialVersionUID
= 1565797119368313987L;
35 @SuppressWarnings("unused")
36 private static final Logger logger
= LogManager
.getLogger(PostMergeEntityListener
.class);
38 private static Map
<Session
, Set
<CdmBase
>> newEntitiesMap
= new ConcurrentHashMap
<>();
40 public static void addSession(Session session
) {
41 newEntitiesMap
.put(session
, new HashSet
<>());
44 public static void removeSession(Session session
) {
45 newEntitiesMap
.remove(session
);
48 public static Set
<CdmBase
> getNewEntities(Session session
) {
49 return newEntitiesMap
.get(session
);
53 public void onMerge(MergeEvent event
) throws HibernateException
{
54 //Note AM: TODO is there a reason wyh we neglect onMerge in this case?
55 // Shouldn't we do something like "onMerge(event, new HashMap<>());"
56 // Object entity = event.getEntity();
60 public void onMerge(MergeEvent event
, Map copiedAlready
) throws HibernateException
{
61 // any new entities are added to a map which is retrieved at the end of the
62 // CdmEntityDaoBase.merge(T transientObject, boolean returnTransientEntity) call
63 if(event
.getOriginal() != null && CdmBase
.class.isAssignableFrom(event
.getOriginal().getClass()) &&
64 event
.getResult() != null && CdmBase
.class.isAssignableFrom(event
.getResult().getClass())) {
65 CdmBase original
= (CdmBase
) event
.getOriginal();
66 CdmBase result
= (CdmBase
) event
.getResult();
67 handleTreeNodes(result
, original
, event
, copiedAlready
);
68 if(original
!= null && Hibernate
.isInitialized(original
) && original
.getId() == 0 &&
69 result
!= null && Hibernate
.isInitialized(result
) && result
.getId() > 0) {
70 //see IService#merge(detachedObject, returnTransientEntity)
71 original
.setId(result
.getId());
72 Set
<CdmBase
> newEntities
= newEntitiesMap
.get(event
.getSession());
73 if(newEntities
!= null) {
74 newEntities
.add(result
);
80 private static void handleTreeNodes(CdmBase result
, CdmBase original
, MergeEvent event
, Map copiedAlready
) {
81 if (original
!= null){
82 Class
<?
> entityClazz
= original
.getClass();
84 if (ITreeNode
.class.isAssignableFrom(entityClazz
)){ //TaxonNode or TermNode
86 } else if (PolytomousKeyNode
.class.isAssignableFrom(entityClazz
)){
87 // #10101 the following code tried to handle orphanRemoval for key nodes that were
88 // really removed from the graph. Generally the removal worked but it was not possible at this
89 // place to guarantee that the node which was removed from the parent was not used elsewhere
90 // (has a new parent). For this one needs to retrieve the new state of the node (or of its new parent).
91 // But this is not difficult or impossible at this point as the node is not part of the graph to
92 // to be merged or if it is because its new parent is part of the graph also, it is not guaranteed
93 // that it has already treated so far.
94 // Maybe it can better be handled by another type of listener therefore I keep this code here.
95 // See #10101 for further information on this issue and how it was solved.
96 // The implementation was partly copied from https://stackoverflow.com/questions/812364/how-to-determine-collection-changes-in-a-hibernate-postupdateeventlistener
98 // EventSource session = event.getSession();
99 // PolytomousKeyNode resultPkn = (PolytomousKeyNode)result;
100 // //copied from https://stackoverflow.com/questions/812364/how-to-determine-collection-changes-in-a-hibernate-postupdateeventlistener
101 // PersistenceContext pc = session.getPersistenceContext();
102 // CollectionEntry childrenEntry = pc.getCollectionEntry((PersistentCollection)resultPkn.getChildren());
103 // List<PolytomousKeyNode> childrenEntrySnapshot = (List<PolytomousKeyNode>)childrenEntry.getSnapshot();
104 // if (childrenEntrySnapshot != null) {
105 // for (PolytomousKeyNode snapshotChild: childrenEntrySnapshot){
106 // if (!resultPkn.getChildren().contains(snapshotChild)) {
107 // EntityEntry currentChild = pc.getEntry(snapshotChild);
108 // Object parent = currentChild == null ? null :
109 // currentChild.getLoadedValue("parent");
110 // if (parent == null || parent == resultPkn) {
111 // session.delete(snapshotChild);