cleanup
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / OccurrenceServiceImpl.java
index d606965f37163a97663b45bbf19e3e5490de9a15..270fb3af85c01e2979bb300dde7cf366b20193e9 100644 (file)
@@ -1,4 +1,3 @@
-// $Id$
 /**
  * Copyright (C) 2007 EDIT
  * European Distributed Institute of Taxonomy
@@ -19,6 +18,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -26,7 +26,6 @@ import java.util.Set;
 import java.util.UUID;
 
 import org.apache.log4j.Logger;
-import org.apache.lucene.index.CorruptIndexException;
 import org.apache.lucene.queryparser.classic.ParseException;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery.Builder;
@@ -47,9 +46,9 @@ import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
 import eu.etaxonomy.cdm.api.service.UpdateResult.Status;
 import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
 import eu.etaxonomy.cdm.api.service.config.FindOccurrencesConfigurator;
-import eu.etaxonomy.cdm.api.service.config.FindOccurrencesConfigurator.AssignmentStatus;
 import eu.etaxonomy.cdm.api.service.config.IIdentifiableEntityServiceConfigurator;
 import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;
+import eu.etaxonomy.cdm.api.service.dto.DNASampleDTO;
 import eu.etaxonomy.cdm.api.service.dto.DerivateDTO;
 import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO;
 import eu.etaxonomy.cdm.api.service.dto.DerivateDataDTO.ContigFile;
@@ -63,6 +62,7 @@ import eu.etaxonomy.cdm.api.service.pager.Pager;
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
 import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;
 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
+import eu.etaxonomy.cdm.api.service.search.LuceneParseException;
 import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
 import eu.etaxonomy.cdm.api.service.search.QueryFactory;
 import eu.etaxonomy.cdm.api.service.search.SearchResult;
@@ -70,13 +70,14 @@ import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
 import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;
 import eu.etaxonomy.cdm.common.CdmUtils;
 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
+import eu.etaxonomy.cdm.format.CdmFormatterFactory;
+import eu.etaxonomy.cdm.format.ICdmFormatter.FormatKey;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
 import eu.etaxonomy.cdm.model.CdmBaseType;
 import eu.etaxonomy.cdm.model.agent.AgentBase;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.common.DefinedTerm;
 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
-import eu.etaxonomy.cdm.model.common.ICdmBase;
 import eu.etaxonomy.cdm.model.common.Language;
 import eu.etaxonomy.cdm.model.description.CategoricalData;
 import eu.etaxonomy.cdm.model.description.DescriptionBase;
@@ -87,6 +88,7 @@ import eu.etaxonomy.cdm.model.description.SpecimenDescription;
 import eu.etaxonomy.cdm.model.description.TaxonDescription;
 import eu.etaxonomy.cdm.model.location.Country;
 import eu.etaxonomy.cdm.model.location.NamedArea;
+import eu.etaxonomy.cdm.model.location.Point;
 import eu.etaxonomy.cdm.model.media.Media;
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;
 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
@@ -96,7 +98,7 @@ import eu.etaxonomy.cdm.model.molecular.DnaSample;
 import eu.etaxonomy.cdm.model.molecular.Sequence;
 import eu.etaxonomy.cdm.model.molecular.SingleRead;
 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
-import eu.etaxonomy.cdm.model.name.TaxonNameBase;
+import eu.etaxonomy.cdm.model.name.TaxonName;
 import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
 import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
@@ -110,15 +112,17 @@ import eu.etaxonomy.cdm.model.taxon.Taxon;
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
 import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
-import eu.etaxonomy.cdm.persistence.dao.molecular.ISingleReadDao;
 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
+import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
+import eu.etaxonomy.cdm.persistence.query.AssignmentStatus;
 import eu.etaxonomy.cdm.persistence.query.OrderHint;
 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
+import eu.etaxonomy.cdm.strategy.cache.common.IdentifiableEntityDefaultCacheStrategy;
 
 /**
  * @author a.babadshanjan
- * @created 01.09.2008
+ * @since 01.09.2008
  */
 @Service
 @Transactional(readOnly = true)
@@ -136,13 +140,13 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     private INameService nameService;
 
     @Autowired
-    private ITaxonService taxonService;
+    private IEventBaseService eventService;
 
     @Autowired
-    private ISequenceService sequenceService;
+    private ITaxonService taxonService;
 
     @Autowired
-    private ISingleReadDao singleReadDao;
+    private ISequenceService sequenceService;
 
     @Autowired
     private AbstractBeanInitializer beanInitializer;
@@ -152,6 +156,16 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
     private static final String SEPARATOR_STRING = ", ";
 
+    private static final List<String> DERIVED_UNIT_INIT_STRATEGY =  Arrays.asList(new String []{
+            "derivedFrom.derivatives",
+            "derivedFrom.originals",
+            "specimenTypeDesignations.*",
+            "specimenTypeDesignations.citation.*",
+            "specimenTypeDesignations.homotypicalGroup.*",
+            "specimenTypeDesignations.typifiedNames",
+            "collection.$"
+    });
+
     public OccurrenceServiceImpl() {
         logger.debug("Load OccurrenceService Bean");
     }
@@ -182,8 +196,8 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
      */
     @Override
     public List<Country> getCountryByName(String name) {
-        List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitle(Country.class, name, null, null, null, null, null, null);
-        List<Country> countries = new ArrayList<Country>();
+        List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitleWithRestrictions(Country.class, name, null, null, null, null, null, null);
+        List<Country> countries = new ArrayList<>();
         for (int i = 0; i < terms.size(); i++) {
             countries.add((Country) terms.get(i));
         }
@@ -198,9 +212,9 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
     @Override
     public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
-        Integer numberOfResults = dao.countDerivationEvents(occurence);
+        long numberOfResults = dao.countDerivationEvents(occurence);
 
-        List<DerivationEvent> results = new ArrayList<DerivationEvent>();
+        List<DerivationEvent> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = dao.getDerivationEvents(occurence, pageSize, pageNumber, propertyPaths);
         }
@@ -209,27 +223,28 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     }
 
     @Override
-    public int countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
+    public long countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
         return dao.countDeterminations(occurence, taxonbase);
     }
 
     @Override
-    public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
-        Integer numberOfResults = dao.countDeterminations(occurrence, taxonBase);
+    public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase,
+            Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
+        long numberOfResults = dao.countDeterminations(occurrence, taxonBase);
 
-        List<DeterminationEvent> results = new ArrayList<DeterminationEvent>();
+        List<DeterminationEvent> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = dao.getDeterminations(occurrence, taxonBase, pageSize, pageNumber, propertyPaths);
         }
 
-        return new DefaultPagerImpl<DeterminationEvent>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
     @Override
     public Pager<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
-        Integer numberOfResults = dao.countMedia(occurence);
+        long numberOfResults = dao.countMedia(occurence);
 
-        List<Media> results = new ArrayList<Media>();
+        List<Media> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
             results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);
         }
@@ -240,7 +255,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     @Override
     public Pager<Media> getMediainHierarchy(SpecimenOrObservationBase rootOccurence, Integer pageSize,
             Integer pageNumber, List<String> propertyPaths) {
-        List<Media> media = new ArrayList<Media>();
+        List<Media> media = new ArrayList<>();
         //media specimens
         if(rootOccurence.isInstanceOf(MediaSpecimen.class)){
             MediaSpecimen mediaSpecimen = HibernateProxyHelper.deproxy(rootOccurence, MediaSpecimen.class);
@@ -252,7 +267,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             Set<Sequence> sequences = dnaSample.getSequences();
             //we do show only those gelPhotos which lead to a consensus sequence
             for (Sequence sequence : sequences) {
-                Set<Media> dnaRelatedMedia = new HashSet<Media>();
+                Set<Media> dnaRelatedMedia = new HashSet<>();
                 for (SingleRead singleRead : sequence.getSingleReads()){
                     AmplificationResult amplification = singleRead.getAmplificationResult();
                     dnaRelatedMedia.add(amplification.getGelPhoto());
@@ -270,36 +285,36 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                 }
             }
         }
-        return new DefaultPagerImpl<Media>(pageNumber, media.size(), pageSize, media);
+        return new DefaultPagerImpl<Media>(pageNumber, Long.valueOf(media.size()), pageSize, media);
     }
 
     @Override
