Project

General

Profile

Download (42.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy 
4
* http://www.e-taxonomy.eu
5
* 
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.persistence.dao.hibernate.common;
11

    
12
import java.lang.reflect.Field;
13
import java.lang.reflect.InvocationTargetException;
14
import java.lang.reflect.Method;
15
import java.lang.reflect.Modifier;
16
import java.util.ArrayList;
17
import java.util.Collection;
18
import java.util.HashMap;
19
import java.util.HashSet;
20
import java.util.List;
21
import java.util.Map;
22
import java.util.Set;
23

    
24
import javax.naming.NamingException;
25
import javax.naming.Reference;
26

    
27
import org.apache.commons.lang.StringUtils;
28
import org.apache.commons.lang.UnhandledException;
29
import org.apache.log4j.Logger;
30
import org.hibernate.Criteria;
31
import org.hibernate.HibernateException;
32
import org.hibernate.MappingException;
33
import org.hibernate.Query;
34
import org.hibernate.Session;
35
import org.hibernate.SessionFactory;
36
import org.hibernate.criterion.CriteriaSpecification;
37
import org.hibernate.criterion.Criterion;
38
import org.hibernate.criterion.Restrictions;
39
import org.hibernate.impl.SessionFactoryImpl;
40
import org.hibernate.impl.SessionImpl;
41
import org.hibernate.metadata.ClassMetadata;
42
import org.hibernate.metadata.CollectionMetadata;
43
import org.hibernate.persister.collection.CollectionPersister;
44
import org.hibernate.persister.collection.OneToManyPersister;
45
import org.hibernate.persister.entity.AbstractEntityPersister;
46
import org.hibernate.stat.Statistics;
47
import org.hibernate.type.AnyType;
48
import org.hibernate.type.BooleanType;
49
import org.hibernate.type.CollectionType;
50
import org.hibernate.type.ComponentType;
51
import org.hibernate.type.DoubleType;
52
import org.hibernate.type.EntityType;
53
import org.hibernate.type.EnumType;
54
import org.hibernate.type.FloatType;
55
import org.hibernate.type.IntegerType;
56
import org.hibernate.type.LongType;
57
import org.hibernate.type.SerializableType;
58
import org.hibernate.type.SetType;
59
import org.hibernate.type.StringClobType;
60
import org.hibernate.type.StringType;
61
import org.hibernate.type.Type;
62
import org.joda.time.contrib.hibernate.PersistentDateTime;
63
import org.springframework.dao.DataAccessException;
64
import org.springframework.stereotype.Repository;
65

    
66
import eu.etaxonomy.cdm.common.CdmUtils;
67
import eu.etaxonomy.cdm.common.DoubleResult;
68
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
69
import eu.etaxonomy.cdm.hibernate.PartialUserType;
70
import eu.etaxonomy.cdm.hibernate.URIUserType;
71
import eu.etaxonomy.cdm.hibernate.UUIDUserType;
72
import eu.etaxonomy.cdm.hibernate.WSDLDefinitionUserType;
73
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
74
import eu.etaxonomy.cdm.model.common.Annotation;
75
import eu.etaxonomy.cdm.model.common.CdmBase;
76
import eu.etaxonomy.cdm.model.common.CdmMetaData;
77
import eu.etaxonomy.cdm.model.common.Extension;
78
import eu.etaxonomy.cdm.model.common.ICdmBase;
79
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
80
import eu.etaxonomy.cdm.model.common.Marker;
81
import eu.etaxonomy.cdm.model.name.BotanicalName;
82
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
83
import eu.etaxonomy.cdm.model.taxon.Taxon;
84
import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
85
import eu.etaxonomy.cdm.strategy.match.CacheMatcher;
86
import eu.etaxonomy.cdm.strategy.match.DefaultMatchStrategy;
87
import eu.etaxonomy.cdm.strategy.match.FieldMatcher;
88
import eu.etaxonomy.cdm.strategy.match.IMatchStrategy;
89
import eu.etaxonomy.cdm.strategy.match.IMatchable;
90
import eu.etaxonomy.cdm.strategy.match.MatchException;
91
import eu.etaxonomy.cdm.strategy.match.MatchMode;
92
import eu.etaxonomy.cdm.strategy.match.Matching;
93
import eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy;
94
import eu.etaxonomy.cdm.strategy.merge.IMergable;
95
import eu.etaxonomy.cdm.strategy.merge.IMergeStrategy;
96
import eu.etaxonomy.cdm.strategy.merge.MergeException;
97

    
98
@Repository
99
public class CdmGenericDaoImpl extends CdmEntityDaoBase<CdmBase> implements ICdmGenericDao{
100
	private static final Logger logger = Logger.getLogger(CdmGenericDaoImpl.class);
101

    
102
	
103
	private Set<Class<? extends CdmBase>> allCdmClasses = null;
104
	private Map<Class<? extends CdmBase>, Set<ReferenceHolder>> referenceMap = new HashMap<Class<? extends CdmBase>, Set<ReferenceHolder>>();
105
	
106
	private class ReferenceHolder{
107
		String propertyName;
108
		Class<? extends CdmBase> otherClass;
109
		Class<? extends CdmBase> itemClass;
110
		Field field;
111
		public boolean isCollection(){return itemClass != null;};
112
		public String toString(){return otherClass.getSimpleName() + "." + propertyName ;};
113
	}
114

    
115
	
116
	public CdmGenericDaoImpl() {
117
		super(CdmBase.class);
118
	}
119
	
120
	/* (non-Javadoc)
121
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#getCdmBasesByFieldAndClass(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.common.CdmBase)
122
	 */
123
	
124
	public List<CdmBase> getCdmBasesByFieldAndClass(Class clazz, String propertyName, CdmBase referencedCdmBase){
125
		Session session = super.getSession();
126
		Criteria criteria = session.createCriteria(clazz);
127
		criteria.add(Restrictions.eq(propertyName, referencedCdmBase));
128
		return criteria.list();
129
	}
130
	
131
	/* (non-Javadoc)
132
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#getCdmBasesByFieldAndClass(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.common.CdmBase)
133
	 */
134
	public List<CdmBase> getCdmBasesWithItemInCollection(Class itemClass, Class clazz, String propertyName, CdmBase item){
135
		Session session = super.getSession();
136
		String thisClassStr = itemClass.getSimpleName();
137
		String otherClassStr = clazz.getSimpleName();
138
		String queryStr = " SELECT other FROM "+ thisClassStr + " this, " + otherClassStr + " other " + 
139
			" WHERE this = :referencedObject AND this member of other."+propertyName ;
140
		Query query = session.createQuery(queryStr).setEntity("referencedObject", item);
141
		List<CdmBase> result = query.list();
142
		return result;
143
	}
144
	
145
	/* (non-Javadoc)
146
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#getAllCdmClasses(boolean)
147
	 */
148
	public Set<Class<? extends CdmBase>> getAllCdmClasses(boolean includeAbstractClasses){
149
		Set<Class<? extends CdmBase>> result = new HashSet<Class<? extends CdmBase>>();
150
		
151
		SessionFactory sessionFactory = getSession().getSessionFactory();
152
		Map<?,?> allClassMetadata = sessionFactory.getAllClassMetadata();
153
		Collection<?> keys = allClassMetadata.keySet();
154
		for (Object oKey : keys){
155
			if (oKey instanceof String){
156
				String strKey = (String)oKey;
157
				if (! strKey.endsWith("_AUD")){
158
					try {
159
						Class clazz = Class.forName(strKey);
160
						boolean isAbstractClass = Modifier.isAbstract(clazz.getModifiers());
161
						if (! isAbstractClass || includeAbstractClasses){
162
							result.add(clazz);
163
						}
164
					} catch (ClassNotFoundException e) {
165
						logger.warn("Class not found: " + strKey);
166
					}
167
				}
168
			}else{
169
				logger.warn("key is not of type String: " +  oKey);
170
			}
171
		}
172
		return result;
173
	}
174
	
175
	
176

    
177
	
178
	public Set<CdmBase> getReferencingObjects(CdmBase referencedCdmBase){
179
		Set<CdmBase> result = new HashSet<CdmBase>();
180
		try {
181
			referencedCdmBase = (CdmBase)HibernateProxyHelper.deproxy(referencedCdmBase);
182
			Class<? extends CdmBase> referencedClass = referencedCdmBase.getClass();
183
			
184
			Set<ReferenceHolder> holderSet = referenceMap.get(referencedClass);
185
			if (holderSet == null){
186
				holderSet = makeHolderSet(referencedClass);
187
				referenceMap.put(referencedClass, holderSet);
188
			}
189
			for (ReferenceHolder refHolder: holderSet){
190
				handleReferenceHolder(referencedCdmBase, result, refHolder);
191
			}
192
			return result;	
193
		} catch (Exception e) {
194
			e.printStackTrace();
195
			throw new RuntimeException(e);
196
		}
197
		
198
	}
199

    
200
	/**
201
	 * @param referencedCdmBase
202
	 * @param result
203
	 * @param refHolder
204
	 */
205
	private void handleReferenceHolder(CdmBase referencedCdmBase,
206
			Set<CdmBase> result, ReferenceHolder refHolder) {
207
		boolean isCollection = refHolder.isCollection();
208
		if (isCollection){
209
			result.addAll(getCdmBasesWithItemInCollection(refHolder.itemClass, refHolder.otherClass, refHolder.propertyName, referencedCdmBase));
210
		}else{
211
			result.addAll(getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, referencedCdmBase));
212
		}
213
	}
214

    
215
	
216
	/**
217
	 * @param referencedClass
218
	 * @return
219
	 * @throws NoSuchFieldException 
220
	 * @throws ClassNotFoundException 
221
	 */
222
	private Set<ReferenceHolder> makeHolderSet(Class referencedClass) throws ClassNotFoundException, NoSuchFieldException {
223
		Set<ReferenceHolder> result = new HashSet<ReferenceHolder>();
224
		
225
		//init
226
		if (allCdmClasses == null){
227
			allCdmClasses = getAllCdmClasses(false); //findAllCdmClasses();
228
		}
229
		//referencedCdmBase = (CdmBase)HibernateProxyHelper.deproxy(referencedCdmBase);
230
		SessionFactory sessionFactory = getSession().getSessionFactory();
231
		
232
		
233
		for (Class<? extends CdmBase> cdmClass : allCdmClasses){
234
			ClassMetadata classMetadata = sessionFactory.getClassMetadata(cdmClass);
235
			Type[] propertyTypes = classMetadata.getPropertyTypes();
236
			int propertyNr = 0;
237
			for (Type propertyType: propertyTypes){
238
				String propertyName = classMetadata.getPropertyNames()[propertyNr];
239
				makePropertyType(result, referencedClass, sessionFactory, cdmClass, propertyType, propertyName, false);
240
				propertyNr++;
241
			}
242
			
243
		}
244
		return result;
245
	}
246

    
247
	/**
248
	 * @param referencedCdmBase
249
	 * @param result
250
	 * @param referencedClass
251
	 * @param sessionFactory
252
	 * @param cdmClass
253
	 * @param propertyType
254
	 * @param propertyName
255
	 * @throws ClassNotFoundException
256
	 * @throws NoSuchFieldException
257
	 */
258
	private void makePropertyType(
259
//			CdmBase referencedCdmBase,
260
			Set<ReferenceHolder> result,
261
			Class referencedClass,
262
			SessionFactory sessionFactory, Class<? extends CdmBase> cdmClass,
263
			Type propertyType, String propertyName, boolean isCollection)
264
				throws ClassNotFoundException, NoSuchFieldException {
265
		
266
		
267
		if (propertyType.isEntityType()){
268
			EntityType entityType = (EntityType)propertyType;
269
			String associatedEntityName = entityType.getAssociatedEntityName();
270
			Class entityClass = Class.forName(associatedEntityName);
271
			if (entityClass.isInterface()){
272
				logger.debug("There is an interface");
273
			}
274
			if (entityClass.isAssignableFrom(referencedClass)){
275
				makeSingleProperty(referencedClass, entityClass, propertyName, cdmClass, result, isCollection);
276
			}
277
		}else if (propertyType.isCollectionType()){
278
			CollectionType collectionType = (CollectionType)propertyType;
279
			//String role = collectionType.getRole();
280
			Type elType = collectionType.getElementType((SessionFactoryImpl)sessionFactory);
281
			makePropertyType(result, referencedClass, sessionFactory, cdmClass, elType, propertyName, true);
282
		}else if (propertyType.isAnyType()){
283
			AnyType anyType = (AnyType)propertyType;
284
			Field field = cdmClass.getDeclaredField(propertyName);
285
			Class returnType = field.getType();
286
			if (returnType.isInterface()){
287
				logger.debug("There is an interface");
288
			}
289
			if (returnType.isAssignableFrom(referencedClass)){
290
				makeSingleProperty(referencedClass, returnType, propertyName, cdmClass, result, isCollection);
291
			}
292
		}else if (propertyType.isComponentType()){
293
			ComponentType componentType = (ComponentType)propertyType;
294
			Type[] subTypes = componentType.getSubtypes();
295
//			Field field = cdmClass.getDeclaredField(propertyName);
296
//			Class returnType = field.getType();
297
			int propertyNr = 0;
298
			for (Type subType: subTypes){
299
				String subPropertyName = componentType.getPropertyNames()[propertyNr];
300
				if (!isNoDoType(subType)){
301
					logger.warn("SubType not yet handled: " + subType);
302
				}
303
//				handlePropertyType(referencedCdmBase, result, referencedClass, 
304
//						sessionFactory, cdmClass, subType, subPropertyName, isCollection);
305
				propertyNr++;
306
			}
307
		}else if (isNoDoType(propertyType)){
308
			//do nothing
309
		}else{
310
			logger.warn("propertyType not yet handled: " + propertyType.getName());
311
		}
312
		//OLD: 
313
				//		if (! type.isInterface()){
314
		//		if (referencedClass.isAssignableFrom(type)|| 
315
		//				type.isAssignableFrom(referencedClass) && CdmBase.class.isAssignableFrom(type)){
316
		//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
317
		//		}
318
		//	//interface
319
		//	}else if (type.isAssignableFrom(referencedClass)){
320
		//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
321

    
322
	}
323
	
324
	private boolean makeSingleProperty(Class itemClass, Class type, String propertyName, Class cdmClass, Set<ReferenceHolder> result,/*CdmBase item,*/ boolean isCollection){
325
			String fieldName = StringUtils.rightPad(propertyName, 30);
326
			String className = StringUtils.rightPad(cdmClass.getSimpleName(), 30);
327
			String returnTypeName = StringUtils.rightPad(type.getSimpleName(), 30);
328
			
329
//			logger.debug(fieldName +   "\t\t" + className + "\t\t" + returnTypeName);
330
			ReferenceHolder refHolder = new ReferenceHolder();
331
			refHolder.propertyName = propertyName;
332
			refHolder.otherClass = cdmClass;
333
			refHolder.itemClass = (isCollection ? itemClass : null) ;
334
			result.add(refHolder);
335
		return true;
336
	}
337

    
338
	/**
339
	 * @param propertyType
340
	 * @return
341
	 */
342
	private boolean isNoDoType(Type propertyType) {
343
		boolean result = false;
344
		Class[] classes = new Class[]{
345
				PersistentDateTime.class, 
346
				WSDLDefinitionUserType.class,
347
				UUIDUserType.class, 
348
				PartialUserType.class,
349
				StringType.class,
350
				BooleanType.class, 
351
				IntegerType.class, 
352
				StringClobType.class,
353
				LongType.class,
354
				FloatType.class,
355
				SerializableType.class,
356
				DoubleType.class,
357
				URIUserType.class,
358
				EnumType.class
359
				};
360
		Set<String> classNames = new HashSet<String>();
361
		for (Class clazz: classes){
362
			classNames.add(clazz.getCanonicalName());
363
			if (clazz == propertyType.getClass()){
364
				return true;
365
			}
366
		}
367
		String propertyTypeClassName = propertyType.getName();
368
		if (classNames.contains(propertyTypeClassName)){
369
			return true;
370
		}
371
		return result;
372
	}
373

    
374
	/* (non-Javadoc)
375
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#getHqlResult(java.lang.String)
376
	 */
377
	public List<CdmBase> getHqlResult(String hqlQuery){
378
		Query query = getSession().createQuery(hqlQuery);
379
		List<CdmBase> result = query.list();
380
		return result;
381
	}
382
	
383
	public <T extends CdmBase> void   merge(T cdmBase1, T cdmBase2, IMergeStrategy mergeStrategy) throws MergeException {
384
		Class<T> clazz = (Class<T>)cdmBase1.getClass();
385
		SessionImpl session = (SessionImpl) getSession();
386
		SessionFactory sessionFactory = session.getSessionFactory();
387
		if (mergeStrategy == null){
388
			mergeStrategy = DefaultMergeStrategy.NewInstance(cdmBase1.getClass());
389
		}
390
		try {
391
			//test null and types
392
			testMergeValid(cdmBase1, cdmBase2);
393
			
394
			//merge objects
395
			//externel impl
396
			//internal impl
397
			session.flush();
398
			Set<ICdmBase> deleteSet = new HashSet<ICdmBase>();
399
			Set<ICdmBase> cloneSet = new HashSet<ICdmBase>();
400
			if (cdmBase1 instanceof IMergable){
401
				IMergable mergable1 = (IMergable)cdmBase1;
402
				IMergable mergable2 = (IMergable)cdmBase2;
403
				deleteSet = mergeStrategy.invoke(mergable1, mergable2, cloneSet);
404
				//session.saveOrUpdate(mergable1);
405

    
406
				session.flush();
407
				//((IMergable)cdmBase1).mergeInto(cdmBase2, DefaultMergeStrategy.NewInstance(cdmBase1.getClass()));
408
			}else{
409
				mergeExternal(cdmBase1, cdmBase2, clazz, session);
410
			}
411
			
412
			
413
			if (cdmBase2.getId() > 0){
414
				session.saveOrUpdate(cdmBase2);
415
				//rearrange references to cdmBase2
416
				reallocateReferences(cdmBase1, cdmBase2, sessionFactory, clazz, cloneSet);
417
			}
418
			
419
			//remove deleted objects 
420
			
421
			//session.delete(null, mergable2, true, null);
422
			session.delete(cdmBase2);
423
			for (ICdmBase toBeDeleted : deleteSet){
424
				logger.debug("Delete " + toBeDeleted);
425
				if (toBeDeleted != cdmBase2){
426
					session.delete(toBeDeleted);
427
				}
428
				
429
			}
430
			
431
			//flush
432
			session.flush();
433
			
434
		} catch (Exception e) {
435
			throw new MergeException(e);
436
		} 
437
	}
438

    
439
	
440
	/**
441
	 * @param <T>
442
	 * @param cdmBase1
443
	 * @param cdmBase2
444
	 * @param clazz
445
	 * @param sessionFactory
446
	 * @throws MergeException 
447
	 * @throws ClassNotFoundException
448
	 * @throws NoSuchFieldException
449
	 */
450
	private <T extends CdmBase> void mergeExternal(T cdmBase1, T cdmBase2, Class<T> clazz,
451
			Session session) throws MergeException {
452
//		handleAnnotations
453
		logger.warn("Merge external");
454
		handleAnnotationsEtc(cdmBase1, cdmBase2, session);
455
		
456
		SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory();
457
		
458
		Map allClassMetadata = sessionFactory.getAllClassMetadata();
459
		
460
		//TODO cast
461
		getCollectionRoles(clazz, sessionFactory);
462
		
463
		TaxonNameBase name1 = BotanicalName.NewInstance(null);
464
		name1.getTaxonBases();
465
		
466
		Type propType = sessionFactory.getReferencedPropertyType(BotanicalName.class.getCanonicalName(), "taxonBases");
467
		Map collMetadata = sessionFactory.getAllCollectionMetadata();
468
		//roles = sessionFactory.getCollectionRolesByEntityParticipant("eu.etaxonomy.cdm.model.name.BotanicalName");
469
		CollectionPersister collPersister;
470
		try {
471
			collPersister = sessionFactory.getCollectionPersister(TaxonNameBase.class.getCanonicalName()+".annotations");
472
		} catch (MappingException e) {
473
			// TODO Auto-generated catch block
474
			e.printStackTrace();
475
		}
476
		Statistics statistics = sessionFactory.getStatistics();
477
		logger.debug("");
478
		ClassMetadata taxonMetaData = sessionFactory.getClassMetadata(Taxon.class);
479
		String ename = taxonMetaData.getEntityName();
480
		try {
481
			Reference ref = sessionFactory.getReference();
482
			logger.debug("");
483
		} catch (NamingException e) {
484
			// TODO Auto-generated catch block
485
			e.printStackTrace();
486
		}
487
		//sessionFactory.get
488
		ClassMetadata classMetadata = getSession().getSessionFactory().getClassMetadata(clazz);
489
		Type[] propertyTypes = classMetadata.getPropertyTypes();
490
		int propertyNr = 0;
491
		for (Type propertyType: propertyTypes){
492
			String propertyName = classMetadata.getPropertyNames()[propertyNr];
493
			logger.debug(propertyName);
494
			makeMergeProperty(cdmBase1, cdmBase2, propertyType, propertyName, sessionFactory, false);
495
			propertyNr++;
496
		}
497
		Set<String> collectionRoles;
498
		if (classMetadata instanceof AbstractEntityPersister){
499
			AbstractEntityPersister persister = (AbstractEntityPersister)classMetadata;
500
			String rootName = persister.getRootEntityName();
501
			collectionRoles = sessionFactory.getCollectionRolesByEntityParticipant(rootName);
502
			for (String collectionRole : collectionRoles){
503
				CollectionMetadata collMetadata2 = sessionFactory.getCollectionMetadata(collectionRole);
504
				String role = collMetadata2.getRole();
505
				Type elType = collMetadata2.getElementType();
506
				logger.debug(role);
507
			}
508
		}
509
	}
510

    
511
	/**
512
	 * @param <T>
513
	 * @param clazz
514
	 * @param sessionFactory
515
	 */
516
	private <T> Set<String> getCollectionRoles(Class<T> clazz,
517
			SessionFactoryImpl sessionFactory) {
518
		Set<String> collectionRoles = null;
519
		ClassMetadata classMetaData = sessionFactory.getClassMetadata(clazz);
520
		if (classMetaData instanceof AbstractEntityPersister){
521
			AbstractEntityPersister persister = (AbstractEntityPersister)classMetaData;
522
			String rootName = persister.getRootEntityName();
523
			collectionRoles = sessionFactory.getCollectionRolesByEntityParticipant(rootName);
524
			for (String collectionRole : collectionRoles){
525
				CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
526
				CollectionPersister collPersister = sessionFactory.getCollectionPersister(collectionRole);
527
				logger.debug("");
528
			}
529
		}else{
530
			logger.warn("Class metadata is not of type AbstractEntityPersister");
531
			throw new UnhandledException("Class metadata is not of type AbstractEntityPersister", null);
532
		}
533
		return collectionRoles;
534
	}
535
	
536
	
537
	private <T extends CdmBase> void makeMergeProperty(T cdmBase1, T cdmBase2, Type propertyType, String propertyName, SessionFactoryImpl sessionFactory, boolean isCollection) throws MergeException
538
			 {
539
	
540
		try {
541
			Class<T> clazz = (Class<T>)cdmBase1.getClass();
542
			if (isNoDoType(propertyType)){
543
						//do nothing 
544
			}else if (propertyType.isEntityType()){
545
				//Field field = clazz.getField(propertyName);	
546
				EntityType entityType = (EntityType)propertyType;
547
				String associatedEntityName = entityType.getAssociatedEntityName();
548
				Class entityClass = Class.forName(associatedEntityName);
549
//				 Type refPropType = sessionFactory.getReferencedPropertyType(entityClass.getCanonicalName(), propertyName);
550
				Set<String> collectionRoles = getCollectionRoles(clazz, sessionFactory);
551
				for (String collectionRole : collectionRoles){
552
					CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
553
					String role = collMetadata.getRole();
554
					logger.debug(role);
555
					
556
				}
557
				
558
//				if (entityClass.isInterface()){
559
//					logger.debug("So ein interface");
560
//				}
561
//				if (entityClass.isAssignableFrom(clazz)){
562
//					makeSingleProperty(referencedClass, entityClass, propertyName, cdmClass, result, isCollection);
563
//				}
564
			}else if (propertyType.isCollectionType()){
565
				CollectionType collectionType = (CollectionType)propertyType;
566
				String role = collectionType.getRole();
567
				Type elType = collectionType.getElementType((SessionFactoryImpl)sessionFactory);
568
				String n = collectionType.getAssociatedEntityName(sessionFactory);
569
				CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(role);
570
				if (collMetadata instanceof OneToManyPersister){
571
					OneToManyPersister oneManyPersister = (OneToManyPersister)collMetadata;
572
					String className = oneManyPersister.getOwnerEntityName();
573
					Class<?> myClass = Class.forName(className);
574
					Field field = myClass.getDeclaredField(propertyName);
575
					field.setAccessible(true);
576
					try {
577
						if (collectionType instanceof SetType){
578
							Set set2 = (Set)field.get(cdmBase2);
579
							Set<Object> set1 = (Set<Object>)field.get(cdmBase1);
580
							for (Object obj2: set2){
581
								set1.add(obj2);
582
							}
583
						}
584
					} catch (IllegalArgumentException e) {
585
						// TODO Auto-generated catch block
586
						e.printStackTrace();
587
					} catch (IllegalAccessException e) {
588
						// TODO Auto-generated catch block
589
						e.printStackTrace();
590
					}
591
					
592
				}
593
				logger.debug("");
594
				
595
//			makePropertyType(result, referencedClass, sessionFactory, cdmClass, elType, propertyName, true);
596
			}else if (propertyType.isAnyType()){
597
				AnyType anyType = (AnyType)propertyType;
598
				Field field = clazz.getDeclaredField(propertyName);
599
				Class returnType = field.getType();
600
//			if (returnType.isInterface()){
601
//				logger.debug("So ein interface");
602
//			}
603
//			if (returnType.isAssignableFrom(referencedClass)){
604
//				makeSingleProperty(referencedClass, returnType, propertyName, cdmClass, result, isCollection);
605
//			}
606
			}else if (propertyType.isComponentType()){
607
				ComponentType componentType = (ComponentType)propertyType;
608
				Type[] subTypes = componentType.getSubtypes();
609
//		Field field = cdmClass.getDeclaredField(propertyName);
610
//		Class returnType = field.getType();
611
				int propertyNr = 0;
612
				for (Type subType: subTypes){
613
					String subPropertyName = componentType.getPropertyNames()[propertyNr];
614
					if (!isNoDoType(subType)){
615
						logger.warn("SubType not yet handled: " + subType);
616
					}
617
//					handlePropertyType(referencedCdmBase, result, referencedClass, 
618
//					sessionFactory, cdmClass, subType, subPropertyName, isCollection);
619
					propertyNr++;
620
				}
621
			}else{
622
				logger.warn("propertyType not yet handled: " + propertyType.getName());
623
			}
624
			//OLD: 
625
					//		if (! type.isInterface()){
626
			//		if (referencedClass.isAssignableFrom(type)|| 
627
			//				type.isAssignableFrom(referencedClass) && CdmBase.class.isAssignableFrom(type)){
628
			//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
629
			//		}
630
			//	//interface
631
			//	}else if (type.isAssignableFrom(referencedClass)){
632
			//			handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
633
		} catch (Exception e) {
634
			throw new MergeException(e);
635
		}
636
	}
637

    
638

    
639
		
640
		
641
	private void reallocateReferences(CdmBase cdmBase1, CdmBase cdmBase2, SessionFactory sessionFactory, Class clazz, Set<ICdmBase> cloneSet){
642
		try {
643
			Set<ReferenceHolder> holderSet = referenceMap.get(clazz);
644
			if (holderSet == null){
645
				holderSet = makeHolderSet(clazz);
646
				referenceMap.put(clazz, holderSet);
647
			}
648
			for (ReferenceHolder refHolder: holderSet){
649
				reallocateByHolder(cdmBase1, cdmBase2, refHolder, cloneSet);
650
			}
651
			return;	
652
		} catch (Exception e) {
653
			e.printStackTrace();
654
			throw new RuntimeException(e);
655
		}
656
	}
657
	
658
	/**
659
	 * @param cdmBase1
660
	 * @param cdmBase2
661
	 * @param refHolder
662
	 * @throws MergeException 
663
	 */
664
	private void reallocateByHolder(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws MergeException {
665
		try {
666
			if (refHolder.isCollection()){
667
				reallocateCollection(cdmBase1, cdmBase2, refHolder, cloneSet);
668
			}else{
669
				reallocateSingleItem(cdmBase1, cdmBase2, refHolder, cloneSet);
670
			}
671
		} catch (Exception e) {
672
			throw new MergeException("Error during reallocation of references to merge object: " + cdmBase2, e);
673
		}
674
		
675
	}
676

    
677
	/**
678
	 * @param cdmBase1
679
	 * @param cdmBase2
680
	 * @param refHolder
681
	 * @param cloneSet
682
	 * @throws MergeException 
683
	 * @throws NoSuchFieldException 
684
	 * @throws SecurityException 
685
	 * @throws IllegalAccessException 
686
	 * @throws IllegalArgumentException 
687
	 * @throws InvocationTargetException 
688
	 */
689
	private void reallocateCollection(CdmBase cdmBase1, CdmBase cdmBase2,
690
			ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws MergeException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
691
		List<CdmBase> list = getCdmBasesWithItemInCollection(refHolder.itemClass, refHolder.otherClass, refHolder.propertyName, cdmBase2);
692
		for (CdmBase referencingObject : list){
693
			Field referencingField = getFieldRecursive(refHolder.otherClass, refHolder.propertyName);
694
			referencingField.setAccessible(true);
695
			Object collection = referencingField.get(referencingObject);
696
			if (! (collection instanceof Collection)){
697
				throw new MergeException ("Reallocation of collections for collection other than set and list not yet implemented");
698
			}
699
			Method addMethod = DefaultMergeStrategy.getAddMethod(referencingField, false);
700
			Method removeMethod = DefaultMergeStrategy.getAddMethod(referencingField, true);
701
			addMethod.invoke(referencingObject, cdmBase1);
702
			removeMethod.invoke(referencingObject, cdmBase2);
703
		}
704
	}
705
	
706
	private Field getFieldRecursive(Class clazz, String propertyName) throws NoSuchFieldException{
707
		try {
708
			return clazz.getDeclaredField(propertyName);
709
		} catch (NoSuchFieldException e) {
710
			Class superClass = clazz.getSuperclass();
711
			if (CdmBase.class.isAssignableFrom(superClass)){
712
				return getFieldRecursive(superClass, propertyName);
713
			}else{
714
				throw e;
715
			}
716
		}
717
	}
718

    
719
	/**
720
	 * @throws NoSuchFieldException 
721
	 * @throws SecurityException 
722
	 * @throws IllegalAccessException 
723
	 * @throws IllegalArgumentException 
724
	 * 
725
	 */
726
	private void reallocateSingleItem_Old(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
727
		List<CdmBase> referencingObjects = getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2);
728
		for (CdmBase referencingObject : referencingObjects){
729
			Field referencingField = refHolder.otherClass.getDeclaredField(refHolder.propertyName);
730
			referencingField.setAccessible(true);
731
			Object test = referencingField.get(referencingObject);
732
			assert(test.equals(cdmBase2));
733
			referencingField.set(referencingObject, cdmBase1);
734
		}
735
	}
736

    
737
	private void reallocateSingleItem(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
738
		List<CdmBase> referencingObjects = getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2);
739
		Session session = getSession(); 
740
		for (CdmBase referencingObject : referencingObjects){
741
			if (!cloneSet.contains(referencingObject)){
742
		        String className = refHolder.otherClass.getSimpleName();
743
	            String propertyName = refHolder.propertyName;
744
		        String hql = "update " + className + " c set c."+propertyName+" = :newValue where c.id = :id";
745
		        Query query = session.createQuery(hql);
746
		        query.setEntity("newValue", cdmBase1);
747
		        query.setInteger("id",referencingObject.getId());
748
		        int rowCount = query.executeUpdate();
749
		        logger.debug("Rows affected: " + rowCount);
750
		        session.refresh(referencingObject);
751
	        }
752
	    }
753
		session.flush();
754
	}
