Project

General

Profile

Download (27.2 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
public class DeduplicationHelper {
62
	private static final Logger logger = Logger.getLogger(DeduplicationHelper.class);
63

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

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

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

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

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

    
93
		if (mergeStrategy == null){
94
			mergeStrategy = DefaultMergeStrategy.NewInstance(cdmBase1.getClass());
95
		}
96
		try {
97
			//check null and types
98
			checkMergeValid(cdmBase1, cdmBase2, mergeStrategy);
99

    
100
			//merge objects
101
			//externel impl
102
			//internal impl
103

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

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

    
119
			if (cdmBase2.getId() > 0){
120
				session.saveOrUpdate(cdmBase2);
121
				session.flush();
122
				//rearrange references pointing to cdmBase2 to cdmBase1 in future
123
				reallocateReferences(cdmBase1, cdmBase2, clazz2, cloneSet);
124
			}
125

    
126
			//remove deleted objects
127

    
128
			//session.delete(null, mergable2, true, null);
129
			boolean deleteSecond = true;
130
			if (mergeStrategy instanceof ConvertMergeStrategy) {
131
			    deleteSecond = ((ConvertMergeStrategy)mergeStrategy).isDeleteSecondObject();
132
			}
133
			if(deleteSecond){
134
			    session.delete(cdmBase2);
135

    
136
			    for (ICdmBase toBeDeleted : deleteSet){
137
	                logger.debug("Delete " + toBeDeleted);
138
	                if (toBeDeleted != cdmBase2){
139
	                    session.delete(toBeDeleted);
140

    
141
	                }
142
	            }
143
			}
144

    
145
			//flush
146
			session.flush();
147
		} catch (Exception e) {
148
			e.printStackTrace();
149
		    throw new MergeException(e);
150
		}
151
	}
152

    
153
	/**
154
	 * Throws an exception if merge is not possible.
155
	 * @param cdmBase1
156
	 * @param cdmBase2
157
	 * @param strategy
158
	 * @throws IllegalArgumentException
159
	 * @throws NullPointerException
160
	 */
161
	private <T extends CdmBase> void checkMergeValid(T cdmBase1, T cdmBase2, IMergeStrategy strategy)throws IllegalArgumentException, NullPointerException{
162
		if (cdmBase1 == null || cdmBase2 == null){
163
			throw new NullPointerException("Merge arguments must not be (null)");
164
		}
165
		cdmBase1 = HibernateProxyHelper.deproxy(cdmBase1);
166
		cdmBase2 = HibernateProxyHelper.deproxy(cdmBase2);
167

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

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

    
203
	/**
204
	 * Checks if 2 can be merged and reallocation of referencing objects is allowed.
205
	 * This is <code>true</code> if
206
	 * classes are same or for some explicit cases like both
207
	 * inherit form {@link TeamOrPersonBase} or from {@link TaxonName}.
208
	 * Necessary condition is that both classes are mapped to the same table.
209
	 *
210
	 * @param class1
211
	 * @param class2
212
	 * @return true if mer
213
	 */
214
	private boolean  checkOnlyReallocationAllowed(Class<? extends CdmBase> class1,
215
			Class<? extends CdmBase> class2) {
216
		if (class1 == class2){
217
			return true;
218
		}else{
219
			if (classesAssignableFrom(TeamOrPersonBase.class, class1, class2)){
220
				return true;
221
			}else if (classesAssignableFrom(TaxonName.class, class1, class2)){
222
				return true;
223
			}else{
224
				return false;
225
			}
226
		}
227
	}
228

    
229
	private boolean classesAssignableFrom(Class<? extends CdmBase> superClass,
230
			Class<? extends CdmBase> class1, Class<? extends CdmBase> class2) {
231
		return superClass.isAssignableFrom(class1) && superClass.isAssignableFrom(class2);
232
	}
233

    
234
	/**
235
	 * @param <T>
236
	 * @param cdmBase1
237
	 * @param cdmBase2
238
	 * @param clazz
239
	 * @param sessionFactory
240
	 * @throws MergeException
241
	 * @throws ClassNotFoundException
242
	 * @throws NoSuchFieldException
243
	 */
244
	private <T extends CdmBase> void mergeExternal(T cdmBase1, T cdmBase2, Class<T> clazz,
245
			Session session) throws MergeException {
246
//		handleAnnotations
247
		logger.warn("Merge external");
248
		handleAnnotationsEtc(cdmBase1, cdmBase2, session);
249

    
250
		SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory();
251

    
252
//		Map<String, ClassMetadata> allClassMetadata = sessionFactory.getAllClassMetadata();
253

    
254
		//TODO cast
255
		getCollectionRoles(clazz, sessionFactory);
256

    
257
		TaxonName name1 = TaxonNameFactory.NewBotanicalInstance(null);
258
		name1.getTaxonBases();
259

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

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

    
306

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

    
327
		session.saveOrUpdate(cdmBase1);
328
		session.saveOrUpdate(cdmBase2);
329
		session.flush();
330
	}
331

    
332

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

    
362
		//marker
363
		List<Marker> removeListMarker = new ArrayList<>();
364
		for (Marker marker : annotatableEntity2.getMarkers()){
365
			Marker clone = null;
366
			try {
367
				clone = marker.clone();
368
			} catch (CloneNotSupportedException e) {
369
				e.printStackTrace();
370
			}
371
			annotatableEntity1.addMarker(clone);
372
			removeListMarker.add(marker);
373
		}
374
		for (Marker marker : removeListMarker){
375
			annotatableEntity2.removeMarker(marker);
376
			session.delete(marker);
377
		}
378
	}
379

    
380
	/**
381
	 * Clones all extensions of cdmBase2 and
382
	 * attaches the clones to cdmBase1.
383
	 * Finally removes all annotations and markers from cdmBase2.
384
	 * @param cdmBase1
385
	 * @param cdmBase2
386
	 * @param session
387
	 */
388
	//TODO Why do we not handle credits, rights and sources here
389
	private <T> void copyIdentifiableExtensions(T cdmBase1, T cdmBase2,
390
			Session session) {
391
		IdentifiableEntity<?> identifiableEntity1 = (IdentifiableEntity<?>)cdmBase1;
392
		IdentifiableEntity<?> identifiableEntity2 = (IdentifiableEntity<?>)cdmBase2;
393

    
394
		//extensions
395
		List<Extension> removeListExtension = new ArrayList<>();
396
		for (Extension changeObject : identifiableEntity2.getExtensions()){
397
			try {
398
				Extension clone = changeObject.clone();
399
				identifiableEntity1.addExtension(clone);
400
				removeListExtension.add(changeObject);
401
			} catch (CloneNotSupportedException e) {
402
				throw new RuntimeException("Clone is not yet supported for class " + changeObject.getClass().getName() + " but should.");
403
			}
404
		}
405
		for (Extension removeObject : removeListExtension){
406
			identifiableEntity2.removeExtension(removeObject);
407
			session.delete(removeObject);
408
		}
409

    
410
		//identifiers
411
		List<Identifier<?>> removeListIdentifier = new ArrayList<>();
412
		for (Identifier<?> changeObject : identifiableEntity2.getIdentifiers()){
413
			try {
414
				Identifier<?> clone = changeObject.clone();
415
				identifiableEntity1.addIdentifier(clone);
416
				removeListIdentifier.add(changeObject);
417
			} catch (CloneNotSupportedException e) {
418
			    throw new RuntimeException(e);
419
			}
420
		}
421
		for (Identifier<?> removeObject : removeListIdentifier){
422
			identifiableEntity2.removeIdentifier(removeObject);
423
			session.delete(removeObject);
424
		}
425

    
426
	}
427

    
428
	private void reallocateReferences(CdmBase cdmBase1, CdmBase cdmBase2, Class<? extends CdmBase> clazz, Set<ICdmBase> cloneSet){
429
		try {
430
			Set<ReferenceHolder> holderSet = genericDao.getOrMakeHolderSet(clazz);
431
			for (ReferenceHolder refHolder: holderSet){
432
				reallocateByHolder(cdmBase1, cdmBase2, refHolder, cloneSet);
433
			}
434
			return;
435
		} catch (Exception e) {
436
			throw new RuntimeException(e);
437
		}
438
	}
439

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

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

    
476
	private boolean reallocateCollectionPossible(CdmBase cdmBase1, CdmBase cdmBase2,
477
			ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws SecurityException, IllegalArgumentException {
478
		Class<?> targetClass = refHolder.targetClass;
479
		Class<?> clazz1 = cdmBase1.getClass();
480
		if (! targetClass.isAssignableFrom(clazz1)){
481
			//FIXME only do count or hasXXX, we do not need to instantiate objects here
482
			List<CdmBase> referencingObjects = genericDao.getCdmBasesWithItemInCollection(refHolder.itemClass, refHolder.otherClass, refHolder.propertyName, cdmBase2, null);
483
			if (! referencingObjects.isEmpty()){
484
				return false;
485
			}
486
		}
487
		return true;
488
	}
489

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

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

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

    
560
		            //TODO
561
		            /*
562
		             * UPDATE LanguageString
563
		             * SET text = Replace(text, cdmBase2.getUuuid(), cdmBase1.getUuid)
564
		             * WHERE id IN (SELECT * FROM IntextReference
565
		             *
566
		             */
567
		            System.out.println("IntextReference found");
568
		        }
569
	        }