-    public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonNameBase determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
-        Integer numberOfResults = dao.count(type, determinedAs);
-        List<SpecimenOrObservationBase> results = new ArrayList<SpecimenOrObservationBase>();
-        pageNumber = pageNumber == null ? 0 : pageNumber;
+    public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonName determinedAs,
+            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+        long numberOfResults = dao.count(type, determinedAs);
+        @SuppressWarnings("rawtypes")
+        List<SpecimenOrObservationBase> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
-            Integer start = pageSize == null ? 0 : pageSize * pageNumber;
-            results = dao.list(type, determinedAs, pageSize, start, orderHints, propertyPaths);
+            results = dao.list(type, determinedAs, pageSize, pageNumber, orderHints, propertyPaths);
         }
-        return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
     @Override
-    public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
-        Integer numberOfResults = dao.count(type, determinedAs);
-        List<SpecimenOrObservationBase> results = new ArrayList<SpecimenOrObservationBase>();
-        pageNumber = pageNumber == null ? 0 : pageNumber;
+    public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs,
+            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
+        long numberOfResults = dao.count(type, determinedAs);
+        @SuppressWarnings("rawtypes")
+        List<SpecimenOrObservationBase> results = new ArrayList<>();
         if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
-            Integer start = pageSize == null ? 0 : pageSize * pageNumber;
-            results = dao.list(type, determinedAs, pageSize, start, orderHints, propertyPaths);
+            results = dao.list(type, determinedAs, pageSize, pageNumber, orderHints, propertyPaths);
         }
-        return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
+        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
     }
 
     @Override
-    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache() {
-        return dao.getDerivedUnitUuidAndTitleCache();
+    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {
+        return dao.getDerivedUnitUuidAndTitleCache(limit, pattern);
     }
 
     @Override
@@ -321,7 +336,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     public List<DerivedUnitFacade> listDerivedUnitFacades(
             DescriptionBase description, List<String> propertyPaths) {
 
-        List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<DerivedUnitFacade>();
+        List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<>();
         IndividualsAssociation tempIndividualsAssociation;
         SpecimenOrObservationBase tempSpecimenOrObservationBase;
         List<IndividualsAssociation> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
@@ -352,6 +367,12 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
     }
 
+    @Override
+    public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,
+            Integer limit, Integer start) {
+        return dao.listUuidAndTitleCacheByAssociatedTaxon(taxonNodeUuids, limit, start);
+        }
+
     @Override
     public Collection<SpecimenOrObservationBase> listFieldUnitsByAssociatedTaxon(Taxon associatedTaxon, List<OrderHint> orderHints, List<String> propertyPaths) {
         return pageFieldUnitsByAssociatedTaxon(null, associatedTaxon, null, null, null, null, propertyPaths).getRecords();
@@ -367,33 +388,32 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         }
 
         // gather the IDs of all relevant field units
-        Set<UUID> fieldUnitUuids = new HashSet<UUID>();
+        Set<UUID> fieldUnitUuids = new HashSet<>();
         List<SpecimenOrObservationBase> records = listByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, null, null, orderHints, propertyPaths);
         for (SpecimenOrObservationBase<?> specimen : records) {
-            for (FieldUnit fieldUnit : getFieldUnits(specimen.getUuid())) {
+            for (FieldUnit fieldUnit : findFieldUnits(specimen.getUuid(), null)) {
                 fieldUnitUuids.add(fieldUnit.getUuid());
             }
         }
         //dao.list() does the paging of the field units. Passing the field units directly to the Pager would not work
         List<SpecimenOrObservationBase> fieldUnits = dao.list(fieldUnitUuids, pageSize, pageNumber, orderHints, propertyPaths);
-        return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, fieldUnitUuids.size(), pageSize, fieldUnits);
+        return new DefaultPagerImpl<>(pageNumber, fieldUnitUuids.size(), pageSize, fieldUnits);
     }
 
     @Override