755
	
756

    
757

    
758
	/**
759
	 * @param <T>
760
	 * @param cdmBase1
761
	 * @param cdmBase2
762
	 * @param session
763
	 */
764
	private <T> void handleAnnotationsEtc(T cdmBase1, T cdmBase2, Session session) {
765
		//when handling annotations and other elements linked via @Any an JDBC errors occurs
766
		//due to the unique column constraint in the association table on the column referencing
767
		//the annotation.
768
		//For some reason not delete command is executed for the old collection
769
		// Hibernate bug ??
770
		session.flush();  //for debugging
771
		if (cdmBase1 instanceof AnnotatableEntity){
772
			AnnotatableEntity annotatableEntity1 = (AnnotatableEntity)cdmBase1;
773
			AnnotatableEntity annotatableEntity2 = (AnnotatableEntity)cdmBase2;
774
			//annotations
775
			List<Annotation> removeListAnnotation = new ArrayList<Annotation>();
776
			for (Annotation annotation : annotatableEntity2.getAnnotations()){
777
				Annotation clone = null;
778
				try {
779
					clone = annotation.clone(annotatableEntity1);
780
				} catch (CloneNotSupportedException e) {
781
					e.printStackTrace();
782
				}
783
				annotatableEntity1.addAnnotation(clone);
784
				removeListAnnotation.add(annotation);
785
			}
786
			for (Annotation annotation : removeListAnnotation){
787
				annotatableEntity2.removeAnnotation(annotation);
788
				getSession().delete(annotation);
789
			}
790
			//marker
791
			List<Marker> removeListMarker = new ArrayList<Marker>();
792
			for (Marker marker : annotatableEntity2.getMarkers()){
793
				Marker clone = null;
794
				try {
795
					clone = marker.clone(annotatableEntity1);
796
				} catch (CloneNotSupportedException e) {
797
					e.printStackTrace();
798
				}
799
				annotatableEntity1.addMarker(clone);
800
				removeListMarker.add(marker);
801
			}
802
			for (Marker marker : removeListMarker){
803
				annotatableEntity2.removeMarker(marker);
804
				getSession().delete(marker);
805
			}
806
		}
807
		if (cdmBase1 instanceof IdentifiableEntity){
808
			IdentifiableEntity identifiableEntity1 = (IdentifiableEntity)cdmBase1;
809
			IdentifiableEntity identifiableEntity2 = (IdentifiableEntity)cdmBase2;
810
			//annotations
811
			List<Extension> removeListExtension = new ArrayList<Extension>();
812
			for (Extension changeObject : (Set<Extension>)identifiableEntity2.getExtensions()){
813
				try {
814
					Extension clone = changeObject.clone(identifiableEntity1);
815
					identifiableEntity1.addExtension(clone);
816
					removeListExtension.add(changeObject);
817
				} catch (CloneNotSupportedException e) {
818
					e.printStackTrace();
819
				}
820
				
821
			}
822
			for (Extension removeObject : removeListExtension){
823
				identifiableEntity2.removeExtension(removeObject);
824
				getSession().delete(removeObject);
825
			}
826
		}
827
		
828
		session.saveOrUpdate(cdmBase1);
829
		session.saveOrUpdate(cdmBase2);
830
		session.flush();
831
	}
