cleanup
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / occurrence / OccurrenceDaoHibernateImpl.java
index 8d4d8b499b733bc11ca67d5e741b9919127118f0..6c33f68e1f6e260f3e905cd7c204ec968d52995e 100644 (file)
@@ -1,12 +1,14 @@
 /**\r
 * Copyright (C) 2008 EDIT\r
-* European Distributed Institute of Taxonomy \r
+* European Distributed Institute of Taxonomy\r
 * http://www.e-taxonomy.eu\r
 */\r
 \r
 package eu.etaxonomy.cdm.persistence.dao.hibernate.occurrence;\r
 \r
 import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
 import java.util.HashSet;\r
 import java.util.List;\r
 import java.util.Set;\r
@@ -17,6 +19,8 @@ import org.hibernate.Criteria;
 import org.hibernate.Hibernate;\r
 import org.hibernate.Query;\r
 import org.hibernate.Session;\r
+import org.hibernate.criterion.Disjunction;\r
+import org.hibernate.criterion.ProjectionList;\r
 import org.hibernate.criterion.Projections;\r
 import org.hibernate.criterion.Restrictions;\r
 import org.hibernate.envers.query.AuditEntity;\r
@@ -26,19 +30,25 @@ import org.hibernate.search.Search;
 import org.springframework.beans.factory.annotation.Autowired;\r
 import org.springframework.stereotype.Repository;\r
 \r
-import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;\r
+import eu.etaxonomy.cdm.model.common.CdmBase;\r
+import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;\r
+import eu.etaxonomy.cdm.model.location.Point;\r
 import eu.etaxonomy.cdm.model.media.Media;\r
 import eu.etaxonomy.cdm.model.molecular.DnaSample;\r
 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;\r
 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;\r
+import eu.etaxonomy.cdm.model.name.TaxonName;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;\r
 import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;\r
 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;\r
 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;\r
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;\r
+import eu.etaxonomy.cdm.model.taxon.Synonym;\r
 import eu.etaxonomy.cdm.model.taxon.Taxon;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonNode;\r
 import eu.etaxonomy.cdm.model.view.AuditEvent;\r
 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;\r
 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;\r
@@ -46,391 +56,946 @@ import eu.etaxonomy.cdm.persistence.dao.hibernate.taxon.TaxonDaoHibernateImpl;
 import eu.etaxonomy.cdm.persistence.dao.name.IHomotypicalGroupDao;\r
 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;\r
 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;\r
+import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;\r
+import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;\r
+import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;\r
+import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
 import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
 \r
 /**\r
  * @author a.babadshanjan\r
- * @created 01.09.2008\r
+ * @since 01.09.2008\r
  */\r
 @Repository\r