-    public FieldUnitDTO assembleFieldUnitDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid) {
+    public FieldUnitDTO assembleFieldUnitDTO(FieldUnit fieldUnit) {
 
         if (!getSession().contains(fieldUnit)) {
             fieldUnit = (FieldUnit) load(fieldUnit.getUuid());
         }
-        TaxonBase associatedTaxon = taxonService.load(associatedTaxonUuid);
 
-        FieldUnitDTO fieldUnitDTO = new FieldUnitDTO();
+        FieldUnitDTO fieldUnitDTO = new FieldUnitDTO(fieldUnit);
 
         if (fieldUnit.getGatheringEvent() != null) {
             GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
             // Country
             NamedArea country = gatheringEvent.getCountry();
-            fieldUnitDTO.setCountry(country != null ? country.getDescription() : null);
+            fieldUnitDTO.setCountry(country != null ? country.getLabel() : null);
             // Collection
             AgentBase collector = gatheringEvent.getCollector();
             String fieldNumber = fieldUnit.getFieldNumber();
@@ -411,7 +431,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             Partial gatheringDate = gatheringEvent.getGatheringDate();
             String dateString = null;
             if (gatheringDate != null) {
-                gatheringDate.toString();
+                dateString = gatheringDate.toString();
             }
             else if(gatheringEvent.getTimeperiod()!=null && gatheringEvent.getTimeperiod().getFreeText()!=null){
                 dateString = gatheringEvent.getTimeperiod().getFreeText();
@@ -419,13 +439,10 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             fieldUnitDTO.setDate(dateString);
         }
 
-        // Taxon Name
-        fieldUnitDTO.setTaxonName(associatedTaxon.getName().getTitleCache());
-
         // Herbaria map
-        Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();
+        Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<>();
         // List of accession numbers for citation
-        List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();
+        List<String> preservedSpecimenAccessionNumbers = new ArrayList<>();
 
         // assemble preserved specimen DTOs
         Set<DerivationEvent> derivationEvents = fieldUnit.getDerivationEvents();
@@ -436,21 +453,27 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                     continue;
                 }
                 // collect accession numbers for citation
-                String mostSignificantIdentifier = getMostSignificantIdentifier(derivedUnit);
-                if (mostSignificantIdentifier != null) {
-                    preservedSpecimenAccessionNumbers.add(mostSignificantIdentifier);
-                }
+                String identifier = getMostSignificantIdentifier(derivedUnit);
                 // collect collections for herbaria column
-                if (derivedUnit.getCollection() != null) {
-                    Integer herbariumCount = collectionToCountMap.get(derivedUnit.getCollection());
+                eu.etaxonomy.cdm.model.occurrence.Collection collection = derivedUnit.getCollection();
+                if (collection != null) {
+                    //combine collection with identifier
+                    if (identifier != null) {
+                        if(collection.getCode()!=null){
+                            identifier = (collection.getCode()!=null?collection.getCode():"[no collection]")+" "+identifier;
+                        }
+                        preservedSpecimenAccessionNumbers.add(identifier);
+                    }
+
+                    Integer herbariumCount = collectionToCountMap.get(collection);
                     if (herbariumCount == null) {
                         herbariumCount = 0;
                     }
-                    collectionToCountMap.put(derivedUnit.getCollection(), herbariumCount + 1);
+                    collectionToCountMap.put(collection, herbariumCount + 1);
                 }
                 if (derivedUnit.getRecordBasis().equals(SpecimenOrObservationType.PreservedSpecimen)) {
                     PreservedSpecimenDTO preservedSpecimenDTO = assemblePreservedSpecimenDTO(derivedUnit, fieldUnitDTO);
-                    fieldUnitDTO.addPreservedSpecimenDTO(preservedSpecimenDTO);
+                    fieldUnitDTO.addDerivate(preservedSpecimenDTO);
                     fieldUnitDTO.setHasCharacterData(fieldUnitDTO.isHasCharacterData() || preservedSpecimenDTO.isHasCharacterData());
                     fieldUnitDTO.setHasDetailImage(fieldUnitDTO.isHasDetailImage() || preservedSpecimenDTO.isHasDetailImage());
                     fieldUnitDTO.setHasDna(fieldUnitDTO.isHasDna() || preservedSpecimenDTO.isHasDna());
@@ -463,7 +486,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
         // assemble citation
         String citation = fieldUnit.getTitleCache();
-        if((CdmUtils.isBlank(citation) || citation.contains("title cache generation not implemented"))
+        if((CdmUtils.isBlank(citation) || citation.equals(IdentifiableEntityDefaultCacheStrategy.TITLE_CACHE_GENERATION_NOT_IMPLEMENTED))
                 && !fieldUnit.isProtectedTitleCache()){
             fieldUnit.setTitleCache(null);
             citation = fieldUnit.getTitleCache();
@@ -493,7 +516,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             herbariaString += SEPARATOR_STRING;
         }
         herbariaString = removeTail(herbariaString, SEPARATOR_STRING);
-        fieldUnitDTO.setHerbarium(herbariaString);
+        fieldUnitDTO.setCollection(herbariaString);
 
         return fieldUnitDTO;
     }
@@ -521,33 +544,31 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         if (!getSession().contains(derivedUnit)) {
             derivedUnit = (DerivedUnit) load(derivedUnit.getUuid());
         }
-        PreservedSpecimenDTO preservedSpecimenDTO = new PreservedSpecimenDTO();
+        PreservedSpecimenDTO preservedSpecimenDTO = new PreservedSpecimenDTO(derivedUnit);
 
-        // check identifiers in priority order accNo>barCode>catalogNumber>collection
-        String identifier = derivedUnit.getMostSignificantIdentifier();
-        if(CdmUtils.isBlank(identifier) && derivedUnit.getCollection()!=null){
-               identifier = derivedUnit.getCollection().toString();
+        //specimen identifier
+        FormatKey collectionKey = FormatKey.COLLECTION_CODE;
+        String specimenIdentifier = CdmFormatterFactory.format(derivedUnit, collectionKey);
+        if (CdmUtils.isBlank(specimenIdentifier)) {
+            collectionKey = FormatKey.COLLECTION_NAME;
         }
-        if(CdmUtils.isBlank(identifier)){
-               identifier = derivedUnit.getTitleCache();
-               if(CdmUtils.isBlank(identifier) && !derivedUnit.isProtectedTitleCache()){
-                       //regenerate title cache if it is empty
-                       derivedUnit.setTitleCache(null);
-                       identifier = derivedUnit.getTitleCache();
-               }
+        specimenIdentifier = CdmFormatterFactory.format(derivedUnit, new FormatKey[] {
+                collectionKey, FormatKey.SPACE,
+                FormatKey.MOST_SIGNIFICANT_IDENTIFIER, FormatKey.SPACE });
+        if(CdmUtils.isBlank(specimenIdentifier)){
+            specimenIdentifier = derivedUnit.getTitleCache();
         }
-        if(CdmUtils.isBlank(identifier)){
-               //default fallback UUID
-               identifier = derivedUnit.getUuid().toString();
+        if(CdmUtils.isBlank(specimenIdentifier)){
+            specimenIdentifier = derivedUnit.getUuid().toString();
         }
-        preservedSpecimenDTO.setAccessionNumber(identifier);
-        preservedSpecimenDTO.setUuid(derivedUnit.getUuid().toString());
+        preservedSpecimenDTO.setAccessionNumber(specimenIdentifier);
+
 
         //preferred stable URI
         preservedSpecimenDTO.setPreferredStableUri(derivedUnit.getPreferredStableUri());
 
         // citation
-        Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);
+        Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit, null);
         if (fieldUnits.size() == 1) {
             preservedSpecimenDTO.setCitation(fieldUnits.iterator().next().getTitleCache());
         }
@@ -564,7 +585,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         }
         for (DescriptionElementBase descriptionElementBase : characterDataForSpecimen) {
             String character = descriptionElementBase.getFeature().getLabel();
-            ArrayList<Language> languages = new ArrayList<Language>(Collections.singleton(Language.DEFAULT()));
+            ArrayList<Language> languages = new ArrayList<>(Collections.singleton(Language.DEFAULT()));
             if (descriptionElementBase instanceof QuantitativeData) {
                 QuantitativeData quantitativeData = (QuantitativeData) descriptionElementBase;
                 DefaultQuantitativeDescriptionBuilder builder = new DefaultQuantitativeDescriptionBuilder();
@@ -585,15 +606,12 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                 fieldUnitDTO.setHasType(true);
             }
             TypeDesignationStatusBase<?> typeStatus = specimenTypeDesignation.getTypeStatus();
-            if (typeStatus != null) {
-                List<String> typedTaxaNames = new ArrayList<String>();
-                String label = typeStatus.getLabel();
-                Set<TaxonNameBase> typifiedNames = specimenTypeDesignation.getTypifiedNames();
-                for (TaxonNameBase taxonNameBase : typifiedNames) {
-                    typedTaxaNames.add(taxonNameBase.getFullTitleCache());
-                }
-                preservedSpecimenDTO.addTypes(label, typedTaxaNames);
+            Set<TaxonName> typifiedNames = specimenTypeDesignation.getTypifiedNames();
+            List<String> typedTaxaNames = new ArrayList<>();
+            for (TaxonName taxonName : typifiedNames) {
+                typedTaxaNames.add(taxonName.getTitleCache());
             }
+            preservedSpecimenDTO.addTypes(typeStatus!=null?typeStatus.getLabel():"", typedTaxaNames);
         }
 
         // individuals associations
@@ -725,7 +743,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     }
 
     private Collection<DerivedUnit> getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen) {
-        Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();
+        Collection<DerivedUnit> derivedUnits = new ArrayList<>();
         for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
             for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
                 derivedUnits.add(derivative);
@@ -735,15 +753,58 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         return derivedUnits;
     }
 
+    private Set<DerivateDTO> getDerivedUnitDTOsFor(DerivateDTO specimenDto, DerivedUnit specimen, HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen) {
+        Set<DerivateDTO> derivedUnits = new HashSet<>();
+//        load
+        for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
+            for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
+                if (!alreadyCollectedSpecimen.containsKey(specimenDto.getUuid())){
+                    PreservedSpecimenDTO dto;
+                    if (derivative instanceof DnaSample) {
+                        dto = new DNASampleDTO(derivative);
+                    } else {
+                        dto = new PreservedSpecimenDTO(derivative);
+                    }
+                    alreadyCollectedSpecimen.put(dto.getUuid(), dto);
+                    dto.addAllDerivates(getDerivedUnitDTOsFor(dto, derivative, alreadyCollectedSpecimen));
+                    derivedUnits.add(dto);
+                }
+            }
+        }
+        return derivedUnits;
+    }
+
+//    private Set<DerivateDTO> getDerivedUnitDTOsFor(DerivateDTO specimenDto, DerivedUnit specimen, HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen) {
+//        Set<DerivateDTO> derivedUnits = new HashSet<>();
+////        load
+//        for (DerivationEvent derivationEvent : specimen.getDerivationEvents()) {
+//            for (DerivedUnit derivative : derivationEvent.getDerivatives()) {
+//                if (!alreadyCollectedSpecimen.containsKey(specimenDto.getUuid())){
+//                    PreservedSpecimenDTO dto;
+//                    if (derivative instanceof DnaSample){
+//                        dto = DNASampleDTO.newInstance(derivative);
+//                    }else{
+//                        dto = PreservedSpecimenDTO.newInstance(derivative);
+//                    }
+//                    alreadyCollectedSpecimen.put(dto.getUuid(), dto);
+//                    dto.addAllDerivates(getDerivedUnitDTOsFor(dto, derivative, alreadyCollectedSpecimen));
+//                    derivedUnits.add(dto);
+//                }
+//            }
+//        }
+//        return derivedUnits;
+//    }
+
 
     @SuppressWarnings("unchecked")
     @Override
-    public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
+    public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includedRelationships,
             Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
 
-        Set<Taxon> taxa = new HashSet<Taxon>();
-        Set<Integer> occurrenceIds = new HashSet<Integer>();
-        List<T> occurrences = new ArrayList<T>();
+        Set<Taxon> taxa = new HashSet<>();
+        Set<Integer> occurrenceIds = new HashSet<>();
+        List<T> occurrences = new ArrayList<>();
+        boolean includeUnpublished = INCLUDE_UNPUBLISHED;
 
         // Integer limit = PagerUtils.limitFor(pageSize);
         // Integer start = PagerUtils.startFor(pageSize, pageNumber);
@@ -752,21 +813,21 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
         }
 