832
	
833
	private <T extends CdmBase> void testMergeValid(T cdmBase1, T cdmBase2)throws IllegalArgumentException, NullPointerException{
834
		if (cdmBase1 == null || cdmBase2 == null){
835
			throw new NullPointerException("Merge arguments must not be (null)");
836
		}
837
		cdmBase1 = (T)HibernateProxyHelper.deproxy(cdmBase1);
838
		cdmBase2 = (T)HibernateProxyHelper.deproxy(cdmBase2);
839
		
840
		if (cdmBase1.getClass() != cdmBase2.getClass()){
841
			throw new IllegalArgumentException("Merge arguments must be of same type");
842
		}
843
	}
844
	
845
	/* (non-Javadoc)
846
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#test()
847
	 */
848
	public void test() {
849
		SessionFactoryImpl factory = (SessionFactoryImpl)getSession().getSessionFactory();
850
		Type propType = factory.getReferencedPropertyType(BotanicalName.class.getCanonicalName(), "titleCache");
851
		Map collMetadata = factory.getAllCollectionMetadata();
852
		Object roles = factory.getCollectionRolesByEntityParticipant("eu.etaxonomy.cdm.model.name.BotanicalName");
853
		CollectionPersister collPersister;
854
		try {
855
			collPersister = factory.getCollectionPersister(TaxonNameBase.class.getCanonicalName()+".annotations");
856
		} catch (MappingException e) {
857
			// TODO Auto-generated catch block
858
			e.printStackTrace();
859
		}
860
		Statistics statistics = factory.getStatistics();
861
		Map allClassMetadata = factory.getAllClassMetadata();
862
		logger.debug("");
863
		
864
	}
