Project

General

Profile

Download (27.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 *
3
 */
4
package eu.etaxonomy.cdm.persistence.dao.hibernate.common;
5

    
6
import java.lang.reflect.Field;
7
import java.lang.reflect.InvocationTargetException;
8
import java.lang.reflect.Method;
9
import java.util.ArrayList;
10
import java.util.Collection;
11
import java.util.HashSet;
12
import java.util.List;
13
import java.util.Set;
14

    
15
import javax.naming.Reference;
16

    
17
import org.apache.commons.lang.UnhandledException;
18
import org.apache.log4j.Logger;
19
import org.hibernate.MappingException;
20
import org.hibernate.Query;
21
import org.hibernate.Session;
22
import org.hibernate.internal.SessionFactoryImpl;
23
import org.hibernate.internal.SessionImpl;
24
import org.hibernate.metadata.ClassMetadata;
25
import org.hibernate.metadata.CollectionMetadata;
26
import org.hibernate.persister.collection.CollectionPersister;
27
import org.hibernate.persister.collection.OneToManyPersister;
28
import org.hibernate.persister.entity.AbstractEntityPersister;
29
import org.hibernate.type.AnyType;
30
import org.hibernate.type.CollectionType;
31
import org.hibernate.type.ComponentType;
32
import org.hibernate.type.EntityType;
33
import org.hibernate.type.SetType;
34
import org.hibernate.type.Type;
35

    
36
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
37
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
38
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
39
import eu.etaxonomy.cdm.model.common.Annotation;
40
import eu.etaxonomy.cdm.model.common.CdmBase;
41
import eu.etaxonomy.cdm.model.common.Extension;
42
import eu.etaxonomy.cdm.model.common.ICdmBase;
43
import eu.etaxonomy.cdm.model.common.IIntextReferencable;
44
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
45
import eu.etaxonomy.cdm.model.common.Identifier;
46
import eu.etaxonomy.cdm.model.common.IntextReference;
47
import eu.etaxonomy.cdm.model.common.Marker;
48
import eu.etaxonomy.cdm.model.name.TaxonName;
49
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
50
import eu.etaxonomy.cdm.model.taxon.Taxon;
51
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmGenericDaoImpl.ReferenceHolder;
52
import eu.etaxonomy.cdm.strategy.merge.ConvertMergeStrategy;
53
import eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy;
54
import eu.etaxonomy.cdm.strategy.merge.IMergable;
55
import eu.etaxonomy.cdm.strategy.merge.IMergeStrategy;
56
import eu.etaxonomy.cdm.strategy.merge.MergeException;
57

    
58
/**
59
 * @author a.mueller
60
 *
61
 */
62
public class DeduplicationHelper {
63
	private static final Logger logger = Logger.getLogger(DeduplicationHelper.class);
64

    
65
	private final SessionImpl session;
66
	private final CdmGenericDaoImpl genericDao;
67

    
68
	protected DeduplicationHelper(SessionImpl session, CdmGenericDaoImpl genericDao){
69
		this.session = session;
70
		this.genericDao = genericDao;
71
	}
72

    
73
	public <T extends CdmBase>  boolean isMergeable(T cdmBase1, T cdmBase2, IMergeStrategy mergeStrategy) {
74

    
75
		if (mergeStrategy == null){
76
			mergeStrategy = DefaultMergeStrategy.NewInstance(cdmBase1.getClass());
77
		}
78
		try {
79
			checkMergeValid(cdmBase1, cdmBase2, mergeStrategy);
80
			return true;
81
		} catch (IllegalArgumentException e) {
82
			return false;
83
		} catch (NullPointerException e) {
84
			return false;
85
		}
86
	}
87

    
88

    
89
	public <T extends CdmBase>  void merge(T cdmBase1, T cdmBase2, IMergeStrategy mergeStrategy) throws MergeException {
90
		@SuppressWarnings("unchecked")
91
		Class<T> clazz = (Class<T>)cdmBase1.getClass();
92
		@SuppressWarnings("unchecked")
93
		Class<T> clazz2 = (Class<T>)cdmBase2.getClass();
94

    
95
//		SessionFactory sessionFactory = session.getSessionFactory();
96
		if (mergeStrategy == null){
97
			mergeStrategy = DefaultMergeStrategy.NewInstance(cdmBase1.getClass());
98
		}
99
		try {
100
			//check null and types
101
			checkMergeValid(cdmBase1, cdmBase2, mergeStrategy);
102

    
103
			//merge objects
104
			//externel impl
105
			//internal impl
106

    
107
			Set<ICdmBase> deleteSet = new HashSet<>();
108
			Set<ICdmBase> cloneSet = new HashSet<>();
109
			if (cdmBase1 instanceof IMergable){
110
				IMergable mergable1 = (IMergable)cdmBase1;
111
				IMergable mergable2 = (IMergable)cdmBase2;
112
				deleteSet = mergeStrategy.invoke(mergable1, mergable2, cloneSet);
113
				//session.saveOrUpdate(mergable1);
114

    
115
				//session.flush();
116
				//((IMergable)cdmBase1).mergeInto(cdmBase2, DefaultMergeStrategy.NewInstance(cdmBase1.getClass()));
117
			}else{
118
				//TODO should we better use clazz2 here?
119
				mergeExternal(cdmBase1, cdmBase2, clazz, session);
120
			}
121

    
122

    
123
			if (cdmBase2.getId() > 0){
124
				session.saveOrUpdate(cdmBase2);
125
				session.flush();
126
				//rearrange references pointing to cdmBase2 to cdmBase1 in future
127
				reallocateReferences(cdmBase1, cdmBase2, clazz2, cloneSet);
128
			}
129

    
130
			//remove deleted objects
131

    
132
			//session.delete(null, mergable2, true, null);
133
			boolean deleteSecond = true;
134
			if (mergeStrategy instanceof ConvertMergeStrategy) {
135
			    deleteSecond = ((ConvertMergeStrategy)mergeStrategy).isDeleteSecondObject();
136
			}
137
			if(deleteSecond){
138
			    session.delete(cdmBase2);
139

    
140
			    for (ICdmBase toBeDeleted : deleteSet){
141
	                logger.debug("Delete " + toBeDeleted);
142
	                if (toBeDeleted != cdmBase2){
143
	                    session.delete(toBeDeleted);
144

    
145
	                }
146
	            }
147
			}
148

    
149
			//flush
150
			session.flush();
151

    
152
		} catch (Exception e) {
153
			e.printStackTrace();
154
		    throw new MergeException(e);
155
		}
156
	}
157

    
158
	/**
159
	 * Throws an exception if merge is not possible.
160
	 * @param cdmBase1
161
	 * @param cdmBase2
162
	 * @param strategy
163
	 * @throws IllegalArgumentException
164
	 * @throws NullPointerException
165
	 */
166

    
167
	private <T extends CdmBase> void checkMergeValid(T cdmBase1, T cdmBase2, IMergeStrategy strategy)throws IllegalArgumentException, NullPointerException{
168
		if (cdmBase1 == null || cdmBase2 == null){
169
			throw new NullPointerException("Merge arguments must not be (null)");
170
		}
171
		cdmBase1 = HibernateProxyHelper.deproxy(cdmBase1);
172
		cdmBase2 = HibernateProxyHelper.deproxy(cdmBase2);
173

    
174

    
175
		if (cdmBase1.getClass() != cdmBase2.getClass()){
176
			boolean reallocationPossible = checkOnlyReallocationAllowed(cdmBase1.getClass(), cdmBase2.getClass());
177
			if (! reallocationPossible){
178
				String msg = "Merge not possible for objects of type %s and type %s";
179
				msg = String.format(msg, cdmBase1.getClass().getSimpleName(), cdmBase2.getClass().getSimpleName());
180
				throw new IllegalArgumentException(msg);
181
			}else{
182
				if (! checkInstancesMergeable(cdmBase1, cdmBase2, strategy)){
183
					throw new IllegalArgumentException("Object can not be merged into new object as it is referenced in a way that does not allow merging");
184
				}
185
			}
186
		}
187
	}
188

    
189
	@SuppressWarnings("unchecked")
190
	private <T extends CdmBase> boolean checkInstancesMergeable(T cdmBase1, T cdmBase2, IMergeStrategy strategy){
191
		Class<T> clazz2 = (Class<T>)cdmBase2.getClass();
192
		//FIXME do we need to compute the cloneSet? See #reallocateReferences for comparison
193
		//this is only a copy from there. Maybe we do not need the cloneSet at all here
194
		Set<ICdmBase> cloneSet = new HashSet<ICdmBase>();
195
		Set<ReferenceHolder> holderSet;
196
		try {
197
			boolean result = true;
198
			holderSet = genericDao.getOrMakeHolderSet(clazz2);
199
			for (ReferenceHolder refHolder: holderSet){
200
				if (! reallocateByHolderPossible(cdmBase1, cdmBase2, refHolder, cloneSet)){
201
					return false;
202
				}
203
			}
204
			return result;
205
		} catch (ClassNotFoundException e) {
206
			return false;
207
		} catch (NoSuchFieldException e) {
208
			return false;
209
		} catch (MergeException e) {
210
			return false;
211
		}
212
	}
213

    
214
	/**
215
	 * Checks if 2 can be merged and reallocation of referencing objects is allowed.
216
	 * This is <code>true</code> if
217
	 * classes are same or for some explicit cases like both
218
	 * inherit form {@link TeamOrPersonBase} or from {@link TaxonName}.
219
	 * Necessary condition is that both classes are mapped to the same table.
220
	 *
221
	 * @param class1
222
	 * @param class2
223
	 * @return true if mer
224
	 */
225
	private boolean  checkOnlyReallocationAllowed(Class<? extends CdmBase> class1,
226
			Class<? extends CdmBase> class2) {
227
		if (class1 == class2){
228
			return true;
229
		}else{
230
			if (classesAssignableFrom(TeamOrPersonBase.class, class1, class2)){
231
				return true;
232
			}else if (classesAssignableFrom(TaxonName.class, class1, class2)){
233
				return true;
234
			}else{
235
				return false;
236
			}
237
		}
238
	}
239

    
240
	private boolean classesAssignableFrom(Class<? extends CdmBase> superClass,
241
			Class<? extends CdmBase> class1, Class<? extends CdmBase> class2) {
242
		return superClass.isAssignableFrom(class1) && superClass.isAssignableFrom(class2);
243
	}
244

    
245
	/**
246
	 * @param <T>
247
	 * @param cdmBase1
248
	 * @param cdmBase2
249
	 * @param clazz
250
	 * @param sessionFactory
251
	 * @throws MergeException
252
	 * @throws ClassNotFoundException
253
	 * @throws NoSuchFieldException
254
	 */
255
	private <T extends CdmBase> void mergeExternal(T cdmBase1, T cdmBase2, Class<T> clazz,
256
			Session session) throws MergeException {
257
//		handleAnnotations
258
		logger.warn("Merge external");
259
		handleAnnotationsEtc(cdmBase1, cdmBase2, session);
260

    
261
		SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory();
262

    
263
//		Map<String, ClassMetadata> allClassMetadata = sessionFactory.getAllClassMetadata();
264

    
265
		//TODO cast
266
		getCollectionRoles(clazz, sessionFactory);
267

    
268
		TaxonName name1 = TaxonNameFactory.NewBotanicalInstance(null);
269
		name1.getTaxonBases();
270

    
271
		Type propType = sessionFactory.getReferencedPropertyType(TaxonName.class.getCanonicalName(), "taxonBases");
272
//		Map<?,?> collMetadata = sessionFactory.getAllCollectionMetadata();
273
		//roles = sessionFactory.getCollectionRolesByEntityParticipant("eu.etaxonomy.cdm.model.name.BotanicalName");
274
		CollectionPersister collPersister;
275
		try {
276
			collPersister = sessionFactory.getCollectionPersister(TaxonName.class.getCanonicalName()+".annotations");
277
		} catch (MappingException e) {
278
		    // TODO Auto-generated catch block
279
            e.printStackTrace();
280
		}
281
//		Statistics statistics = sessionFactory.getStatistics();
282
		logger.debug("");
283
		ClassMetadata taxonMetaData = sessionFactory.getClassMetadata(Taxon.class);
284
		String ename = taxonMetaData.getEntityName();
285
		try {
286
			Reference ref = sessionFactory.getReference();
287
			logger.debug("");
288
		} catch (Exception e) {
289
			// TODO Auto-generated catch block
290
			e.printStackTrace();
291
		}
292

    
293
		//sessionFactory.get
294
		ClassMetadata classMetadata = session.getSessionFactory().getClassMetadata(clazz);
295
		Type[] propertyTypes = classMetadata.getPropertyTypes();
296
		int propertyNr = 0;
297
		for (Type propertyType: propertyTypes){
298
			String propertyName = classMetadata.getPropertyNames()[propertyNr];
299
			logger.debug(propertyName);
300
			makeMergeProperty(cdmBase1, cdmBase2, propertyType, propertyName, sessionFactory, false);
301
			propertyNr++;
302
		}
303
		Set<String> collectionRoles;
304
		if (classMetadata instanceof AbstractEntityPersister){
305
			AbstractEntityPersister persister = (AbstractEntityPersister)classMetadata;
306
			String rootName = persister.getRootEntityName();
307
			collectionRoles = sessionFactory.getCollectionRolesByEntityParticipant(rootName);
308
			for (String collectionRole : collectionRoles){
309
				CollectionMetadata collMetadata2 = sessionFactory.getCollectionMetadata(collectionRole);
310
				String role = collMetadata2.getRole();
311
				Type elType = collMetadata2.getElementType();
312
				logger.debug(role);
313
			}
314
		}
315
	}
316

    
317

    
318
	/**
319
	 * @param <T>
320
	 * @param cdmBase1
321
	 * @param cdmBase2
322
	 * @param session
323
	 */
324
	private <T> void handleAnnotationsEtc(T cdmBase1, T cdmBase2, Session session) {
325
		//when handling annotations and other elements linked via @Any an JDBC errors occurs
326
		//due to the unique column constraint in the association table on the column referencing
327
		//the annotation.
328
		//For some reason not delete command is executed for the old collection
329
		// Hibernate bug ??
330
		session.flush();  //for debugging
331
		if (cdmBase1 instanceof AnnotatableEntity){
332
			copyAnnotatableExtensions(cdmBase1, cdmBase2, session);
333
		}
334
		if (cdmBase1 instanceof IdentifiableEntity){
335
			copyIdentifiableExtensions(cdmBase1, cdmBase2, session);
336
		}
337

    
338
		session.saveOrUpdate(cdmBase1);
339
		session.saveOrUpdate(cdmBase2);
340
		session.flush();
341
	}
342

    
343

    
344
	/**
345
	 * Clones all annotations and markers of cdmBase2 and
346
	 * attaches the clones to cdmBase1.
347
	 * Finally removes all annotations and markers from cdmBase2.
348
	 * @param cdmBase1
349
	 * @param cdmBase2
350
	 * @param session
351
	 */
352
	private <T> void copyAnnotatableExtensions(T cdmBase1, T cdmBase2,
353
			Session session) {
354
		AnnotatableEntity annotatableEntity1 = (AnnotatableEntity)cdmBase1;
355
		AnnotatableEntity annotatableEntity2 = (AnnotatableEntity)cdmBase2;
356
		//annotations
357
		List<Annotation> removeListAnnotation = new ArrayList<>();
358
		for (Annotation annotation : annotatableEntity2.getAnnotations()){
359
			Annotation clone = null;
360
			try {
361
				clone = (Annotation)annotation.clone();
362
			} catch (CloneNotSupportedException e) {
363
				e.printStackTrace();
364
			}
365
			annotatableEntity1.addAnnotation(clone);
366
			removeListAnnotation.add(annotation);
367
		}
368
		for (Annotation annotation : removeListAnnotation){
369
			annotatableEntity2.removeAnnotation(annotation);
370
			session.delete(annotation);
371
		}
372

    
373
		//marker
374
		List<Marker> removeListMarker = new ArrayList<>();
375
		for (Marker marker : annotatableEntity2.getMarkers()){
376
			Marker clone = null;
377
			try {
378
				clone = (Marker)marker.clone();
379
			} catch (CloneNotSupportedException e) {
380
				e.printStackTrace();
381
			}
382
			annotatableEntity1.addMarker(clone);
383
			removeListMarker.add(marker);
384
		}
385
		for (Marker marker : removeListMarker){
386
			annotatableEntity2.removeMarker(marker);
387
			session.delete(marker);
388
		}
389
	}
390

    
391
	/**
392
	 * Clones all extensions of cdmBase2 and
393
	 * attaches the clones to cdmBase1.
394
	 * Finally removes all annotations and markers from cdmBase2.
395
	 * @param cdmBase1
396
	 * @param cdmBase2
397
	 * @param session
398
	 */
399
	//TODO Why do we not handle credits, rights and sources here
400
	private <T> void copyIdentifiableExtensions(T cdmBase1, T cdmBase2,
401
			Session session) {
402
		IdentifiableEntity<?> identifiableEntity1 = (IdentifiableEntity<?>)cdmBase1;
403
		IdentifiableEntity<?> identifiableEntity2 = (IdentifiableEntity<?>)cdmBase2;
404

    
405
		//extensions
406
		List<Extension> removeListExtension = new ArrayList<>();
407
		for (Extension changeObject : identifiableEntity2.getExtensions()){
408
			try {
409
				Extension clone = (Extension)changeObject.clone();
410
				identifiableEntity1.addExtension(clone);
411
				removeListExtension.add(changeObject);
412
			} catch (CloneNotSupportedException e) {
413
				throw new RuntimeException("Clone is not yet supported for class " + changeObject.getClass().getName() + " but should.");
414
			}
415
		}
416
		for (Extension removeObject : removeListExtension){
417
			identifiableEntity2.removeExtension(removeObject);
418
			session.delete(removeObject);
419
		}
420

    
421
		//identifiers
422
		List<Identifier<?>> removeListIdentifier = new ArrayList<>();
423
		for (Identifier<?> changeObject : identifiableEntity2.getIdentifiers()){
424
			try {
425
				Identifier<?> clone = (Identifier<?>)changeObject.clone();
426
				identifiableEntity1.addIdentifier(clone);
427
				removeListIdentifier.add(changeObject);
428
			} catch (CloneNotSupportedException e) {
429
			    throw new RuntimeException(e);
430
			}
431
		}
432
		for (Identifier<?> removeObject : removeListIdentifier){
433
			identifiableEntity2.removeIdentifier(removeObject);
434
			session.delete(removeObject);
435
		}
436

    
437
	}
438

    
439
	private void reallocateReferences(CdmBase cdmBase1, CdmBase cdmBase2, Class<? extends CdmBase> clazz, Set<ICdmBase> cloneSet){
440
		try {
441
			Set<ReferenceHolder> holderSet = genericDao.getOrMakeHolderSet(clazz);
442
			for (ReferenceHolder refHolder: holderSet){
443
				reallocateByHolder(cdmBase1, cdmBase2, refHolder, cloneSet);
444
			}
445
			return;
446
		} catch (Exception e) {
447
			throw new RuntimeException(e);
448
		}
449
	}
450

    
451
	/**
452
	 * @param cdmBase1
453
	 * @param cdmBase2
454
	 * @param refHolder
455
	 * @throws MergeException
456
	 */
457
	private boolean reallocateByHolderPossible(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws MergeException {
458
		try {
459
			if (refHolder.isCollection()){
460
				return reallocateCollectionPossible(cdmBase1, cdmBase2, refHolder, cloneSet);
461
			}else{
462
				return reallocateSingleItemPossible(cdmBase1, cdmBase2, refHolder, cloneSet);
463
			}
464
		} catch (Exception e) {
465
			throw new MergeException("Error during reallocation of references to merge object: " + cdmBase2, e);
466
		}
467
	}
468

    
469
	/**
470
	 * @param cdmBase1
471
	 * @param cdmBase2
472
	 * @param refHolder
473
	 * @throws MergeException
474
	 */
475
	private void reallocateByHolder(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws MergeException {
476
		try {
477
			if (refHolder.isCollection()){
478
				reallocateCollection(cdmBase1, cdmBase2, refHolder, cloneSet);
479
			}else{
480
				reallocateSingleItem(cdmBase1, cdmBase2, refHolder, cloneSet);
481
			}
482
		} catch (Exception e) {
483
			throw new MergeException("Error during reallocation of references to merge object: " + cdmBase2, e);
484
		}
485
	}
486

    
487
	private boolean reallocateCollectionPossible(CdmBase cdmBase1, CdmBase cdmBase2,
488
			ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws SecurityException, IllegalArgumentException {
489
		Class<?> targetClass = refHolder.targetClass;
490
		Class<?> clazz1 = cdmBase1.getClass();
491
		if (! targetClass.isAssignableFrom(clazz1)){
492
			//FIXME only do count or hasXXX, we do not need to instantiate objects here
493
			List<CdmBase> referencingObjects = genericDao.getCdmBasesWithItemInCollection(refHolder.itemClass, refHolder.otherClass, refHolder.propertyName, cdmBase2, null);
494
			if (! referencingObjects.isEmpty()){
495
				return false;
496
			}
497
		}
498
		return true;
499
	}
500

    
501
	/**
502
	 * @param cdmBase1
503
	 * @param cdmBase2
504
	 * @param refHolder
505
	 * @param cloneSet
506
	 * @throws MergeException
507
	 * @throws NoSuchFieldException
508
	 * @throws SecurityException
509
	 * @throws IllegalAccessException
510
	 * @throws IllegalArgumentException
511
	 * @throws InvocationTargetException
512
	 */
513
	private void reallocateCollection(CdmBase cdmBase1, CdmBase cdmBase2,
514
			ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws MergeException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
515
		List<CdmBase> list = genericDao.getCdmBasesWithItemInCollection(refHolder.itemClass, refHolder.otherClass, refHolder.propertyName, cdmBase2, null);
516
		for (CdmBase referencingObject : list){
517
			Field referencingField = getFieldRecursive(refHolder.otherClass, refHolder.propertyName);
518
			referencingField.setAccessible(true);
519
			Object collection = referencingField.get(referencingObject);
520
			if (! (collection instanceof Collection)){
521
				throw new MergeException ("Reallocation of collections for collection other than set and list not yet implemented");
522
			}else if (collection instanceof List){
523
			    Method replaceMethod = DefaultMergeStrategy.getReplaceMethod(referencingField);
524
			    replaceMethod.invoke(referencingObject, cdmBase1, cdmBase2);
525
			}else{
526
			    Method addMethod = DefaultMergeStrategy.getAddMethod(referencingField, false);
527
			    Method removeMethod = DefaultMergeStrategy.getAddMethod(referencingField, true);
528
			    addMethod.invoke(referencingObject, cdmBase1);
529
			    removeMethod.invoke(referencingObject, cdmBase2);
530
			}
531
		}
532
	}
533

    
534
	private boolean reallocateSingleItemPossible(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
535
		Class<?> targetClass = refHolder.targetClass;
536
		Class<?> clazz1 = cdmBase1.getClass();
537
		if (! targetClass.isAssignableFrom(clazz1)){
538
			//FIXME only do count or hasXXX, we do not need to instantiate objects here
539
			List<CdmBase> referencingObjects = genericDao.getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2, null);
540
			if (! referencingObjects.isEmpty()){
541
				return false;
542
			}
543
		}
544
		return true;
545
	}
546

    
547
	private void reallocateSingleItem(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
548
		List<CdmBase> referencingObjects = genericDao.getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2, null);
549
		for (CdmBase referencingObject : referencingObjects){
550
			if (!cloneSet.contains(referencingObject)){
551
		        String className = refHolder.otherClass.getSimpleName();
552
	            String propertyName = refHolder.propertyName;
553
		        String hql = " UPDATE " + className + " c "
554
		                + " SET c."+propertyName+" = :newValue "
555
		                + " WHERE c.id = :id ";
556
		        Query query = session.createQuery(hql);
557
		        query.setEntity("newValue", cdmBase1);
558
		        query.setInteger("id",referencingObject.getId());
559
		        int rowCount = query.executeUpdate();
560
		        if (logger.isDebugEnabled()){logger.debug("Rows affected: " + rowCount);}
561
		        session.refresh(referencingObject);
562
		        if (refHolder.otherClass == IntextReference.class){
563
		            IntextReference intextRef = CdmBase.deproxy(referencingObject, IntextReference.class);
564
		            IIntextReferencable refEnt = intextRef.getReferencedEntity();
565
		            if (refEnt != null) {
566
                        String newText = refEnt.getText() == null? null: refEnt.getText().replace(cdmBase2.getUuid().toString(), cdmBase1.getUuid().toString());
567
                        refEnt.setText(newText);
568
                        session.saveOrUpdate(refEnt);
569
                    }
570

    
571
		            //TODO
572
		            /*
573
		             * UPDATE LanguageString
574
		             * SET text = Replace(text, cdmBase2.getUuuid(), cdmBase1.getUuid)
575
		             * WHERE id IN (SELECT * FROM IntextReference
576
		             *
577
		             */
578
		            System.out.println("IntextReference found");
579
		        }
580
	        }
581
	    }
582
		session.flush();
583
	}
584

    
585
	private Field getFieldRecursive(Class<?> clazz, String propertyName) throws NoSuchFieldException{
586
		try {
587
			return clazz.getDeclaredField(propertyName);
588
		} catch (NoSuchFieldException e) {
589
			Class<?> superClass = clazz.getSuperclass();
590
			if (CdmBase.class.isAssignableFrom(superClass)){
591
				return getFieldRecursive(superClass, propertyName);
592
			}else{
593
				throw e;
594
			}
595
		}
596
	}
597

    
598
	/**
599
	 * @throws NoSuchFieldException
600
	 * @throws SecurityException
601
	 * @throws IllegalAccessException
602
	 * @throws IllegalArgumentException
603
	 *
604
	 */
605
	private void reallocateSingleItem_Old(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
606
		List<CdmBase> referencingObjects = genericDao.getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2, null);
607
		for (CdmBase referencingObject : referencingObjects){
608
			Field referencingField = refHolder.otherClass.getDeclaredField(refHolder.propertyName);
609
			referencingField.setAccessible(true);
610
			Object test = referencingField.get(referencingObject);
611
			assert(test.equals(cdmBase2));
612
			referencingField.set(referencingObject, cdmBase1);
613
		}
614
	}
615

    
616

    
617

    
618

    
619
	/**
620
	 * @param <T>
621
	 * @param clazz
622
	 * @param sessionFactory
623
	 */
624
	private <T> Set<String> getCollectionRoles(Class<T> clazz,
625
			SessionFactoryImpl sessionFactory) {
626
		Set<String> collectionRoles = null;
627
		ClassMetadata classMetaData = sessionFactory.getClassMetadata(clazz);
628
		if (classMetaData instanceof AbstractEntityPersister){
629
			AbstractEntityPersister persister = (AbstractEntityPersister)classMetaData;
630
			String rootName = persister.getRootEntityName();
631
			collectionRoles = sessionFactory.getCollectionRolesByEntityParticipant(rootName);
632
			for (String collectionRole : collectionRoles){
633
				CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
634
				CollectionPersister collPersister = sessionFactory.getCollectionPersister(collectionRole);
635
				logger.debug("");
636
			}
637
		}else{
638
			logger.warn("Class metadata is not of type AbstractEntityPersister");
639
			throw new UnhandledException("Class metadata is not of type AbstractEntityPersister", null);
640
		}
641
		return collectionRoles;
642
	}
643

    
644

    
645
	private <T extends CdmBase> void makeMergeProperty(T cdmBase1, T cdmBase2, Type propertyType, String propertyName, SessionFactoryImpl sessionFactory, boolean isCollection) throws MergeException{
646

    
647
		try {
648
			Class<T> clazz = (Class<T>)cdmBase1.getClass();
649
			if (CdmGenericDaoImpl.isNoDoType(propertyType)){
650
						//do nothing
651
			}else if (propertyType.isEntityType()){
652
				//Field field = clazz.getField(propertyName);
653
				EntityType entityType = (EntityType)propertyType;
654
				String associatedEntityName = entityType.getAssociatedEntityName();
655
				Class<?> entityClass = Class.forName(associatedEntityName);
656
//				 Type refPropType = sessionFactory.getReferencedPropertyType(entityClass.getCanonicalName(), propertyName);
657
				Set<String> collectionRoles = getCollectionRoles(clazz, sessionFactory);
658
				for (String collectionRole : collectionRoles){
659
					CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
660
					String role = collMetadata.getRole();
661
					logger.debug(role);
662

    
663
				}
664

    
665
//				if (entityClass.isInterface()){
666
//					logger.debug("So ein interface");
667
//				}
668
//				if (entityClass.isAssignableFrom(clazz)){
669
//					makeSingleProperty(referencedClass, entityClass, propertyName, cdmClass, result, isCollection);
670
//				}
671
			}else if (propertyType.isCollectionType()){
672
				CollectionType collectionType = (CollectionType)propertyType;
673
				String role = collectionType.getRole();
674
				Type elType = collectionType.getElementType(sessionFactory);
675
				String n = collectionType.getAssociatedEntityName(sessionFactory);
676
				CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(role);
677
				if (collMetadata instanceof OneToManyPersister){
678
					OneToManyPersister oneManyPersister = (OneToManyPersister)collMetadata;
679
					String className = oneManyPersister.getOwnerEntityName();
680
					Class<?> myClass = Class.forName(className);
681
					Field field = myClass.getDeclaredField(propertyName);
682
					field.setAccessible(true);
683
					try {
684
						if (collectionType instanceof SetType){
685
							Set<?> set2 = (Set<?>)field.get(cdmBase2);
686
							Set<Object> set1 = (Set<Object>)field.get(cdmBase1);
687
							for (Object obj2: set2){
688
								set1.add(obj2);
689
							}
690
						}
691
					} catch (IllegalArgumentException e) {
692
						// TODO Auto-generated catch block
693
						e.printStackTrace();
694
					} catch (IllegalAccessException e) {
695
						// TODO Auto-generated catch block
696
						e.printStackTrace();
697
					}
698

    
699
				}
700
				logger.debug("");
701

    
702
//			makePropertyType(result, referencedClass, sessionFactory, cdmClass, elType, propertyName, true);
703
			}else if (propertyType.isAnyType()){
704
				AnyType anyType = (AnyType)propertyType;
705
				Field field = clazz.getDeclaredField(propertyName);
706
				Class returnType = field.getType();
707
//			if (returnType.isInterface()){
708
//				logger.debug("So ein interface");
709
//			}
710
//			if (returnType.isAssignableFrom(referencedClass)){
711
//				makeSingleProperty(referencedClass, returnType, propertyName, cdmClass, result, isCollection);
712
//			}
713
			}else if (propertyType.isComponentType()){
714
				ComponentType componentType = (ComponentType)propertyType;
715
				Type[] subTypes = componentType.getSubtypes();
716
//		Field field = cdmClass.getDeclaredField(propertyName);
717
//		Class returnType = field.getType();
718
				int propertyNr = 0;
719
				for (Type subType: subTypes){
720
					String subPropertyName = componentType.getPropertyNames()[propertyNr];
721
					if (! CdmGenericDaoImpl.isNoDoType(subType)){
722
						logger.warn("SubType not yet handled: " + subType);
723
					}
724
//					handlePropertyType(referencedCdmBase, result, referencedClass,
725
//					sessionFactory, cdmClass, subType, subPropertyName, isCollection);
726
					propertyNr++;
727
				}
728
			}else{
729
				logger.warn("propertyType not yet handled: " + propertyType.getName());
730
			}
731
			//OLD:
732
					//		if (! type.isInterface()){
733
			//		if (referencedClass.isAssignableFrom(type)||
734
			//				type.isAssignableFrom(referencedClass) && CdmBase.class.isAssignableFrom(type)){
735
			//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
736
			//		}
737
			//	//interface
738
			//	}else if (type.isAssignableFrom(referencedClass)){
739
			//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
740
		} catch (Exception e) {
741
			throw new MergeException(e);
742
		}
743
	}
744

    
745

    
746

    
747
}
(6-6/24)