When retrieving associated specimens retrieve all
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / occurrence / OccurrenceDaoHibernateImpl.java
index f4d5c996f0466ebe3e2010229a92d593adadd396..fd1320e57e84cc1dd394fb72d6083a9b6d8e4651 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
@@ -26,23 +28,18 @@ 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.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;\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.TypeDesignationBase;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;\r
-import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase;\r
 import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;\r
-import eu.etaxonomy.cdm.model.occurrence.FieldObservation;\r
-import eu.etaxonomy.cdm.model.occurrence.Fossil;\r
-import eu.etaxonomy.cdm.model.occurrence.LivingBeing;\r
-import eu.etaxonomy.cdm.model.occurrence.Observation;\r
-import eu.etaxonomy.cdm.model.occurrence.Specimen;\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.Taxon;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
 import eu.etaxonomy.cdm.model.view.AuditEvent;\r
@@ -52,6 +49,8 @@ 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.UuidAndTitleCache;\r
+import eu.etaxonomy.cdm.persistence.query.MatchMode;\r
 import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
 \r
 /**\r
@@ -60,387 +59,610 @@ import eu.etaxonomy.cdm.persistence.query.OrderHint;
  */\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] = FieldObservation.class;\r
-               indexedClasses[1] = DerivedUnit.class;\r
-               indexedClasses[2] = LivingBeing.class;\r
-               indexedClasses[3] = Observation.class;\r
-               indexedClasses[4] = Specimen.class;\r
-               indexedClasses[5] = DnaSample.class;\r
-               indexedClasses[6] = Fossil.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
+\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
+    @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
+    @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
             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
-            }\r
-            \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
-               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
-                       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
+                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
+    @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
+    @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 = query.list();\r
+        defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+        return result;\r
+    }\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
+            }\r
+\r
+            if(taxonBase != null) {\r
+                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
+            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
+            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 = query.getResultList();\r
+            defaultBeanInitializer.initializeAll(result, propertyPaths);\r
+            return result;\r
+        }\r
+    }\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 = 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 DerivedUnitBase) {\r
-                               DerivedUnitBase derivedUnit = (DerivedUnitBase) 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(FieldObservation.class)) {\r
-                                       FieldObservation fieldObservation = original.deproxy(original, FieldObservation.class);\r
-                                       Hibernate.initialize(fieldObservation.getGatheringEvent());\r
-                                       if(fieldObservation.getGatheringEvent() != null) {\r
-                                               Hibernate.initialize(fieldObservation.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#getDerivedUnitBaseUuidAndTitleCache()\r
-        */\r
-       @Override\r
-       public List<UuidAndTitleCache<DerivedUnitBase>> getDerivedUnitBaseUuidAndTitleCache() {\r
-               List<UuidAndTitleCache<DerivedUnitBase>> list = new ArrayList<UuidAndTitleCache<DerivedUnitBase>>();\r
-               Session session = getSession();\r
-               \r
-               Query query = session.createQuery("select uuid, titleCache from " + type.getSimpleName() + " where NOT dtype = " + FieldObservation.class.getSimpleName());\r
-               \r
-               List<Object[]> result = query.list();\r
-               \r
-               for(Object[] object : result){\r
-                       list.add(new UuidAndTitleCache<DerivedUnitBase>(DerivedUnitBase.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#getFieldObservationUuidAndTitleCache()\r
-        */\r
-       @Override\r
-       public List<UuidAndTitleCache<FieldObservation>> getFieldObservationUuidAndTitleCache() {\r
-               List<UuidAndTitleCache<FieldObservation>> list = new ArrayList<UuidAndTitleCache<FieldObservation>>();\r
-               Session session = getSession();\r
-               \r
-               Query query = session.createQuery("select uuid, titleCache from " + type.getSimpleName() + " where dtype = " + FieldObservation.class.getSimpleName());\r
-               \r
-               List<Object[]> result = query.list();\r
-               \r
-               for(Object[] object : result){\r
-                       list.add(new UuidAndTitleCache<FieldObservation>(FieldObservation.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 DerivedUnitBases \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
+\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
+    @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
+    @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 = criteria.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> List<T> findOccurrences(Class<T> clazz, String queryString,\r
+            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon,\r
+            MatchMode matchmode, Integer limit,\r
+            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+\r
+        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,\r
+                associatedTaxon, matchmode, limit, start, orderHints, propertyPaths);\r
+\r
+        if(criteria!=null){\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
+\r
+            List<T> results = criteria.list();\r
+            defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+            return results;\r
+        }\r
+        return Collections.EMPTY_LIST;\r
+    }\r
+\r
+    /**\r
+     * @param clazz\r
+     * @param queryString\r
+     * @param recordBasis\r
+     * @param associatedTaxon\r
+     * @param matchmode\r
+     * @param limit\r
+     * @param start\r
+     * @param orderHints\r
+     * @param propertyPaths\r
+     * @return\r
+     */\r
+    private <T extends SpecimenOrObservationBase> Criteria createFindOccurrenceCriteria(Class<T> clazz, String queryString,\r
+            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, 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<SpecimenOrObservationType>();\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
+        //taxon associations\r
+        if(associatedTaxon!=null){\r
+            List<UUID> associatedTaxonUuids = new ArrayList<UUID>();\r
+            List<? extends SpecimenOrObservationBase> associatedTaxaList = listByAssociatedTaxon(clazz, associatedTaxon, limit, start, orderHints, propertyPaths);\r
+            if(associatedTaxaList!=null){\r
+                for (SpecimenOrObservationBase specimenOrObservationBase : associatedTaxaList) {\r
+                    associatedTaxonUuids.add(specimenOrObservationBase.getUuid());\r
+                }\r
+            }\r
+            if(!associatedTaxonUuids.isEmpty()){\r
+                criteria.add(Restrictions.in("uuid", associatedTaxonUuids));\r
+            }\r
+            else{\r
+                return null;\r
+            }\r
+        }\r
+\r
+        return criteria;\r
+    }\r
+\r
+\r
+    @Override\r
+    public <T extends SpecimenOrObservationBase> int countOccurrences(Class<T> clazz, String queryString,\r
+            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon,\r
+            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,\r
+                associatedTaxon, matchmode, limit, start, orderHints, propertyPaths);\r
+\r
+        if(criteria!=null){\r
+\r
+            criteria.setProjection(Projections.rowCount());\r
+\r
+            return ((Number)criteria.uniqueResult()).intValue();\r
+        }\r
+        return 0;\r
+    }\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, id, 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], (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<UuidAndTitleCache<FieldUnit>>();\r
+        Session session = getSession();\r
+\r
+        Query query = session.createQuery("select uuid, id, 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], (Integer)object[1], (String) object[2]));\r
+        }\r
+\r
+        return list;\r
+    }\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.getUuid(), 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 = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\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 WHERE specimens.recordBasis = :type";\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 += "specimens." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();\r
+            }\r
+            queryString += orderStr;\r
+        }\r
+\r
+        Query query = getSession().createQuery(queryString);\r
+        query.setParameter("type", type);\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
+        List 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
+\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
+\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
+\r
+        List results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\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
+\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
+\r
+        List 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 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
+\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
+\r
+        List results = query.list();\r
+        defaultBeanInitializer.initializeAll(results, propertyPaths);\r
+        return results;\r
+    }\r
+\r
 }
\ No newline at end of file