- commented unused fields of DeleteResult
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / OccurrenceServiceImpl.java
index 300c3d6314a6c2b9564a21970ded6bbd47d0fc11..74b2b6cb5dbc774af0300c5aa9167d1506d8fa5f 100644 (file)
@@ -12,11 +12,13 @@ package eu.etaxonomy.cdm.api.service;
 \r
 import java.io.IOException;\r
 import java.net.URI;\r
+import java.net.URISyntaxException;\r
 import java.util.ArrayList;\r
 import java.util.Arrays;\r
 import java.util.Collection;\r
 import java.util.HashMap;\r
 import java.util.HashSet;\r
+import java.util.LinkedHashSet;\r
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Map.Entry;\r
@@ -39,7 +41,12 @@ import org.springframework.transaction.annotation.Transactional;
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;\r
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;\r
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;\r
+import eu.etaxonomy.cdm.api.service.DeleteResult.DeleteStatus;\r
+import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;\r
 import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO;\r
+import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO.ContigFile;\r
+import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO.MolecularData;\r
+import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;\r
 import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;\r
 import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
@@ -55,22 +62,30 @@ import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
 import eu.etaxonomy.cdm.model.CdmBaseType;\r
 import eu.etaxonomy.cdm.model.agent.AgentBase;\r
+import eu.etaxonomy.cdm.model.common.CdmBase;\r
 import eu.etaxonomy.cdm.model.common.DefinedTerm;\r
 import eu.etaxonomy.cdm.model.common.DefinedTermBase;\r
+import eu.etaxonomy.cdm.model.common.ICdmBase;\r
 import eu.etaxonomy.cdm.model.common.Language;\r
 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;\r
 import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
+import eu.etaxonomy.cdm.model.description.DescriptionElementSource;\r
 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;\r
+import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
 import eu.etaxonomy.cdm.model.location.Country;\r
 import eu.etaxonomy.cdm.model.location.NamedArea;\r
 import eu.etaxonomy.cdm.model.media.Media;\r
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
 import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;\r
+import eu.etaxonomy.cdm.model.media.MediaUtils;\r
 import eu.etaxonomy.cdm.model.molecular.DnaSample;\r
 import eu.etaxonomy.cdm.model.molecular.Sequence;\r
+import eu.etaxonomy.cdm.model.molecular.SingleRead;\r
+import eu.etaxonomy.cdm.model.name.NameTypeDesignation;\r
 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;\r
 import eu.etaxonomy.cdm.model.name.TaxonNameBase;\r
+import eu.etaxonomy.cdm.model.name.TypeDesignationBase;\r
 import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;\r
 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;\r
@@ -82,10 +97,10 @@ import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
 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.persistence.dao.common.ICdmGenericDao;\r
 import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;\r
 import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;\r
 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;\r
-import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;\r
 import eu.etaxonomy.cdm.persistence.query.OrderHint;\r
 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;\r
 \r
@@ -108,6 +123,12 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     @Autowired\r
     private ITaxonService taxonService;\r
 \r
+    @Autowired\r
+    private ITermService termService;\r
+\r
+    @Autowired\r
+    private INameService nameService;\r
+\r
     @Autowired\r
     private ISequenceService sequenceService;\r
 \r
@@ -115,10 +136,10 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     private AbstractBeanInitializer beanInitializer;\r
 \r
     @Autowired\r
-    private ITaxonDao taxonDao;\r
+    private ILuceneIndexToolProvider luceneIndexToolProvider;\r
 \r
     @Autowired\r
-    private ILuceneIndexToolProvider luceneIndexToolProvider;\r
+    private ICdmGenericDao genericDao;\r
 \r
 \r
     public OccurrenceServiceImpl() {\r
@@ -303,7 +324,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
 \r
         if(!getSession().contains(associatedTaxon)){\r
-            associatedTaxon = (Taxon) taxonDao.load(associatedTaxon.getUuid());\r
+            associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());\r
         }\r
 \r
         Set<FieldUnit> fieldUnits = new HashSet<FieldUnit>();\r
