Project

General

Profile

Download (26.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.Map;
14
import java.util.Set;
15

    
16
import javax.naming.Reference;
17

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

    
38
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
39
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
40
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
41
import eu.etaxonomy.cdm.model.common.Annotation;
42
import eu.etaxonomy.cdm.model.common.CdmBase;
43
import eu.etaxonomy.cdm.model.common.Extension;
44
import eu.etaxonomy.cdm.model.common.ICdmBase;
45
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
46
import eu.etaxonomy.cdm.model.common.Identifier;
47
import eu.etaxonomy.cdm.model.common.Marker;
48
import eu.etaxonomy.cdm.model.name.BotanicalName;
49
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
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) throws MergeException {
74
		Class<T> clazz = (Class<T>)cdmBase1.getClass();
75
		Class<T> clazz2 = (Class<T>)cdmBase2.getClass();
76

    
77
		SessionFactory sessionFactory = session.getSessionFactory();
78
		if (mergeStrategy == null){
79
			mergeStrategy = DefaultMergeStrategy.NewInstance(cdmBase1.getClass());
80
		}
81
		try {
82
			testMergeValid(cdmBase1, cdmBase2, mergeStrategy);
83
			return true;
84
		} catch (IllegalArgumentException e) {
85
			return false;
86
		} catch (NullPointerException e) {
87
			return false;
88
		}
89
	}
90

    
91

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

    
98
		SessionFactory sessionFactory = session.getSessionFactory();
99
		if (mergeStrategy == null){
100
			mergeStrategy = DefaultMergeStrategy.NewInstance(cdmBase1.getClass());
101
		}