-        if (includeRelationships != null) {
-            taxa = taxonService.listRelatedTaxa(associatedTaxon, includeRelationships, maxDepth, null, null, propertyPaths);
+        if (includedRelationships != null) {
+            taxa = taxonService.listRelatedTaxa(associatedTaxon, includedRelationships, maxDepth, includeUnpublished, null, null, propertyPaths);
         }
 
         taxa.add(associatedTaxon);
 
         for (Taxon taxon : taxa) {
             List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);
-            for (SpecimenOrObservationBase o : perTaxonOccurrences) {
+            for (SpecimenOrObservationBase<?> o : perTaxonOccurrences) {
                 occurrenceIds.add(o.getId());
             }
         }
         occurrences = (List<T>) dao.loadList(occurrenceIds, propertyPaths);
 
-        return new DefaultPagerImpl<T>(pageNumber, occurrenceIds.size(), pageSize, occurrences);
+        return new DefaultPagerImpl<T>(pageNumber, Long.valueOf(occurrences.size()), pageSize, occurrences);
 
     }
 
@@ -782,18 +843,90 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
     }
 
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<FieldUnitDTO> findFieldUnitDTOByAssociatedTaxon(Set<TaxonRelationshipEdge> includedRelationships,
+            UUID associatedTaxonUuid) {
+
+        Set<Taxon> taxa = new HashSet<>();
+        Set<Integer> occurrenceIds = new HashSet<>();
+        List<FieldUnitDTO> fieldUnitDTOs = new ArrayList<>();
+        HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen = new HashMap<>();
+        List<SpecimenOrObservationBase> occurrences = new ArrayList<>();
+        boolean includeUnpublished = INCLUDE_UNPUBLISHED;
+
+        // Integer limit = PagerUtils.limitFor(pageSize);
+        // Integer start = PagerUtils.startFor(pageSize, pageNumber);
+
+        Taxon associatedTaxon = (Taxon) taxonService.load(associatedTaxonUuid);
+
+
+        if (includedRelationships != null) {
+            taxa = taxonService.listRelatedTaxa(associatedTaxon, includedRelationships, null, includeUnpublished, null, null, null);
+        }
+
+        taxa.add(associatedTaxon);
+
+        for (Taxon taxon : taxa) {
+            List<SpecimenOrObservationBase> perTaxonOccurrences = dao.listByAssociatedTaxon(null,taxon, null, null, null, DERIVED_UNIT_INIT_STRATEGY);
+            for (SpecimenOrObservationBase<?> o : perTaxonOccurrences) {
+                if (o.isInstanceOf(DerivedUnit.class)){
+                    DerivedUnit derivedUnit;
+                    DerivateDTO derivedUnitDTO;
+                    if (o.isInstanceOf(DnaSample.class)) {
+                         derivedUnit = HibernateProxyHelper.deproxy(o, DnaSample.class);
+                        derivedUnitDTO = new DNASampleDTO(derivedUnit);
+                    } else {
+                        derivedUnit = HibernateProxyHelper.deproxy(o, DerivedUnit.class);
+                        derivedUnitDTO = new PreservedSpecimenDTO(derivedUnit);
+                    }
+                    if (alreadyCollectedSpecimen.get(derivedUnitDTO.getUuid()) == null){
+                        alreadyCollectedSpecimen.put(derivedUnitDTO.getUuid(), derivedUnitDTO);
+                    }
+                    derivedUnitDTO.addAllDerivates(getDerivedUnitDTOsFor(derivedUnitDTO, derivedUnit, alreadyCollectedSpecimen));
+                    this.findFieldUnitDTO(derivedUnitDTO, fieldUnitDTOs, alreadyCollectedSpecimen);
+                }
+            }
+
+        }
+
+        return fieldUnitDTOs;
+
+    }
+
+
+
+    @Override
+    public  List<DerivedUnit> findByAccessionNumber(
+            String accessionNumberString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
+            List<String> propertyPaths)  {
+
+        List<DerivedUnit> records = new ArrayList<>();
+        records = dao.findByGeneticAccessionNumber(accessionNumberString, propertyPaths);
+
+        return records;
+
+    }
+
     @Override
     public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(
             Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,
             boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
-            List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
+            List<String> propertyPaths) throws IOException, LuceneParseException {
 
         LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
 
         // --- execute search
-        TopGroups<BytesRef> topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
+        TopGroups<BytesRef> topDocsResultSet;
+        try {
+            topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
+        } catch (ParseException e) {
+            LuceneParseException parseException = new LuceneParseException(e.getMessage());
+            parseException.setStackTrace(e.getStackTrace());
+            throw parseException;
+        }
 
-        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
+        Map<CdmBaseType, String> idFieldMap = new HashMap<>();
         idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");
 
         // --- initialize taxa, highlight matches ....
@@ -804,8 +937,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
         int totalHits = topDocsResultSet != null ? topDocsResultSet.totalGroupCount : 0;
 
-        return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,
-                searchResults);
+        return new DefaultPagerImpl<>(pageNumber, Long.valueOf(totalHits), pageSize, searchResults);
 
     }
 
@@ -844,40 +976,96 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
 
     @Override
-    public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {
+    public Collection<FieldUnit> findFieldUnits(UUID derivedUnitUuid, List<String> propertyPaths) {
         //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
         //from which this DerivedUnit was derived until all FieldUnits are found.
 
         // FIXME: use HQL queries to increase performance
-        SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);
+        SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid, propertyPaths);
 //        specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
-        Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();
+        Collection<FieldUnit> fieldUnits = new ArrayList<>();
 
         if (specimen.isInstanceOf(FieldUnit.class)) {
             fieldUnits.add(HibernateProxyHelper.deproxy(specimen, FieldUnit.class));
         }
         else if(specimen.isInstanceOf(DerivedUnit.class)){
-            fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class)));
+            fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class), propertyPaths));
         }
         return fieldUnits;
     }
 