865

    
866
	public <T extends CdmBase> T find(Class<T> clazz, int id){
867
		Session session;
868
		session =  getSession();
869
		//session = getSession().getSessionFactory().getCurrentSession();
870
		return (T)session.get(clazz, id);
871
	}
872

    
873
	/* (non-Javadoc)
874
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#findMatching(eu.etaxonomy.cdm.strategy.match.IMatchable, eu.etaxonomy.cdm.strategy.match.IMatchStrategy)
875
	 */
876
	public <T extends IMatchable> List<T> findMatching(T objectToMatch,
877
			IMatchStrategy matchStrategy) throws MatchException {
878
		try {
879
			List<T> result = new ArrayList<T>();
880
			if(objectToMatch == null){
881
				return result;
882
			}
883
			if (matchStrategy == null){
884
				matchStrategy = DefaultMatchStrategy.NewInstance(objectToMatch.getClass());
885
			}
886
			result.addAll(findMatchingNullSafe(objectToMatch, matchStrategy));
887
			return result;
888
		} catch (IllegalArgumentException e) {
889
			throw new MatchException(e);
890
		} catch (IllegalAccessException e) {
891
			throw new MatchException(e);
892
		}
893
	}
894
	
895
	public <T extends IMatchable> List<T> findMatchingNullSafe(T objectToMatch,	IMatchStrategy matchStrategy) throws IllegalArgumentException, IllegalAccessException, MatchException {
896
		List<T> result = new ArrayList<T>();
897
		Session session = getSession();
898
		Class matchClass = objectToMatch.getClass();
899
		ClassMetadata classMetaData = session.getSessionFactory().getClassMetadata(matchClass.getCanonicalName());
900
		Criteria criteria = session.createCriteria(matchClass);
901
		boolean noMatch = makeCriteria(objectToMatch, matchStrategy, classMetaData, criteria);
902
		logger.debug(criteria);
903
		//session.flush();
904
		if (noMatch == false){
905
			List<T> matchCandidates = criteria.list();
906
			matchCandidates.remove(objectToMatch);
907
			for (T matchCandidate : matchCandidates ){
908
				if (matchStrategy.invoke(objectToMatch, matchCandidate)){
909
					result.add(matchCandidate);
910
				}else{
911
					logger.warn("Match candidate did not match: " + matchCandidate);
912
				}
913
			}
914
		}
915
		return result;
916
	}
