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

    
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
				session.flush();
129
				//rearrange references pointing to cdmBase2 to cdmBase1 in future
130
				reallocateReferences(cdmBase1, cdmBase2, sessionFactory, clazz2, cloneSet);
131
			}
132

    
133
			//remove deleted objects
134

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

    
143
			    for (ICdmBase toBeDeleted : deleteSet){
144
	                logger.debug("Delete " + toBeDeleted);
145
	                if (toBeDeleted != cdmBase2){
146
	                    session.delete(toBeDeleted);
147

    
148
	                }
149
	            }
150
			}
151

    
152
			//flush
153
			session.flush();
154

    
155
		} catch (Exception e) {
156
			e.printStackTrace();
157
		    throw new MergeException(e);
158
		}
159
	}
160

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

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

    
177

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

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

    
217
	/**
218
	 * Test if 2 classes
219
	 * @param class1
220
	 * @param class2
221
	 * @return
222
	 */
223
	private boolean  testOnlyReallocationAllowed(Class<? extends CdmBase> class1,
224
			Class<? extends CdmBase> class2) {
225
		if (class1 == class2){
226
			return true;
227
		}else{
228
			if (classesAssignableFrom(TeamOrPersonBase.class, class1, class2)){
229
				return true;
230
			}else if (classesAssignableFrom(TaxonNameBase.class, class1, class2)){
231
				return true;
232
			}else{
233
				return false;
234
			}
235
		}
236
	}
237

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

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

    
259
		SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory();
260

    
261
		Map<String, ClassMetadata> allClassMetadata = sessionFactory.getAllClassMetadata();
262

    
263
		//TODO cast
264
		getCollectionRoles(clazz, sessionFactory);
265

    
266
		TaxonNameBase name1 = TaxonNameBase.NewBotanicalInstance(null);
267
		name1.getTaxonBases();
268

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

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

    
315

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

    
336
		session.saveOrUpdate(cdmBase1);
337
		session.saveOrUpdate(cdmBase2);
338
		session.flush();
339
	}
340

    
341

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

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

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

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

    
414
		}
415
		for (Extension removeObject : removeListExtension){
416
			identifiableEntity2.removeExtension(removeObject);
417
			session.delete(removeObject);
418
		}
419

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

    
436
	}
437

    
438
	private void reallocateReferences(CdmBase cdmBase1, CdmBase cdmBase2, SessionFactory sessionFactory, Class clazz, Set<ICdmBase> cloneSet){
439
		try {
440
			Set<ReferenceHolder> holderSet = genericDao.getOrMakeHolderSet(clazz);
441
			for (ReferenceHolder refHolder: holderSet){
442
				reallocateByHolder(cdmBase1, cdmBase2, refHolder, cloneSet);
443
			}
444
			return;
445
		} catch (Exception e) {
446
			e.printStackTrace();
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 MergeException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
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 SET c."+propertyName+" = :newValue WHERE c.id = :id";
554
		        Query query = session.createQuery(hql);
555
		        query.setEntity("newValue", cdmBase1);
556
		        query.setInteger("id",referencingObject.getId());
557
		        int rowCount = query.executeUpdate();
558
		        logger.debug("Rows affected: " + rowCount);
559
		        session.refresh(referencingObject);
560
	        }
561
	    }
562
		session.flush();
563
	}
564

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

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

    
596

    
597

    
598

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

    
624

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

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

    
643
				}
644

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

    
679
				}
680
				logger.debug("");
681

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

    
725

    
726

    
727
}
(6-6/23)