cleanup
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / occurrence / OccurrenceDaoHibernateImpl.java
index b6d395cec0604122f152eb40ef367c26ce7f157d..6c33f68e1f6e260f3e905cd7c204ec968d52995e 100644 (file)
@@ -8,6 +8,7 @@ package eu.etaxonomy.cdm.persistence.dao.hibernate.occurrence;
 \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
@@ -18,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
@@ -27,20 +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
@@ -48,16 +56,21 @@ 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
+public class OccurrenceDaoHibernateImpl\r
+          extends IdentifiableDaoBase<SpecimenOrObservationBase>\r
+          implements IOccurrenceDao {\r
 \r
-    @SuppressWarnings("unused")\r
     private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);\r
 \r
     @Autowired\r
@@ -77,26 +90,20 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
         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
+    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()).intValue();\r
+        return (Long)query.uniqueResult();\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
+    public long countDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase) {\r
         AuditEvent auditEvent = getAuditEventFromContext();\r
         if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {\r
-            Criteria criteria = getSession().createCriteria(DeterminationEvent.class);\r
+            Criteria criteria = getCriteria(DeterminationEvent.class);\r
             if(occurrence != null) {\r
                 criteria.add(Restrictions.eq("identifiedUnit",occurrence));\r
             }\r
@@ -106,9 +113,9 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
             }\r
 \r
             criteria.setProjection(Projections.rowCount());\r
-            return ((Number)criteria.uniqueResult()).intValue();\r
+            return (Long)criteria.uniqueResult();\r
         } else {\r
-            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());\r
+            AuditQuery query = makeAuditQuery(DeterminationEvent.class,auditEvent);\r
 \r
             if(occurrence != null) {\r
                 query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));\r
@@ -117,52 +124,38 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
             if(taxonBase != null) {\r
                 query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));\r
             }\r
-            query.addProjection(AuditEntity.id().count("id"));\r
+            query.addProjection(AuditEntity.id().count());\r
 \r