102
		try {
103
			//test null and types
104
			testMergeValid(cdmBase1, cdmBase2, mergeStrategy);
105

    
106
			//merge objects
107
			//externel impl
108
			//internal impl
109
			session.flush();
110
			Set<ICdmBase> deleteSet = new HashSet<ICdmBase>();
111
			Set<ICdmBase> cloneSet = new HashSet<ICdmBase>();
112
			if (cdmBase1 instanceof IMergable){
113
				IMergable mergable1 = (IMergable)cdmBase1;
114
				IMergable mergable2 = (IMergable)cdmBase2;
115
				deleteSet = mergeStrategy.invoke(mergable1, mergable2, cloneSet);
116
				//session.saveOrUpdate(mergable1);
117

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

    
125

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

    
132
			//remove deleted objects
133

    
134
			//session.delete(null, mergable2, true, null);
135
			boolean deleteSecond = true;
136
			if (mergeStrategy instanceof ConvertMergeStrategy) {
137
			    deleteSecond = ((ConvertMergeStrategy)mergeStrategy).isDeleteSecondObject();
138
			}
139
			if(deleteSecond){
140
			    session.delete(cdmBase2);
141
			    for (ICdmBase toBeDeleted : deleteSet){
142
	                logger.debug("Delete " + toBeDeleted);
143
	                if (toBeDeleted != cdmBase2){
144
	                    session.delete(toBeDeleted);
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 testMergeValid(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 = testOnlyReallocationAllowed(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("Merge not possible for objects of type %s and type %s");
181
			}else{
182
				if (! testInstancesMergeable(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 testInstancesMergeable(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
	 * Test if 2 classes
216
	 * @param class1
217
	 * @param class2
218
	 * @return
219
	 */
220
	private boolean  testOnlyReallocationAllowed(Class<? extends CdmBase> class1,
221
			Class<? extends CdmBase> class2) {
222
		if (class1 == class2){
223
			return true;
224
		}else{
225
			if (classesAssignableFrom(TeamOrPersonBase.class, class1, class2)){
226
				return true;
227
			}else if (classesAssignableFrom(TaxonNameBase.class, class1, class2)){
228
				return true;
229
			}else{
230
				return false;
231
			}
232
		}
233
	}
234

    
235
	private boolean classesAssignableFrom(Class<? extends CdmBase> superClass,
236
			Class<? extends CdmBase> class1, Class<? extends CdmBase> class2) {
237
		return superClass.isAssignableFrom(class1) && superClass.isAssignableFrom(class2);
238
	}
239

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

    
256
		SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory();
257

    
258
		Map<String, ClassMetadata> allClassMetadata = sessionFactory.getAllClassMetadata();
259

    
260
		//TODO cast
261
		getCollectionRoles(clazz, sessionFactory);
262

    
263
		TaxonNameBase name1 = BotanicalName.NewInstance(null);
264
		name1.getTaxonBases();
265

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

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

    
312

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

    
333
		session.saveOrUpdate(cdmBase1);
334
		session.saveOrUpdate(cdmBase2);
335
		session.flush();
336
	}
337

    
338

    
339
	/**
340
	 * Clones all annotations and markers of cdmBase2 and
341
	 * attaches the clones to cdmBase1.
342
	 * Finally removes all annotations and markers from cdmBase2.
343
	 * @param cdmBase1
344
	 * @param cdmBase2
345
	 * @param session
346
	 */
347
	private <T> void copyAnnotatableExtensions(T cdmBase1, T cdmBase2,
348
			Session session) {
349
		AnnotatableEntity annotatableEntity1 = (AnnotatableEntity)cdmBase1;
350
		AnnotatableEntity annotatableEntity2 = (AnnotatableEntity)cdmBase2;
351
		//annotations
352
		List<Annotation> removeListAnnotation = new ArrayList<Annotation>();
353
		for (Annotation annotation : annotatableEntity2.getAnnotations()){
354
			Annotation clone = null;
355
			try {
356
				clone = annotation.clone(annotatableEntity1);
357
			} catch (CloneNotSupportedException e) {
358
				e.printStackTrace();
359
			}
360
			annotatableEntity1.addAnnotation(clone);
361
			removeListAnnotation.add(annotation);
362
		}
363
		for (Annotation annotation : removeListAnnotation){
364
			annotatableEntity2.removeAnnotation(annotation);
365
			session.delete(annotation);
366
		}
367
		//marker
368
		List<Marker> removeListMarker = new ArrayList<Marker>();
369
		for (Marker marker : annotatableEntity2.getMarkers()){
370
			Marker clone = null;
371
			try {
372
				clone = marker.clone(annotatableEntity1);
373
			} catch (CloneNotSupportedException e) {
374
				e.printStackTrace();
375
			}
376
			annotatableEntity1.addMarker(clone);
377
			removeListMarker.add(marker);
378
		}
379
		for (Marker marker : removeListMarker){
380
			annotatableEntity2.removeMarker(marker);
381
			session.delete(marker);
382
		}
383
	}
384

    
385
	/**
386
	 * Clones all extensions   of cdmBase2 and
387
	 * attaches the clones to cdmBase1.
388
	 * Finally removes all annotations and markers from cdmBase2.
389
	 * @param cdmBase1
390
	 * @param cdmBase2
391
	 * @param session
392
	 */
393
	//TODO Why do we not handle credits (credits are reusable), identifier and sources here
394
	private <T> void copyIdentifiableExtensions(T cdmBase1, T cdmBase2,
395
			Session session) {
396
		IdentifiableEntity identifiableEntity1 = (IdentifiableEntity)cdmBase1;
397
		IdentifiableEntity identifiableEntity2 = (IdentifiableEntity)cdmBase2;
398

    
399
		//extensions
400
		List<Extension> removeListExtension = new ArrayList<Extension>();
401
		for (Extension changeObject : (Set<Extension>)identifiableEntity2.getExtensions()){
402
			try {
403
				Extension clone = changeObject.clone(identifiableEntity1);
404
				identifiableEntity1.addExtension(clone);
405
				removeListExtension.add(changeObject);
406
			} catch (CloneNotSupportedException e) {
407
				e.printStackTrace();
408
			}
409

    
410
		}
411
		for (Extension removeObject : removeListExtension){
412
			identifiableEntity2.removeExtension(removeObject);
413
			session.delete(removeObject);
414
		}
415

    
416
		//identifiers
417
		List<Identifier> removeListIdentifier = new ArrayList<Identifier>();
418
		for (Identifier<?> changeObject : (List<Identifier>)identifiableEntity2.getIdentifiers()){
419
			try {
420
				Identifier<?> clone = changeObject.clone(identifiableEntity1);
421
				identifiableEntity1.addIdentifier(clone);
422
				removeListIdentifier.add(changeObject);
423
			} catch (CloneNotSupportedException e) {
424
				e.printStackTrace();
425
			}
426
		}
427
		for (Identifier removeObject : removeListIdentifier){
428
			identifiableEntity2.removeIdentifier(removeObject);
429
			session.delete(removeObject);
430
		}
431

    
432
	}
433

    
434
	private void reallocateReferences(CdmBase cdmBase1, CdmBase cdmBase2, SessionFactory sessionFactory, Class clazz, Set<ICdmBase> cloneSet){
435
		try {
436
			Set<ReferenceHolder> holderSet = genericDao.getOrMakeHolderSet(clazz);
437
			for (ReferenceHolder refHolder: holderSet){
438
				reallocateByHolder(cdmBase1, cdmBase2, refHolder, cloneSet);
439
			}
440
			return;
441
		} catch (Exception e) {
442
			e.printStackTrace();
443
			throw new RuntimeException(e);
444
		}
445
	}
446

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

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

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

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

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

    
543
	private void reallocateSingleItem(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
544
		List<CdmBase> referencingObjects = genericDao.getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2);
545
		for (CdmBase referencingObject : referencingObjects){
546
			if (!cloneSet.contains(referencingObject)){
547
		        String className = refHolder.otherClass.getSimpleName();
548
	            String propertyName = refHolder.propertyName;
549
		        String hql = "UPDATE " + className + " c SET c."+propertyName+" = :newValue WHERE c.id = :id";
550
		        Query query = session.createQuery(hql);
551
		        query.setEntity("newValue", cdmBase1);
552
		        query.setInteger("id",referencingObject.getId());
553
		        int rowCount = query.executeUpdate();
554
		        logger.debug("Rows affected: " + rowCount);
555
		        session.refresh(referencingObject);
556
	        }
557
	    }
558
		session.flush();
559
	}
560

    
561
	private Field getFieldRecursive(Class clazz, String propertyName) throws NoSuchFieldException{
562
		try {
563
			return clazz.getDeclaredField(propertyName);
564
		} catch (NoSuchFieldException e) {
565
			Class superClass = clazz.getSuperclass();
566
			if (CdmBase.class.isAssignableFrom(superClass)){
567
				return getFieldRecursive(superClass, propertyName);
568
			}else{
569
				throw e;
570
			}
571
		}
572
	}
573

    
574
	/**
575
	 * @throws NoSuchFieldException
576
	 * @throws SecurityException
577
	 * @throws IllegalAccessException
578
	 * @throws IllegalArgumentException
579
	 *
580
	 */
581
	private void reallocateSingleItem_Old(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
582
		List<CdmBase> referencingObjects = genericDao.getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2);
583
		for (CdmBase referencingObject : referencingObjects){
584
			Field referencingField = refHolder.otherClass.getDeclaredField(refHolder.propertyName);
585
			referencingField.setAccessible(true);
586
			Object test = referencingField.get(referencingObject);
587
			assert(test.equals(cdmBase2));
588
			referencingField.set(referencingObject, cdmBase1);
589
		}
590
	}
591

    
592

    
593

    
594

    
595
	/**
596
	 * @param <T>
597
	 * @param clazz
598
	 * @param sessionFactory
599
	 */
600
	private <T> Set<String> getCollectionRoles(Class<T> clazz,
601
			SessionFactoryImpl sessionFactory) {
602
		Set<String> collectionRoles = null;
603
		ClassMetadata classMetaData = sessionFactory.getClassMetadata(clazz);
604
		if (classMetaData instanceof AbstractEntityPersister){
605
			AbstractEntityPersister persister = (AbstractEntityPersister)classMetaData;
606
			String rootName = persister.getRootEntityName();
607
			collectionRoles = sessionFactory.getCollectionRolesByEntityParticipant(rootName);
608
			for (String collectionRole : collectionRoles){
609
				CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
610
				CollectionPersister collPersister = sessionFactory.getCollectionPersister(collectionRole);
611
				logger.debug("");
612
			}
613
		}else{
614
			logger.warn("Class metadata is not of type AbstractEntityPersister");
615
			throw new UnhandledException("Class metadata is not of type AbstractEntityPersister", null);
616
		}
617
		return collectionRoles;
618
	}
619

    
620

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

    
623
		try {
624
			Class<T> clazz = (Class<T>)cdmBase1.getClass();
625
			if (CdmGenericDaoImpl.isNoDoType(propertyType)){
626
						//do nothing
627
			}else if (propertyType.isEntityType()){
628
				//Field field = clazz.getField(propertyName);
629
				EntityType entityType = (EntityType)propertyType;
630
				String associatedEntityName = entityType.getAssociatedEntityName();
631
				Class entityClass = Class.forName(associatedEntityName);
632
//				 Type refPropType = sessionFactory.getReferencedPropertyType(entityClass.getCanonicalName(), propertyName);
633
				Set<String> collectionRoles = getCollectionRoles(clazz, sessionFactory);
634
				for (String collectionRole : collectionRoles){
635
					CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
636
					String role = collMetadata.getRole();
637
					logger.debug(role);
638

    
639
				}
640

    
641
//				if (entityClass.isInterface()){
642
//					logger.debug("So ein interface");
643
//				}
644
//				if (entityClass.isAssignableFrom(clazz)){
645
//					makeSingleProperty(referencedClass, entityClass, propertyName, cdmClass, result, isCollection);
646
//				}
647
			}else if (propertyType.isCollectionType()){
648
				CollectionType collectionType = (CollectionType)propertyType;
649
				String role = collectionType.getRole();
650
				Type elType = collectionType.getElementType(sessionFactory);
651
				String n = collectionType.getAssociatedEntityName(sessionFactory);
652
				CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(role);
653
				if (collMetadata instanceof OneToManyPersister){
654
					OneToManyPersister oneManyPersister = (OneToManyPersister)collMetadata;
655
					String className = oneManyPersister.getOwnerEntityName();
656
					Class<?> myClass = Class.forName(className);
657
					Field field = myClass.getDeclaredField(propertyName);
658
					field.setAccessible(true);
659
					try {
660
						if (collectionType instanceof SetType){
661
							Set set2 = (Set)field.get(cdmBase2);
662
							Set<Object> set1 = (Set<Object>)field.get(cdmBase1);
663
							for (Object obj2: set2){
664
								set1.add(obj2);
665
							}
666
						}
667
					} catch (IllegalArgumentException e) {
668
						// TODO Auto-generated catch block
669
						e.printStackTrace();
670
					} catch (IllegalAccessException e) {
671
						// TODO Auto-generated catch block
672
						e.printStackTrace();
673
					}
674

    
675
				}
676
				logger.debug("");
677

    
678
//			makePropertyType(result, referencedClass, sessionFactory, cdmClass, elType, propertyName, true);
679
			}else if (propertyType.isAnyType()){
680
				AnyType anyType = (AnyType)propertyType;
681
				Field field = clazz.getDeclaredField(propertyName);
682
				Class returnType = field.getType();
683
//			if (returnType.isInterface()){
684
//				logger.debug("So ein interface");
685
//			}
686
//			if (returnType.isAssignableFrom(referencedClass)){
687
//				makeSingleProperty(referencedClass, returnType, propertyName, cdmClass, result, isCollection);
688
//			}
689
			}else if (propertyType.isComponentType()){
690
				ComponentType componentType = (ComponentType)propertyType;
691
				Type[] subTypes = componentType.getSubtypes();
692
//		Field field = cdmClass.getDeclaredField(propertyName);
693
//		Class returnType = field.getType();
694
				int propertyNr = 0;
695
				for (Type subType: subTypes){
696
					String subPropertyName = componentType.getPropertyNames()[propertyNr];
697
					if (! CdmGenericDaoImpl.isNoDoType(subType)){
698
						logger.warn("SubType not yet handled: " + subType);
699
					}
700
//					handlePropertyType(referencedCdmBase, result, referencedClass,
701
//					sessionFactory, cdmClass, subType, subPropertyName, isCollection);
702
					propertyNr++;
703
				}
704
			}else{
705
				logger.warn("propertyType not yet handled: " + propertyType.getName());
706
			}
707
			//OLD:
708
					//		if (! type.isInterface()){
709
			//		if (referencedClass.isAssignableFrom(type)||
710
			//				type.isAssignableFrom(referencedClass) && CdmBase.class.isAssignableFrom(type)){
711
			//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
712
			//		}
713
			//	//interface
714
			//	}else if (type.isAssignableFrom(referencedClass)){
715
			//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
716
		} catch (Exception e) {
717
			throw new MergeException(e);
718
		}
719
	}
720

    
721

    
722

    
723
}
(6-6/23)