@@ -317,7 +338,6 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 \r
     @Override\r
     public DerivateHierarchyDTO assembleDerivateHierarchyDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid){\r
-        final String separator = ", ";\r
 \r
         if(!getSession().contains(fieldUnit)){\r
             fieldUnit = (FieldUnit) load(fieldUnit.getUuid());\r
@@ -347,7 +367,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             //Collection\r
             final AgentBase collector = gatheringEvent.getCollector();\r
             final String fieldNumber = fieldUnit.getFieldNumber();\r
-            dto.setCollection((collector!=null?collector:"") + " " + (fieldNumber!=null?fieldNumber:""));\r
+            dto.setCollection(((collector!=null?collector:"") + " " + (fieldNumber!=null?fieldNumber:"")).trim());\r
             //Date\r
             final Partial gatheringDate = gatheringEvent.getGatheringDate();\r
             dto.setDate(gatheringDate!=null?gatheringDate.toString():"");\r
@@ -359,8 +379,11 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 \r
         Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();\r
         getDerivedUnitsFor(fieldUnit, derivedUnits);\r
+\r
         //Herbaria map\r
         Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();\r
+        //List of accession numbers for citation\r
+        List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();\r
 \r
         //iterate over sub derivates\r
         for (DerivedUnit derivedUnit : derivedUnits) {\r
@@ -389,14 +412,44 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                 dto.addTypes(typeStatus, currentAccessionNumber);\r
             }\r
             //assemble molecular data\r
-            if(derivedUnit instanceof DnaSample){//.getRecordBasis()==SpecimenOrObservationType.DnaSample){\r
-                dto.setHasDna(true);\r
-\r
-                DnaSample dna = (DnaSample)derivedUnit;\r
-                for(Sequence sequence:dna.getSequences()){\r
-                    final URI boldUri = sequence.getBoldUri();\r
-                    final DefinedTerm dnaMarker = sequence.getDnaMarker();\r
-                    dto.addMolecularData(boldUri!=null?boldUri.toString():"", dnaMarker!=null?dnaMarker.getLabel():"[no marker]");\r
+            //pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...\r
+            if(derivedUnit instanceof DnaSample){\r
+                if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.TissueSample){\r
+                    //TODO implement TissueSample assembly for web service\r
+                }\r
+                if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.DnaSample){\r
+\r
+                    DnaSample dna = (DnaSample)derivedUnit;\r
+                    if(!dna.getSequences().isEmpty()){\r
+                        dto.setHasDna(true);\r
+                    }\r
+                    for(Sequence sequence:dna.getSequences()){\r
+                        URI boldUri = null;\r
+                        try {\r
+                            boldUri = sequence.getBoldUri();\r
+                        } catch (URISyntaxException e1) {\r
+                            logger.error("Could not create BOLD URI", e1);\r
+                        }\r
+                        final DefinedTerm dnaMarker = sequence.getDnaMarker();\r
+                        MolecularData molecularData = dto.addProviderLink(boldUri!=null?boldUri:null,dnaMarker!=null?dnaMarker.getLabel():"[no marker]");\r
+\r
+                        //contig file FIXME show primer although contig not present?\r
+                        if(sequence.getContigFile()!=null){\r
+                            MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());\r
+                            if(contigMediaRepresentationPart!=null){\r
+                                ContigFile contigFile = molecularData.addContigFile(contigMediaRepresentationPart.getUri(), "contig");\r
+                                //primer files\r
+                                if(sequence.getSingleReads()!=null){\r
+                                    for (SingleRead singleRead : sequence.getSingleReads()) {\r
+                                        MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());\r
+                                        if(pherogramMediaRepresentationPart!=null){\r
+                                            contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "primer");\r
+                                        }\r
+                                    }\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
                 }\r
             }\r
             //assemble media data\r
@@ -405,35 +458,35 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                 MediaSpecimen media = (MediaSpecimen)derivedUnit;\r
                 String mediaUriString = getMediaUriString(media);\r
                 if(media.getKindOfUnit()!=null){\r
+                    //specimen scan\r
                     if(media.getKindOfUnit().getUuid().equals(UUID.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))){\r
                         dto.setHasSpecimenScan(true);\r
-                        if(mediaUriString!=null){\r
                             final String imageLinkText = currentHerbarium+" "+currentAccessionNumber;\r
-                            dto.addSpecimenScan(mediaUriString, !imageLinkText.equals(" ")?imageLinkText:"[no accession]");\r
-                        }\r
+                            dto.addSpecimenScan(mediaUriString==null?"":mediaUriString, !imageLinkText.equals(" ")?imageLinkText:"[no accession]");\r
                     }\r
+                    //detail image\r
                     else if(media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))){\r
                         dto.setHasDetailImage(true);\r
-                        if(mediaUriString!=null){\r
-                            String motif = "";\r
-                            if(media.getMediaSpecimen()!=null && media.getMediaSpecimen().getTitle()!=null){\r
-                                motif = media.getMediaSpecimen().getTitle().getText();\r
-                            }\r
-                            dto.addDetailImage(mediaUriString, motif!=null?motif:"[no motif]");\r
+                        String motif = "";\r
+                        if(media.getMediaSpecimen()!=null && media.getMediaSpecimen().getTitle()!=null){\r
+                            motif = media.getMediaSpecimen().getTitle().getText();\r
                         }\r
+                        dto.addDetailImage(mediaUriString==null?"":mediaUriString, motif!=null?motif:"[no motif]");\r
                     }\r
                 }\r
             }\r
             //assemble preserved specimen data\r
             else if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.PreservedSpecimen){\r
-\r
+                if(!currentAccessionNumber.isEmpty()){\r
+                    preservedSpecimenAccessionNumbers.add(currentAccessionNumber);\r
+                }\r
             }\r
         }\r
 \r