-            return ((Long)query.getSingleResult()).intValue();\r
+            return (Long)query.getSingleResult();\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
+    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 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
+        return (Long)query.uniqueResult();\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 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
+        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
-    /* (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
+    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
@@ -174,14 +167,9 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
                 criteria.add(Restrictions.eq("taxon",taxonBase));\r
             }\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
+            addPageSizeAndNumber(criteria, pageSize, pageNumber);\r
+\r
+            @SuppressWarnings("unchecked")\r
             List<DeterminationEvent> result = criteria.list();\r
             defaultBeanInitializer.initializeAll(result, propertyPaths);\r
             return result;\r
@@ -194,53 +182,41 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
             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
+            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
-    /* (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
+    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("select media from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");\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
-        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
+        addPageSizeAndNumber(query, pageSize, pageNumber);\r
 \r
+        @SuppressWarnings("unchecked")\r
         List<Media> results = 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
         FullTextSession fullTextSession = Search.getFullTextSession(getSession());\r
 \r
-        for(SpecimenOrObservationBase occurrence : list(null,null)) { // re-index all taxon base\r
+        for(SpecimenOrObservationBase<?> occurrence : list(null,null)) { // re-index all taxon base\r
 \r
-            for(DeterminationEvent determination : (Set<DeterminationEvent>)occurrence.getDeterminations()) {\r
+            for(DeterminationEvent determination : occurrence.getDeterminations()) {\r
                 Hibernate.initialize(determination.getActor());\r
                 Hibernate.initialize(determination.getTaxon());\r
             }\r
@@ -253,9 +229,9 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
                     Hibernate.initialize(derivedUnit.getCollection().getInstitute());\r
                 }\r
                 Hibernate.initialize(derivedUnit.getStoredUnder());\r
-                SpecimenOrObservationBase original = derivedUnit.getOriginalUnit();\r
+                SpecimenOrObservationBase<?> original = derivedUnit.getOriginalUnit();\r
                 if(original != null && original.isInstanceOf(FieldUnit.class)) {\r
-                    FieldUnit fieldUnit = original.deproxy(original, 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
@@ -267,38 +243,179 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
         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
+    public long count(Class<? extends SpecimenOrObservationBase> clazz,        TaxonName determinedAs) {\r
 \r
-        Criteria criteria = null;\r
-        if(clazz == null) {\r
-            criteria = getSession().createCriteria(type);\r
-        } else {\r
-            criteria = getSession().createCriteria(clazz);\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 ((Number)criteria.uniqueResult()).intValue();\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
-    /* (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
+    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
-        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));\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
@@ -308,98 +425,341 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
             criteria.setMaxResults(limit);\r
         }\r
 \r
-        addOrder(criteria,orderHints);\r
+        if(orderHints!=null){\r
+            addOrder(criteria,orderHints);\r
+        }\r
+        return criteria;\r
+    }\r
 \r
-        List<SpecimenOrObservationBase> results = criteria.list();\r
-        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
-        return results;\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
-    /* (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
+    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
-        Query query = session.createQuery("select uuid, titleCache from " + type.getSimpleName() + " where NOT 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<DerivedUnit>(DerivedUnit.class, (UUID) object[0], (String) object[1]));\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
-    /* (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
+        List<UuidAndTitleCache<FieldUnit>> list = new ArrayList<>();\r
         Session session = getSession();\r
 \r
-        Query query = session.createQuery("select uuid, titleCache from " + type.getSimpleName() + " where dtype = " + FieldUnit.class.getSimpleName());\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], (String) object[1]));\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
-    /* (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
+    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
-        Set<SpecimenOrObservationBase> setOfAll = new HashSet<SpecimenOrObservationBase>();\r
+        Disjunction determinationOr = Restrictions.disjunction();\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
+        Criteria determinationsCriteria = criteria.createCriteria("determinations");\r
 \r
-        // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits\r
-        List<IndividualsAssociation> byIndividualsAssociation = descriptionDao.getDescriptionElementForTaxon(\r
-                associatedTaxon.getUuid(), null, IndividualsAssociation.class, null, 0, null);\r
-        for(IndividualsAssociation individualsAssociation : byIndividualsAssociation){\r
-            setOfAll.add(individualsAssociation.getAssociatedSpecimenOrObservation());\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
-        // 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
+        //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
-                setOfAll.add(specimenTypeDesignation.getTypeSpecimen());\r
+                if (specimenTypeDesignation.getTypeSpecimen() != null){\r
+                    setOfAllIds.add(specimenTypeDesignation.getTypeSpecimen().getId());\r
+                }\r
             }\r
         }\r
 \r
-        if(setOfAll.size() == 0){\r
+        if(setOfAllIds.size() == 0){\r
             // no need querying the data base\r
-            return new ArrayList<T>();\r
+            return null;\r
         }\r
 \r
         String queryString =\r
-            "select sob " +\r
+            "select "+select+\r
             " from SpecimenOrObservationBase sob" +\r
-            " where sob in (:setOfAll)";\r
+            " where sob.id in (:setOfAllIds)";\r
 \r
-        if(type != null){\r
-            queryString += " and sob.class = :type";\r
+        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){\r
+            queryString += " and sob.class = :type ";\r
         }\r
 \r
         if(orderHints != null && orderHints.size() > 0){\r
@@ -415,132 +775,227 @@ public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrOb
         }\r
 \r
         Query query = getSession().createQuery(queryString);\r
-        query.setParameterList("setOfAll", setOfAll);\r
+        query.setParameterList("setOfAllIds", setOfAllIds);\r
 \r
-        if(type != null){\r
-            query.setParameter("type", type.getSimpleName());\r
+        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){\r
+            query.setParameter("type", clazz.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
+        addLimitAndStart(query, limit, start);\r
 \r
+        return query;\r
+    }\r
 \r
-        List<T> results = query.list();\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 WHERE designations.typeSpecimen = :specimen";\r
+        String queryString = "FROM SpecimenTypeDesignation designations "\r
+                + " WHERE designations.typeSpecimen = :specimen";\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 += "designations." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();\r
-            }\r
-            queryString += orderStr;\r
-        }\r
+        queryString += orderByClause("designations", orderHints);\r
 \r
         Query query = getSession().createQuery(queryString);\r
         query.setParameter("specimen", specimen);\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
+        addLimitAndStart(query, limit, start);\r
 \r
-        List results = query.list();\r
+        @SuppressWarnings("unchecked")\r
+        List<SpecimenTypeDesignation> results = query.list();\r
         defaultBeanInitializer.initializeAll(results, propertyPaths);\r
         return results;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#listAssociatedTaxa(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)\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
-        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 += "associations." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();\r
-            }\r
-            queryString += orderStr;\r
-        }\r
+        queryString += orderByClause("associations", orderHints);\r
 \r
         Query query = getSession().createQuery(queryString);\r
         query.setParameter("specimen", specimen);\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
+        addLimitAndStart(query, limit, start);\r
 \r
-        List results = query.list();\r
+        @SuppressWarnings("unchecked")\r
+        List<IndividualsAssociation> results = query.list();\r
         defaultBeanInitializer.initializeAll(results, propertyPaths);\r
         return results;\r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao#listAssociatedTaxa(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)\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 WHERE descriptions.describedSpecimenOrObservation = :specimen";\r
+        String queryString = "FROM DescriptionBase descriptions "\r
+                + " WHERE descriptions.describedSpecimenOrObservation = :specimen";\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 += "descriptions." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();\r
-            }\r
-            queryString += orderStr;\r
-        }\r
+        queryString += orderByClause("descriptions", orderHints);\r
 \r
         Query query = getSession().createQuery(queryString);\r
         query.setParameter("specimen", specimen);\r
 \r
-        if(limit != null) {\r
-            if(start != null) {\r
-                query.setFirstResult(start);\r
-            } else {\r
-                query.setFirstResult(0);\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
-            query.setMaxResults(limit);\r
         }\r
+    }\r
 \r
-        List results = query.list();\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
-}
\ No newline at end of file
+    /**\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
+}