-    private Collection<FieldUnit> getFieldUnits(DerivedUnit derivedUnit) {
-        Collection<FieldUnit> fieldUnits = new HashSet<FieldUnit>();
+    private Collection<FieldUnit> getFieldUnits(DerivedUnit derivedUnit, List<String> propertyPaths) {
+        Collection<FieldUnit> fieldUnits = new HashSet<>();
         Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
         if (originals != null && !originals.isEmpty()) {
             for (SpecimenOrObservationBase<?> original : originals) {
                 if (original.isInstanceOf(FieldUnit.class)) {
-                    fieldUnits.add(HibernateProxyHelper.deproxy(original, FieldUnit.class));
+                    fieldUnits.add((FieldUnit) load(original.getUuid(), propertyPaths));
                 }
                 else if(original.isInstanceOf(DerivedUnit.class)){
-                    fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(original, DerivedUnit.class)));
+                    fieldUnits.addAll(getFieldUnits(HibernateProxyHelper.deproxy(original, DerivedUnit.class), propertyPaths));
                 }
             }
         }
         return fieldUnits;
     }
 
+
+
+    @Override
+    public FieldUnitDTO findFieldUnitDTO(DerivateDTO derivedUnitDTO, Collection<FieldUnitDTO> fieldUnits, HashMap<UUID, DerivateDTO> alreadyCollectedSpecimen) {
+        //It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
+        //from which this DerivedUnit was derived until all FieldUnits are found.
+        List<SpecimenOrObservationBase> specimens = new ArrayList<>();
+        List<String> propertyPaths = new ArrayList<>();
+
+        propertyPaths.add("descriptions.elements.media.title");
+        propertyPaths.add("kindOfUnit");
+
+        specimens = dao.findOriginalsForDerivedUnit(derivedUnitDTO.getUuid(), propertyPaths);
+
+        if (specimens.size() > 1){
+            logger.debug("The derived unit with uuid " + derivedUnitDTO.getUuid() + "has more than one orginal");
+        }
+      //  for (SpecimenOrObservationBase specimen: specimens){
+        SpecimenOrObservationBase specimen = null;
+        if (specimens.size() > 0){
+            specimen = specimens.get(0);
+        }else{
+            return null;
+        }
+        FieldUnitDTO fieldUnitDto = null;
+        if (alreadyCollectedSpecimen.get(specimen.getUuid()) != null){
+            alreadyCollectedSpecimen.get(specimen.getUuid()).addDerivate(derivedUnitDTO);
+            if ( alreadyCollectedSpecimen.get(specimen.getUuid()) instanceof FieldUnitDTO){
+                ((FieldUnitDTO)alreadyCollectedSpecimen.get(specimen.getUuid())).getTaxonRelatedDerivedUnits().add(derivedUnitDTO.getUuid());
+            }
+        }else{
+            if (specimen.isInstanceOf(FieldUnit.class)){
+                fieldUnitDto = FieldUnitDTO.newInstance((FieldUnit)specimen);
+                fieldUnitDto.addDerivate(derivedUnitDTO);
+                fieldUnits.add(fieldUnitDto);
+            }else{
+                DerivateDTO originalDTO;
+                if (specimen instanceof DnaSample){
+                    originalDTO = new DNASampleDTO((DnaSample)specimen);
+                } else {
+                    originalDTO = new PreservedSpecimenDTO((DerivedUnit)specimen);
+                }
+                originalDTO.addDerivate(derivedUnitDTO);
+                fieldUnitDto = findFieldUnitDTO(originalDTO, fieldUnits, alreadyCollectedSpecimen);
+            }
+
+        }
+      //  }
+        alreadyCollectedSpecimen.put(derivedUnitDTO.getUuid(), derivedUnitDTO);
+        if (fieldUnitDto != null){
+            fieldUnitDto.addTaxonRelatedDerivedUnits(derivedUnitDTO);
+        }
+        return fieldUnitDto;
+
+    }
+
     @Override
     @Transactional(readOnly = false)
     public UpdateResult moveSequence(DnaSample from, DnaSample to, Sequence sequence) {
@@ -977,121 +1165,6 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         return result;
     }
 
-    @Override
-    public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen) {
-        // potential fields that are not persisted cascadingly
-        /*
-         * SOOB
-        -DescriptionBase
-        -determinations
-        --modifier TERM
-        -kindOfUnit TERM
-        -lifeStage TERM
-        -sex TERM
-
-        FieldUnit
-        -GatheringEvent
-        --Country TERM
-        --CollectingAreas TERM
-
-        DerivedUnit
-        -collection
-        --institute
-        ---types TERM
-        -preservationMethod
-        --medium TERM
-        -storedUnder CDM TaxonNameBase
-         */
-
-        Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
-
-        //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
-
-        // FieldUnit
-        if (specimen.isInstanceOf(FieldUnit.class)) {
-            nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(HibernateProxyHelper.deproxy(specimen, FieldUnit.class)));
-        }
-        // DerivedUnit
-        else if (specimen.isInstanceOf(DerivedUnit.class)) {
-            DerivedUnit derivedUnit = HibernateProxyHelper.deproxy(specimen, DerivedUnit.class);
-            if (derivedUnit.getDerivedFrom() != null) {
-                Collection<FieldUnit> fieldUnits = getFieldUnits(derivedUnit);
-                for (FieldUnit fieldUnit : fieldUnits) {
-                    nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));
-                }
-            }
-        }
-        return nonCascadedCdmEntities;
-    }
-
-    private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit) {
-        // get non cascaded element on SpecimenOrObservationBase level
-        Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);
-
-        // get FieldUnit specific elements
-        GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
-        if (gatheringEvent != null) {
-            // country
-            if (gatheringEvent.getCountry() != null) {
-                nonCascadedCdmEntities.add(gatheringEvent.getCountry());
-            }
-            // collecting areas
-            for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {
-                nonCascadedCdmEntities.add(namedArea);
-            }
-        }
-        for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {
-            for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {
-                nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));
-            }
-        }
-        return nonCascadedCdmEntities;
-    }
-
-    private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit) {
-        // get non cascaded element on SpecimenOrObservationBase level
-        Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);
-
-        // get DerivedUnit specific elements
-        if (derivedUnit.getCollection() != null && derivedUnit.getCollection().getInstitute() != null) {
-            for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {
-                nonCascadedCdmEntities.add(type);
-            }
-        }
-        if (derivedUnit.getPreservation() != null && derivedUnit.getPreservation().getMedium() != null) {
-            nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());
-        }
-        if (derivedUnit.getStoredUnder() != null) {
-            nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());
-        }
-        return nonCascadedCdmEntities;
-    }
-
-    private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(
-            SpecimenOrObservationBase<?> specimen) {
-        Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
-        // scan SpecimenOrObservationBase
-        for (DeterminationEvent determinationEvent : specimen.getDeterminations()) {
-            // modifier
-            if (determinationEvent.getModifier() != null) {
-                nonCascadedCdmEntities.add(determinationEvent.getModifier());
-            }
-        }
-        // kindOfUnit
-        if (specimen.getKindOfUnit() != null) {
-            nonCascadedCdmEntities.add(specimen.getKindOfUnit());
-        }
-        // lifeStage
-        if (specimen.getLifeStage() != null) {
-            nonCascadedCdmEntities.add(specimen.getLifeStage());
-        }
-        // sex
-        if (specimen.getSex() != null) {
-            nonCascadedCdmEntities.add(specimen.getSex());
-        }
-        return nonCascadedCdmEntities;
-    }
-
     @Override
     public DeleteResult isDeletable(UUID specimenUuid, DeleteConfiguratorBase config) {
         DeleteResult deleteResult = new DeleteResult();
@@ -1104,14 +1177,14 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             // check for type designation
             if (cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()) {
                 deleteResult.setAbort();
-                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));
+                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is a type specimen."));
                 deleteResult.addRelatedObject(cdmBase);
                 break;
             }
             // check for IndividualsAssociations
             else if (cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()) {
                 deleteResult.setAbort();
-                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated via IndividualsAssociations"));
+                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still associated via IndividualsAssociations"));
                 deleteResult.addRelatedObject(cdmBase);
                 break;
             }