917

    
918
	/**
919
	 * @param <T>
920
	 * @param objectToMatch
921
	 * @param matchStrategy
922
	 * @param classMetaData
923
	 * @param criteria
924
	 * @return
925
	 * @throws IllegalAccessException
926
	 * @throws MatchException
927
	 */
928
	private <T> boolean makeCriteria(T objectToMatch,
929
			IMatchStrategy matchStrategy, ClassMetadata classMetaData,
930
			Criteria criteria) throws IllegalAccessException, MatchException {
931
		Matching matching = matchStrategy.getMatching();
932
		boolean noMatch = false;
933
		Map<String, List<MatchMode>> replaceMatchers = new HashMap<String, List<MatchMode>>();
934
		for (CacheMatcher cacheMatcher: matching.getCacheMatchers()){
935
			boolean cacheProtected = (Boolean)cacheMatcher.getProtectedField(matching).get(objectToMatch);
936
			if (cacheProtected == true){
937
				String cacheValue = (String)cacheMatcher.getField().get(objectToMatch);
938
				if (CdmUtils.isEmpty(cacheValue)){
939
					return true;  //no match
940
				}else{
941
					criteria.add(Restrictions.eq(cacheMatcher.getPropertyName(), cacheValue));
942
					criteria.add(Restrictions.eq(cacheMatcher.getProtectedPropertyName(), cacheProtected));
943
					
944
					List<DoubleResult<String, MatchMode>> replacementModes = cacheMatcher.getReplaceMatchModes(matching);
945
					for (DoubleResult<String, MatchMode> replacementMode: replacementModes ){
946
						String propertyName = replacementMode.getFirstResult();
947
						List<MatchMode> replaceMatcherList = replaceMatchers.get(propertyName);
948
						if (replaceMatcherList == null){
949
							replaceMatcherList = new ArrayList<MatchMode>();
950
							replaceMatchers.put(propertyName, replaceMatcherList);
951
						}
952
						replaceMatcherList.add(replacementMode.getSecondResult());
953
					}
954

    
955
				}
956
			}
957
		}
958
		for (FieldMatcher fieldMatcher : matching.getFieldMatchers(false)){
959
			String propertyName = fieldMatcher.getPropertyName();
960
			Type propertyType = classMetaData.getPropertyType(propertyName);
961
			Object value = fieldMatcher.getField().get(objectToMatch);
962
			List<MatchMode> matchModes= new ArrayList<MatchMode>();
963
			matchModes.add(fieldMatcher.getMatchMode());
964
			if (replaceMatchers.get(propertyName) != null){
965
				matchModes.addAll(replaceMatchers.get(propertyName));
966
			}
967
			
968
			boolean isIgnore = false;
969
			for (MatchMode matchMode : matchModes){
970
				isIgnore |= matchMode.isIgnore(value);
971
			}
972
			if (! isIgnore ){
973
				if (propertyType.isComponentType()){
974
					matchComponentType(criteria, fieldMatcher, propertyName, value, matchModes);
975
				}else{
976
					noMatch = matchNonComponentType(criteria, fieldMatcher, propertyName, value, matchModes, propertyType);
977
				}
978
			}
979
			if (noMatch){
980
				return noMatch;
981
			}
982
		}
983
		return noMatch;
984
	}