570
	    }
571
		session.flush();
572
	}
573

    
574
	private Field getFieldRecursive(Class<?> clazz, String propertyName) throws NoSuchFieldException{
575
		try {
576
			return clazz.getDeclaredField(propertyName);
577
		} catch (NoSuchFieldException e) {
578
			Class<?> superClass = clazz.getSuperclass();
579
			if (CdmBase.class.isAssignableFrom(superClass)){
580
				return getFieldRecursive(superClass, propertyName);
581
			}else{
582
				throw e;
583
			}
584
		}
585
	}
586

    
587
	/**
588
	 * @throws NoSuchFieldException
589
	 * @throws SecurityException
590
	 * @throws IllegalAccessException
591
	 * @throws IllegalArgumentException
592
	 *
593
	 */
594
	private void reallocateSingleItem_Old(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
595
		List<CdmBase> referencingObjects = genericDao.getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2, null);
596
		for (CdmBase referencingObject : referencingObjects){
597
			Field referencingField = refHolder.otherClass.getDeclaredField(refHolder.propertyName);
598
			referencingField.setAccessible(true);
599
			Object test = referencingField.get(referencingObject);
600
			assert(test.equals(cdmBase2));
601
			referencingField.set(referencingObject, cdmBase1);
602
		}
603
	}
604

    
605

    
606

    
607

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

    
633

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

    
636
		try {
637
			Class<T> clazz = (Class<T>)cdmBase1.getClass();
638
			if (CdmGenericDaoImpl.isNoDoType(propertyType)){
639
						//do nothing
640
			}else if (propertyType.isEntityType()){
641
				//Field field = clazz.getField(propertyName);
642
				EntityType entityType = (EntityType)propertyType;
643
				String associatedEntityName = entityType.getAssociatedEntityName();
644
				Class<?> entityClass = Class.forName(associatedEntityName);
645
//				 Type refPropType = sessionFactory.getReferencedPropertyType(entityClass.getCanonicalName(), propertyName);
646
				Set<String> collectionRoles = getCollectionRoles(clazz, sessionFactory);
647
				for (String collectionRole : collectionRoles){
648
					CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
649
					String role = collMetadata.getRole();
650
					logger.debug(role);
651

    
652
				}
653

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

    
688
				}
689
				logger.debug("");
690

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

    
734

    
735

    
736
}
(7-7/18)