e7228924a873fe98fe8bbc1c5d7717c5ea4f0db1
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / common / CdmGenericDaoImpl.java
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.Reference;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.commons.lang.UnhandledException;
28 import org.apache.log4j.Logger;
29 import org.hibernate.Criteria;
30 import org.hibernate.HibernateException;
31 import org.hibernate.MappingException;
32 import org.hibernate.Query;
33 import org.hibernate.Session;
34 import org.hibernate.SessionFactory;
35 import org.hibernate.collection.internal.AbstractPersistentCollection;
36 import org.hibernate.collection.spi.PersistentCollection;
37 import org.hibernate.criterion.CriteriaSpecification;
38 import org.hibernate.criterion.Criterion;
39 import org.hibernate.criterion.Restrictions;
40 import org.hibernate.engine.spi.CollectionEntry;
41 import org.hibernate.engine.spi.SessionFactoryImplementor;
42 import org.hibernate.engine.spi.SessionImplementor;
43 import org.hibernate.internal.SessionFactoryImpl;
44 import org.hibernate.internal.SessionImpl;
45 import org.hibernate.metadata.ClassMetadata;
46 import org.hibernate.metadata.CollectionMetadata;
47 import org.hibernate.persister.collection.CollectionPersister;
48 import org.hibernate.persister.collection.OneToManyPersister;
49 import org.hibernate.persister.entity.AbstractEntityPersister;
50 import org.hibernate.stat.Statistics;
51 import org.hibernate.type.AnyType;
52 import org.hibernate.type.BooleanType;
53 import org.hibernate.type.CollectionType;
54 import org.hibernate.type.ComponentType;
55 import org.hibernate.type.DoubleType;
56 import org.hibernate.type.EntityType;
57 import org.hibernate.type.EnumType;
58 import org.hibernate.type.FloatType;
59 import org.hibernate.type.IntegerType;
60 import org.hibernate.type.LongType;
61 import org.hibernate.type.MaterializedClobType;
62 import org.hibernate.type.SerializableType;
63 import org.hibernate.type.SetType;
64 import org.hibernate.type.StringType;
65 import org.hibernate.type.Type;
66 import org.jadira.usertype.dateandtime.joda.PersistentDateTime;
67 import org.springframework.dao.DataAccessException;
68 import org.springframework.stereotype.Repository;
69
70 import eu.etaxonomy.cdm.common.CdmUtils;
71 import eu.etaxonomy.cdm.common.DoubleResult;
72 import eu.etaxonomy.cdm.hibernate.DOIUserType;
73 import eu.etaxonomy.cdm.hibernate.EnumUserType;
74 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
75 import eu.etaxonomy.cdm.hibernate.PartialUserType;
76 import eu.etaxonomy.cdm.hibernate.URIUserType;
77 import eu.etaxonomy.cdm.hibernate.UUIDUserType;
78 import eu.etaxonomy.cdm.hibernate.WSDLDefinitionUserType;
79 import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
80 import eu.etaxonomy.cdm.model.common.Annotation;
81 import eu.etaxonomy.cdm.model.common.CdmBase;
82 import eu.etaxonomy.cdm.model.common.Extension;
83 import eu.etaxonomy.cdm.model.common.ICdmBase;
84 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
85 import eu.etaxonomy.cdm.model.common.Marker;
86 import eu.etaxonomy.cdm.model.metadata.CdmMetaData;
87 import eu.etaxonomy.cdm.model.name.BotanicalName;
88 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
89 import eu.etaxonomy.cdm.model.taxon.Taxon;
90 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
91 import eu.etaxonomy.cdm.strategy.match.CacheMatcher;
92 import eu.etaxonomy.cdm.strategy.match.DefaultMatchStrategy;
93 import eu.etaxonomy.cdm.strategy.match.FieldMatcher;
94 import eu.etaxonomy.cdm.strategy.match.IMatchStrategy;
95 import eu.etaxonomy.cdm.strategy.match.IMatchable;
96 import eu.etaxonomy.cdm.strategy.match.MatchException;
97 import eu.etaxonomy.cdm.strategy.match.MatchMode;
98 import eu.etaxonomy.cdm.strategy.match.Matching;
99 import eu.etaxonomy.cdm.strategy.merge.DefaultMergeStrategy;
100 import eu.etaxonomy.cdm.strategy.merge.IMergable;
101 import eu.etaxonomy.cdm.strategy.merge.IMergeStrategy;
102 import eu.etaxonomy.cdm.strategy.merge.MergeException;
103
104 @Repository
105 public class CdmGenericDaoImpl extends CdmEntityDaoBase<CdmBase> implements ICdmGenericDao{
106 private static final Logger logger = Logger.getLogger(CdmGenericDaoImpl.class);
107
108
109 private Set<Class<? extends CdmBase>> allCdmClasses = null;
110 private Map<Class<? extends CdmBase>, Set<ReferenceHolder>> referenceMap = new HashMap<Class<? extends CdmBase>, Set<ReferenceHolder>>();
111
112 private class ReferenceHolder{
113 String propertyName;
114 Class<? extends CdmBase> otherClass;
115 Class<? extends CdmBase> itemClass;
116 public boolean isCollection(){return itemClass != null;};
117 public String toString(){return otherClass.getSimpleName() + "." + propertyName ;};
118 }
119
120
121 public CdmGenericDaoImpl() {
122 super(CdmBase.class);
123 }
124
125 @Override
126 public List<CdmBase> getCdmBasesByFieldAndClass(Class clazz, String propertyName, CdmBase referencedCdmBase){
127 Session session = super.getSession();
128
129 Criteria criteria = session.createCriteria(clazz);
130 criteria.add(Restrictions.eq(propertyName, referencedCdmBase));
131 return criteria.list();
132 }
133
134 @Override
135 public List<CdmBase> getCdmBasesWithItemInCollection(Class itemClass, Class clazz, String propertyName, CdmBase item){
136 Session session = super.getSession();
137 String thisClassStr = itemClass.getSimpleName();
138 String otherClassStr = clazz.getSimpleName();
139 String queryStr = " SELECT other FROM "+ thisClassStr + " this, " + otherClassStr + " other " +
140 " WHERE this = :referencedObject AND this member of other."+propertyName ;
141 Query query = session.createQuery(queryStr).setEntity("referencedObject", item);
142 List<CdmBase> result = query.list();
143 return result;
144 }
145
146 @Override
147 public Set<Class<? extends CdmBase>> getAllCdmClasses(boolean includeAbstractClasses){
148 Set<Class<? extends CdmBase>> result = new HashSet<Class<? extends CdmBase>>();
149
150 SessionFactory sessionFactory = getSession().getSessionFactory();
151 Map<?,?> allClassMetadata = sessionFactory.getAllClassMetadata();
152 Collection<?> keys = allClassMetadata.keySet();
153 for (Object oKey : keys){
154 if (oKey instanceof String){
155 String strKey = (String)oKey;
156 if (! strKey.endsWith("_AUD")){
157 try {
158 Class clazz = Class.forName(strKey);
159 boolean isAbstractClass = Modifier.isAbstract(clazz.getModifiers());
160 if (! isAbstractClass || includeAbstractClasses){
161 result.add(clazz);
162 }
163 } catch (ClassNotFoundException e) {
164 logger.warn("Class not found: " + strKey);
165 }
166 }
167 }else{
168 logger.warn("key is not of type String: " + oKey);
169 }
170 }
171 return result;
172 }
173
174 @Override
175 public Set<CdmBase> getReferencingObjects(CdmBase referencedCdmBase){
176 Set<CdmBase> result = new HashSet<CdmBase>();
177 try {
178 referencedCdmBase = (CdmBase)HibernateProxyHelper.deproxy(referencedCdmBase);
179 Class<? extends CdmBase> referencedClass = referencedCdmBase.getClass();
180
181 Set<ReferenceHolder> holderSet = referenceMap.get(referencedClass);
182 if (holderSet == null){
183 holderSet = makeHolderSet(referencedClass);
184 referenceMap.put(referencedClass, holderSet);
185 }
186 for (ReferenceHolder refHolder: holderSet){
187 handleReferenceHolder(referencedCdmBase, result, refHolder);
188 }
189 return result;
190 } catch (Exception e) {
191 e.printStackTrace();
192 throw new RuntimeException(e);
193 }
194
195 }
196 @Override
197 public Set<CdmBase> getReferencingObjectsForDeletion(CdmBase referencedCdmBase){
198 Set<CdmBase> result = getReferencingObjects(referencedCdmBase);
199 Set<ReferenceHolder> holderSet = referenceMap.get(IdentifiableEntity.class);
200 try {
201 if (holderSet == null){
202 holderSet = makeHolderSet(IdentifiableEntity.class);
203 referenceMap.put(IdentifiableEntity.class, holderSet);
204 }
205 Set<CdmBase> resultIdentifiableEntity = new HashSet<CdmBase>();
206 for (ReferenceHolder refHolder: holderSet){
207 handleReferenceHolder(referencedCdmBase, resultIdentifiableEntity, refHolder);
208 }
209 result.removeAll(resultIdentifiableEntity);
210
211 return result;
212 } catch (Exception e) {
213 e.printStackTrace();
214 throw new RuntimeException(e);
215 }
216
217 }
218
219 /**
220 * @param referencedCdmBase
221 * @param result
222 * @param refHolder
223 */
224 private void handleReferenceHolder(CdmBase referencedCdmBase,
225 Set<CdmBase> result, ReferenceHolder refHolder) {
226 boolean isCollection = refHolder.isCollection();
227 if (isCollection){
228 result.addAll(getCdmBasesWithItemInCollection(refHolder.itemClass, refHolder.otherClass, refHolder.propertyName, referencedCdmBase));
229 }else{
230 result.addAll(getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, referencedCdmBase));
231 }
232 }
233
234
235 /**
236 * @param referencedClass
237 * @return
238 * @throws NoSuchFieldException
239 * @throws ClassNotFoundException
240 */
241 private Set<ReferenceHolder> makeHolderSet(Class<?> referencedClass) throws ClassNotFoundException, NoSuchFieldException {
242 Set<ReferenceHolder> result = new HashSet<ReferenceHolder>();
243
244 //init
245 if (allCdmClasses == null){
246 allCdmClasses = getAllCdmClasses(false); //findAllCdmClasses();
247 }
248 //referencedCdmBase = (CdmBase)HibernateProxyHelper.deproxy(referencedCdmBase);
249 SessionFactory sessionFactory = getSession().getSessionFactory();
250
251
252 for (Class<? extends CdmBase> cdmClass : allCdmClasses){
253 ClassMetadata classMetadata = sessionFactory.getClassMetadata(cdmClass);
254 Type[] propertyTypes = classMetadata.getPropertyTypes();
255 int propertyNr = 0;
256 for (Type propertyType: propertyTypes){
257 String propertyName = classMetadata.getPropertyNames()[propertyNr];
258 makePropertyType(result, referencedClass, sessionFactory, cdmClass, propertyType, propertyName, false);
259 propertyNr++;
260 }
261
262 }
263 return result;
264 }
265
266 /**
267 * @param referencedCdmBase
268 * @param result
269 * @param referencedClass
270 * @param sessionFactory
271 * @param cdmClass
272 * @param propertyType
273 * @param propertyName
274 * @throws ClassNotFoundException
275 * @throws NoSuchFieldException
276 */
277 private void makePropertyType(
278 // CdmBase referencedCdmBase,
279 Set<ReferenceHolder> result,
280 Class<?> referencedClass,
281 SessionFactory sessionFactory, Class<? extends CdmBase> cdmClass,
282 Type propertyType, String propertyName, boolean isCollection)
283 throws ClassNotFoundException, NoSuchFieldException {
284
285
286 if (propertyType.isEntityType()){
287 EntityType entityType = (EntityType)propertyType;
288 String associatedEntityName = entityType.getAssociatedEntityName();
289 Class<?> entityClass = Class.forName(associatedEntityName);
290 if (entityClass.isInterface()){
291 logger.debug("There is an interface");
292 }
293 if (entityClass.isAssignableFrom(referencedClass)){
294 makeSingleProperty(referencedClass, entityClass, propertyName, cdmClass, result, isCollection);
295 }
296 }else if (propertyType.isCollectionType()){
297 CollectionType collectionType = (CollectionType)propertyType;
298 //String role = collectionType.getRole();
299 Type elType = collectionType.getElementType((SessionFactoryImplementor)sessionFactory);
300 makePropertyType(result, referencedClass, sessionFactory, cdmClass, elType, propertyName, true);
301 }else if (propertyType.isAnyType()){
302 // AnyType anyType = (AnyType)propertyType;
303 Field field = cdmClass.getDeclaredField(propertyName);
304 Class<?> returnType = field.getType();
305 if (returnType.isInterface()){
306 logger.debug("There is an interface");
307 }
308 if (returnType.isAssignableFrom(referencedClass)){
309 makeSingleProperty(referencedClass, returnType, propertyName, cdmClass, result, isCollection);
310 }
311 }else if (propertyType.isComponentType()){
312 ComponentType componentType = (ComponentType)propertyType;
313 Type[] subTypes = componentType.getSubtypes();
314 // Field field = cdmClass.getDeclaredField(propertyName);
315 // Class returnType = field.getType();
316 int propertyNr = 0;
317 for (Type subType: subTypes){
318 String subPropertyName = componentType.getPropertyNames()[propertyNr];
319 if (!isNoDoType(subType)){
320 logger.warn("SubType not yet handled: " + subType);
321 }
322 // handlePropertyType(referencedCdmBase, result, referencedClass,
323 // sessionFactory, cdmClass, subType, subPropertyName, isCollection);
324 propertyNr++;
325 }
326 }else if (isNoDoType(propertyType)){
327 //do nothing
328 }else{
329 logger.warn("propertyType not yet handled: " + propertyType.getName());
330 }
331 //OLD:
332 // if (! type.isInterface()){
333 // if (referencedClass.isAssignableFrom(type)||
334 // type.isAssignableFrom(referencedClass) && CdmBase.class.isAssignableFrom(type)){
335 // handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
336 // }
337 // //interface
338 // }else if (type.isAssignableFrom(referencedClass)){
339 // handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
340
341 }
342
343 private boolean makeSingleProperty(Class itemClass, Class<?> type, String propertyName, Class cdmClass, Set<ReferenceHolder> result,/*CdmBase item,*/ boolean isCollection){
344 String fieldName = StringUtils.rightPad(propertyName, 30);
345 String className = StringUtils.rightPad(cdmClass.getSimpleName(), 30);
346 String returnTypeName = StringUtils.rightPad(type.getSimpleName(), 30);
347
348 // logger.debug(fieldName + "\t\t" + className + "\t\t" + returnTypeName);
349 ReferenceHolder refHolder = new ReferenceHolder();
350 refHolder.propertyName = propertyName;
351 refHolder.otherClass = cdmClass;
352 refHolder.itemClass = (isCollection ? itemClass : null) ;
353 result.add(refHolder);
354 return true;
355 }
356
357 /**
358 * @param propertyType
359 * @return
360 */
361 private boolean isNoDoType(Type propertyType) {
362 boolean result = false;
363 Class<?>[] classes = new Class[]{
364 PersistentDateTime.class,
365 WSDLDefinitionUserType.class,
366 UUIDUserType.class,
367 PartialUserType.class,
368 StringType.class,
369 BooleanType.class,
370 IntegerType.class,
371 MaterializedClobType.class,
372 LongType.class,
373 FloatType.class,
374 SerializableType.class,
375 DoubleType.class,
376 URIUserType.class,
377 EnumType.class,
378 EnumUserType.class,
379 DOIUserType.class
380 };
381 Set<String> classNames = new HashSet<String>();
382 for (Class<?> clazz: classes){
383 classNames.add(clazz.getCanonicalName());
384 if (clazz == propertyType.getClass()){
385 return true;
386 }
387 }
388 String propertyTypeClassName = propertyType.getName();
389 if (classNames.contains(propertyTypeClassName)){
390 return true;
391 }
392 return result;
393 }
394
395 @Override
396 public List<CdmBase> getHqlResult(String hqlQuery){
397 Query query = getSession().createQuery(hqlQuery);
398 List<CdmBase> result = query.list();
399 return result;
400 }
401
402 @Override
403 public Query getHqlQuery(String hqlQuery){
404 Query query = getSession().createQuery(hqlQuery);
405 return query;
406 }
407
408 @Override
409 public <T extends CdmBase> void merge(T cdmBase1, T cdmBase2, IMergeStrategy mergeStrategy) throws MergeException {
410 Class<T> clazz = (Class<T>)cdmBase1.getClass();
411 SessionImpl session = (SessionImpl) getSession();
412 SessionFactory sessionFactory = session.getSessionFactory();
413 if (mergeStrategy == null){
414 mergeStrategy = DefaultMergeStrategy.NewInstance(cdmBase1.getClass());
415 }
416 try {
417 //test null and types
418 testMergeValid(cdmBase1, cdmBase2);
419
420 //merge objects
421 //externel impl
422 //internal impl
423 session.flush();
424 Set<ICdmBase> deleteSet = new HashSet<ICdmBase>();
425 Set<ICdmBase> cloneSet = new HashSet<ICdmBase>();
426 if (cdmBase1 instanceof IMergable){
427 IMergable mergable1 = (IMergable)cdmBase1;
428 IMergable mergable2 = (IMergable)cdmBase2;
429 deleteSet = mergeStrategy.invoke(mergable1, mergable2, cloneSet);
430 //session.saveOrUpdate(mergable1);
431
432 session.flush();
433 //((IMergable)cdmBase1).mergeInto(cdmBase2, DefaultMergeStrategy.NewInstance(cdmBase1.getClass()));
434 }else{
435 mergeExternal(cdmBase1, cdmBase2, clazz, session);
436 }
437
438
439 if (cdmBase2.getId() > 0){
440 session.saveOrUpdate(cdmBase2);
441 //rearrange references to cdmBase2
442 reallocateReferences(cdmBase1, cdmBase2, sessionFactory, clazz, cloneSet);
443 }
444
445 //remove deleted objects
446
447 //session.delete(null, mergable2, true, null);
448 session.delete(cdmBase2);
449 for (ICdmBase toBeDeleted : deleteSet){
450 logger.debug("Delete " + toBeDeleted);
451 if (toBeDeleted != cdmBase2){
452 session.delete(toBeDeleted);
453 }
454
455 }
456
457 //flush
458 session.flush();
459
460 } catch (Exception e) {
461 throw new MergeException(e);
462 }
463 }
464
465
466 /**
467 * @param <T>
468 * @param cdmBase1
469 * @param cdmBase2
470 * @param clazz
471 * @param sessionFactory
472 * @throws MergeException
473 * @throws ClassNotFoundException
474 * @throws NoSuchFieldException
475 */
476 private <T extends CdmBase> void mergeExternal(T cdmBase1, T cdmBase2, Class<T> clazz,
477 Session session) throws MergeException {
478 // handleAnnotations
479 logger.warn("Merge external");
480 handleAnnotationsEtc(cdmBase1, cdmBase2, session);
481
482 SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory();
483
484 Map<String, ClassMetadata> allClassMetadata = sessionFactory.getAllClassMetadata();
485
486 //TODO cast
487 getCollectionRoles(clazz, sessionFactory);
488
489 TaxonNameBase name1 = BotanicalName.NewInstance(null);
490 name1.getTaxonBases();
491
492 Type propType = sessionFactory.getReferencedPropertyType(BotanicalName.class.getCanonicalName(), "taxonBases");
493 Map collMetadata = sessionFactory.getAllCollectionMetadata();
494 //roles = sessionFactory.getCollectionRolesByEntityParticipant("eu.etaxonomy.cdm.model.name.BotanicalName");
495 CollectionPersister collPersister;
496 try {
497 collPersister = sessionFactory.getCollectionPersister(TaxonNameBase.class.getCanonicalName()+".annotations");
498 } catch (MappingException e) {
499 // TODO Auto-generated catch block
500 e.printStackTrace();
501 }
502 // Statistics statistics = sessionFactory.getStatistics();
503 logger.debug("");
504 ClassMetadata taxonMetaData = sessionFactory.getClassMetadata(Taxon.class);
505 String ename = taxonMetaData.getEntityName();
506 try {
507 Reference ref = sessionFactory.getReference();
508 logger.debug("");
509 } catch (Exception e) {
510 // TODO Auto-generated catch block
511 e.printStackTrace();
512 }
513
514 //sessionFactory.get
515 ClassMetadata classMetadata = getSession().getSessionFactory().getClassMetadata(clazz);
516 Type[] propertyTypes = classMetadata.getPropertyTypes();
517 int propertyNr = 0;
518 for (Type propertyType: propertyTypes){
519 String propertyName = classMetadata.getPropertyNames()[propertyNr];
520 logger.debug(propertyName);
521 makeMergeProperty(cdmBase1, cdmBase2, propertyType, propertyName, sessionFactory, false);
522 propertyNr++;
523 }
524 Set<String> collectionRoles;
525 if (classMetadata instanceof AbstractEntityPersister){
526 AbstractEntityPersister persister = (AbstractEntityPersister)classMetadata;
527 String rootName = persister.getRootEntityName();
528 collectionRoles = sessionFactory.getCollectionRolesByEntityParticipant(rootName);
529 for (String collectionRole : collectionRoles){
530 CollectionMetadata collMetadata2 = sessionFactory.getCollectionMetadata(collectionRole);
531 String role = collMetadata2.getRole();
532 Type elType = collMetadata2.getElementType();
533 logger.debug(role);
534 }
535 }
536 }
537
538 /**
539 * @param <T>
540 * @param clazz
541 * @param sessionFactory
542 */
543 private <T> Set<String> getCollectionRoles(Class<T> clazz,
544 SessionFactoryImpl sessionFactory) {
545 Set<String> collectionRoles = null;
546 ClassMetadata classMetaData = sessionFactory.getClassMetadata(clazz);
547 if (classMetaData instanceof AbstractEntityPersister){
548 AbstractEntityPersister persister = (AbstractEntityPersister)classMetaData;
549 String rootName = persister.getRootEntityName();
550 collectionRoles = sessionFactory.getCollectionRolesByEntityParticipant(rootName);
551 for (String collectionRole : collectionRoles){
552 CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
553 CollectionPersister collPersister = sessionFactory.getCollectionPersister(collectionRole);
554 logger.debug("");
555 }
556 }else{
557 logger.warn("Class metadata is not of type AbstractEntityPersister");
558 throw new UnhandledException("Class metadata is not of type AbstractEntityPersister", null);
559 }
560 return collectionRoles;
561 }
562
563
564 private <T extends CdmBase> void makeMergeProperty(T cdmBase1, T cdmBase2, Type propertyType, String propertyName, SessionFactoryImpl sessionFactory, boolean isCollection) throws MergeException
565 {
566
567 try {
568 Class<T> clazz = (Class<T>)cdmBase1.getClass();
569 if (isNoDoType(propertyType)){
570 //do nothing
571 }else if (propertyType.isEntityType()){
572 //Field field = clazz.getField(propertyName);
573 EntityType entityType = (EntityType)propertyType;
574 String associatedEntityName = entityType.getAssociatedEntityName();
575 Class entityClass = Class.forName(associatedEntityName);
576 // Type refPropType = sessionFactory.getReferencedPropertyType(entityClass.getCanonicalName(), propertyName);
577 Set<String> collectionRoles = getCollectionRoles(clazz, sessionFactory);
578 for (String collectionRole : collectionRoles){
579 CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(collectionRole);
580 String role = collMetadata.getRole();
581 logger.debug(role);
582
583 }
584
585 // if (entityClass.isInterface()){
586 // logger.debug("So ein interface");
587 // }
588 // if (entityClass.isAssignableFrom(clazz)){
589 // makeSingleProperty(referencedClass, entityClass, propertyName, cdmClass, result, isCollection);
590 // }
591 }else if (propertyType.isCollectionType()){
592 CollectionType collectionType = (CollectionType)propertyType;
593 String role = collectionType.getRole();
594 Type elType = collectionType.getElementType((SessionFactoryImplementor)sessionFactory);
595 String n = collectionType.getAssociatedEntityName(sessionFactory);
596 CollectionMetadata collMetadata = sessionFactory.getCollectionMetadata(role);
597 if (collMetadata instanceof OneToManyPersister){
598 OneToManyPersister oneManyPersister = (OneToManyPersister)collMetadata;
599 String className = oneManyPersister.getOwnerEntityName();
600 Class<?> myClass = Class.forName(className);
601 Field field = myClass.getDeclaredField(propertyName);
602 field.setAccessible(true);
603 try {
604 if (collectionType instanceof SetType){
605 Set set2 = (Set)field.get(cdmBase2);
606 Set<Object> set1 = (Set<Object>)field.get(cdmBase1);
607 for (Object obj2: set2){
608 set1.add(obj2);
609 }
610 }
611 } catch (IllegalArgumentException e) {
612 // TODO Auto-generated catch block
613 e.printStackTrace();
614 } catch (IllegalAccessException e) {
615 // TODO Auto-generated catch block
616 e.printStackTrace();
617 }
618
619 }
620 logger.debug("");
621
622 // makePropertyType(result, referencedClass, sessionFactory, cdmClass, elType, propertyName, true);
623 }else if (propertyType.isAnyType()){
624 AnyType anyType = (AnyType)propertyType;
625 Field field = clazz.getDeclaredField(propertyName);
626 Class returnType = field.getType();
627 // if (returnType.isInterface()){
628 // logger.debug("So ein interface");
629 // }
630 // if (returnType.isAssignableFrom(referencedClass)){
631 // makeSingleProperty(referencedClass, returnType, propertyName, cdmClass, result, isCollection);
632 // }
633 }else if (propertyType.isComponentType()){
634 ComponentType componentType = (ComponentType)propertyType;
635 Type[] subTypes = componentType.getSubtypes();
636 // Field field = cdmClass.getDeclaredField(propertyName);
637 // Class returnType = field.getType();
638 int propertyNr = 0;
639 for (Type subType: subTypes){
640 String subPropertyName = componentType.getPropertyNames()[propertyNr];
641 if (!isNoDoType(subType)){
642 logger.warn("SubType not yet handled: " + subType);
643 }
644 // handlePropertyType(referencedCdmBase, result, referencedClass,
645 // sessionFactory, cdmClass, subType, subPropertyName, isCollection);
646 propertyNr++;
647 }
648 }else{
649 logger.warn("propertyType not yet handled: " + propertyType.getName());
650 }
651 //OLD:
652 // if (! type.isInterface()){
653 // if (referencedClass.isAssignableFrom(type)||
654 // type.isAssignableFrom(referencedClass) && CdmBase.class.isAssignableFrom(type)){
655 // handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
656 // }
657 // //interface
658 // }else if (type.isAssignableFrom(referencedClass)){
659 // handleSingleClass(referencedClass, type, field, cdmClass, result, referencedCdmBase, false);
660 } catch (Exception e) {
661 throw new MergeException(e);
662 }
663 }
664
665
666
667
668 private void reallocateReferences(CdmBase cdmBase1, CdmBase cdmBase2, SessionFactory sessionFactory, Class clazz, Set<ICdmBase> cloneSet){
669 try {
670 Set<ReferenceHolder> holderSet = referenceMap.get(clazz);
671 if (holderSet == null){
672 holderSet = makeHolderSet(clazz);
673 referenceMap.put(clazz, holderSet);
674 }
675 for (ReferenceHolder refHolder: holderSet){
676 reallocateByHolder(cdmBase1, cdmBase2, refHolder, cloneSet);
677 }
678 return;
679 } catch (Exception e) {
680 e.printStackTrace();
681 throw new RuntimeException(e);
682 }
683 }
684
685 /**
686 * @param cdmBase1
687 * @param cdmBase2
688 * @param refHolder
689 * @throws MergeException
690 */
691 private void reallocateByHolder(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws MergeException {
692 try {
693 if (refHolder.isCollection()){
694 reallocateCollection(cdmBase1, cdmBase2, refHolder, cloneSet);
695 }else{
696 reallocateSingleItem(cdmBase1, cdmBase2, refHolder, cloneSet);
697 }
698 } catch (Exception e) {
699 throw new MergeException("Error during reallocation of references to merge object: " + cdmBase2, e);
700 }
701
702 }
703
704 /**
705 * @param cdmBase1
706 * @param cdmBase2
707 * @param refHolder
708 * @param cloneSet
709 * @throws MergeException
710 * @throws NoSuchFieldException
711 * @throws SecurityException
712 * @throws IllegalAccessException
713 * @throws IllegalArgumentException
714 * @throws InvocationTargetException
715 */
716 private void reallocateCollection(CdmBase cdmBase1, CdmBase cdmBase2,
717 ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws MergeException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
718 List<CdmBase> list = getCdmBasesWithItemInCollection(refHolder.itemClass, refHolder.otherClass, refHolder.propertyName, cdmBase2);
719 for (CdmBase referencingObject : list){
720 Field referencingField = getFieldRecursive(refHolder.otherClass, refHolder.propertyName);
721 referencingField.setAccessible(true);
722 Object collection = referencingField.get(referencingObject);
723 if (! (collection instanceof Collection)){
724 throw new MergeException ("Reallocation of collections for collection other than set and list not yet implemented");
725 }
726 Method addMethod = DefaultMergeStrategy.getAddMethod(referencingField, false);
727 Method removeMethod = DefaultMergeStrategy.getAddMethod(referencingField, true);
728 addMethod.invoke(referencingObject, cdmBase1);
729 removeMethod.invoke(referencingObject, cdmBase2);
730 }
731 }
732
733 private Field getFieldRecursive(Class clazz, String propertyName) throws NoSuchFieldException{
734 try {
735 return clazz.getDeclaredField(propertyName);
736 } catch (NoSuchFieldException e) {
737 Class superClass = clazz.getSuperclass();
738 if (CdmBase.class.isAssignableFrom(superClass)){
739 return getFieldRecursive(superClass, propertyName);
740 }else{
741 throw e;
742 }
743 }
744 }
745
746 /**
747 * @throws NoSuchFieldException
748 * @throws SecurityException
749 * @throws IllegalAccessException
750 * @throws IllegalArgumentException
751 *
752 */
753 private void reallocateSingleItem_Old(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
754 List<CdmBase> referencingObjects = getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2);
755 for (CdmBase referencingObject : referencingObjects){
756 Field referencingField = refHolder.otherClass.getDeclaredField(refHolder.propertyName);
757 referencingField.setAccessible(true);
758 Object test = referencingField.get(referencingObject);
759 assert(test.equals(cdmBase2));
760 referencingField.set(referencingObject, cdmBase1);
761 }
762 }
763
764 private void reallocateSingleItem(CdmBase cdmBase1, CdmBase cdmBase2, ReferenceHolder refHolder, Set<ICdmBase> cloneSet) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
765 List<CdmBase> referencingObjects = getCdmBasesByFieldAndClass(refHolder.otherClass, refHolder.propertyName, cdmBase2);
766 Session session = getSession();
767 for (CdmBase referencingObject : referencingObjects){
768 if (!cloneSet.contains(referencingObject)){
769 String className = refHolder.otherClass.getSimpleName();
770 String propertyName = refHolder.propertyName;
771 String hql = "update " + className + " c set c."+propertyName+" = :newValue where c.id = :id";
772 Query query = session.createQuery(hql);
773 query.setEntity("newValue", cdmBase1);
774 query.setInteger("id",referencingObject.getId());
775 int rowCount = query.executeUpdate();
776 logger.debug("Rows affected: " + rowCount);
777 session.refresh(referencingObject);
778 }
779 }
780 session.flush();
781 }
782
783
784
785 /**
786 * @param <T>
787 * @param cdmBase1
788 * @param cdmBase2
789 * @param session
790 */
791 private <T> void handleAnnotationsEtc(T cdmBase1, T cdmBase2, Session session) {
792 //when handling annotations and other elements linked via @Any an JDBC errors occurs
793 //due to the unique column constraint in the association table on the column referencing
794 //the annotation.
795 //For some reason not delete command is executed for the old collection
796 // Hibernate bug ??
797 session.flush(); //for debugging
798 if (cdmBase1 instanceof AnnotatableEntity){
799 AnnotatableEntity annotatableEntity1 = (AnnotatableEntity)cdmBase1;
800 AnnotatableEntity annotatableEntity2 = (AnnotatableEntity)cdmBase2;
801 //annotations
802 List<Annotation> removeListAnnotation = new ArrayList<Annotation>();
803 for (Annotation annotation : annotatableEntity2.getAnnotations()){
804 Annotation clone = null;
805 try {
806 clone = annotation.clone(annotatableEntity1);
807 } catch (CloneNotSupportedException e) {
808 e.printStackTrace();
809 }
810 annotatableEntity1.addAnnotation(clone);
811 removeListAnnotation.add(annotation);
812 }
813 for (Annotation annotation : removeListAnnotation){
814 annotatableEntity2.removeAnnotation(annotation);
815 getSession().delete(annotation);
816 }
817 //marker
818 List<Marker> removeListMarker = new ArrayList<Marker>();
819 for (Marker marker : annotatableEntity2.getMarkers()){
820 Marker clone = null;
821 try {
822 clone = marker.clone(annotatableEntity1);
823 } catch (CloneNotSupportedException e) {
824 e.printStackTrace();
825 }
826 annotatableEntity1.addMarker(clone);
827 removeListMarker.add(marker);
828 }
829 for (Marker marker : removeListMarker){
830 annotatableEntity2.removeMarker(marker);
831 getSession().delete(marker);
832 }
833 }
834 if (cdmBase1 instanceof IdentifiableEntity){
835 IdentifiableEntity identifiableEntity1 = (IdentifiableEntity)cdmBase1;
836 IdentifiableEntity identifiableEntity2 = (IdentifiableEntity)cdmBase2;
837 //annotations
838 List<Extension> removeListExtension = new ArrayList<Extension>();
839 for (Extension changeObject : (Set<Extension>)identifiableEntity2.getExtensions()){
840 try {
841 Extension clone = changeObject.clone(identifiableEntity1);
842 identifiableEntity1.addExtension(clone);
843 removeListExtension.add(changeObject);
844 } catch (CloneNotSupportedException e) {
845 e.printStackTrace();
846 }
847
848 }
849 for (Extension removeObject : removeListExtension){
850 identifiableEntity2.removeExtension(removeObject);
851 getSession().delete(removeObject);
852 }
853 }
854
855 session.saveOrUpdate(cdmBase1);
856 session.saveOrUpdate(cdmBase2);
857 session.flush();
858 }
859
860 private <T extends CdmBase> void testMergeValid(T cdmBase1, T cdmBase2)throws IllegalArgumentException, NullPointerException{
861 if (cdmBase1 == null || cdmBase2 == null){
862 throw new NullPointerException("Merge arguments must not be (null)");
863 }
864 cdmBase1 = (T)HibernateProxyHelper.deproxy(cdmBase1);
865 cdmBase2 = (T)HibernateProxyHelper.deproxy(cdmBase2);
866
867 if (cdmBase1.getClass() != cdmBase2.getClass()){
868 throw new IllegalArgumentException("Merge arguments must be of same type");
869 }
870 }
871
872 //TODO Move to test classes if still needed
873 private void test() {
874 SessionFactoryImpl factory = (SessionFactoryImpl)getSession().getSessionFactory();
875 Type propType = factory.getReferencedPropertyType(BotanicalName.class.getCanonicalName(), "titleCache");
876 Map collMetadata = factory.getAllCollectionMetadata();
877 Object roles = factory.getCollectionRolesByEntityParticipant("eu.etaxonomy.cdm.model.name.BotanicalName");
878 CollectionPersister collPersister;
879 try {
880 collPersister = factory.getCollectionPersister(TaxonNameBase.class.getCanonicalName()+".annotations");
881 } catch (MappingException e) {
882 // TODO Auto-generated catch block
883 e.printStackTrace();
884 }
885 Statistics statistics = factory.getStatistics();
886 Map allClassMetadata = factory.getAllClassMetadata();
887 logger.debug("");
888
889 }
890
891 @Override
892 public <T extends CdmBase> T find(Class<T> clazz, int id){
893 Session session;
894 session = getSession();
895 //session = getSession().getSessionFactory().getCurrentSession();
896 Object o = session.get(clazz, id);
897 return (T)o;
898 }
899
900 @Override
901 public <T extends IMatchable> List<T> findMatching(T objectToMatch,
902 IMatchStrategy matchStrategy) throws MatchException {
903 try {
904 List<T> result = new ArrayList<T>();
905 if(objectToMatch == null){
906 return result;
907 }
908 if (matchStrategy == null){
909 matchStrategy = DefaultMatchStrategy.NewInstance(objectToMatch.getClass());
910 }
911 result.addAll(findMatchingNullSafe(objectToMatch, matchStrategy));
912 return result;
913 } catch (IllegalArgumentException e) {
914 throw new MatchException(e);
915 } catch (IllegalAccessException e) {
916 throw new MatchException(e);
917 }
918 }
919
920 private <T extends IMatchable> List<T> findMatchingNullSafe(T objectToMatch, IMatchStrategy matchStrategy) throws IllegalArgumentException, IllegalAccessException, MatchException {
921 List<T> result = new ArrayList<T>();
922 Session session = getSession();
923 Class<?> matchClass = objectToMatch.getClass();
924 ClassMetadata classMetaData = session.getSessionFactory().getClassMetadata(matchClass.getCanonicalName());
925 Criteria criteria = session.createCriteria(matchClass);
926 boolean noMatch = makeCriteria(objectToMatch, matchStrategy, classMetaData, criteria);
927 logger.debug(criteria);
928 //session.flush();
929 if (noMatch == false){
930 List<T> matchCandidates = criteria.list();
931 matchCandidates.remove(objectToMatch);
932 for (T matchCandidate : matchCandidates ){
933 if (matchStrategy.invoke(objectToMatch, matchCandidate)){
934 result.add(matchCandidate);
935 }else{
936 logger.warn("Match candidate did not match: " + matchCandidate);
937 }
938 }
939 }
940 return result;
941 }
942
943 /**
944 * @param <T>
945 * @param objectToMatch
946 * @param matchStrategy
947 * @param classMetaData
948 * @param criteria
949 * @return
950 * @throws IllegalAccessException
951 * @throws MatchException
952 */
953 private <T> boolean makeCriteria(T objectToMatch,
954 IMatchStrategy matchStrategy, ClassMetadata classMetaData,
955 Criteria criteria) throws IllegalAccessException, MatchException {
956 Matching matching = matchStrategy.getMatching();
957 boolean noMatch = false;
958 Map<String, List<MatchMode>> replaceMatchers = new HashMap<String, List<MatchMode>>();
959 for (CacheMatcher cacheMatcher: matching.getCacheMatchers()){
960 boolean cacheProtected = (Boolean)cacheMatcher.getProtectedField(matching).get(objectToMatch);
961 if (cacheProtected == true){
962 String cacheValue = (String)cacheMatcher.getField().get(objectToMatch);
963 if (StringUtils.isBlank(cacheValue)){
964 return true; //no match
965 }else{
966 criteria.add(Restrictions.eq(cacheMatcher.getPropertyName(), cacheValue));
967 criteria.add(Restrictions.eq(cacheMatcher.getProtectedPropertyName(), cacheProtected));
968
969 List<DoubleResult<String, MatchMode>> replacementModes = cacheMatcher.getReplaceMatchModes(matching);
970 for (DoubleResult<String, MatchMode> replacementMode: replacementModes ){
971 String propertyName = replacementMode.getFirstResult();
972 List<MatchMode> replaceMatcherList = replaceMatchers.get(propertyName);
973 if (replaceMatcherList == null){
974 replaceMatcherList = new ArrayList<MatchMode>();
975 replaceMatchers.put(propertyName, replaceMatcherList);
976 }
977 replaceMatcherList.add(replacementMode.getSecondResult());
978 }
979
980 }
981 }
982 }
983 for (FieldMatcher fieldMatcher : matching.getFieldMatchers(false)){
984 String propertyName = fieldMatcher.getPropertyName();
985 Type propertyType = classMetaData.getPropertyType(propertyName);
986 Object value = fieldMatcher.getField().get(objectToMatch);
987 List<MatchMode> matchModes= new ArrayList<MatchMode>();
988 matchModes.add(fieldMatcher.getMatchMode());
989 if (replaceMatchers.get(propertyName) != null){
990 matchModes.addAll(replaceMatchers.get(propertyName));
991 }
992
993 boolean isIgnore = false;
994 for (MatchMode matchMode : matchModes){
995 isIgnore |= matchMode.isIgnore(value);
996 }
997 if (! isIgnore ){
998 if (propertyType.isComponentType()){
999 matchComponentType(criteria, fieldMatcher, propertyName, value, matchModes);
1000 }else{
1001 noMatch = matchNonComponentType(criteria, fieldMatcher, propertyName, value, matchModes, propertyType);
1002 }
1003 }
1004 if (noMatch){
1005 return noMatch;
1006 }
1007 }
1008 return noMatch;
1009 }
1010
1011 /**
1012 * @param criteria
1013 * @param fieldMatcher
1014 * @param propertyName
1015 * @param value
1016 * @param matchMode
1017 * @throws MatchException
1018 * @throws IllegalAccessException
1019 */
1020 private void matchComponentType(Criteria criteria,
1021 FieldMatcher fieldMatcher, String propertyName, Object value,
1022 List<MatchMode> matchModes) throws MatchException, IllegalAccessException {
1023 if (value == null){
1024 boolean requiresSecondNull = requiresSecondNull(matchModes, value);
1025 if (requiresSecondNull){
1026 criteria.add(Restrictions.isNull(propertyName));
1027 }else{
1028 //TODO
1029 logger.warn("Component type not yet implemented for (null) value: " + propertyName);
1030 throw new MatchException("Component type not yet fully implemented for (null) value. Property: " + propertyName);
1031 }
1032 }else{
1033 Class<?> componentClass = fieldMatcher.getField().getType();
1034 Map<String, Field> fields = CdmUtils.getAllFields(componentClass, Object.class, false, false, true, false);
1035 for (String fieldName : fields.keySet()){
1036 String restrictionPath = propertyName +"."+fieldName;
1037 Object componentValue = fields.get(fieldName).get(value);
1038 //TODO diffentiate matchMode
1039 createCriterion(criteria, restrictionPath, componentValue, matchModes);
1040 }
1041 }
1042 }
1043
1044 private boolean matchNonComponentType(Criteria criteria,
1045 FieldMatcher fieldMatcher, String propertyName, Object value,
1046 List<MatchMode> matchModes, Type propertyType) throws HibernateException, DataAccessException, MatchException, IllegalAccessException{
1047 boolean noMatch = false;
1048 if (isRequired(matchModes) && value == null){
1049 noMatch = true;
1050 return noMatch;
1051 }else if (requiresSecondNull(matchModes,value)){
1052 criteria.add(Restrictions.isNull(propertyName));
1053 }else{
1054 if (isMatch(matchModes)){
1055 if (propertyType.isCollectionType()){
1056 //TODO collection not yet handled for match
1057 }else{
1058 int joinType = CriteriaSpecification.INNER_JOIN;
1059 if (! requiresSecondValue(matchModes,value)){
1060 joinType = CriteriaSpecification.LEFT_JOIN;
1061 }
1062 Criteria matchCriteria = criteria.createCriteria(propertyName, joinType).add(Restrictions.isNotNull("id"));
1063 Class matchClass = value.getClass();
1064 if (IMatchable.class.isAssignableFrom(matchClass)){
1065 IMatchStrategy valueMatchStrategy = DefaultMatchStrategy.NewInstance((Class<IMatchable>)matchClass);
1066 ClassMetadata valueClassMetaData = getSession().getSessionFactory().getClassMetadata(matchClass.getCanonicalName());;
1067 noMatch = makeCriteria(value, valueMatchStrategy, valueClassMetaData, matchCriteria);
1068 }else{
1069 logger.error("Class to match (" + matchClass + ") is not of type IMatchable");
1070 throw new MatchException("Class to match (" + matchClass + ") is not of type IMatchable");
1071 }
1072 }
1073 }else if (isEqual(matchModes)){
1074 createCriterion(criteria, propertyName, value, matchModes);
1075 }else {
1076 logger.warn("Unhandled match mode: " + matchModes + ", value: " + (value==null?"null":value));
1077 }
1078 }
1079 return noMatch;
1080 }
1081
1082 /**
1083 * @param criteria
1084 * @param propertyName
1085 * @param value
1086 * @param matchMode
1087 * @throws MatchException
1088 */
1089 private void createCriterion(Criteria criteria, String propertyName,
1090 Object value, List<MatchMode> matchModes) throws MatchException {
1091 Criterion finalRestriction = null;
1092 Criterion equalRestriction = Restrictions.eq(propertyName, value);
1093 Criterion nullRestriction = Restrictions.isNull(propertyName);
1094 if (this.requiresSecondValue(matchModes, value)){
1095 finalRestriction = equalRestriction;
1096 }else if (requiresSecondNull(matchModes, value) ){
1097 finalRestriction = nullRestriction;
1098 }else{
1099 finalRestriction = Restrictions.or(equalRestriction, nullRestriction);
1100 }
1101 //return finalRestriction;
1102 criteria.add(finalRestriction);
1103 }
1104
1105 /**
1106 * @param matchModes
1107 * @param value
1108 * @return
1109 * @throws MatchException
1110 */
1111 private boolean requiresSecondNull(List<MatchMode> matchModes, Object value) throws MatchException {
1112 boolean result = true;
1113 for (MatchMode matchMode: matchModes){
1114 result &= matchMode.requiresSecondNull(value);
1115 }
1116 return result;
1117 }
1118
1119 /**
1120 * @param matchModes
1121 * @param value
1122 * @return
1123 * @throws MatchException
1124 */
1125 private boolean requiresSecondValue(List<MatchMode> matchModes, Object value) throws MatchException {
1126 boolean result = true;
1127 for (MatchMode matchMode: matchModes){
1128 result &= matchMode.requiresSecondValue(value);
1129 }
1130 return result;
1131 }
1132
1133 /**
1134 * @param matchModes
1135 * @param value
1136 * @return
1137 * @throws MatchException
1138 */
1139 private boolean isRequired(List<MatchMode> matchModes) throws MatchException {
1140 boolean result = true;
1141 for (MatchMode matchMode: matchModes){
1142 result &= matchMode.isRequired();
1143 }
1144 return result;
1145 }
1146
1147 /**
1148 * Returns true if at least one match mode is of typ MATCH_XXX
1149 * @param matchModes
1150 * @param value
1151 * @return
1152 * @throws MatchException
1153 */
1154 private boolean isMatch(List<MatchMode> matchModes) throws MatchException {
1155 boolean result = false;
1156 for (MatchMode matchMode: matchModes){
1157 result |= matchMode.isMatch();
1158 }
1159 return result;
1160 }
1161
1162 /**
1163 * Returns true if at least one match mode is of typ EQUAL_XXX
1164 * @param matchModes
1165 * @param value
1166 * @return
1167 * @throws MatchException
1168 */
1169 private boolean isEqual(List<MatchMode> matchModes) throws MatchException {
1170 boolean result = false;
1171 for (MatchMode matchMode: matchModes){
1172 result |= matchMode.isEqual();
1173 }
1174 return result;
1175 }
1176
1177 /* (non-Javadoc)
1178 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#saveMetaData(eu.etaxonomy.cdm.model.common.CdmMetaData)
1179 */
1180 public void saveMetaData(CdmMetaData cdmMetaData) {
1181 getSession().saveOrUpdate(cdmMetaData);
1182 }
1183
1184 /* (non-Javadoc)
1185 * @see eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao#getMetaData()
1186 */
1187 public List<CdmMetaData> getMetaData() {
1188 Session session = getSession();
1189 Criteria crit = session.createCriteria(CdmMetaData.class);
1190 List<CdmMetaData> results = crit.list();
1191 return results;
1192 }
1193
1194 @Override
1195 public PersistentCollection initializeCollection(PersistentCollection col) {
1196 Session session = getSession();
1197 col.setCurrentSession((SessionImplementor) session);
1198
1199 if(!((SessionImplementor)session).getPersistenceContext().getCollectionEntries().containsKey(col)) {
1200 ((SessionImplementor)session).getPersistenceContext().addUninitializedDetachedCollection(
1201 ((SessionImplementor)session).getFactory().getCollectionPersister( col.getRole() ),col);
1202 }
1203 col.forceInitialization();
1204 logger.debug("initialising persistent collection with with role : " + col.getRole() + " and key : " + col.getKey());
1205 return col;
1206 }
1207
1208 @Override
1209 public boolean isEmpty(PersistentCollection col) {
1210 return initializeCollection(col).empty();
1211 }
1212
1213 @Override
1214 public int size(PersistentCollection col) {
1215 logger.debug("remote size() - for role : " + col.getRole() + " and key : " + col.getKey());
1216 initializeCollection(col);
1217 SessionImplementor session = (SessionImplementor)getSession();
1218 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(col);
1219
1220 if ( entry != null ) {
1221
1222 CollectionPersister persister = entry.getLoadedPersister();
1223 return persister.getSize( entry.getLoadedKey(), session );
1224 }
1225 return -1;
1226 }
1227
1228 @Override
1229 public Object get(PersistentCollection col, int index) {
1230 logger.debug("remote get() - for role : " + col.getRole() + " and key : " + col.getKey());
1231 initializeCollection(col);
1232 SessionImplementor session = (SessionImplementor)getSession();
1233 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(col);
1234
1235 if ( entry != null ) {
1236
1237 CollectionPersister persister = entry.getLoadedPersister();
1238 return persister.getElementByIndex(entry.getLoadedKey(), index, session, col);
1239
1240 }
1241 //FIXME:Remoting Should we not be throwing an exception here ?
1242 return null;
1243 }
1244
1245 @Override
1246 public boolean contains(PersistentCollection col, Object element) {
1247 logger.debug("remote contains() - for role : " + col.getRole() + " and key : " + col.getKey());
1248 initializeCollection(col);
1249 SessionImplementor session = (SessionImplementor)getSession();
1250 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(col);
1251
1252 if ( entry != null ) {
1253
1254 CollectionPersister persister = entry.getLoadedPersister();
1255 return persister.elementExists(entry.getLoadedKey(), element, session);
1256 }
1257 //FIXME:Remoting Should we not be throwing an exception here ?
1258 return false;
1259 }
1260
1261 @Override
1262 public boolean containsKey(PersistentCollection col, Object key) {
1263 logger.debug("remote containsKey() - for role : " + col.getRole() + " and key : " + col.getKey());
1264 initializeCollection(col);
1265 SessionImplementor session = (SessionImplementor)getSession();
1266 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(col);
1267
1268 if ( entry != null ) {
1269
1270 CollectionPersister persister = entry.getLoadedPersister();
1271 return persister.indexExists(entry.getLoadedKey(), key, session);
1272 }
1273 //FIXME:Remoting Should we not be throwing an exception here ?
1274 return false;
1275
1276 }
1277
1278 @Override
1279 public boolean containsValue(PersistentCollection col, Object element) {
1280 return contains(col, element);
1281 }
1282
1283
1284 }
1285
1286