985

    
986
	/**
987
	 * @param criteria
988
	 * @param fieldMatcher
989
	 * @param propertyName
990
	 * @param value
991
	 * @param matchMode
992
	 * @throws MatchException
993
	 * @throws IllegalAccessException
994
	 */
995
	private void matchComponentType(Criteria criteria,
996
			FieldMatcher fieldMatcher, String propertyName, Object value,
997
			List<MatchMode> matchModes) throws MatchException, IllegalAccessException {
998
		if (value == null){
999
			boolean requiresSecondNull = requiresSecondNull(matchModes, value);
1000
			if (requiresSecondNull){
1001
				criteria.add(Restrictions.isNull(propertyName));
1002
			}else{
1003
				//TODO 
1004
				logger.warn("Component type not yet implemented for (null) value: " + propertyName);
1005
				throw new MatchException("Component type not yet fully implemented for (null) value. Property: " + propertyName);
1006
			}
1007
		}else{
1008
			Class<?> componentClass = fieldMatcher.getField().getType();
1009
			Map<String, Field> fields = CdmUtils.getAllFields(componentClass, Object.class, false, false, true, false);
1010
			for (String fieldName : fields.keySet()){
1011
				String restrictionPath = propertyName +"."+fieldName;
1012
				Object componentValue = fields.get(fieldName).get(value);
1013
				//TODO diffentiate matchMode
1014
				createCriterion(criteria, restrictionPath, componentValue, matchModes);
1015
			}
1016
		}
1017
	}