+        final String separator = ", ";\r
         //assemble citation\r
         String citation = "";\r
-        citation += dto.getCountry();\r
-        citation += separator;\r
+        citation += !dto.getCountry().isEmpty()?dto.getCountry()+separator:"";\r
         if(fieldUnit.getGatheringEvent()!=null){\r
             if(fieldUnit.getGatheringEvent().getLocality()!=null){\r
                 citation += fieldUnit.getGatheringEvent().getLocality().getText();\r
@@ -448,10 +501,18 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
                 citation += separator;\r
             }\r
         }\r
-        citation += dto.getCollection();\r
-        if(citation.endsWith(separator)){\r
-            citation = citation.substring(0, citation.length()-separator.length());\r
+        citation += !dto.getCollection().isEmpty()?dto.getCollection():"";\r
+        if(!preservedSpecimenAccessionNumbers.isEmpty()){\r
+            citation += " (";\r
+            for(String accessionNumber:preservedSpecimenAccessionNumbers){\r
+                if(!accessionNumber.isEmpty()){\r
+                    citation += accessionNumber+separator;\r
+                }\r
+            }\r
+            citation = removeTail(citation, separator);\r
+            citation += ")";\r
         }\r
+        citation = removeTail(citation, separator);\r
         dto.setCitation(citation);\r
 \r
         //assemble herbaria string\r
@@ -466,13 +527,25 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
             }\r
             herbariaString += separator;\r
         }\r
-        if(herbariaString.endsWith(separator)){\r
-            herbariaString = herbariaString.substring(0, herbariaString.length()-separator.length());\r
-        }\r
+        herbariaString = removeTail(herbariaString, separator);\r
         dto.setHerbarium(herbariaString);\r
+\r
         return dto;\r
     }\r
 \r
+\r
+    /**\r
+     * @param string\r
+     * @param tail\r
+     * @return\r
+     */\r
+    private String removeTail(String string, final String tail) {\r
+        if(string.endsWith(tail)){\r
+            string = string.substring(0, string.length()-tail.length());\r
+        }\r
+        return string;\r
+    }\r
+\r
     private String getMediaUriString(MediaSpecimen mediaSpecimen){\r
         String mediaUri = null;\r
         Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();\r
@@ -514,7 +587,7 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 //        Integer start = PagerUtils.startFor(pageSize, pageNumber);\r
 \r
         if(!getSession().contains(associatedTaxon)){\r
-            associatedTaxon = (Taxon) taxonDao.load(associatedTaxon.getUuid());\r
+            associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());\r
         }\r
 \r
         if(includeRelationships != null) {\r
@@ -535,18 +608,15 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
 \r
     }\r
 \r
-    /* (non-Javadoc)\r
-     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#pageByAssociatedTaxon(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
-     */\r
-    @SuppressWarnings("unchecked")\r
+\r
     @Override\r
     public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,\r
             String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {\r
 \r
         UUID uuid = UUID.fromString(taxonUUID);\r
-        Taxon tax = (Taxon) taxonDao.load(uuid);\r
+        Taxon tax = (Taxon) taxonService.load(uuid);\r
        //TODO REMOVE NULL STATEMENT\r
-type=null;\r
+        type=null;\r
         return pageByAssociatedTaxon( type,includeRelationships,tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths );\r
 \r
     }\r