@@ -1120,7 +1193,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                     && HibernateProxyHelper.deproxy(cdmBase, TaxonDescription.class).getDescribedSpecimenOrObservation().equals(specimen)
                     && !specimenDeleteConfigurator.isDeleteFromDescription()){
                 deleteResult.setAbort();
-                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still used as \"Described Specimen\" in a taxon description."));
+                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation is still used as \"Described Specimen\" in a taxon description."));
                 deleteResult.addRelatedObject(cdmBase);
                 break;
             }
@@ -1137,7 +1210,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                     if(!specimenDeleteConfigurator.isDeleteChildren()){
                         //if children should not be deleted then it is undeletable
                         deleteResult.setAbort();
-                        deleteResult.addException(new ReferencedObjectUndeletableException("Derivative still has child derivatives."));
+                        deleteResult.addException(new ReferencedObjectUndeletableException("Specimen or obeservation still has child derivatives."));
                         deleteResult.addRelatedObject(cdmBase);
                         break;
                     }
@@ -1198,23 +1271,32 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
         specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
 
+        DeleteResult deleteResult = isDeletable(specimen.getUuid(), config);
+        if (!deleteResult.isOk()) {
+            return deleteResult;
+        }
+
         if (config.isDeleteChildren()) {
             Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
             //clone to avoid concurrent modification
             //can happen if the child is deleted and deleted its own derivedFrom event
-            Set<DerivationEvent> derivationEventsClone = new HashSet<DerivationEvent>(derivationEvents);
+            Set<DerivationEvent> derivationEventsClone = new HashSet<>(derivationEvents);
             for (DerivationEvent derivationEvent : derivationEventsClone) {
                 Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
-                for (DerivedUnit derivedUnit : derivatives) {
-                    delete(derivedUnit, config);
+                Iterator<DerivedUnit> it = derivatives.iterator();
+                Set<DerivedUnit> derivativesToDelete = new HashSet<>();
+                while (it.hasNext()) {
+                    DerivedUnit unit = it.next();
+                    derivativesToDelete.add(unit);
+                }
+                for (DerivedUnit unit:derivativesToDelete){
+                    deleteResult.includeResult(delete(unit, config));
                 }
             }
         }
 
-        DeleteResult deleteResult = isDeletable(specimen.getUuid(), config);
-        if (!deleteResult.isOk()) {
-            return deleteResult;
-        }
+
+
 
         // check related objects
         Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
@@ -1224,10 +1306,10 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             if (relatedObject.isInstanceOf(SpecimenTypeDesignation.class)) {
                 SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);
                 designation.setTypeSpecimen(null);
-                List<TaxonNameBase> typifiedNames = new ArrayList<TaxonNameBase>();
+                List<TaxonName> typifiedNames = new ArrayList<>();
                 typifiedNames.addAll(designation.getTypifiedNames());
-                for (TaxonNameBase taxonNameBase : typifiedNames) {
-                    taxonNameBase.removeTypeDesignation(designation);
+                for (TaxonName taxonName : typifiedNames) {
+                    taxonName.removeTypeDesignation(designation);
                 }
             }
             // delete IndividualsAssociation
@@ -1251,7 +1333,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                 }
                 DeleteResult descriptionDelete = descriptionService.isDeletable(specimenDescription.getUuid(), null);
                 if (descriptionDelete.isOk()){
-                    descriptionService.delete(specimenDescription);
+                    deleteResult.includeResult(descriptionService.delete(specimenDescription));
                 }
             }
             // check for amplification
@@ -1276,6 +1358,8 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                             specimenOrObservationBase.removeDerivationEvent(derivationEvent);
                             deleteResult.addUpdatedObject(specimenOrObservationBase);
                         }
+                        // if derivationEvent has no derivates anymore, delete it
+                        deleteResult.includeResult(eventService.delete(derivationEvent));
                     }
                 }
                 else{
@@ -1283,7 +1367,18 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                 }
             }
         }
+        if (specimen instanceof FieldUnit){
+            FieldUnit fieldUnit = HibernateProxyHelper.deproxy(specimen, FieldUnit.class);
+            GatheringEvent event = fieldUnit.getGatheringEvent();
+            fieldUnit.setGatheringEvent(null);
+            if (event != null){
+                DeleteResult result = eventService.isDeletable(event.getUuid(), null);
+                if (result.isOk()){
+                    deleteResult.includeResult( eventService.delete(event));
+                }
+            }
 
+        }
         deleteResult.includeResult(delete(specimen));
 
         return deleteResult;
@@ -1291,68 +1386,109 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
     @Override
     public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
-        return dao.listIndividualsAssociations(specimen, null, null, null, null);
+        return dao.listIndividualsAssociations(specimen, limit, start, orderHints, propertyPaths);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start,
-            List<OrderHint> orderHints, List<String> propertyPaths) {
-        Collection<TaxonBase<?>> associatedTaxa = new HashSet<TaxonBase<?>>();
+    public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit,
+            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+        return listAssociatedTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
+    }
+    @Override
+    public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, boolean includeUnpublished,
+            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
 
         //individuals associations
-        associatedTaxa.addAll(listIndividualsAssociationTaxa(specimen, limit, start, orderHints, propertyPaths));
+        associatedTaxa.addAll(listIndividualsAssociationTaxa(specimen, includeUnpublished, limit, start, orderHints, propertyPaths));
         //type designation
         if(specimen.isInstanceOf(DerivedUnit.class)){
-            associatedTaxa.addAll(listTypeDesignationTaxa(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class), limit, start, orderHints, propertyPaths));
+            associatedTaxa.addAll(listTypeDesignationTaxa(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class),
+                  includeUnpublished, limit, start, orderHints, propertyPaths));
         }
         //determinations
-        associatedTaxa.addAll(listDeterminedTaxa(specimen, limit, start, orderHints, propertyPaths));
+        associatedTaxa.addAll(listDeterminedTaxa(specimen, includeUnpublished, limit, start, orderHints, propertyPaths));
 
         return associatedTaxa;
     }
 
 
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Collection<TaxonBase<?>> listDeterminedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit,
+            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+        return listDeterminedTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
+    }
     @Override