1018

    
1019
	private boolean matchNonComponentType(Criteria criteria,
1020
			FieldMatcher fieldMatcher, String propertyName, Object value,
1021
			List<MatchMode> matchModes, Type propertyType) throws HibernateException, DataAccessException, MatchException, IllegalAccessException{
1022
		boolean noMatch = false;
1023
		if (isRequired(matchModes) && value == null){
1024
			noMatch = true;
1025
			return noMatch;
1026
		}else if (requiresSecondNull(matchModes,value)){
1027
			criteria.add(Restrictions.isNull(propertyName));
1028
		}else{
1029
			if (isMatch(matchModes)){
1030
				if (propertyType.isCollectionType()){
1031
					//TODO collection not yet handled for match	
1032
				}else{
1033
					int joinType = CriteriaSpecification.INNER_JOIN;
1034
					if (! requiresSecondValue(matchModes,value)){
1035
						joinType = CriteriaSpecification.LEFT_JOIN;
1036
					}
1037
					Criteria matchCriteria = criteria.createCriteria(propertyName, joinType).add(Restrictions.isNotNull("id"));
1038
					Class matchClass = value.getClass();
1039
					if (IMatchable.class.isAssignableFrom(matchClass)){
1040
						IMatchStrategy valueMatchStrategy = DefaultMatchStrategy.NewInstance((Class<IMatchable>)matchClass);
1041
						ClassMetadata valueClassMetaData = getSession().getSessionFactory().getClassMetadata(matchClass.getCanonicalName());;
1042
						noMatch = makeCriteria(value, valueMatchStrategy, valueClassMetaData, matchCriteria); 
1043
					}else{
1044
						logger.error("Class to match (" + matchClass + ") is not of type IMatchable");
1045
						throw new MatchException("Class to match (" + matchClass + ") is not of type IMatchable");
1046
					}
1047
				}
1048
			}else if (isEqual(matchModes)){
1049
				createCriterion(criteria, propertyName, value, matchModes);
1050
			}else {
1051
				logger.warn("Unhandled match mode: " + matchModes + ", value: " + (value==null?"null":value));
1052
			}
1053
		}
1054
		return noMatch;
1055
	}