@@ -715,11 +785,302 @@ type=null;
             from.removeDerivationEvent(eventToRemove);\r
             saveOrUpdate(from);\r
             //add new derivation event to target\r
-            to.addDerivationEvent(DerivationEvent.NewSimpleInstance(to, derivate, eventToRemove==null?null:eventToRemove.getType()));\r
+            DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, eventToRemove==null?null:eventToRemove.getType());\r
+            to.addDerivationEvent(derivedFromNewOriginalEvent);\r
+            derivate.setDerivedFrom(derivedFromNewOriginalEvent);\r
             saveOrUpdate(to);\r
             return true;\r
         }\r
         return false;\r
     }\r
 \r
+    @Override\r
+    public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen){\r
+        //potential fields that are not persisted cascadingly\r
+        /*\r
+         * SOOB\r
+        -DescriptionBase\r
+        -determinations\r
+        --modifier TERM\r
+        -kindOfUnit TERM\r
+        -lifeStage TERM\r
+        -sex TERM\r
+\r
+        FieldUnit\r
+        -GatheringEvent\r
+        --Country TERM\r
+        --CollectingAreas TERM\r
+\r
+        DerivedUnit\r
+        -collection\r
+        --institute\r
+        ---types TERM\r
+        -preservationMethod\r
+        --medium TERM\r
+        -storedUnder CDM TaxonNameBase\r
+        */\r
+\r
+        Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();\r
+\r
+        //Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)\r
+\r
+        //FieldUnit\r
+        if(specimen instanceof FieldUnit){\r
+            nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements((FieldUnit)specimen));\r
+        }\r
+        //DerivedUnit\r
+        else if(specimen instanceof DerivedUnit){\r
+            DerivedUnit derivedUnit = (DerivedUnit)specimen;\r
+            if(derivedUnit.getDerivedFrom()!=null){\r
+                Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();\r
+                getFieldUnits(derivedUnit, fieldUnits);\r
+                for(FieldUnit fieldUnit:fieldUnits){\r
+                    nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));\r
+                }\r
+            }\r
+        }\r
+        return nonCascadedCdmEntities;\r
+    }\r
+\r
+    private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit){\r
+        //get non cascaded element on SpecimenOrObservationBase level\r
+        Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);\r
+\r
+        //get FieldUnit specific elements\r
+        GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();\r
+        if(gatheringEvent!=null){\r
+            //country\r
+            if(gatheringEvent.getCountry()!=null){\r
+                nonCascadedCdmEntities.add(gatheringEvent.getCountry());\r
+            }\r
+            //collecting areas\r
+            for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {\r
+                nonCascadedCdmEntities.add(namedArea);\r
+            }\r
+        }\r
+        for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {\r
+            for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {\r
+                nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));\r
+            }\r
+        }\r
+        return nonCascadedCdmEntities;\r
+    }\r
+\r
+    private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit){\r
+        //get non cascaded element on SpecimenOrObservationBase level\r
+        Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);\r
+\r
+        //get DerivedUnit specific elements\r
+        if(derivedUnit.getCollection()!=null && derivedUnit.getCollection().getInstitute()!=null){\r
+            for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {\r
+                nonCascadedCdmEntities.add(type);\r
+            }\r
+        }\r
+        if(derivedUnit.getPreservation()!=null && derivedUnit.getPreservation().getMedium()!=null){\r
+            nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());\r
+        }\r
+        if(derivedUnit.getStoredUnder()!=null){\r
+            nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());\r
+        }\r
+        return nonCascadedCdmEntities;\r
+    }\r
+\r
+    /**\r
+     * @param specimen\r
+     * @return\r
+     */\r
+    private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(\r
+            SpecimenOrObservationBase<?> specimen) {\r
+        Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();\r
+        //scan SpecimenOrObservationBase\r
+        for(DeterminationEvent determinationEvent:specimen.getDeterminations()){\r
+            //modifier\r
+            if(determinationEvent.getModifier()!=null){\r
+                nonCascadedCdmEntities.add(determinationEvent.getModifier());\r
+            }\r
+        }\r
+        //kindOfUnit\r
+        if(specimen.getKindOfUnit()!=null){\r
+            nonCascadedCdmEntities.add(specimen.getKindOfUnit());\r
+        }\r
+        //lifeStage\r
+        if(specimen.getLifeStage()!=null){\r
+            nonCascadedCdmEntities.add(specimen.getLifeStage());\r
+        }\r
+        //sex\r
+        if(specimen.getSex()!=null){\r
+            nonCascadedCdmEntities.add(specimen.getSex());\r
+        }\r
+        return nonCascadedCdmEntities;\r
+    }\r
+\r
+\r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#delete(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator)\r
+     */\r
+    @Override\r
+    public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {\r
+        DeleteResult deleteResult = new DeleteResult();\r
+        //check for derivation events\r
+        Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();\r
+        for (DerivationEvent derivationEvent : derivationEvents) {\r
+            if(!derivationEvent.getDerivatives().isEmpty()){\r
+                deleteResult.setAbort();\r
+                deleteResult.addException(new ReferencedObjectUndeletableException("Derivate with children cannot be deleted."));\r
+                return deleteResult;\r
+            }\r
+        }\r
+        //check for original (parent derivate)\r
+        if(specimen instanceof DerivedUnit){\r
+            DerivationEvent derivedFromEvent = ((DerivedUnit) specimen).getDerivedFrom();\r
+            if(derivedFromEvent!=null){\r
+                derivedFromEvent.removeDerivative((DerivedUnit) specimen);\r
+            }\r
+        }\r
+        //check for IndividualsAssociation (e.g. in TaxonDescriptions)\r
+        Collection<TaxonBase<?>> associatedTaxa = listAssociatedTaxa(specimen, null, null, null, null);\r
+        if(!associatedTaxa.isEmpty()){\r
+            if(config.isDeleteFromIndividualsAssociation()){\r
+                for (TaxonBase<?> taxonBase : associatedTaxa) {\r
+                    if(taxonBase instanceof Taxon){\r
+                        Set<TaxonDescription> descriptions = ((Taxon) taxonBase).getDescriptions();\r
+                        for (TaxonDescription taxonDescription : descriptions) {\r
+                            Set<DescriptionElementBase> elements = taxonDescription.getElements();\r
+                            for (DescriptionElementBase descriptionElementBase : elements) {\r
+                                if(descriptionElementBase instanceof IndividualsAssociation){\r
+                                    IndividualsAssociation individualsAssociation = (IndividualsAssociation) descriptionElementBase;\r
+                                    if(individualsAssociation.getAssociatedSpecimenOrObservation().equals(specimen)){\r
+                                        individualsAssociation.setAssociatedSpecimenOrObservation(null);\r
+                                    }\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+            else{\r
+                deleteResult.addRelatedObjects(new HashSet<CdmBase>(associatedTaxa));\r
+                deleteResult.setAbort();\r
+                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated with taxa."));\r
+                return deleteResult;\r
+            }\r
+        }\r
+        //check for TypeDesignations\r
+        Collection<TaxonBase<?>> typedTaxa = listTypedTaxa(specimen, null, null, null, null);\r
+        if(!typedTaxa.isEmpty()){\r
+            if(config.isdeleteFromTypeDesignation()){\r
+                for (TaxonBase<?> taxonBase : typedTaxa) {\r
+                    if(taxonBase.getName()!=null){\r
+                        Set<TypeDesignationBase> typeDesignations = taxonBase.getName().getTypeDesignations();\r
+                        for (TypeDesignationBase typeDesignationBase : typeDesignations) {\r
+                            if(typeDesignationBase instanceof SpecimenTypeDesignation){\r
+                                ((SpecimenTypeDesignation) typeDesignationBase).setTypeSpecimen(null);\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+            else{\r
+                deleteResult.addRelatedObjects(new HashSet<CdmBase>(typedTaxa));\r
+                deleteResult.setAbort();\r
+                deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));\r
+                return deleteResult;\r
+            }\r
+        }\r
+        if(!config.isDeleteChildren()){\r
+            Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(specimen);\r
+            for (CdmBase referencingObject : referencingObjects){\r
+                //DerivedUnit?.storedUnder\r
+                if (referencingObject.isInstanceOf(DerivedUnit.class)){\r
+                    String message = "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";\r
+                    message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnit.class).getTitleCache());\r
+                }\r
+                //DescriptionElementSource#nameUsedInSource\r
+                if (referencingObject.isInstanceOf(DescriptionElementSource.class)){\r
+                    String message = "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";\r
+                }\r
+                //NameTypeDesignation#typeName\r
+                if (referencingObject.isInstanceOf(NameTypeDesignation.class)){\r
+                    String message = "Name can't be deleted as it is used as a name type in a NameTypeDesignation";\r
+                }\r
+            }\r
+            deleteResult = delete(specimen);\r
+        }\r
+        else{\r
+            //TODO implement deep delete\r
+        }\r
+        return deleteResult;\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#deleteDerivateHierarchy(eu.etaxonomy.cdm.model.common.ICdmBase)\r
+     */\r
+    @Override\r
+    public DeleteResult deleteDerivateHierarchy(ICdmBase from, SpecimenDeleteConfigurator config) {\r
+        DeleteResult deleteResult = new DeleteResult();\r
+        if(from instanceof Sequence){\r
+            Sequence sequence = (Sequence)from;\r
+            sequence.getDnaSample().removeSequence(sequence);\r
+            deleteResult.setStatus(DeleteStatus.OK);\r
+        }\r
+        else if(from instanceof SpecimenOrObservationBase<?>)  {\r
+            deleteResult = delete((SpecimenOrObservationBase<?>) from, config);\r
+        }\r
+        return deleteResult;\r
+    }\r
+\r
+    private Set<ICdmBase> collectEntitiesToDelete(ICdmBase entity){\r
+        Set<ICdmBase> entitiesToDelete = new LinkedHashSet<ICdmBase>();\r
+\r
+        if(entity instanceof SpecimenOrObservationBase<?>){\r
+            SpecimenOrObservationBase<?> specimen = (SpecimenOrObservationBase<?>) entity;\r
+            if(entity instanceof DerivedUnit){\r
+                DerivedUnit derivedUnit = (DerivedUnit)entity;\r
+                DerivationEvent derivedFrom = derivedUnit.getDerivedFrom();\r
+                Set<SpecimenOrObservationBase> originals = derivedFrom.getOriginals();\r
+                for (SpecimenOrObservationBase<?> original: originals) {\r
+                        original.removeDerivationEvent(derivedFrom);\r
+//                        saveOrUpdate(original);\r
+                }\r
+            }\r
+            if(entity instanceof DnaSample && ((DnaSample) entity).getRecordBasis()==SpecimenOrObservationType.DnaSample){\r
+                DnaSample dnaSample = (DnaSample)entity;\r
+                for (Sequence sequence : dnaSample.getSequences()) {\r
+                    entitiesToDelete.addAll(collectEntitiesToDelete(sequence));\r
+                    dnaSample.removeSequence(sequence);\r
+//                    saveOrUpdate(dnaSample);\r
+                }\r
+            }\r
+            Set<DerivationEvent> derivationEvents = specimen.getDerivationEvents();\r
+            for (DerivationEvent derivationEvent : derivationEvents) {\r
+                for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {\r
+                    entitiesToDelete.addAll(collectEntitiesToDelete(derivedUnit));\r
+                }\r
+            }\r
+        }\r
+        else if(entity instanceof Sequence){\r
+            Sequence sequence = (Sequence)entity;\r
+            for (SingleRead singleRead : sequence.getSingleReads()) {\r
+                entitiesToDelete.addAll(collectEntitiesToDelete(singleRead));\r
+                sequence.removeSingleRead(singleRead);\r
+            }\r
+//            sequenceService.saveOrUpdate(sequence);\r
+        }\r
+        entitiesToDelete.add(entity);\r
+        return entitiesToDelete;\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listAssociatedTaxa(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)\r
+     */\r
+    @Override\r
+    public Collection<TaxonBase<?>> listAssociatedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        return dao.listAssociatedTaxa(specimen, null, null, null, null);\r
+    }\r
+\r
+    @Override\r
+    public Collection<TaxonBase<?>> listTypedTaxa(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {\r
+        return dao.listTypedTaxa(specimen, limit, start, orderHints, propertyPaths);\r
+    }\r
+\r
 }\r