-    public Collection<TaxonBase<?>> listDeterminedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start,
+    public Collection<TaxonBase<?>> listDeterminedTaxa(SpecimenOrObservationBase<?> specimen, boolean includeUnpublished, Integer limit, Integer start,
             List<OrderHint> orderHints, List<String> propertyPaths) {
-        Collection<TaxonBase<?>> associatedTaxa = new HashSet<TaxonBase<?>>();
+        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
         for (DeterminationEvent determinationEvent : listDeterminationEvents(specimen, limit, start, orderHints, propertyPaths)) {
             if(determinationEvent.getIdentifiedUnit().equals(specimen)){
                 if(determinationEvent.getTaxon()!=null){
-                    associatedTaxa.add(determinationEvent.getTaxon());
+                    associatedTaxa.add(taxonService.load(determinationEvent.getTaxon().getUuid(), includeUnpublished, propertyPaths));
                 }
                 if(determinationEvent.getTaxonName()!=null){
-                    associatedTaxa.addAll(determinationEvent.getTaxonName().getTaxonBases());
+                    Collection<TaxonBase> taxonBases = determinationEvent.getTaxonName().getTaxonBases();
+                    for (TaxonBase taxonBase : taxonBases) {
+                        associatedTaxa.add(taxonService.load(taxonBase.getUuid(), includeUnpublished, propertyPaths));
+                    }
                 }
             }
         }
         return associatedTaxa;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public Collection<TaxonBase<?>> listTypeDesignationTaxa(DerivedUnit specimen, Integer limit, Integer start,
             List<OrderHint> orderHints, List<String> propertyPaths) {
-        Collection<TaxonBase<?>> associatedTaxa = new HashSet<TaxonBase<?>>();
+        return listTypeDesignationTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
+    }
+    @Override
+    public Collection<TaxonBase<?>> listTypeDesignationTaxa(DerivedUnit specimen, boolean includeUnpublished,
+            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
         for (SpecimenTypeDesignation typeDesignation : listTypeDesignations(specimen, limit, start, orderHints, propertyPaths)) {
             if(typeDesignation.getTypeSpecimen().equals(specimen)){
-                Set<TaxonNameBase> typifiedNames = typeDesignation.getTypifiedNames();
-                for (TaxonNameBase taxonNameBase : typifiedNames) {
-                    associatedTaxa.addAll(taxonNameBase.getTaxa());
+                Set<TaxonName> typifiedNames = typeDesignation.getTypifiedNames();
+                for (TaxonName taxonName : typifiedNames) {
+                    Set<Taxon> taxa = taxonName.getTaxa();
+                    for (Taxon taxon : taxa) {
+                        associatedTaxa.add(taxonService.load(taxon.getUuid(), includeUnpublished, propertyPaths));
+                    }
                 }
             }
         }
         return associatedTaxa;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public Collection<TaxonBase<?>> listIndividualsAssociationTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start,
-            List<OrderHint> orderHints, List<String> propertyPaths) {
-        Collection<TaxonBase<?>> associatedTaxa = new HashSet<TaxonBase<?>>();
-        for (IndividualsAssociation individualsAssociation : listIndividualsAssociations(specimen, limit, start, orderHints, propertyPaths)) {
+    public Collection<TaxonBase<?>> listIndividualsAssociationTaxa(SpecimenOrObservationBase<?> specimen, Integer limit,
+            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+        return listIndividualsAssociationTaxa(specimen, INCLUDE_UNPUBLISHED, limit, start, orderHints, propertyPaths);
+    }
+
+    @Override
+    public Collection<TaxonBase<?>> listIndividualsAssociationTaxa(SpecimenOrObservationBase<?> specimen, boolean includeUnpublished,
+            Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
+        Collection<TaxonBase<?>> associatedTaxa = new HashSet<>();
+        for (IndividualsAssociation individualsAssociation : listIndividualsAssociations(specimen, null, null, null, null)) {
             if(individualsAssociation.getInDescription().isInstanceOf(TaxonDescription.class)){
                 TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(individualsAssociation.getInDescription(), TaxonDescription.class);
                 if(taxonDescription.getTaxon()!=null){
-                    associatedTaxa.add(taxonDescription.getTaxon());
+                    associatedTaxa.add(taxonService.load(taxonDescription.getTaxon().getUuid(), includeUnpublished, propertyPaths));
                 }
             }
         }
@@ -1369,7 +1505,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     public Map<DerivedUnit, Collection<SpecimenTypeDesignation>> listTypeDesignations(
             Collection<DerivedUnit> specimens, Integer limit, Integer start,
             List<OrderHint> orderHints, List<String> propertyPaths) {
-        Map<DerivedUnit, Collection<SpecimenTypeDesignation>> typeDesignationMap = new HashMap<DerivedUnit, Collection<SpecimenTypeDesignation>>();
+        Map<DerivedUnit, Collection<SpecimenTypeDesignation>> typeDesignationMap = new HashMap<>();
         for (DerivedUnit specimen : specimens) {
             Collection<SpecimenTypeDesignation> typeDesignations = listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
             typeDesignationMap.put(specimen, typeDesignations);
@@ -1396,7 +1532,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         if (specimen != null) {
             return specimen.characterData();
         }else{
-            return new ArrayList<DescriptionElementBase>();
+            return new ArrayList<>();
         }
     }
 
@@ -1413,68 +1549,141 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
 
     @Override
-    public Pager<SpecimenOrObservationBase> findByTitle(
-            IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config) {
+    public long countByTitle(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
         if (config instanceof FindOccurrencesConfigurator) {
             FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
-            List<SpecimenOrObservationBase> occurrences = new ArrayList<SpecimenOrObservationBase>();
             Taxon taxon = null;
             if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
-                TaxonBase taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
+                TaxonBase<?> taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
                 if(taxonBase.isInstanceOf(Taxon.class)){
                     taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
                 }
             }
-            TaxonNameBase taxonName = null;
+            TaxonName taxonName = null;
             if(occurrenceConfig.getAssociatedTaxonNameUuid()!=null){
                 taxonName = nameService.load(occurrenceConfig.getAssociatedTaxonNameUuid());
             }
-            occurrences.addAll(dao.findOccurrences(occurrenceConfig.getClazz(),
+            /*TODO: #6484 Neither isRetrieveIndirectlyAssociatedSpecimens() nor the AssignmentStatus
+             * is currently reflected in the HQL query. So using these in the count method will
+             * significantly slow down this method as we have to retreive the entities instead of
+             * the just the amount.
+             */
+            if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens() || !occurrenceConfig.getAssignmentStatus().equals(AssignmentStatus.ALL_SPECIMENS)){
+                List<SpecimenOrObservationBase> occurrences = new ArrayList<>();
+                occurrences.addAll(dao.findOccurrences(occurrenceConfig.getClazz(),
+                        occurrenceConfig.getTitleSearchStringSqlized(), occurrenceConfig.getSignificantIdentifier(),
+                        occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
+                        occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths()));
+                occurrences = filterOccurencesByAssignmentAndHierarchy(occurrenceConfig, occurrences, taxon, taxonName);
+                return occurrences.size();
+            }
+
+            return dao.countOccurrences(occurrenceConfig.getClazz(),
+                    occurrenceConfig.getTitleSearchStringSqlized(), occurrenceConfig.getSignificantIdentifier(),
+                    occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
+                    occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths());
+        }
+        else{
+            return super.countByTitle(config);
+        }
+    }
+
+    @Override
+    public Pager<UuidAndTitleCache<SpecimenOrObservationBase>> findByTitleUuidAndTitleCache(
+            FindOccurrencesConfigurator config){
+        List<UuidAndTitleCache<SpecimenOrObservationBase>> occurrences = new ArrayList<>();
+        Taxon taxon = null;
+        if(config.getAssociatedTaxonUuid()!=null){
+            TaxonBase<?> taxonBase = taxonService.load(config.getAssociatedTaxonUuid());
+            if(taxonBase.isInstanceOf(Taxon.class)){
+                taxon = CdmBase.deproxy(taxonBase, Taxon.class);
+            }
+        }
+        TaxonName taxonName = null;
+        if(config.getAssociatedTaxonNameUuid()!=null){
+            taxonName = nameService.load(config.getAssociatedTaxonNameUuid());
+        }
+        occurrences.addAll(dao.findOccurrencesUuidAndTitleCache(config.getClazz(),
+                config.getTitleSearchString(), config.getSignificantIdentifier(),
+                config.getSpecimenType(), taxon, taxonName, config.getMatchMode(), null, null,
+                config.getOrderHints()));
+
+        return new DefaultPagerImpl<>(config.getPageNumber(), occurrences.size(), config.getPageSize(), occurrences);
+    }
+
+    @Override
+    public <S extends SpecimenOrObservationBase> Pager<S> findByTitle(
+            IIdentifiableEntityServiceConfigurator<S> config) {
+        if (config instanceof FindOccurrencesConfigurator) {
+            FindOccurrencesConfigurator occurrenceConfig = (FindOccurrencesConfigurator) config;
+            List<SpecimenOrObservationBase> occurrences = new ArrayList<>();
+            Taxon taxon = null;
+            if(occurrenceConfig.getAssociatedTaxonUuid()!=null){
+                TaxonBase<?> taxonBase = taxonService.load(occurrenceConfig.getAssociatedTaxonUuid());
+                if(taxonBase.isInstanceOf(Taxon.class)){
+                    taxon = HibernateProxyHelper.deproxy(taxonBase, Taxon.class);
+                }
+            }
+            TaxonName taxonName = null;
+            if(occurrenceConfig.getAssociatedTaxonNameUuid()!=null){
+                taxonName = nameService.load(occurrenceConfig.getAssociatedTaxonNameUuid());
+            }
+            List<? extends SpecimenOrObservationBase> foundOccurrences = dao.findOccurrences(occurrenceConfig.getClazz(),
                     occurrenceConfig.getTitleSearchString(), occurrenceConfig.getSignificantIdentifier(),
                     occurrenceConfig.getSpecimenType(), taxon, taxonName, occurrenceConfig.getMatchMode(), null, null,
-                    occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths()));
-            //filter out (un-)assigned specimens
-            if(taxon==null && taxonName==null){
-                AssignmentStatus assignmentStatus = occurrenceConfig.getAssignmentStatus();
-                List<SpecimenOrObservationBase<?>> specimenWithAssociations = new ArrayList<SpecimenOrObservationBase<?>>();
-                if(!assignmentStatus.equals(AssignmentStatus.ALL_SPECIMENS)){
-                    for (SpecimenOrObservationBase specimenOrObservationBase : occurrences) {
-                        Collection<TaxonBase<?>> associatedTaxa = listAssociatedTaxa(specimenOrObservationBase, null, null, null, null);
-                        if(!associatedTaxa.isEmpty()){
-                            specimenWithAssociations.add(specimenOrObservationBase);
-                        }
+                    occurrenceConfig.getOrderHints(), occurrenceConfig.getPropertyPaths());
+            occurrences.addAll(foundOccurrences);
+            occurrences = filterOccurencesByAssignmentAndHierarchy(occurrenceConfig, occurrences, taxon, taxonName);
+
+            return new DefaultPagerImpl<>(config.getPageNumber(), occurrences.size(), config.getPageSize(), (List<S>)occurrences);
+        }
+        return super.findByTitle(config);
+    }
+
+    private List<SpecimenOrObservationBase> filterOccurencesByAssignmentAndHierarchy(
+            FindOccurrencesConfigurator occurrenceConfig, List<SpecimenOrObservationBase> occurrences, Taxon taxon,
+            TaxonName taxonName) {
+        //filter out (un-)assigned specimens
+        if(taxon==null && taxonName==null){
+            AssignmentStatus assignmentStatus = occurrenceConfig.getAssignmentStatus();
+            List<SpecimenOrObservationBase> specimenWithAssociations = new ArrayList<>();
+            if(!assignmentStatus.equals(AssignmentStatus.ALL_SPECIMENS)){
+                for (SpecimenOrObservationBase specimenOrObservationBase : occurrences) {
+                    boolean includeUnpublished = true;  //TODO not sure if this is correct, maybe we have to propagate publish flag to higher methods.
+                    Collection<TaxonBase<?>> associatedTaxa = listAssociatedTaxa(specimenOrObservationBase,
+                            includeUnpublished, null, null, null, null);
+                    if(!associatedTaxa.isEmpty()){
+                        specimenWithAssociations.add(specimenOrObservationBase);
                     }
                 }
-                if(assignmentStatus.equals(AssignmentStatus.UNASSIGNED_SPECIMENS)){
-                    occurrences.removeAll(specimenWithAssociations);
-                }
-                if(assignmentStatus.equals(AssignmentStatus.ASSIGNED_SPECIMENS)){
-                    occurrences = new ArrayList<SpecimenOrObservationBase>(specimenWithAssociations);
-                }
             }
-            // indirectly associated specimens
-            List<SpecimenOrObservationBase> indirectlyAssociatedOccurrences = new ArrayList<SpecimenOrObservationBase>(occurrences);
-            if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
-                for (SpecimenOrObservationBase specimen : occurrences) {
-                    List<SpecimenOrObservationBase<?>> allHierarchyDerivates = getAllHierarchyDerivatives(specimen);
-                    for (SpecimenOrObservationBase<?> specimenOrObservationBase : allHierarchyDerivates) {
-                        if(!occurrences.contains(specimenOrObservationBase)){
-                            indirectlyAssociatedOccurrences.add(specimenOrObservationBase);
-                        }
+            if(assignmentStatus.equals(AssignmentStatus.UNASSIGNED_SPECIMENS)){
+                occurrences.removeAll(specimenWithAssociations);
+            }
+            if(assignmentStatus.equals(AssignmentStatus.ASSIGNED_SPECIMENS)){
+                occurrences = new ArrayList<>(specimenWithAssociations);
+            }
+        }
+        // indirectly associated specimens
+        if(occurrenceConfig.isRetrieveIndirectlyAssociatedSpecimens()){
+            List<SpecimenOrObservationBase> indirectlyAssociatedOccurrences = new ArrayList<>(occurrences);
+            for (SpecimenOrObservationBase<?> specimen : occurrences) {
+                List<SpecimenOrObservationBase<?>> allHierarchyDerivates = getAllHierarchyDerivatives(specimen);
+                for (SpecimenOrObservationBase<?> specimenOrObservationBase : allHierarchyDerivates) {
+                    if(!occurrences.contains(specimenOrObservationBase)){
+                        indirectlyAssociatedOccurrences.add(specimenOrObservationBase);
                     }
                 }
-                occurrences = indirectlyAssociatedOccurrences;
             }
-
-            return new DefaultPagerImpl<SpecimenOrObservationBase>(config.getPageNumber(), occurrences.size(), config.getPageSize(), occurrences);
+            occurrences = indirectlyAssociatedOccurrences;
         }
-        return super.findByTitle(config);
+        return occurrences;
     }
 
     @Override
     public List<SpecimenOrObservationBase<?>> getAllHierarchyDerivatives(SpecimenOrObservationBase<?> specimen){
-        List<SpecimenOrObservationBase<?>> allHierarchyDerivatives = new ArrayList<SpecimenOrObservationBase<?>>();
-        Collection<FieldUnit> fieldUnits = getFieldUnits(specimen.getUuid());
+        List<SpecimenOrObservationBase<?>> allHierarchyDerivatives = new ArrayList<>();
+        Collection<FieldUnit> fieldUnits = findFieldUnits(specimen.getUuid(), null);
         if(fieldUnits.isEmpty()){
             allHierarchyDerivatives.add(specimen);
             allHierarchyDerivatives.addAll(getAllChildDerivatives(specimen));
@@ -1495,7 +1704,10 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 
     @Override
     public List<DerivedUnit> getAllChildDerivatives(SpecimenOrObservationBase<?> specimen){
-        List<DerivedUnit> childDerivate = new ArrayList<DerivedUnit>();
+        if (specimen == null){
+            return null;
+        }
+        List<DerivedUnit> childDerivate = new ArrayList<>();
         Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();
         for (DerivationEvent derivationEvent : derivationEvents) {
             Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
@@ -1508,8 +1720,25 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     }
 
     @Override
-    public int countOccurrences(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
-        return findByTitle(config).getRecords().size();
+    public long countOccurrences(IIdentifiableEntityServiceConfigurator<SpecimenOrObservationBase> config){
+        return countByTitle(config);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<FieldUnit> findFieldUnitsForGatheringEvent(UUID gatheringEventUuid) {
+        return dao.findFieldUnitsForGatheringEvent(gatheringEventUuid, null, null, null, null);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<Point> findPointsForFieldUnitList(List<UUID> fieldUnitUuids) {
+
+        return dao.findPointsForFieldUnitList(fieldUnitUuids);
+    }
 }