-public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrObservationBase> implements IOccurrenceDao {\r
-       \r
-       @SuppressWarnings("unused")\r
-       private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);\r
-       \r
-       @Autowired\r
-       private IDescriptionDao descriptionDao;\r
-       \r
-       @Autowired\r
-       private ITaxonNameDao taxonNameDao;\r
-       \r
-       @Autowired\r
-       private IHomotypicalGroupDao homotypicalGroupDao;\r
-\r
-       public OccurrenceDaoHibernateImpl() {\r
-               super(SpecimenOrObservationBase.class);\r
-               indexedClasses = new Class[7];\r
-               indexedClasses[0] = FieldUnit.class;\r
-               indexedClasses[1] = DerivedUnit.class;\r
-               indexedClasses[5] = DnaSample.class;\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#countDerivationEvents(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)\r
-        */\r
-       @Override\r
-       public int countDerivationEvents(SpecimenOrObservationBase occurence) {\r
-               checkNotInPriorView("OccurrenceDaoHibernateImpl.countDerivationEvents(SpecimenOrObservationBase occurence)");\r
-               Query query = getSession().createQuery("select count(distinct derivationEvent) from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");\r
-               query.setParameter("occurence", occurence);\r
-               \r
-               return ((Long)query.uniqueResult()).intValue();\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#countDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)\r
-        */\r
-       @Override\r
-       public int countDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase) {\r
-               AuditEvent auditEvent = getAuditEventFromContext();\r
-               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
-                       Criteria criteria = getSession().createCriteria(DeterminationEvent.class);\r
+public class OccurrenceDaoHibernateImpl\r
+          extends IdentifiableDaoBase<SpecimenOrObservationBase>\r
+          implements IOccurrenceDao {\r
+\r
+    private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);\r
+\r
+    @Autowired\r
+    private IDescriptionDao descriptionDao;\r
+\r
+    @Autowired\r
+    private ITaxonNameDao taxonNameDao;\r
+\r
+    @Autowired\r
+    private IHomotypicalGroupDao homotypicalGroupDao;\r
+\r
+    public OccurrenceDaoHibernateImpl() {\r
+        super(SpecimenOrObservationBase.class);\r
+        indexedClasses = new Class[7];\r
+        indexedClasses[0] = FieldUnit.class;\r
+        indexedClasses[1] = DerivedUnit.class;\r
+        indexedClasses[5] = DnaSample.class;\r
+    }\r
+\r
+    @Override\r
+    public long countDerivationEvents(SpecimenOrObservationBase occurence) {\r
+        checkNotInPriorView("OccurrenceDaoHibernateImpl.countDerivationEvents(SpecimenOrObservationBase occurence)");\r
+        Query query = getSession().createQuery("select count(distinct derivationEvent) from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");\r
+        query.setParameter("occurence", occurence);\r
+\r
+        return (Long)query.uniqueResult();\r
+    }\r
+\r
+    @Override\r
+    public long countDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase) {\r
+        AuditEvent auditEvent = getAuditEventFromContext();\r
+        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+            Criteria criteria = getCriteria(DeterminationEvent.class);\r
             if(occurrence != null) {\r
-               criteria.add(Restrictions.eq("identifiedUnit",occurrence));\r
+                criteria.add(Restrictions.eq("identifiedUnit",occurrence));\r
             }\r
-            \r
+\r
             if(taxonBase != null) {\r
-               criteria.add(Restrictions.eq("taxon",taxonBase));\r
+                criteria.add(Restrictions.eq("taxon",taxonBase));\r
             }\r
-                       \r
+\r
             criteria.setProjection(Projections.rowCount());\r
-               return ((Number)criteria.uniqueResult()).intValue();\r
-               } else {\r
-                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());\r
-                       \r
-                       if(occurrence != null) {\r
-                           query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));\r
-                       }\r
-                       \r
-                       if(taxonBase != null) {\r
-                           query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));\r
-                       }\r
-                       query.addProjection(AuditEntity.id().count("id"));\r
-\r
-                       return ((Long)query.getSingleResult()).intValue();\r
-               }\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#countMedia(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)\r
-        */\r
-       @Override\r
-       public int countMedia(SpecimenOrObservationBase occurence) {\r
-               checkNotInPriorView("OccurrenceDaoHibernateImpl.countMedia(SpecimenOrObservationBase occurence)");\r
-               Query query = getSession().createQuery("select count(media) from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");\r
-               query.setParameter("occurence", occurence);\r
-               \r
-               return ((Long)query.uniqueResult()).intValue();\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#getDerivationEvents(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List)\r
-        */\r
-       @Override\r
-       public List<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {\r
-               checkNotInPriorView("OccurrenceDaoHibernateImpl.getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber)");\r
-               Query query = getSession().createQuery("select distinct derivationEvent from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");\r
-               query.setParameter("occurence", occurence);\r
-               \r
-               if(pageSize != null) {\r
-                   query.setMaxResults(pageSize);\r
-                   if(pageNumber != null) {\r
-                       query.setFirstResult(pageNumber * pageSize);\r
-                   } else {\r
-                       query.setFirstResult(0);\r
-                   }\r
-               }\r
-               \r
-               List<DerivationEvent> result = (List<DerivationEvent>)query.list();\r
-               defaultBeanInitializer.initializeAll(result, propertyPaths);\r
-               return result;\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#getDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)\r
-        */\r
-       @Override\r
-       public List<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {\r
-               AuditEvent auditEvent = getAuditEventFromContext();\r
-               if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
-                       Criteria criteria = getSession().createCriteria(DeterminationEvent.class);\r
-                       if(occurrence != null) {\r
-               criteria.add(Restrictions.eq("identifiedUnit",occurrence));\r
+            return (Long)criteria.uniqueResult();\r
+        } else {\r
+            AuditQuery query = makeAuditQuery(DeterminationEvent.class,auditEvent);\r
+\r
+            if(occurrence != null) {\r
+                query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));\r
+            }\r
+\r
+            if(taxonBase != null) {\r
+                query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));\r
+            }\r
+            query.addProjection(AuditEntity.id().count());\r
+\r
+            return (Long)query.getSingleResult();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public long countMedia(SpecimenOrObservationBase occurence) {\r
+        checkNotInPriorView("OccurrenceDaoHibernateImpl.countMedia(SpecimenOrObservationBase occurence)");\r
+        Query query = getSession().createQuery("SELECT count(media) FROM SpecimenOrObservationBase occurence JOIN occurence.media media WHERE occurence = :occurence");\r
+        query.setParameter("occurence", occurence);\r
+\r
+        return (Long)query.uniqueResult();\r
+    }\r
+\r
+    @Override\r
+    public List<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {\r
+        checkNotInPriorView("OccurrenceDaoHibernateImpl.getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber)");\r
+        Query query = getSession().createQuery("SELECT DISTINCT derivationEvent FROM DerivationEvent derivationEvent JOIN derivationEvent.originals occurence WHERE occurence = :occurence");\r
+        query.setParameter("occurence", occurence);\r
+\r
+        addPageSizeAndNumber(query, pageSize, pageNumber);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<DerivationEvent> result = query.list();\r
+        defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public List<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence,\r
+            TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {\r
+        AuditEvent auditEvent = getAuditEventFromContext();\r
+        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
+            Criteria criteria = getSession().createCriteria(DeterminationEvent.class);\r
+            if(occurrence != null) {\r
+                criteria.add(Restrictions.eq("identifiedUnit",occurrence));\r
+            }\r
+\r
+            if(taxonBase != null) {\r
+                criteria.add(Restrictions.eq("taxon",taxonBase));\r
+            }\r
+\r
+            addPageSizeAndNumber(criteria, pageSize, pageNumber);\r
+\r
+            @SuppressWarnings("unchecked")\r
+            List<DeterminationEvent> result = criteria.list();\r
+            defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+            return result;\r
+        } else {\r
+            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());\r
+            if(occurrence != null) {\r
+                query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));\r
             }\r
-            \r
+\r
             if(taxonBase != null) {\r
-               criteria.add(Restrictions.eq("taxon",taxonBase));\r
+                query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));\r
             }\r
