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)annotation.clone();
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

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

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

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

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

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

    
433
	}
434

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

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

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

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

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

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

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

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

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

    
593

    
594

    
595

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

    
621

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

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

    
640
				}
641

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

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

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

    
722

    
723

    
724
}
(6-6/23)