1056
	
1057
	/**
1058
	 * @param criteria
1059
	 * @param propertyName
1060
	 * @param value
1061
	 * @param matchMode
1062
	 * @throws MatchException
1063
	 */
1064
	private void createCriterion(Criteria criteria, String propertyName,
1065
			Object value, List<MatchMode> matchModes) throws MatchException {
1066
		Criterion finalRestriction = null;
1067
		Criterion equalRestriction = Restrictions.eq(propertyName, value);
1068
		Criterion nullRestriction = Restrictions.isNull(propertyName);
1069
		if (this.requiresSecondValue(matchModes, value)){
1070
			finalRestriction = equalRestriction;
1071
		}else if (requiresSecondNull(matchModes, value) ){
1072
			finalRestriction = nullRestriction;
1073
		}else{
1074
			finalRestriction = Restrictions.or(equalRestriction, nullRestriction);
1075
		}
1076
		//return finalRestriction;
1077
		criteria.add(finalRestriction);
1078
	}
1079
	
1080
	/**
1081
	 * @param matchModes
1082
	 * @param value
1083
	 * @return
1084
	 * @throws MatchException 
1085
	 */
1086
	private boolean requiresSecondNull(List<MatchMode> matchModes, Object value) throws MatchException {
1087
		boolean result = true;
1088
		for (MatchMode matchMode: matchModes){
1089
			result &= matchMode.requiresSecondNull(value);
1090
		}
1091
		return result;
1092
	}
1093
	
1094
	/**
1095
	 * @param matchModes
1096
	 * @param value
1097
	 * @return
1098
	 * @throws MatchException 
1099
	 */
1100
	private boolean requiresSecondValue(List<MatchMode> matchModes, Object value) throws MatchException {
1101
		boolean result = true;
1102
		for (MatchMode matchMode: matchModes){
1103
			result &= matchMode.requiresSecondValue(value);
1104
		}
1105
		return result;
1106
	}
1107
	
1108
	/**
1109
	 * @param matchModes
1110
	 * @param value
1111
	 * @return
1112
	 * @throws MatchException 
1113
	 */
1114
	private boolean isRequired(List<MatchMode> matchModes) throws MatchException {
1115
		boolean result = true;
1116
		for (MatchMode matchMode: matchModes){
1117
			result &= matchMode.isRequired();
1118
		}
1119
		return result;
1120
	}
1121
	
1122
	/**
1123
	 * Returns true if at least one match mode is of typ MATCH_XXX
1124
	 * @param matchModes
1125
	 * @param value
1126
	 * @return
1127
	 * @throws MatchException 
1128
	 */
1129
	private boolean isMatch(List<MatchMode> matchModes) throws MatchException {
1130
		boolean result = false;
1131
		for (MatchMode matchMode: matchModes){
1132
			result |= matchMode.isMatch();
1133
		}
1134
		return result;
1135
	}
1136

    
1137
	/**
1138
	 * Returns true if at least one match mode is of typ EQUAL_XXX
1139
	 * @param matchModes
1140
	 * @param value
1141
	 * @return
1142
	 * @throws MatchException 
1143
	 */
1144
	private boolean isEqual(List<MatchMode> matchModes) throws MatchException {
1145
		boolean result = false;
1146
		for (MatchMode matchMode: matchModes){
1147
			result |= matchMode.isEqual();
1148
		}
1149
		return result;
1150
	}
1151

    
1152
	/* (non-Javadoc)
1153
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#saveMetaData(eu.etaxonomy.cdm.model.common.CdmMetaData)
1154
	 */
1155
	public void saveMetaData(CdmMetaData cdmMetaData) {
1156
		getSession().saveOrUpdate(cdmMetaData);
1157
	}
1158

    
1159
	/* (non-Javadoc)
1160
	 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#getMetaData()
1161
	 */
1162
	public List<CdmMetaData> getMetaData() {
1163
		Session session = getSession();
1164
		Criteria crit = session.createCriteria(CdmMetaData.class);
1165
		List<CdmMetaData> results = crit.list();
1166
		return results;
1167
	}
1168
}
1169

    
1170

    
(4-4/20)