+            addPageSizeAndNumber(query, pageSize, pageNumber);\r
+\r
+            @SuppressWarnings("unchecked")\r
+            List<DeterminationEvent> result = query.getResultList();\r
+            defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+            return result;\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public List<Media> getMedia(SpecimenOrObservationBase occurence,\r
+            Integer pageSize, Integer pageNumber, List<String> propertyPaths) {\r
+        checkNotInPriorView("OccurrenceDaoHibernateImpl.getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths)");\r
+        Query query = getSession().createQuery(\r
+                "   SELECT media "\r
+                + " FROM SpecimenOrObservationBase occurence "\r
+                + " JOIN occurence.media media "\r
+                + " WHERE occurence = :occurence");\r
+        query.setParameter("occurence", occurence);\r
+\r
+        addPageSizeAndNumber(query, pageSize, pageNumber);\r
 \r
-                       if(pageSize != null) {\r
-                               criteria.setMaxResults(pageSize);\r
-                               if(pageNumber != null) {\r
-                                       criteria.setFirstResult(pageNumber * pageSize);\r
-                               } else {\r
-                                       criteria.setFirstResult(0);\r
-                               }\r
-                       }\r
-                       List<DeterminationEvent> result = (List<DeterminationEvent>)criteria.list();\r
-            defaultBeanInitializer.initializeAll(result, propertyPaths);                       \r
-                       return result;\r
-               } else {\r
-                       AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());\r
-                       if(occurrence != null) {\r
-                           query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));\r
-                       }\r
-                       \r
-                       if(taxonBase != null) {\r
-                           query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));\r
-                       }\r
-                       if(pageSize != null) {\r
-                               query.setMaxResults(pageSize);\r
-                               if(pageNumber != null) {\r
-                                       query.setFirstResult(pageNumber * pageSize);\r
-                               } else {\r
-                                       query.setFirstResult(0);\r
-                               }\r
-                       }\r
-                       List<DeterminationEvent> result = (List<DeterminationEvent>)query.getResultList();\r
-            defaultBeanInitializer.initializeAll(result, propertyPaths);                       \r
-                       return result;\r
-               }\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#getMedia(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List)\r
-        */\r
-       @Override\r
-       public List<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {\r
-               checkNotInPriorView("OccurrenceDaoHibernateImpl.getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths)");\r
-               Query query = getSession().createQuery("select media from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");\r
-               query.setParameter("occurence", occurence);\r
-               \r
-               if(pageSize != null) {\r
-                   query.setMaxResults(pageSize);\r
-                   if(pageNumber != null) {\r
-                       query.setFirstResult(pageNumber * pageSize);\r
-                   } else {\r
-                       query.setFirstResult(0);\r
-                   }\r
-               }\r
-               \r
-               List<Media> results = (List<Media>)query.list();\r
-               defaultBeanInitializer.initializeAll(results, propertyPaths);           \r
-               return results;\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase#rebuildIndex()\r
-        */\r
-       @Override\r
-       public void rebuildIndex() {\r
+        @SuppressWarnings("unchecked")\r
+        List<Media> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    @Override\r
+    public void rebuildIndex() {\r
         FullTextSession fullTextSession = Search.getFullTextSession(getSession());\r
-               \r
-               for(SpecimenOrObservationBase occurrence : list(null,null)) { // re-index all taxon base\r
-\r
-                       for(DeterminationEvent determination : (Set<DeterminationEvent>)occurrence.getDeterminations()) {\r
-                           Hibernate.initialize(determination.getActor());\r
-                           Hibernate.initialize(determination.getTaxon());\r
-                       }\r
-                       Hibernate.initialize(occurrence.getDefinition());\r
-                       if(occurrence instanceof DerivedUnit) {\r
-                               DerivedUnit derivedUnit = (DerivedUnit) occurrence;\r
-                               Hibernate.initialize(derivedUnit.getCollection());\r
-                               if(derivedUnit.getCollection() != null) {\r
-                                       Hibernate.initialize(derivedUnit.getCollection().getSuperCollection());\r
-                                       Hibernate.initialize(derivedUnit.getCollection().getInstitute());\r
-                               }\r
-                               Hibernate.initialize(derivedUnit.getStoredUnder());\r
-                               SpecimenOrObservationBase original = derivedUnit.getOriginalUnit();\r
-                               if(original != null && original.isInstanceOf(FieldUnit.class)) {\r
-                                       FieldUnit fieldUnit = original.deproxy(original, FieldUnit.class);\r
-                                       Hibernate.initialize(fieldUnit.getGatheringEvent());\r
-                                       if(fieldUnit.getGatheringEvent() != null) {\r
-                                               Hibernate.initialize(fieldUnit.getGatheringEvent().getActor());\r
-                                       }\r
-                               }\r
-                       }\r
-                       fullTextSession.index(occurrence);\r
-               }\r
-               fullTextSession.flushToIndexes();\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#count(java.lang.Class, eu.etaxonomy.cdm.model.taxon.TaxonBase)\r
-        */\r
-       @Override\r
-       public int count(Class<? extends SpecimenOrObservationBase> clazz,      TaxonBase determinedAs) {\r
-\r
-               Criteria criteria = null;\r
-               if(clazz == null) {\r
-                       criteria = getSession().createCriteria(type);\r
-               } else {\r
-                   criteria = getSession().createCriteria(clazz);\r
-               }\r
-               \r
-               criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));\r
-               criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));\r
-               return ((Number)criteria.uniqueResult()).intValue();\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#list(java.lang.Class, eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-        */\r
-       @Override\r
-       public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonBase determinedAs, Integer limit, Integer start,     List<OrderHint> orderHints, List<String> propertyPaths) {\r
-               Criteria criteria = null;\r
-               if(clazz == null) {\r
-                       criteria = getSession().createCriteria(type); \r
-               } else {\r
-                   criteria = getSession().createCriteria(clazz);      \r
-               } \r
-               \r
-               criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));\r
-               \r
-               if(limit != null) {\r
-                       if(start != null) {\r
-                           criteria.setFirstResult(start);\r
-                       } else {\r
-                               criteria.setFirstResult(0);\r
-                       }\r
-                       criteria.setMaxResults(limit);\r
-               }\r
-               \r
-               addOrder(criteria,orderHints);\r
-               \r
-               List<SpecimenOrObservationBase> results = (List<SpecimenOrObservationBase>)criteria.list();\r
-               defaultBeanInitializer.initializeAll(results, propertyPaths);\r
-               return results; \r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#getDerivedUnitUuidAndTitleCache()\r
-        */\r
-       @Override\r
-       public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache() {\r
-               List<UuidAndTitleCache<DerivedUnit>> list = new ArrayList<UuidAndTitleCache<DerivedUnit>>();\r
-               Session session = getSession();\r
-               \r
-               Query query = session.createQuery("select uuid, titleCache from " + type.getSimpleName() + " where NOT dtype = " + FieldUnit.class.getSimpleName());\r
-               \r
-               List<Object[]> result = query.list();\r
-               \r
-               for(Object[] object : result){\r
-                       list.add(new UuidAndTitleCache<DerivedUnit>(DerivedUnit.class, (UUID) object[0], (String) object[1]));\r
-               }\r
-               \r
-               return list;\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#getFieldUnitUuidAndTitleCache()\r
-        */\r
-       @Override\r
-       public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {\r
-               List<UuidAndTitleCache<FieldUnit>> list = new ArrayList<UuidAndTitleCache<FieldUnit>>();\r
-               Session session = getSession();\r
-               \r
-               Query query = session.createQuery("select uuid, titleCache from " + type.getSimpleName() + " where dtype = " + FieldUnit.class.getSimpleName());\r
-               \r
-               List<Object[]> result = query.list();\r
-               \r
-               for(Object[] object : result){\r
-                       list.add(new UuidAndTitleCache<FieldUnit>(FieldUnit.class, (UUID) object[0], (String) object[1]));\r
-               }\r
-               \r
-               return list;\r
-       }\r
-\r
-       /* (non-Javadoc)\r
-        * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#listByAnyAssociation(java.lang.Class, eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)\r
-        */\r
-       @Override\r
-       public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type,\r
-                       Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
-               \r
-               Set<SpecimenOrObservationBase> setOfAll = new HashSet<SpecimenOrObservationBase>();\r
-               \r
-               // A Taxon may be referenced by the DeterminationEvent of the SpecimenOrObservationBase\r
-               List<SpecimenOrObservationBase> byDetermination = list(type, associatedTaxon, null, 0, null, null);\r
-               setOfAll.addAll(byDetermination);\r
-               \r
-               // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits \r
-               List<IndividualsAssociation> byIndividualsAssociation = descriptionDao.getDescriptionElementForTaxon(\r
-                               associatedTaxon, null, IndividualsAssociation.class, null, 0, null);\r
-               for(IndividualsAssociation individualsAssociation : byIndividualsAssociation){\r
-                       setOfAll.add(individualsAssociation.getAssociatedSpecimenOrObservation());\r
-               }\r
-               \r
-               // SpecimenTypeDesignations may be associated with the TaxonName.\r
-               List<SpecimenTypeDesignation> bySpecimenTypeDesignation = taxonNameDao.getTypeDesignations(associatedTaxon.getName(), \r
-                               SpecimenTypeDesignation.class, null, null, 0, null);\r
-               for (SpecimenTypeDesignation specimenTypeDesignation : bySpecimenTypeDesignation) {\r
-                       setOfAll.add(specimenTypeDesignation.getTypeSpecimen());\r
-               }\r
-               \r
-               // SpecimenTypeDesignations may be associated with any HomotypicalGroup related to the specific Taxon.\r
-               for(HomotypicalGroup homotypicalGroup :  associatedTaxon.getHomotypicSynonymyGroups()) {\r
-                       List<SpecimenTypeDesignation> byHomotypicalGroup = homotypicalGroupDao.getTypeDesignations(homotypicalGroup, SpecimenTypeDesignation.class, null, null, 0, null);\r
-                       for (SpecimenTypeDesignation specimenTypeDesignation : byHomotypicalGroup) {\r
-                               setOfAll.add(specimenTypeDesignation.getTypeSpecimen());\r
-                       }\r
-               }\r
-               \r
-               if(setOfAll.size() == 0){\r
-                       // no need querying the data base\r
-                       return new ArrayList<T>();\r
-               }\r
-               \r
-               String queryString = \r
-                       "select sob " +\r
-                       " from SpecimenOrObservationBase sob" +\r
-                       " where sob in (:setOfAll)";\r
-               \r
-               if(type != null){\r
-                       queryString += " and sob.class = :type";\r
-               }\r
-               \r
-               if(orderHints != null && orderHints.size() > 0){\r
-                       queryString += " order by ";\r
-                       String orderStr = "";\r
-                       for(OrderHint orderHint : orderHints){\r
-                               if(orderStr.length() > 0){\r
-                                       orderStr += ", ";\r
-                               }\r
-                               queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();\r
-                       }\r
-                       queryString += orderStr;\r
-               }\r
-               \r
-               Query query = getSession().createQuery(queryString);\r
-               query.setParameterList("setOfAll", setOfAll);\r
-               \r
-               if(type != null){\r
-                       query.setParameter("type", type.getSimpleName());\r
-               }\r
-               \r
-               if(limit != null) {\r
-                       if(start != null) {\r
-                               query.setFirstResult(start);\r
-                       } else {\r
-                               query.setFirstResult(0);\r
-                       }\r
-                       query.setMaxResults(limit);\r
-               }\r
-                   \r
-               \r
-           List<T> results = (List<T>) query.list();\r
-           defaultBeanInitializer.initializeAll(results, propertyPaths);\r
-               return results;\r
-       }\r
-}
\ No newline at end of file
+\r
+        for(SpecimenOrObservationBase<?> occurrence : list(null,null)) { // re-index all taxon base\r
+\r
+            for(DeterminationEvent determination : occurrence.getDeterminations()) {\r
+                Hibernate.initialize(determination.getActor());\r
+                Hibernate.initialize(determination.getTaxon());\r
+            }\r
+            Hibernate.initialize(occurrence.getDefinition());\r
+            if(occurrence instanceof DerivedUnit) {\r
+                DerivedUnit derivedUnit = (DerivedUnit) occurrence;\r
+                Hibernate.initialize(derivedUnit.getCollection());\r
+                if(derivedUnit.getCollection() != null) {\r
+                    Hibernate.initialize(derivedUnit.getCollection().getSuperCollection());\r
+                    Hibernate.initialize(derivedUnit.getCollection().getInstitute());\r
+                }\r
+                Hibernate.initialize(derivedUnit.getStoredUnder());\r
+                SpecimenOrObservationBase<?> original = derivedUnit.getOriginalUnit();\r
+                if(original != null && original.isInstanceOf(FieldUnit.class)) {\r
+                    FieldUnit fieldUnit = CdmBase.deproxy(original, FieldUnit.class);\r
+                    Hibernate.initialize(fieldUnit.getGatheringEvent());\r
+                    if(fieldUnit.getGatheringEvent() != null) {\r
+                        Hibernate.initialize(fieldUnit.getGatheringEvent().getActor());\r
+                    }\r
+                }\r
+            }\r
+            fullTextSession.index(occurrence);\r
+        }\r
+        fullTextSession.flushToIndexes();\r
+    }\r
+\r
+    @Override\r
+    public long count(Class<? extends SpecimenOrObservationBase> clazz,        TaxonName determinedAs) {\r
+\r
+        Criteria criteria = getCriteria(clazz);\r
+\r
+        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));\r
+        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));\r
+        return (Long)criteria.uniqueResult();\r
+    }\r
+\r
+    @Override\r
+    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonName determinedAs,\r
+            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        Criteria criteria = getCriteria(clazz);\r
+\r
+        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));\r
+\r
+        addPageSizeAndNumber(criteria, pageSize, pageNumber);\r
+        addOrder(criteria,orderHints);\r
+\r
+        @SuppressWarnings({ "unchecked", "rawtypes" })\r
+        List<SpecimenOrObservationBase> results = criteria.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    @Override\r
+    public long count(Class<? extends SpecimenOrObservationBase> clazz,        TaxonBase determinedAs) {\r
+\r
+        Criteria criteria = getCriteria(clazz);\r
+\r
+        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));\r
+        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));\r
+        return (Long)criteria.uniqueResult();\r
+    }\r
+\r
+\r
+    @Override\r
+    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonBase determinedAs,\r
+            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+\r
+        Criteria criteria = getCriteria(clazz);\r
+\r
+        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));\r
+\r
+        addPageSizeAndNumber(criteria, pageSize, pageNumber);\r
+        addOrder(criteria,orderHints);\r
+\r
+        @SuppressWarnings({ "unchecked", "rawtypes" })\r
+        List<SpecimenOrObservationBase> results = criteria.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> findOccurrencesUuidAndTitleCache(\r
+            Class<T> clazz, String queryString, String significantIdentifier, SpecimenOrObservationType recordBasis,\r
+            Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit, Integer start,\r
+            List<OrderHint> orderHints) {\r
+        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,\r
+                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, null);\r
+        if(criteria!=null){\r
+            ProjectionList projectionList = Projections.projectionList();\r
+            projectionList.add(Projections.property("uuid"));\r
+            projectionList.add(Projections.property("id"));\r
+            projectionList.add(Projections.property("titleCache"));\r
+            criteria.setProjection(projectionList);\r
+\r
+            @SuppressWarnings("unchecked")\r
+            List<Object[]> result = criteria.list();\r
+            List<UuidAndTitleCache<SpecimenOrObservationBase>> uuidAndTitleCacheList = new ArrayList<>();\r
+            for(Object[] object : result){\r
+                uuidAndTitleCacheList.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));\r
+            }\r
+            return uuidAndTitleCacheList;\r
+        }else{\r
+            return Collections.emptyList();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> List<T> findOccurrences(Class<T> clazz, String queryString,\r
+            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,\r
+            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+\r
+        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,\r
+                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);\r
+        if(criteria!=null){\r
+            @SuppressWarnings("unchecked")\r
+            List<T> results = criteria.list();\r
+            defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+            return results;\r
+        }else{\r
+            return Collections.emptyList();\r
+        }\r
+    }\r
+\r
+    private <T extends SpecimenOrObservationBase> Criteria createFindOccurrenceCriteria(Class<T> clazz, String queryString,\r
+            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon,\r
+            TaxonName associatedTaxonName, MatchMode matchmode, Integer limit,\r
+            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        Criteria criteria = null;\r
+\r
+        if(clazz == null) {\r
+            criteria = getSession().createCriteria(type);\r
+        } else {\r
+            criteria = getSession().createCriteria(clazz);\r
+        }\r
+\r
+        //queryString\r
+        if (queryString != null) {\r
+            if(matchmode == null) {\r
+                matchmode = MatchMode.ANYWHERE;\r
+                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));\r
+            } else if(matchmode == MatchMode.BEGINNING) {\r
+                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.START));\r
+            } else if(matchmode == MatchMode.END) {\r
+                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.END));\r
+            } else if(matchmode == MatchMode.EXACT) {\r
+                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.EXACT));\r
+            } else {\r
+                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.ANYWHERE));\r
+            }\r
+        }\r
+\r
+        //significant identifier\r
+        if (significantIdentifier != null) {\r
+            criteria.add(Restrictions.or(Restrictions.ilike("accessionNumber", significantIdentifier),\r
+                    Restrictions.ilike("catalogNumber", significantIdentifier), Restrictions.ilike("barcode", significantIdentifier)));\r
+        }\r
+\r
+        //recordBasis/SpecimenOrObservationType\r
+        Set<SpecimenOrObservationType> typeAndSubtypes = new HashSet<>();\r
+        if(recordBasis==null){\r
+            //add all types\r
+            SpecimenOrObservationType[] values = SpecimenOrObservationType.values();\r
+            for (SpecimenOrObservationType specimenOrObservationType : values) {\r
+                typeAndSubtypes.add(specimenOrObservationType);\r
+            }\r
+        }\r
+        else{\r
+            typeAndSubtypes = recordBasis.getGeneralizationOf(true);\r
+            typeAndSubtypes.add(recordBasis);\r
+        }\r
+        criteria.add(Restrictions.in("recordBasis", typeAndSubtypes));\r
+\r
+        Set<UUID> associationUuids = new HashSet<>();\r
+        //taxon associations\r
+        if(associatedTaxon!=null){\r
+            List<UuidAndTitleCache<SpecimenOrObservationBase>> associatedTaxaList = listUuidAndTitleCacheByAssociatedTaxon(clazz, associatedTaxon, limit, start, orderHints);\r
+            if(associatedTaxaList!=null){\r
+                for (UuidAndTitleCache<SpecimenOrObservationBase> uuidAndTitleCache : associatedTaxaList) {\r
+                    associationUuids.add(uuidAndTitleCache.getUuid());\r
+                }\r
+            }\r
+        }\r
+        //taxon name associations\r
+        else if(associatedTaxonName!=null){\r
+            List<? extends SpecimenOrObservationBase> associatedTaxaList = listByAssociatedTaxonName(clazz, associatedTaxonName, limit, start, orderHints, propertyPaths);\r
+            if(associatedTaxaList!=null){\r
+                for (SpecimenOrObservationBase<?> specimenOrObservationBase : associatedTaxaList) {\r
+                    associationUuids.add(specimenOrObservationBase.getUuid());\r
+                }\r
+            }\r
+        }\r
+        if(associatedTaxon!=null || associatedTaxonName!=null){\r
+            if(!associationUuids.isEmpty()){\r
+                criteria.add(Restrictions.in("uuid", associationUuids));\r
+            }\r
+            else{\r
+                return null;\r
+            }\r
+        }\r
+        if(limit != null) {\r
+            if(start != null) {\r
+                criteria.setFirstResult(start);\r
+            } else {\r
+                criteria.setFirstResult(0);\r
+            }\r
+            criteria.setMaxResults(limit);\r
+        }\r
+\r
+        if(orderHints!=null){\r
+            addOrder(criteria,orderHints);\r
+        }\r
+        return criteria;\r
+    }\r
+\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> long countOccurrences(Class<T> clazz, String queryString,\r
+            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,\r
+            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+\r
+        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,\r
+                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);\r
+\r
+        if(criteria!=null){\r
+            criteria.setProjection(Projections.rowCount());\r
+            return (Long)criteria.uniqueResult();\r
+        }else{\r
+            return 0;\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {\r
+        List<UuidAndTitleCache<DerivedUnit>> list = new ArrayList<>();\r
+        Session session = getSession();\r
+        String hql = "SELECT uuid, id, titleCache "\r
+                + " FROM " + type.getSimpleName()\r
+                + " WHERE NOT dtype = " + FieldUnit.class.getSimpleName();\r
+        Query query;\r
+        if (pattern != null){\r
+            pattern = pattern.replace("*", "%");\r
+            pattern = pattern.replace("?", "_");\r
+            pattern = pattern + "%";\r
+            query = session.createQuery(hql +" AND titleCache like :pattern");\r
+            query.setParameter("pattern", pattern);\r
+        } else {\r
+            query = session.createQuery(hql);\r
+        }\r
+        if (limit != null){\r
+           query.setMaxResults(limit);\r
+        }\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<Object[]> result = query.list();\r
+\r
+        for(Object[] object : result){\r
+            list.add(new UuidAndTitleCache<DerivedUnit>(DerivedUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));\r
+        }\r
+\r
+        return list;\r
+    }\r
+\r
+    @Override\r
+    public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {\r
+        List<UuidAndTitleCache<FieldUnit>> list = new ArrayList<>();\r
+        Session session = getSession();\r
+\r
+        Query query = session.createQuery("select uuid, id, titleCache from " + type.getSimpleName() + " where dtype = " + FieldUnit.class.getSimpleName());\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<Object[]> result = query.list();\r
+\r
+        for(Object[] object : result){\r
+            list.add(new UuidAndTitleCache<FieldUnit>(FieldUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));\r
+        }\r
+\r
+        return list;\r
+    }\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxonName(Class<T> type,\r
+            TaxonName associatedTaxonName, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+\r
+        @SuppressWarnings("rawtypes")\r
+        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();\r
+\r
+        // A Taxon name may be referenced by the DeterminationEvent of the SpecimenOrObservationBase\r
+        @SuppressWarnings("rawtypes")\r
+        List<SpecimenOrObservationBase> byDetermination = list(type, associatedTaxonName, null, 0, null, null);\r
+        setOfAll.addAll(byDetermination);\r
+\r
+        if(setOfAll.size() == 0){\r
+            // no need querying the data base\r
+            return new ArrayList<T>();\r
+        }\r
+\r
+        String queryString =\r
+            "SELECT sob " +\r
+            " FROM SpecimenOrObservationBase sob" +\r
+            " WHERE sob in (:setOfAll)";\r
+\r
+        if(type != null && !type.equals(SpecimenOrObservationBase.class)){\r
+            queryString += " AND sob.class = :type";\r
+        }\r
+        queryString += orderByClause("sob", orderHints);\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameterList("setOfAll", setOfAll);\r
+\r
+        if(type != null && !type.equals(SpecimenOrObservationBase.class)){\r
+            query.setParameter("type", type.getSimpleName());\r
+        }\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<T> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    private List<SpecimenNodeWrapper> querySpecimen(Query query, List<UUID> taxonNodeUuids,\r
+            Integer limit, Integer start){\r
+        query.setParameterList("taxonNodeUuids", taxonNodeUuids);\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        List<SpecimenNodeWrapper> list = new ArrayList<>();\r
+        @SuppressWarnings("unchecked")\r
+        List<Object[]> result = query.list();\r
+        for(Object[] object : result){\r
+            SpecimenNodeWrapper wrapper = new SpecimenNodeWrapper(\r
+                    new UuidAndTitleCache<>(\r
+                            (UUID) object[0],\r
+                            (Integer) object[1],\r
+                            (String) object[2]),\r
+                    (SpecimenOrObservationType)object[3],\r
+                    new TaxonNodeDto((TaxonNode)object[4]));\r
+            if(object.length>5) {\r
+                wrapper.setTaxonDescriptionUuid((UUID)object[5]);\r
+            }\r
+            list.add(wrapper);\r
+        }\r
+        return list;\r
+    }\r
+\r
+    private List<SpecimenNodeWrapper> queryIndividualAssociatedSpecimen(List<UUID> taxonNodeUuids,\r
+            Integer limit, Integer start){\r
+        String queryString =  "SELECT "\r
+                + "de.associatedSpecimenOrObservation.uuid, "\r
+                + "de.associatedSpecimenOrObservation.id, "\r
+                + "de.associatedSpecimenOrObservation.titleCache, "\r
+                + "de.associatedSpecimenOrObservation.recordBasis, "\r
+                + "tn, "\r
+                + "d.uuid "\r
+                + "FROM DescriptionElementBase AS de "\r
+                + "LEFT JOIN de.inDescription AS d "\r
+                + "LEFT JOIN d.taxon AS t "\r
+                + "JOIN t.taxonNodes AS tn "\r
+                + "WHERE d.class = 'TaxonDescription' "\r
+                + "AND tn.uuid in (:taxonNodeUuids) "\r
+                ;\r
+        Query query = getSession().createQuery(queryString);\r
+        return querySpecimen(query, taxonNodeUuids, limit, start);\r
+    }\r
+\r
+    private List<SpecimenNodeWrapper> queryTypeSpecimen(List<UUID> taxonNodeUuids,\r
+            Integer limit, Integer start){\r
+        String queryString =  "SELECT "\r
+                + "td.typeSpecimen.uuid, "\r
+                + "td.typeSpecimen.id, "\r
+                + "td.typeSpecimen.titleCache, "\r
+                + "td.typeSpecimen.recordBasis, "\r
+                + "tn "\r
+                + "FROM SpecimenTypeDesignation AS td "\r
+                + "LEFT JOIN td.typifiedNames AS tn "\r
+                + "LEFT JOIN tn.taxonBases AS t "\r
+                + "JOIN t.taxonNodes AS tn "\r
+                + "WHERE tn.uuid in (:taxonNodeUuids) "\r
+                ;\r
+        Query query = getSession().createQuery(queryString);\r
+        return querySpecimen(query, taxonNodeUuids, limit, start);\r
+    }\r
+\r
+    private List<SpecimenNodeWrapper> queryTaxonDeterminations(List<UUID> taxonNodeUuids,\r
+            Integer limit, Integer start){\r
+        String queryString =  "SELECT "\r
+                + "det.identifiedUnit.uuid, "\r
+                + "det.identifiedUnit.id, "\r
+                + "det.identifiedUnit.titleCache, "\r
+                + "det.identifiedUnit.recordBasis, "\r
+                + "tn "\r
+                + "FROM DeterminationEvent AS det "\r
+                + "LEFT JOIN det.taxon AS t "\r
+                + "JOIN t.taxonNodes AS tn "\r
+                + "WHERE tn.uuid in (:taxonNodeUuids) "\r
+                ;\r
+        Query query = getSession().createQuery(queryString);\r
+        return querySpecimen(query, taxonNodeUuids, limit, start);\r
+    }\r
+\r
+    private List<SpecimenNodeWrapper> queryTaxonNameDeterminations(List<UUID> taxonNodeUuids,\r
+            Integer limit, Integer start){\r
+        String queryString =  "SELECT "\r
+                + "det.identifiedUnit.uuid, "\r
+                + "det.identifiedUnit.id, "\r
+                + "det.identifiedUnit.titleCache, "\r
+                + "det.identifiedUnit.recordBasis, "\r
+                + "tn "\r
+                + "FROM DeterminationEvent AS det "\r
+                + "LEFT JOIN det.taxonName AS n "\r
+                + "LEFT JOIN n.taxonBases AS t "\r
+                + "JOIN t.taxonNodes AS tn "\r
+                + "WHERE tn.uuid in (:taxonNodeUuids) "\r
+                ;\r
+        Query query = getSession().createQuery(queryString);\r
+        return querySpecimen(query, taxonNodeUuids, limit, start);\r
+    }\r
+\r
+    @Override\r
+    public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,\r
+            Integer limit, Integer start){\r
+\r
+        Set<SpecimenNodeWrapper> testSet = new HashSet();\r
+\r
+        testSet.addAll(queryIndividualAssociatedSpecimen(taxonNodeUuids, limit, start));\r
+        testSet.addAll(queryTaxonDeterminations(taxonNodeUuids, limit, start));\r
+        testSet.addAll(queryTaxonNameDeterminations(taxonNodeUuids, limit, start));\r
+        testSet.addAll(queryTypeSpecimen(taxonNodeUuids, limit, start));\r
+\r
+        Collection<SpecimenNodeWrapper> wrappers = new HashSet<>();\r
+        wrappers.addAll(testSet);\r
+        return wrappers;\r
+    }\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> listUuidAndTitleCacheByAssociatedTaxon(Class<T> clazz, Taxon associatedTaxon,\r
+            Integer limit, Integer start, List<OrderHint> orderHints){\r
+        Query query = createSpecimenQuery("sob.uuid, sob.id, sob.titleCache", clazz, associatedTaxon, limit, start, orderHints);\r
+        if(query==null){\r
+            return Collections.emptyList();\r
+        }\r
+        List<UuidAndTitleCache<SpecimenOrObservationBase>> list = new ArrayList<>();\r
+        @SuppressWarnings("unchecked")\r
+        List<Object[]> result = query.list();\r
+        for(Object[] object : result){\r
+            list.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));\r
+        }\r
+        return list;\r
+    }\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> clazz,\r
+            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        Query query = createSpecimenQuery("sob", clazz, associatedTaxon, limit, start, orderHints);\r
+        if(query==null){\r
+            return Collections.emptyList();\r
+        }\r
+        @SuppressWarnings("unchecked")\r
+        List<T> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    private <T extends SpecimenOrObservationBase> Query createSpecimenQuery(String select, Class<T> clazz,\r
+            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints){\r
+//        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();\r
+        Set<Integer> setOfAllIds = new HashSet<>();\r
+\r
+        Criteria criteria = null;\r
+        if(clazz == null) {\r
+            criteria = getSession().createCriteria(type, "specimen");\r
+        } else {\r
+            criteria = getSession().createCriteria(clazz, "specimen");\r
+        }\r
+\r
+        Disjunction determinationOr = Restrictions.disjunction();\r
+\r
+        // A Taxon may be referenced by the DeterminationEvent of the SpecimenOrObservationBase\r
+        Criteria determinationsCriteria = criteria.createCriteria("determinations");\r
+\r
+        determinationOr.add(Restrictions.eq("taxon", associatedTaxon));\r
+        //check also for synonyms\r
+        for (Synonym synonym : associatedTaxon.getSynonyms()) {\r
+            determinationOr.add(Restrictions.eq("taxon", synonym));\r
+        }\r
+\r
+        //check also for name determinations\r
+        determinationOr.add(Restrictions.eq("taxonName", associatedTaxon.getName()));\r
+        for (TaxonName synonymName : associatedTaxon.getSynonymNames()) {\r
+            determinationOr.add(Restrictions.eq("taxonName", synonymName));\r
+        }\r
+\r
+        determinationsCriteria.add(determinationOr);\r
+\r
+        if(limit != null) {\r
+            if(start != null) {\r
+                criteria.setFirstResult(start);\r
+            } else {\r
+                criteria.setFirstResult(0);\r
+            }\r
+            criteria.setMaxResults(limit);\r
+        }\r
+        criteria.setProjection(Projections.property("id"));\r
+\r
+        addOrder(criteria,orderHints);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<Integer> detResults = criteria.list();\r
+        setOfAllIds.addAll(detResults);\r
+\r
+        // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits\r
+        setOfAllIds.addAll(descriptionDao.getIndividualAssociationSpecimenIDs(\r
+                associatedTaxon.getUuid(), null, null, 0, null));\r
+\r
+\r
+        // SpecimenTypeDesignations may be associated with the TaxonName.\r
+        setOfAllIds.addAll(taxonNameDao.getTypeSpecimenIdsForTaxonName(\r
+                associatedTaxon.getName(), null, null, null));\r
+\r
+        // SpecimenTypeDesignations may be associated with any HomotypicalGroup related to the specific Taxon.\r
+        //TODO adapt to set of ids\r
+        for(HomotypicalGroup homotypicalGroup :  associatedTaxon.getHomotypicSynonymyGroups()) {\r
+            List<SpecimenTypeDesignation> byHomotypicalGroup = homotypicalGroupDao.getTypeDesignations(homotypicalGroup, SpecimenTypeDesignation.class, null, null, 0, null);\r
+            for (SpecimenTypeDesignation specimenTypeDesignation : byHomotypicalGroup) {\r
+                if (specimenTypeDesignation.getTypeSpecimen() != null){\r
+                    setOfAllIds.add(specimenTypeDesignation.getTypeSpecimen().getId());\r
+                }\r
+            }\r
+        }\r
+\r
+        if(setOfAllIds.size() == 0){\r
+            // no need querying the data base\r
+            return null;\r
+        }\r
+\r
+        String queryString =\r
+            "select "+select+\r
+            " from SpecimenOrObservationBase sob" +\r
+            " where sob.id in (:setOfAllIds)";\r
+\r
+        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){\r
+            queryString += " and sob.class = :type ";\r
+        }\r
+\r
+        if(orderHints != null && orderHints.size() > 0){\r
+            queryString += " order by ";\r
+            String orderStr = "";\r
+            for(OrderHint orderHint : orderHints){\r
+                if(orderStr.length() > 0){\r
+                    orderStr += ", ";\r
+                }\r
+                queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();\r
+            }\r
+            queryString += orderStr;\r
+        }\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameterList("setOfAllIds", setOfAllIds);\r
+\r
+        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){\r
+            query.setParameter("type", clazz.getSimpleName());\r
+        }\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        return query;\r
+    }\r
+\r
+    @Override\r
+    public Collection<SpecimenOrObservationBase> listBySpecimenOrObservationType(SpecimenOrObservationType type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        String queryString = "FROM SpecimenOrObservationBase specimens "\r
+                + " WHERE specimens.recordBasis = :type ";\r
+\r
+        queryString += orderByClause("specimens", orderHints);\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("type", type);\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        @SuppressWarnings({ "unchecked", "rawtypes" })\r
+        List<SpecimenOrObservationBase> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+\r
+    @Override\r
+    public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        String queryString = "FROM DeterminationEvent determination "\r
+                + " WHERE determination.identifiedUnit = :specimen";\r
+\r
+        queryString += orderByClause("determination", orderHints);\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("specimen", specimen);\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<DeterminationEvent> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    @Override\r
+    public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        String queryString = "FROM SpecimenTypeDesignation designations "\r
+                + " WHERE designations.typeSpecimen = :specimen";\r
+\r
+        queryString += orderByClause("designations", orderHints);\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("specimen", specimen);\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<SpecimenTypeDesignation> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+\r
+    @Override\r
+    public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        //DISTINCT is necessary if more than one description exists for a taxon because we create the cross product of all taxon descriptions and description elements\r
+        String queryString = "FROM IndividualsAssociation associations WHERE associations.associatedSpecimenOrObservation = :specimen";\r
+\r
+        queryString += orderByClause("associations", orderHints);\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("specimen", specimen);\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<IndividualsAssociation> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    @Override\r
+    public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        //DISTINCT is necessary if more than one description exists for a taxon because we create the cross product of all taxon descriptions and description elements\r
+        String queryString = "FROM DescriptionBase descriptions "\r
+                + " WHERE descriptions.describedSpecimenOrObservation = :specimen";\r
+\r
+        queryString += orderByClause("descriptions", orderHints);\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("specimen", specimen);\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<DescriptionBase<?>> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public List<FieldUnit> findFieldUnitsForGatheringEvent(UUID gatheringEventUuid, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        String queryString = "FROM SpecimenOrObservationBase sob "\r
+                + "WHERE sob.gatheringEvent.uuid = :gatheringEventUuid";\r
+\r
+        queryString += orderByClause("sob", orderHints);\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("gatheringEventUuid", gatheringEventUuid);\r
+\r
+        addLimitAndStart(query, limit, start);\r
+\r
+        @SuppressWarnings("unchecked")\r
+        List<FieldUnit> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    /**\r
+     *\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public DnaSample findByGeneticAccessionNumber(String accessionNumberString, List<String> propertyPaths) {\r
+        String queryString = "SELECT dnaSample FROM DnaSample as dnaSample join dnaSample.sequences as sequences WITH sequences.geneticAccessionNumber LIKE :accessionNumberString";\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("accessionNumberString", accessionNumberString);\r
+        @SuppressWarnings("unchecked")\r
+        List<DnaSample> dnaSamples = query.list();\r
+        defaultBeanInitializer.initializeAll(dnaSamples, propertyPaths);\r
+\r
+\r
+        if (dnaSamples.isEmpty()){\r
+            logger.debug("there is no dnaSample for genetic accession number " + accessionNumberString + " this should not happen.");\r
+            return null;\r
+        }else if (dnaSamples.size() == 1){\r
+            return dnaSamples.get(0);\r
+        } else{\r
+            logger.debug("there are more than one dnaSample for genetic accession number " + accessionNumberString + " this should not happen.");\r
+            return null;\r
+        }\r
+\r
+\r
+    }\r
+\r
+    /**\r
+    *\r
+    * {@inheritDoc}\r
+    */\r
+   @Override\r
+   public long countByGeneticAccessionNumber(String accessionNumberString) {\r
+       String queryString = "SELECT count(dnaSample) FROM DnaSample dnaSample JOIN dnaSample.sequences sequence WHERE sequence.geneticAccessionNumber LIKE :accessionNumberString";\r
+       Query query = getSession().createQuery(queryString);\r
+       query.setParameter("accessionNumberString", accessionNumberString);\r
+       @SuppressWarnings("unchecked")\r
+       List<DerivedUnit> dnaSamples = query.list();\r
+       long result = (long)query.uniqueResult();\r
+\r
+       return result;\r
+   }\r
+\r
+    /**\r
+     * @param dnaSamples\r
+     * @param results\r
+     */\r
+    private void extractDeterminedOriginals(List<DerivedUnit> samples, List<DerivedUnit> results) {\r
+        for (DerivedUnit sample:samples){\r
+            if (sample.getDeterminations() != null && !sample.getDeterminations().isEmpty()){\r
+                results.add(sample);\r
+            }else{\r
+                if (sample instanceof DerivedUnit){\r
+                    Set<SpecimenOrObservationBase> originals = sample.getDerivedFrom().getOriginals();\r
+                    List<DerivedUnit> originalDerivedUnits = new ArrayList();\r
+                    for (SpecimenOrObservationBase original:originals){\r
+                        if (original instanceof DerivedUnit){\r
+                            originalDerivedUnits.add((DerivedUnit)original);\r
+                        }\r
+                    }\r
+                    if(!originalDerivedUnits.isEmpty()){\r
+                        extractDeterminedOriginals(originalDerivedUnits, results);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public List<SpecimenOrObservationBase> findOriginalsForDerivedUnit(UUID derivedUnitUuid, List<String> propertyPaths) {\r
+        String queryString = "SELECT DISTINCT o FROM DerivedUnit du"\r
+                + " JOIN du.derivedFrom.originals o WHERE du.uuid LIKE :derivedUnitUuid";\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("derivedUnitUuid", derivedUnitUuid);\r
+        @SuppressWarnings("unchecked")\r
+        List<SpecimenOrObservationBase> results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public List<Point> findPointsForFieldUnitList(List<UUID> fieldUnitUuids) {\r
+        String queryString = "SELECT DISTINCT fu.gatheringEvent.exactLocation FROM FieldUnit fu"\r
+                + "  WHERE fu.uuid IN (:fieldUnitUuids)";\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameterList("fieldUnitUuids", fieldUnitUuids);\r
+        @SuppressWarnings("unchecked")\r
+        List<Point> results = query.list();\r
+\r
+        return results;\r
+    }\r
+\r
+}