Merge branch 'release/5.18.0'
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / hibernate / TaxonGraphHibernateListener.java
1 /**
2 * Copyright (C) 2018 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9 package eu.etaxonomy.cdm.persistence.hibernate;
10
11 import java.lang.reflect.Constructor;
12 import java.lang.reflect.InvocationTargetException;
13 import java.util.HashMap;
14 import java.util.Map;
15
16 import org.apache.log4j.Logger;
17 import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
18 import org.hibernate.event.spi.PostInsertEvent;
19 import org.hibernate.event.spi.PostUpdateEvent;
20 import org.hibernate.event.spi.PreDeleteEvent;
21 import org.hibernate.persister.entity.EntityPersister;
22
23 import eu.etaxonomy.cdm.config.CdmHibernateListenerConfiguration;
24 import eu.etaxonomy.cdm.model.name.NomenclaturalSource;
25 import eu.etaxonomy.cdm.model.name.TaxonName;
26
27 /**
28 * The {@code TaxonGraphHibernateListener} it the implementation of the
29 * according interface. The listener in initially empty and thus will do nothing
30 * unless configured with the {@link TaxonGraphBeforeTransactionCompleteProces}
31 *
32 * @see <a href=
33 * "https://dev.e-taxonomy.eu/redmine/issues/7648">https://dev.e-taxonomy.eu/redmine/issues/7648</a>
34 * @see {@link TaxonGraphBeforeTransactionCompleteProcess}
35 * @see {@link CdmHibernateListenerConfiguration}
36 *
37 * @author a.kohlbecker
38 * @since Sep 27, 2018
39 *
40 */
41 public class TaxonGraphHibernateListener implements ITaxonGraphHibernateListener {
42
43 private static final long serialVersionUID = 5062518307839173935L;
44
45 private Map<Class<? extends BeforeTransactionCompletionProcess>, ProcessConstructorData<? extends BeforeTransactionCompletionProcess>> beforeTransactionCompletionProcessTypes = new HashMap<>();
46
47 @Override
48 public void registerProcessClass(Class<? extends BeforeTransactionCompletionProcess> processClass, Object[] constructorArgs, Class<?>[] paramterTypes) throws NoSuchMethodException, SecurityException{
49 if(constructorArgs == null){
50 constructorArgs = new Object[]{};
51 }
52 beforeTransactionCompletionProcessTypes.put(processClass, new ProcessConstructorData(processClass, constructorArgs, paramterTypes));
53 }
54
55 @Override
56 public void unRegisterProcessClass(Class<? extends BeforeTransactionCompletionProcess> processClass){
57 beforeTransactionCompletionProcessTypes.remove(processClass);
58 }
59
60 @Override
61 public void onPostUpdate(PostUpdateEvent event) {
62
63 if(event.getEntity() instanceof TaxonName || event.getEntity() instanceof NomenclaturalSource){
64 for(Class<? extends BeforeTransactionCompletionProcess> type : beforeTransactionCompletionProcessTypes.keySet()){
65 try {
66 ProcessConstructorData<? extends BeforeTransactionCompletionProcess> pcd = beforeTransactionCompletionProcessTypes.get(type);
67 BeforeTransactionCompletionProcess processorInstance = pcd.postUpdateEventConstructor.newInstance(pcd.buildConstructorArgs(event));
68 event.getSession().getActionQueue().registerProcess(processorInstance);
69 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
70 | InvocationTargetException | SecurityException e) {
71 Logger.getLogger(TaxonGraphHibernateListener.class).error("Error creating new instance of " + type.toString(), e);
72 }
73 }
74 }
75 }
76
77 @Override
78 public void onPostInsert(PostInsertEvent event) {
79
80 if(event.getEntity() instanceof TaxonName || event.getEntity() instanceof NomenclaturalSource){
81 for(Class<? extends BeforeTransactionCompletionProcess> type : beforeTransactionCompletionProcessTypes.keySet()){
82 try {
83 ProcessConstructorData<? extends BeforeTransactionCompletionProcess> pcd = beforeTransactionCompletionProcessTypes.get(type);
84 BeforeTransactionCompletionProcess processorInstance = pcd.postInsertEventConstructor.newInstance(pcd.buildConstructorArgs(event));
85 event.getSession().getActionQueue().registerProcess(processorInstance);
86 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
87 | InvocationTargetException | SecurityException e) {
88 Logger.getLogger(TaxonGraphHibernateListener.class).error("Error creating new instance of " + type.toString(), e);
89 }
90 }
91 }
92 }
93
94 @Override
95 public boolean onPreDelete(PreDeleteEvent event) {
96
97 if(event.getEntity() instanceof TaxonName || event.getEntity() instanceof NomenclaturalSource){
98 for(Class<? extends BeforeTransactionCompletionProcess> type : beforeTransactionCompletionProcessTypes.keySet()){
99 try {
100 ProcessConstructorData<? extends BeforeTransactionCompletionProcess> pcd = beforeTransactionCompletionProcessTypes.get(type);
101 BeforeTransactionCompletionProcess processorInstance = pcd.preDeleteEventConstructor.newInstance(pcd.buildConstructorArgs(event));
102 event.getSession().getActionQueue().registerProcess(processorInstance);
103 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
104 | InvocationTargetException | SecurityException e) {
105 Logger.getLogger(TaxonGraphHibernateListener.class).error("Error creating new instance of " + type.toString(), e);
106 }
107 }
108 }
109 return false; // no veto
110 }
111
112 @Override
113 public boolean requiresPostCommitHanding(EntityPersister persister) {
114 return true;
115 }
116
117 class ProcessConstructorData<T extends BeforeTransactionCompletionProcess> {
118
119 Constructor<T> postInsertEventConstructor;
120 Constructor<T> postUpdateEventConstructor;
121 Constructor<T> preDeleteEventConstructor;
122 Object[] constructorArgs;
123
124 public ProcessConstructorData(Class<T> type, Object[] constructorArgs, Class<?>[] paramterTypes) throws NoSuchMethodException, SecurityException {
125
126 this.constructorArgs = constructorArgs;
127
128 Class<?>[] postInsertEventConstructorArgTypes = new Class<?>[constructorArgs.length + 1];
129 Class<?>[] postUpdateEventConstructorArgTypes = new Class<?>[constructorArgs.length + 1];
130 Class<?>[] preDeleteEventConstructorArgTypes = new Class<?>[constructorArgs.length + 1];
131 postInsertEventConstructorArgTypes[0] = PostInsertEvent.class;
132 postUpdateEventConstructorArgTypes[0] = PostUpdateEvent.class;
133 preDeleteEventConstructorArgTypes[0] = PreDeleteEvent.class;
134 int i = 1;
135 for(Class<?> ptype : paramterTypes){
136 postInsertEventConstructorArgTypes[i] = ptype;
137 postUpdateEventConstructorArgTypes[i] = ptype;
138 preDeleteEventConstructorArgTypes[i] = ptype;
139 }
140 postInsertEventConstructor = type.getConstructor(postInsertEventConstructorArgTypes);
141 postUpdateEventConstructor = type.getConstructor(postUpdateEventConstructorArgTypes);
142 preDeleteEventConstructor = type.getConstructor(preDeleteEventConstructorArgTypes);
143 }
144
145 public Object[] buildConstructorArgs(Object firstArg){
146 Object[] cargs = new Object[constructorArgs.length + 1];
147 cargs[0] = firstArg;
148 int i = 1;
149 for(Object arg : constructorArgs){
150 cargs[i++] = arg;
151 }
152 return cargs;
153 }
154 }
155 }